summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Holzer <mholzer@gentoo.org>2003-12-07 10:56:56 +0000
committerMartin Holzer <mholzer@gentoo.org>2003-12-07 10:56:56 +0000
commit58e128cec8d7e2675cf83c8337fa8f3829282a7f (patch)
tree32cdc73a36b92fdcf0f08d09b08b1187cfe50ba4 /net-mail
parentAdded to ~ppc (diff)
downloadhistorical-58e128cec8d7e2675cf83c8337fa8f3829282a7f.tar.gz
historical-58e128cec8d7e2675cf83c8337fa8f3829282a7f.tar.bz2
historical-58e128cec8d7e2675cf83c8337fa8f3829282a7f.zip
cleanup
Diffstat (limited to 'net-mail')
-rw-r--r--net-mail/exim/Manifest15
-rw-r--r--net-mail/exim/files/exiscan-acl-4.20-09.patch6707
2 files changed, 7 insertions, 6715 deletions
diff --git a/net-mail/exim/Manifest b/net-mail/exim/Manifest
index f230c0738f51..97df6c148bcc 100644
--- a/net-mail/exim/Manifest
+++ b/net-mail/exim/Manifest
@@ -3,14 +3,13 @@ MD5 b4546401419ab569939d6a7b97b117a0 exim-4.10.ebuild 6209
MD5 552b6ba253f6d49c3ae0a92e3c867271 exim-4.12.ebuild 5436
MD5 cb909c0ba85b24cd0c917682f780bee7 exim-4.14.ebuild 5483
MD5 6a279805f089c006ac5a0c242d68d86c exim-4.20-r1.ebuild 6235
-MD5 3cf81a767f62a64891a39ee698821f05 exim-4.20-r2.ebuild 6328
MD5 fb49b47a884b048542837810acb08633 exim-4.20.ebuild 5569
+MD5 ea63797589f6933c74605b04fe13c299 metadata.xml 725
+MD5 3cf81a767f62a64891a39ee698821f05 exim-4.20-r2.ebuild 6328
MD5 76850d186609333f5b5858a5d512a364 exim-4.21.ebuild 6141
MD5 e5754fa101873ae8932f66793cc50626 exim-4.22.ebuild 6356
-MD5 ea63797589f6933c74605b04fe13c299 metadata.xml 725
MD5 1cbb9e2c12ce43f00937397e98cdac76 exim-4.24-r1.ebuild 6365
MD5 5a76bab84c947dc380e3ce396016ea35 exim-4.24.ebuild 6356
-MD5 117455c076e246e7c02d5fa464dd4be7 files/digest-exim-4.24 132
MD5 68fc403ba2c98ccba281939085cb9052 files/auth_conf.sub 775
MD5 0cb2ffe88c81fd7ac8429b5a19d58b35 files/configure 16346
MD5 34def7b529693beda5b84c422d25a878 files/digest-exim-4.10 128
@@ -18,17 +17,17 @@ MD5 100ab1bbdfea50083ecce4bf78af5cc9 files/digest-exim-4.12 129
MD5 091d3610d9a2a0b879f543cc070ef933 files/digest-exim-4.14 128
MD5 04ba8d65b73d23eb58c6d3e4accbed7f files/digest-exim-4.20 198
MD5 04ba8d65b73d23eb58c6d3e4accbed7f files/digest-exim-4.20-r1 198
-MD5 0cc15aecabaeace6ff4cdd1a462b9eb0 files/digest-exim-4.20-r2 62
-MD5 e62c9a744fd2c944af3dbc881156574b files/digest-exim-4.21 132
-MD5 9be54e4b44d4b7b6899302a1f3f74007 files/digest-exim-4.22 132
MD5 369b42cafcbe5631c2d03cbbfd4aeddd files/exim-4.10-gentoo.diff 1889
-MD5 5d5aabea7d56a91803df1312c04d32c0 files/exim-4.14-tail.patch 446
MD5 622b726ea7b32aae93a8fe9f3c2af9cd files/exim-4.20-maildir.patch 478
MD5 f442b68d435598831bab8536ade071b8 files/exim.confd 62
MD5 f0676c8d629efaa211aebbe01750eb41 files/exim.rc5 585
MD5 c90e5fcc2a5dfdd3095c5619d9dcc389 files/exim.rc6 509
-MD5 5898fa2e00e85c771cffe741f3198c07 files/exiscan-acl-4.20-09.patch 263216
MD5 eb249c90af3ab11e5a4d307e184a75ac files/exiscan.conf 22113
MD5 d230e0fa45f2b65d5bc50c0879c40148 files/pam.d-exim 101
MD5 0883fe67a34142a57e6f39ed9419cbee files/system_filter.exim 8118
+MD5 5d5aabea7d56a91803df1312c04d32c0 files/exim-4.14-tail.patch 446
+MD5 0cc15aecabaeace6ff4cdd1a462b9eb0 files/digest-exim-4.20-r2 62
+MD5 e62c9a744fd2c944af3dbc881156574b files/digest-exim-4.21 132
+MD5 9be54e4b44d4b7b6899302a1f3f74007 files/digest-exim-4.22 132
+MD5 117455c076e246e7c02d5fa464dd4be7 files/digest-exim-4.24 132
MD5 117455c076e246e7c02d5fa464dd4be7 files/digest-exim-4.24-r1 132
diff --git a/net-mail/exim/files/exiscan-acl-4.20-09.patch b/net-mail/exim/files/exiscan-acl-4.20-09.patch
deleted file mode 100644
index 42d62d26be3f..000000000000
--- a/net-mail/exim/files/exiscan-acl-4.20-09.patch
+++ /dev/null
@@ -1,6707 +0,0 @@
-diff -urN exim-4.20-orig/OS/Makefile-Base exim-4.20/OS/Makefile-Base
---- exim-4.20-orig/OS/Makefile-Base Mon May 12 15:39:15 2003
-+++ exim-4.20/OS/Makefile-Base Wed May 14 12:07:55 2003
-@@ -246,14 +246,14 @@
- # Targets for final binaries; the main one has a build number which is
- # updated each time. We don't bother with that for the auxiliaries.
-
--OBJ_EXIM = acl.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
-+OBJ_EXIM = acl.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o demime.o \
- directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \
- filtertest.o globals.o \
-- header.o host.o ip.o log.o lss.o match.o moan.o \
-+ header.o host.o ip.o log.o lss.o malware.o match.o moan.o \
- os.o parse.o queue.o \
-- rda.o readconf.o receive.o retry.o rewrite.o \
-- route.o search.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
-- store.o string.o tls.o tod.o transport.o tree.o verify.o \
-+ rda.o readconf.o receive.o regex.o retry.o rewrite.o \
-+ route.o search.o smtp_in.o smtp_out.o spam.o spool_in.o spool_mbox.o spool_out.o \
-+ store.o string.o tls.o tnef.o tod.o transport.o tree.o verify.o \
- local_scan.o $(EXIM_PERL)
-
- exim: pcre/libpcre.a lookups/lookups.a auths/auths.a \
-@@ -465,6 +465,7 @@
- dbfn.o: $(HDRS) dbfn.c
- debug.o: $(HDRS) debug.c
- deliver.o: $(HDRS) deliver.c
-+demime.o: $(HDRS) demime.c
- directory.o: $(HDRS) directory.c
- dns.o: $(HDRS) dns.c
- enq.o: $(HDRS) enq.c
-@@ -478,6 +479,7 @@
- ip.o: $(HDRS) ip.c
- log.o: $(HDRS) log.c
- lss.o: $(HDRS) lss.c
-+malware.o: $(HDRS) malware.c
- match.o: $(HDRS) match.c
- moan.o: $(HDRS) moan.c
- os.o: $(HDRS) os.c
-@@ -486,17 +488,21 @@
- rda.o: $(HDRS) rda.c
- readconf.o: $(HDRS) readconf.c
- receive.o: $(HDRS) receive.c
-+regex.o: $(HDRS) regex.c
- retry.o: $(HDRS) retry.c
- rewrite.o: $(HDRS) rewrite.c
- route.o: $(HDRS) route.c
- search.o: $(HDRS) search.c
- smtp_in.o: $(HDRS) smtp_in.c
- smtp_out.o: $(HDRS) smtp_out.c
-+spam.o: $(HDRS) spam.c
- spool_in.o: $(HDRS) spool_in.c
-+spool_mbox.o: $(HDRS) spool_mbox.c
- spool_out.o: $(HDRS) spool_out.c
- store.o: $(HDRS) store.c
- string.o: $(HDRS) string.c
- tls.o: $(HDRS) tls.c tls-gnu.c tls-openssl.c
-+tnef.o: $(HDRS) tnef.c
- tod.o: $(HDRS) tod.c
- transport.o: $(HDRS) transport.c
- tree.o: $(HDRS) tree.c
-diff -urN exim-4.20-orig/README.EXISCAN exim-4.20/README.EXISCAN
---- exim-4.20-orig/README.EXISCAN Thu Jan 1 01:00:00 1970
-+++ exim-4.20/README.EXISCAN Wed May 14 12:04:24 2003
-@@ -0,0 +1 @@
-+Please refer to doc/exiscan-acl-spec.txt
-diff -urN exim-4.20-orig/doc/exiscan-acl-examples.txt exim-4.20/doc/exiscan-acl-examples.txt
---- exim-4.20-orig/doc/exiscan-acl-examples.txt Thu Jan 1 01:00:00 1970
-+++ exim-4.20/doc/exiscan-acl-examples.txt Fri Jun 6 13:18:19 2003
-@@ -0,0 +1,440 @@
-+--------------------------------------------------------------
-+exiscan-acl example configurations / FAQ
-+--------------------------------------------------------------
-+
-+Author: Tom Kistner <tom@duncanthrax.net>
-+
-+The exiscan website is at http://duncanthrax.net/exiscan/. You
-+will find the latest patch versions, as well as links to the
-+mailing list and its archives there.
-+
-+This document shows some example configuration snippets:
-+
-+1. Basic sitewide virus and spam filtering by rejecting
-+ matching messages after DATA.
-+2. Adding a cryptographic "checks done" header that will
-+ prevent re-scanning when the message re-visits one of your
-+ mail servers, and the body size did not change.
-+3. Marking spam-suspicious messages with extra headers and a
-+ tag in the subject.
-+4. Having more than one spam threshold to act on.
-+5. Redirecting matching messages to special accounts while
-+ preserving envelope recipient information.
-+6. A multi-profile configuration for sites where different
-+ "customers" (or users) have different content scanning
-+ preferences.
-+
-+These examples serve as a guideline and should give you some
-+pointers that can help you to create your own configuration.
-+Please do not copy these examples verbatim. You really need to
-+know what you are doing. The content scanning topic is really
-+complex and you can screw up your mail server easily if you do
-+not get it "right".
-+
-+I recommend to read the exiscan documentation on the above
-+mentioned website before trying to make sense of the following
-+examples.
-+
-+Each example shows part of a DATA ACL definition, unless
-+otherwise noted.
-+
-+--------------------------------------------------------------
-+1. Basic setup for simple site-wide filtering
-+--------------------------------------------------------------
-+The following example only shows the most basic use of the
-+exiscan content filtering features. You should see it as a
-+base that you can build on. However, it may be all you need
-+for smaller systems with only a few users.
-+
-+/* -----------------
-+# Do not scan messages submitted from our own hosts
-+# and locally submitted messages. Since the DATA ACL
-+# is not called for messages not submitted via SMTP
-+# protocols, we do not need to check for an empty
-+# host field.
-+accept hosts = 127.0.0.1:+relay_from_hosts
-+
-+# Unpack MIME containers and reject file extensions
-+# used by worms. Note that the extension list may be
-+# incomplete.
-+deny message = $found_extension files are not accepted here
-+ demime = com:vbs:bat:pif:scr
-+
-+# Reject messages that have serious MIME errors.
-+# This calls the demime condition again, but it
-+# will return cached results.
-+deny message = Serious MIME defect detected ($demime_reason)
-+ demime = *
-+ condition = ${if >{$demime_errorlevel}{2}{1}{0}}
-+
-+# Reject messages containing malware.
-+deny message = This message contains malware ($malware_name)
-+ malware = *
-+
-+# Reject spam messages. Remember to tweak your
-+# site-wide SA profile. Do not spam-scan messages
-+# larger than eighty kilobytes.
-+deny message = Classified as spam (score $spam_score)
-+ condition = ${if <{$message_size}{80k}{1}{0}}
-+ spam = nobody
-+
-+# Finally accept all other messages that have
-+# made it to this point
-+accept
-+------------------ */
-+
-+
-+
-+--------------------------------------------------------------
-+2. Adding a cryptographic "scanning done" header
-+--------------------------------------------------------------
-+
-+If you have a mail setup where the same message may pass your
-+server twice (redirects from other servers), or you have
-+multiple mail servers, you may want to make sure that each
-+message is only checked once, to save processing time. Here is
-+how to do it:
-+
-+At the very beginning of your DATA ACL, put this:
-+
-+/* -----------------
-+# Check our crytographic header. If it matches, accept
-+# the message.
-+accept condition = ${if eq {${hmac{md5}\
-+ {mysecret}\
-+ {$body_linecount}}}\
-+ {$h_X-Scan-Signature:} {1}{0}}
-+------------------ */
-+
-+At the end, just before the final "accept" verb, put this:
-+
-+/* -----------------
-+# Add the cryptographic header.
-+warn message = X-Scan-Signature: ${hmac{md5}{mysecret}\
-+ {$body_linecount}}
-+------------------ */
-+
-+Notice the two "mysecret" strings? Replace them with your own
-+secret, and don't tell anyone :) The hash also includes the
-+number of lines in the message body, to protect against
-+message "modifications".
-+
-+
-+--------------------------------------------------------------
-+3. Marking Spam messages with extra headers and subject tag
-+--------------------------------------------------------------
-+
-+Since the false positive rate with spam scanning is high
-+compared to virus scanning, it is wise to implement a scheme
-+with two thresholds, where you reject messages with high
-+scores and just mark messages with lower scores. End users can
-+then set up filters in their Mail User Agents (MUAs). Since
-+many MUAs can not filter on custom headers, it can be
-+necessary to put a "spam tag" in the subject line. Since it is
-+not (yet) possible to remove headers in Exims DATA ACL, we
-+must do this in a system filter. Please see the Exim docs on
-+how to set up a system filter.
-+
-+The following example will unconditionally put two spam
-+information headers in each message, if it is smaller than
-+eighty kilobytes:
-+
-+/* -----------------
-+# Always put X-Spam-Score header in the message.
-+# It looks like this:
-+# X-Spam-Score: 6.6 (++++++)
-+# When a MUA cannot match numbers, it can match for an
-+# equivalent number of '+' signs.
-+# The 'true' makes sure that the header is always put
-+# in, no matter what the score.
-+warn message = X-Spam-Score: $spam_score ($spam_bar)
-+ condition = ${if <{$message_size}{80k}{1}{0}}
-+ spam = nobody:true
-+
-+# Always put X-Spam-Report header in the message.
-+# This is a multiline header that informs the user
-+# which tests a message has "hit", and how much a
-+# test has contributed to the score.
-+warn message = X-Spam-Report: $spam_report
-+ condition = ${if <{$message_size}{80k}{1}{0}}
-+ spam = nobody:true
-+------------------ */
-+
-+For the subject tag, we prepare a new subject header in the
-+ACL, then swap it with the original Subject in the system
-+filter.
-+
-+In the DATA ACL, put this:
-+/* -----------------
-+warn message = X-New-Subject: *SPAM* $h_subject:
-+ spam = nobody
-+------------------ */
-+
-+In the system filter, put this:
-+/* -----------------
-+if "${if def:header_X-New-Subject: {there}}" is there
-+then
-+ headers remove subject
-+ headers add "Subject: $h_X-New-Subject:"
-+ headers remove X-New-Subject
-+endif
-+------------------ */
-+
-+
-+--------------------------------------------------------------
-+4. Defining multiple spam thresholds with different actions
-+--------------------------------------------------------------
-+If you want to mark messages if they exceed your threshold,
-+but also have a higher "cutoff" threshold where you reject
-+messages, use the example above, plus this part:
-+
-+/* -----------------
-+deny message = Spam score too high ($spam_score)
-+ condition = ${if <{$message_size}{80k}{1}{0}}
-+ spam = nobody:true
-+ condition = ${if >{$spam_score_int}{100}{1}{0}}
-+------------------ */
-+
-+The last condition is only true if the spam score exceeds 10.0
-+points (Keep in mind that $spam_score_int is the messages
-+score multiplied by ten).
-+
-+
-+
-+--------------------------------------------------------------
-+5. Redirect infected or spam messages to special accounts
-+--------------------------------------------------------------
-+Sometimes it is desirable not to reject messages, but to stop
-+them for inspection, and then decide wether to delete, bounce
-+or pass them.
-+
-+There are multiple ways to achieve this. The simplest way is
-+to freeze suspicious messages, and then thaw or bounce them
-+after a review. Here is a simple example that will freeze spam
-+suspicious messages when they exceed the SA threshold:
-+
-+/* -----------------
-+warn log_message = frozen by spam scanner, score $spam_score
-+ spam = nobody
-+ control = freeze
-+------------------ */
-+
-+Another way is to redirect suspicious messages to special
-+postmaster accounts, where they can be reviewed. This involves
-+setting up a router for these special accounts that acts on a
-+header set in the DATA ACL.
-+
-+This is the DATA ACL entry:
-+
-+/* -----------------
-+warn message = X-Redirect-To: spambox@mycompany.com
-+ spam = nobody
-+------------------ */
-+
-+This puts the target address in a special header, which can in
-+turn be read with this router:
-+
-+/* -----------------
-+scan_redirect:
-+ driver = redirect
-+ condition = ${if def:h_X-Redirect-To: {1}{0}}
-+ headers_add = X-Original-Recipient: $local_part@$domain
-+ data = $h_X-Redirect-To:
-+ headers_remove = X-Redirect-To
-+ redirect_router = my_second_router
-+------------------ */
-+
-+This router should probably be your very first one, and you
-+need to edit the last line (redirect_router = ) to replace
-+"my_second_router" with the name of your original first
-+router. Note that the original message recipient is saved in
-+the "X-Original-Recipient" header, and the X-Redirect-To
-+header line is removed.
-+
-+
-+--------------------------------------------------------------
-+6. Having multiple content scanning profiles for several
-+ users or domains.
-+--------------------------------------------------------------
-+This is one of the most often asked questions, and it also has
-+the most complicated answer. To understand the difficulties,
-+you should first remember that the exiscan facilities are run
-+in the DATA ACL. This ACL is called ONCE per message, after
-+the sending server has transmitted the end-of-data marker.
-+This gives us the very cool possibility to reject unwanted
-+messages with a 5xx error code in response. The big drawback
-+is that a message can have multiple recipients, and you can
-+only reject or accept a message for ALL recipients, not
-+individual ones.
-+
-+I will first sum up the possible solutions to this dilemma:
-+
-+ a. Make sure that each incoming message can have only one
-+ envelope recipient. This is brutal, but effective and
-+ reliably solves the problem on your end. :) Drawback:
-+ Incoming mail to multiple recipients is slowed down. The
-+ exact time depends on the retry strategies of the sending
-+ hosts.
-+
-+ b. Offer a limited number of "profiles" that your customers
-+ can subscribe to. Then, similar to a.), only accept
-+ recipients with the same profile in a single "batch", and
-+ defer the others. This does improve on the drawback of
-+ a.) a bit.
-+
-+ c. Do scanning as usual, but never reject messages in the
-+ DATA ACL. Instead put appropriate information in extra
-+ headers and query those in routers or transports later.
-+ Drawback: You'll have to send bounces yourself, and your
-+ queue will fill up with frozen bounces. Advantage: clean
-+ solution, protocol-wise.
-+
-+As you see, you can't have your cake and eat it too. Now lets
-+get into the details of each possible solution.
-+
-+a.) Making sure each incoming message that will be scanned
-+ only has one recipient.
-+
-+ To use this scheme, you must make sure that you do not use
-+ it on your +relay_from_hosts and authenticated senders.
-+ Both of these may be MUAs who cannot cope with such a
-+ thing.
-+
-+ Here is a RCPT ACL that implements the behaviour
-+ (shortened, do not copy 1:1!):
-+
-+ /* ------------
-+ acl_check_rcpt:
-+
-+ # accept local, relay-allowed
-+ # and authenticated sources
-+
-+ accept hosts = :
-+ deny local_parts = ^.*[@%!/|]
-+ accept hosts = 127.0.0.1:+relay_from_hosts
-+ accept authenticated = *
-+
-+ # the following treat non-local,
-+ # non-authenticated sources
-+
-+ defer message = only one recipient at a time
-+ condition = ${if def:acl_m0 {1}{0}}
-+
-+ # [ .. ]
-+ # put RBLs etc. here
-+ # [ .. ]
-+
-+ accept domains = +local_domains
-+ endpass
-+ message = unknown user
-+ verify = recipient
-+ set acl_m0 = $local_part@$domain
-+
-+ accept domains = +relay_to_domains
-+ endpass
-+ message = unrouteable address
-+ verify = recipient
-+ set acl_m0 = $domain
-+
-+ deny message = relay not permitted
-+ ------------ */
-+
-+ The lines which contain acl_m0 are the important ones. The
-+ $acl_m0 variable gets set when a remote server
-+ successfully sends one RCPT. Subsequent RCPT commands are
-+ deferred if this variable is set. The $acl_m0 variable now
-+ contains the single recipient domain, which you can use in
-+ the DATA ACL to determine the scanning profile.
-+
-+ This scheme is only recommended for small servers with a
-+ low number of possible recipients, where recipients do not
-+ belong to the same organization. An example would be a
-+ multiuser shell server.
-+
-+
-+b.) Having several scanning profiles that "customers" can
-+ choose from.
-+
-+ Suppose you want to offer three profiles. Lets call them
-+ "reject-aggressive", "reject-conservative", and "warn
-+ -only". Customers can select one of the profiles for each
-+ of their domains. So you end up with a mapping like this:
-+
-+ domain-a.com: reject-aggressive
-+ domain-b.org: warn-only
-+ domain-c.net: reject-aggressive
-+ domain-d.com: reject-conservative
-+ [ .. ]
-+
-+ Suppose you put that in a file called /etc/exim/scanprefs
-+
-+ Now we make a scheme similar to a.), but we do allow more
-+ than one recipient if they have the same scanning profile
-+ than the first recipient.
-+
-+ Here is a RCPT ACL that implements the behaviour
-+ (shortened, do not copy 1:1!):
-+
-+ /* ------------
-+ acl_check_rcpt:
-+
-+ # accept local, relay-allowed and authenticated sources
-+
-+ accept hosts = :
-+ deny local_parts = ^.*[@%!/|]
-+ accept hosts = 127.0.0.1:+relay_from_hosts
-+ accept authenticated = *
-+
-+ # the following treat non-local, non-authenticated sources
-+
-+ defer message = try this address in the next batch
-+ condition = ${if eq {${acl_m0}}\
-+ {${lookup{$domain}\
-+ lsearch{/etc/exim/scanprefs}}}\
-+ {0}{1}}
-+
-+ # [ .. ]
-+ # put RBLs etc. here
-+ # [ .. ]
-+
-+ accept domains = +local_domains
-+ endpass
-+ message = unknown user
-+ verify = recipient
-+ set acl_m0 = $local_part@$domain
-+
-+ accept domains = +relay_to_domains
-+ endpass
-+ message = unrouteable address
-+ verify = recipient
-+ set acl_m0 = ${lookup{$domain}\
-+ lsearch{/etc/exim/scanprefs}}
-+
-+ deny message = relay not permitted
-+ ------------ */
-+
-+ Now a recipient address get deferred if its scan profile
-+ does not match the current batch profile. The $acl_m0
-+ variable contains the name of the profile, that can be
-+ used for processing in the DATA ACL.
-+
-+ This scheme works pretty well if you keep the number of
-+ possible profiles low, since that will prevent
-+ fragmentation of RCPT blocks.
-+
-+
-+c.) Classic content scanning without the possibility of
-+ rejects after DATA.
-+
-+ This emulates the "classic" content scanning in routers
-+ and transports. The difference is that we still do the
-+ scan in the DATA ACL, but put the outcome of each facility
-+ in message headers, that can the be evaluated in special
-+ routers, individually for each recipient.
-+
-+ A special approach can be taken for spam scanning, since
-+ the $spam_score_int variable is also available in routers
-+ and transports (it gets written to the spool files), so
-+ you do not need to put that information in a header, but
-+ rather act on $spam_score_int directly.
-+
-diff -urN exim-4.20-orig/doc/exiscan-acl-spec.txt exim-4.20/doc/exiscan-acl-spec.txt
---- exim-4.20-orig/doc/exiscan-acl-spec.txt Thu Jan 1 01:00:00 1970
-+++ exim-4.20/doc/exiscan-acl-spec.txt Mon May 26 11:24:25 2003
-@@ -0,0 +1,426 @@
-+--------------------------------------------------------------
-+The exiscan-acl patch for exim4 - Documentation
-+--------------------------------------------------------------
-+(c) Tom Kistner <tom@duncanthrax.net> 2003-????
-+License: GPL
-+
-+The exiscan-acl patch adds content scanning to the exim4 ACL
-+system. It supports the following scanning facilities:
-+
-+ - MIME unpacking, sanity checking, file extension blocking
-+ - Antivirus using 3rd party scanners
-+ - Antispam using SpamAssassin
-+ - Regular expression match against headers and body
-+
-+These facilities are hooked into exim by adding new conditions
-+to exim's ACL system. These conditions are designed to be used
-+in the acl_smtp_data ACL. It is run when the sending host has
-+completed the DATA phase and is waiting for our final response
-+to his end-of-data marker. This allows us to reject messages
-+containing unwanted content at that stage.
-+
-+The exiscan-acl patch also defines several expansion variables
-+that can be used to customise the error responses sent to the
-+remote server.
-+
-+The default exim configure file contains commented
-+configuration examples for all facilites.
-+
-+
-+0. Overall concept
-+--------------------------------------------------------------
-+
-+The exiscan-acl patch adds the following conditions
-+(facilities), which can ONLY be used in the ACL after DATA
-+(acl_smtp_data):
-+
-+- demime (MIME unpacking and file extension checks)
-+- regex (match regular expressions against message headers
-+ and body)
-+- malware (attach 3rd party virus/malware scanner)
-+- spam (attach SpamAssassin)
-+
-+Each of these facilities has its own chapter further below in
-+this document. There is also a commented sample configuration
-+in the "configure" file of the exim distribution.
-+
-+All facilites work on a MBOX copy of the message that is
-+temporarily spooled up in a file called:
-+
-+ <spool_directory>/scan/<message_id>/<message_id>.eml
-+
-+The .eml extension is a friendly hint to virus scanners that
-+they can expect an MBOX-like structure inside that file. The
-+file is only spooled up once, when the first exiscan facility
-+condition is called. Subsequent calls to exiscan conditions
-+will just open the file again. The directory is recursively
-+removed when the acl_smtp_data has finished running. When the
-+"demime" condition has been used, this directory will also
-+contain files produced by the MIME decoder.
-+
-+
-+1. The "demime" facility
-+ MIME unpacking, sanity checking and file extension blocking
-+--------------------------------------------------------------
-+
-+The demime facility unpacks MIME containers in the message. It
-+detects errors in MIME containers and can match file
-+extensions found in the message against a list. Using this
-+facility will produce additional files in the temporary scan
-+directory that contain the unpacked MIME parts of the message.
-+If you do antivirus scanning, it is recommened to use the
-+"demime" condition before the antivirus ("malware") condition.
-+
-+The condition name of this facility is "demime". On the right
-+hand side, you can pass a colon-separated list of file
-+extensions that it should match against. If one of the file
-+extensions is found, the condition will return "OK" (or
-+"true"), otherwise it will return FAIL (or "false"). If there
-+was any TEMPORARY error while demimeing (mostly "disk full"),
-+the condition will return DEFER, and the message will be
-+temporarily rejected.
-+
-+The right-hand side gets "expanded" before being treated as a
-+list, so you can have conditions and lookups there. If it
-+expands to an empty string, "false", or zero ("0"), no
-+demimeing is done and the conditions returns FALSE.
-+
-+A short example:
-+
-+/* ------------
-+deny message = Found blacklisted file attachment
-+ demime = vbs:com:bat:pif:prf:lnk
-+--------------- */
-+
-+When the condition is run, it sets up the following expansion
-+variables:
-+
-+ $demime_errorlevel When an error was detected in a MIME
-+ container, this variable contains the
-+ "severity" of the error, as an integer
-+ number. The higher the value, the
-+ more severe the error. If this
-+ variable is unset or zero, no error has
-+ occured.
-+
-+ $demime_reason When $demime_errorlevel is greater than
-+ zero, this variable contains a human
-+ -readable text string describing the
-+ MIME error that occured.
-+
-+ $found_extension When the "demime" condition returns
-+ "true", this variable contains the file
-+ extension it has found.
-+
-+Both $demime_errorlevel and $demime_reason are set with the
-+first call of the "demime" condition, and are not changed on
-+subsequent calls.
-+
-+If do not want to check for any file extensions, but rather
-+use the demime facility for unpacking or error checking
-+purposes, just pass "*" as the right-hand side value.
-+
-+Here is a more elaborate example on how to use this facility:
-+
-+/* -----------------
-+# Reject messages with serious MIME container errors
-+deny message = Found MIME error ($demime_reason).
-+ demime = *
-+ condition = ${if >{$demime_errorlevel}{2}{1}{0}}
-+
-+# Reject known virus spreading file extensions.
-+# Accepting these is pretty much braindead.
-+deny message = contains $found_extension file (blacklisted).
-+ demime = com:vbs:bat:pif:scr
-+
-+# Freeze .exe and .doc files. Postmaster can
-+# examine them and eventually thaw them up.
-+deny log_message = Another $found_extension file.
-+ demime = exe:doc
-+ control = freeze
-+--------------------- */
-+
-+
-+
-+2. The "spam" facility
-+ Antispam measures with SpamAssassin
-+--------------------------------------------------------------
-+
-+The "spam" facility calls SpamAssassin's "spamd" daemon to get
-+a spam-score and a report for the message. You must first
-+install SpamAssassin. You can get it at
-+http://www.spamassassin.org, or, if you have a working Perl
-+installation, you can use CPAN by calling
-+
-+perl -MCPAN -e 'install Mail::SpamAssassin'
-+
-+SpamAssassin has it's own set of configuration files. Please
-+review its documentation to see how you can tweak it. The
-+default installation should work nicely, however.
-+
-+After having installed and configured SpamAssassin, start the
-+"spamd" daemon. By default, it listens on 127.0.0.1, TCP port
-+783. If you use another host or port for spamd, you must set
-+the spamd_address option in Section 1 of the exim
-+configuration as follows (example):
-+
-+spamd_address = 127.0.0.1 783
-+
-+If you use the above mentioned default, you do NOT need to set
-+this option.
-+
-+To use the antispam facility, put the "spam" condition in a
-+DATA ACL block. Here is a very simple example:
-+
-+/* ---------------
-+deny message = This message was classified as SPAM
-+ spam = joe
-+---------------- */
-+
-+On the right-hand side of the spam condition, you can put the
-+username that SpamAssassin should scan for. That allows you to
-+use per-domain or per-user antispam profiles. The right-hand
-+side is expanded before being used, so you can put lookups or
-+conditions there. When the right-hand side evaluates to "0" or
-+"false", no scanning will be done and the condition will fail
-+immediately.
-+
-+If you do not want to scan for a particular user, but rather
-+use the SpamAssassin system-wide default profile, you can scan
-+for an unknown user, or simply use "nobody".
-+
-+The "spam" condition will return true if the threshold
-+specified in the user's SpamAssassin profile has been matched
-+or exceeded. If you want to use the spam condition for it's
-+side effects (see the variables below), you can make it always
-+return "true" by appending ":true" to the username.
-+
-+When the condition is run, it sets up the following expansion
-+variables:
-+
-+ $spam_score The spam score of the message, for example
-+ "3.4" or "30.5". This is useful for
-+ inclusion in log or reject messages.
-+
-+ $spam_score_int The spam score of the message, multiplied
-+ by ten, as an integer value. For example
-+ "34" or "305". This is useful for numeric
-+ comparisons in conditions. See further
-+ below for a more complicated example. This
-+ variable is special, since it is written
-+ to the spool file, so it can be used
-+ during the whole life of the message on
-+ your exim system, even in routers
-+ or transports.
-+
-+ $spam_bar A string consisting of a number of '+' or
-+ '-' characters, representing the
-+ spam_score value. A spam score of "4.4"
-+ would have a spam_bar of '++++'. This is
-+ useful for inclusion in warning headers,
-+ since MUAs can match on such strings.
-+
-+ $spam_report A multiline text table, containing the
-+ full SpamAssassin report for the message.
-+ Useful for inclusion in headers or reject
-+ messages.
-+
-+The spam condition caches its results. If you call it again
-+with the same user name, it will not really scan again, but
-+rather return the same values as before.
-+
-+Finally, here is a commented example on how to use the spam
-+condition:
-+
-+/* ----------------
-+# put headers in all messages (no matter if spam or not)
-+warn message = X-Spam-Score: $spam_score ($spam_bar)
-+ spam = nobody:true
-+warn message = X-Spam-Report: $spam_report
-+ spam = nobody:true
-+
-+# add second subject line with *SPAM* marker when message
-+# is over threshold
-+warn message = Subject: *SPAM* $h_Subject
-+ spam = nobody
-+
-+# reject spam at high scores (> 12)
-+deny message = This message scored $spam_score spam points.
-+ spam = nobody:true
-+ condition = ${if >{$spam_score_int}{120}{1}{0}}
-+----------------- */
-+
-+
-+
-+3. The "regex" facility
-+ Match headers and body lines of the message against regular
-+ expressions
-+--------------------------------------------------------------
-+
-+The "regex" condition takes one or more regular expressions as
-+arguments and matches them against the full message, that is
-+all headers and the complete body. It is particularly useful
-+to filter trash that cannot be recognized by the spam or
-+malware conditions. With large messages, this condition can be
-+fairly CPU-intensive.
-+
-+The regular expressions are matched linewise, with a maximum
-+line length of 32k characters.
-+
-+The regular expressions are passed as a colon-separated list.
-+To include a literal colon, you must double it. Since the
-+whole right-hand side string is expanded before being used,
-+you must also escape dollar ($) signs with backslashes.
-+
-+Here is a simple example:
-+
-+/* ----------------------
-+deny message = contains blacklisted regex ($regex_match_string)
-+ regex = [Mm]ortgage : URGENT BUSINESS PROPOSAL
-+----------------------- */
-+
-+The condition returns true if one of the regular expressions
-+has matched a line of the message. The $regex_match_string
-+variable is then set up and contains the matching regular
-+expression.
-+
-+
-+
-+4. The "malware" facility
-+ Scan messages for viruses using an external virus scanner
-+--------------------------------------------------------------
-+
-+This facility lets you connect virus scanner software to exim.
-+It supports a "generic" interface to scanners called via the
-+shell, and specialized interfaces for "daemon" type virus
-+scanners, who are resident in memory and thus are much faster.
-+
-+To use this facility, you MUST set the "av_scanner" option in
-+section 1 of the exim config file. It specifies the scanner
-+type to use, and any additional options it needs to run. The
-+basic syntax is as follows:
-+
-+ av_scanner = <scanner-type>:<option1>:<option2>:[...]
-+
-+The following scanner-types are supported in this release:
-+
-+ sophie Sophie is a daemon that uses Sophos' libsavi
-+ library to scan for viruses. You can get Sophie
-+ at http://www.vanja.com/tools/sophie/. The only
-+ option for this scanner type is the path to the
-+ UNIX socket that Sophie uses for client
-+ communication. The default path is
-+ /var/run/sophie, so if you are using this, you
-+ can omit the option. Example:
-+
-+ av_scanner = sophie:/tmp/sophie
-+
-+
-+ kavdaemon Kapersky's kavdaemon is a daemon-type scanner.
-+ You can get a trial version at
-+ http://www.kapersky.com. This scanner type takes
-+ one option, which is the path to the daemon's
-+ UNIX socket. The default is "/var/run/AvpCtl".
-+ Example:
-+
-+ av_scanner = kavdaemon:/opt/AVP/AvpCtl
-+
-+
-+ clamd Another daemon type scanner, this one is GPL and
-+ free. Get it at http://clamav.elektrapro.com/.
-+ Clamd does not seem to unpack MIME containers,
-+ so it is recommended to use the demime facility
-+ with it. It takes one option: either the path
-+ and name of a UNIX socket file, or a
-+ hostname/port pair, separated by space. If
-+ unset, the default is "/tmp/clamd". Example:
-+
-+ av_scanner = clamd:192.168.2.100 1234
-+ or
-+ av_scanner = clamd:/opt/clamd/socket
-+
-+
-+ cmdline This is the keyword for the generic command line
-+ scanner interface. It can be used to attach
-+ virus scanners that are invoked on the shell.
-+ This scanner type takes 3 mantadory options:
-+
-+ - full path and name of the scanner binary, with
-+ all command line options and a placeholder
-+ (%s) for the directory to scan.
-+
-+ - A regular expression to match against the
-+ STDOUT and STDERR output of the virus scanner.
-+ If the expression matches, a virus was found.
-+ You must make absolutely sure that this
-+ expression only matches on "virus found". This
-+ is called the "trigger" expression.
-+
-+ - Another regular expression, containing exactly
-+ ONE pair of braces, to match the name of the
-+ virus found in the scanners output. This is
-+ called the "name" expression.
-+
-+ Example:
-+
-+ Sophos Sweep reports a virus on a line like
-+ this:
-+
-+ Virus 'W32/Magistr-B' found in file ./those.bat
-+
-+ For the "trigger" expression, we just use the
-+ "found" word. For the "name" expression, we want
-+ to get the W32/Magistr-B string, so we can match
-+ for the single quotes left and right of it,
-+ resulting in the regex '(.*)' (WITH the quotes!)
-+
-+ Altogether, this makes the configuration
-+ setting:
-+
-+ av_scanner = cmdline:\
-+ /path/to/sweep -all -rec -archive %s:\
-+ found:'(.+)'
-+
-+
-+When av_scanner is correcly set, you can use the "malware"
-+condition in the DATA ACL. The condition takes a right-hand
-+argument that is expanded before use. It can then be one of
-+
-+ - "true", "*", or "1", in which case the message is scanned
-+ for viruses. The condition will succeed if a virus was
-+ found, or fail otherwise. This is the recommended usage.
-+
-+ - "false" or "0", in which case no scanning is done and the
-+ condition will fail immediately.
-+
-+ - a regular expression, in which case the message is scanned
-+ for viruses. The condition will succeed if a virus found
-+ found and its name matches the regular expression. This
-+ allows you to take special actions on certain types of
-+ viruses.
-+
-+When a virus was found, the condition sets up an expansion
-+variable called $malware_name that contains the name of the
-+virus found. You should use it in a "message" modifier that
-+contains the error returned to the sender.
-+
-+The malware condition caches its results, so when you use it
-+multiple times, the actual scanning process is only carried
-+out once.
-+
-+If your virus scanner cannot unpack MIME and TNEF containers
-+itself, you should use the demime condition prior to the
-+malware condition.
-+
-+Here is a simple example:
-+
-+/* ----------------------
-+deny message = This message contains malware ($malware_name)
-+ demime = *
-+ malware = *
-+---------------------- */
-+
-+
-+--------------------------------------------------------------
-+End of file
-+--------------------------------------------------------------
-diff -urN exim-4.20-orig/exim_monitor/em_globals.c exim-4.20/exim_monitor/em_globals.c
---- exim-4.20-orig/exim_monitor/em_globals.c Mon May 12 15:39:23 2003
-+++ exim-4.20/exim_monitor/em_globals.c Wed May 14 12:04:24 2003
-@@ -133,6 +133,7 @@
-
- BOOL local_error_message = FALSE;
- uschar *local_scan_data = NULL;
-+uschar *spam_score_int = NULL;
- BOOL log_timezone = FALSE;
- int message_age = 0;
- uschar *message_id;
-diff -urN exim-4.20-orig/scripts/MakeLinks exim-4.20/scripts/MakeLinks
---- exim-4.20-orig/scripts/MakeLinks Mon May 12 15:39:17 2003
-+++ exim-4.20/scripts/MakeLinks Wed May 14 12:04:24 2003
-@@ -166,6 +166,7 @@
-
- ln -s ../src/dbfunctions.h dbfunctions.h
- ln -s ../src/dbstuff.h dbstuff.h
-+ln -s ../src/demime.h demime.h
- ln -s ../src/exim.h exim.h
- ln -s ../src/functions.h functions.h
- ln -s ../src/globals.h globals.h
-@@ -173,8 +174,10 @@
- ln -s ../src/macros.h macros.h
- ln -s ../src/mytypes.h mytypes.h
- ln -s ../src/osfunctions.h osfunctions.h
-+ln -s ../src/spam.h spam.h
- ln -s ../src/store.h store.h
- ln -s ../src/structs.h structs.h
-+ln -s ../src/tnef.h tnef.h
-
- ln -s ../src/acl.c acl.c
- ln -s ../src/buildconfig.c buildconfig.c
-@@ -184,6 +187,7 @@
- ln -s ../src/dbfn.c dbfn.c
- ln -s ../src/debug.c debug.c
- ln -s ../src/deliver.c deliver.c
-+ln -s ../src/demime.c demime.c
- ln -s ../src/directory.c directory.c
- ln -s ../src/dns.c dns.c
- ln -s ../src/drtables.c drtables.c
-@@ -202,6 +206,7 @@
- ln -s ../src/ip.c ip.c
- ln -s ../src/log.c log.c
- ln -s ../src/lss.c lss.c
-+ln -s ../src/malware.c malware.c
- ln -s ../src/match.c match.c
- ln -s ../src/moan.c moan.c
- ln -s ../src/parse.c parse.c
-@@ -210,19 +215,23 @@
- ln -s ../src/rda.c rda.c
- ln -s ../src/readconf.c readconf.c
- ln -s ../src/receive.c receive.c
-+ln -s ../src/regex.c regex.c
- ln -s ../src/retry.c retry.c
- ln -s ../src/rewrite.c rewrite.c
- ln -s ../src/route.c route.c
- ln -s ../src/search.c search.c
- ln -s ../src/smtp_in.c smtp_in.c
- ln -s ../src/smtp_out.c smtp_out.c
-+ln -s ../src/spam.c spam.c
- ln -s ../src/spool_in.c spool_in.c
-+ln -s ../src/spool_mbox.c spool_mbox.c
- ln -s ../src/spool_out.c spool_out.c
- ln -s ../src/store.c store.c
- ln -s ../src/string.c string.c
- ln -s ../src/tls.c tls.c
- ln -s ../src/tls-gnu.c tls-gnu.c
- ln -s ../src/tls-openssl.c tls-openssl.c
-+ln -s ../src/tnef.c tnef.c
- ln -s ../src/tod.c tod.c
- ln -s ../src/transport.c transport.c
- ln -s ../src/tree.c tree.c
-diff -urN exim-4.20-orig/src/acl.c exim-4.20/src/acl.c
---- exim-4.20-orig/src/acl.c Mon May 12 15:39:17 2003
-+++ exim-4.20/src/acl.c Fri May 16 09:11:35 2003
-@@ -7,6 +7,8 @@
-
- /* Code for handling Access Control Lists (ACLs) */
-
-+/* This file has been modified by the exiscan-acl patch. */
-+
- #include "exim.h"
-
-
-@@ -32,19 +34,19 @@
- /* ACL condition and modifier codes - keep in step with the table that
- follows. */
-
--enum { ACLC_ACL, ACLC_AUTHENTICATED, ACLC_CONDITION, ACLC_CONTROL, ACLC_DELAY,
-+enum { ACLC_ACL, ACLC_AUTHENTICATED, ACLC_CONDITION, ACLC_CONTROL, ACLC_DELAY, ACLC_DEMIME,
- ACLC_DNSLISTS, ACLC_DOMAINS, ACLC_ENCRYPTED, ACLC_ENDPASS, ACLC_HOSTS,
-- ACLC_LOCAL_PARTS, ACLC_LOG_MESSAGE, ACLC_MESSAGE, ACLC_RECIPIENTS,
-- ACLC_SENDER_DOMAINS, ACLC_SENDERS, ACLC_SET, ACLC_VERIFY };
-+ ACLC_LOCAL_PARTS, ACLC_LOG_MESSAGE, ACLC_MALWARE, ACLC_MESSAGE, ACLC_RECIPIENTS,
-+ ACLC_REGEX, ACLC_SENDER_DOMAINS, ACLC_SENDERS, ACLC_SET, ACLC_SPAM, ACLC_VERIFY };
-
- /* ACL conditions/modifiers: "delay", "control", "endpass", "message",
--"log_message", and "set" are modifiers that look like conditions but always
-+"log_message", "set" and "spam" are modifiers that look like conditions but always
- return TRUE. They are used for their side effects. */
-
- static uschar *conditions[] = { US"acl", US"authenticated", US"condition",
-- US"control", US"delay", US"dnslists", US"domains", US"encrypted",
-- US"endpass", US"hosts", US"local_parts", US"log_message", US"message",
-- US"recipients", US"sender_domains", US"senders", US"set", US"verify" };
-+ US"control", US"delay", US"demime", US"dnslists", US"domains", US"encrypted",
-+ US"endpass", US"hosts", US"local_parts", US"log_message", US"malware", US"message",
-+ US"recipients", US"regex", US"sender_domains", US"senders", US"set", US"spam", US"verify" };
-
- /* Flags to indicate for which conditions /modifiers a string expansion is done
- at the outer level. In the other cases, expansion already occurs in the
-@@ -56,6 +58,7 @@
- TRUE, /* condition */
- TRUE, /* control */
- TRUE, /* delay */
-+ FALSE, /* demime */
- TRUE, /* dnslists */
- FALSE, /* domains */
- FALSE, /* encrypted */
-@@ -63,11 +66,14 @@
- FALSE, /* hosts */
- FALSE, /* local_parts */
- TRUE, /* log_message */
-+ TRUE, /* malware */
- TRUE, /* message */
- FALSE, /* recipients */
-+ TRUE, /* regex */
- FALSE, /* sender_domains */
- FALSE, /* senders */
- TRUE, /* set */
-+ TRUE, /* spam */
- TRUE /* verify */
- };
-
-@@ -79,6 +85,7 @@
- FALSE, /* condition */
- TRUE, /* control */
- TRUE, /* delay */
-+ FALSE, /* demime */
- FALSE, /* dnslists */
- FALSE, /* domains */
- FALSE, /* encrypted */
-@@ -86,11 +93,14 @@
- FALSE, /* hosts */
- FALSE, /* local_parts */
- TRUE, /* log_message */
-+ FALSE, /* malware */
- TRUE, /* message */
- FALSE, /* recipients */
-+ FALSE, /* regex */
- FALSE, /* sender_domains */
- FALSE, /* senders */
- TRUE, /* set */
-+ FALSE, /* spam */
- FALSE /* verify */
- };
-
-@@ -109,6 +119,13 @@
- (1<<ACL_WHERE_STARTTLS)|(ACL_WHERE_VRFY),
-
- 0, /* delay */
-+
-+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* demime */
-+ (1<<ACL_WHERE_CONNECT)|
-+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-+ (1<<ACL_WHERE_VRFY),
-+
- (1<<ACL_WHERE_NOTSMTP), /* dnslists */
-
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* domains */
-@@ -131,6 +148,13 @@
- (1<<ACL_WHERE_VRFY),
-
- 0, /* log_message */
-+
-+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* malware */
-+ (1<<ACL_WHERE_CONNECT)|
-+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-+ (1<<ACL_WHERE_VRFY),
-+
- 0, /* message */
-
- (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* recipients */
-@@ -140,6 +164,12 @@
- (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
- (1<<ACL_WHERE_VRFY),
-
-+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* regex */
-+ (1<<ACL_WHERE_CONNECT)|
-+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-+ (1<<ACL_WHERE_VRFY),
-+
- (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)| /* sender_domains */
- (1<<ACL_WHERE_HELO)|
- (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-@@ -152,6 +182,12 @@
-
- 0, /* set */
-
-+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* spam */
-+ (1<<ACL_WHERE_CONNECT)|
-+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-+ (1<<ACL_WHERE_VRFY),
-+
- /* Certain types of verify are always allowed, so we let it through
- always and check in the verify function itself */
-
-@@ -1096,6 +1132,23 @@
- rc = verify_check_dnsbl(&arg);
- break;
-
-+
-+ case ACLC_DEMIME:
-+ rc = demime(&arg);
-+ break;
-+
-+ case ACLC_MALWARE:
-+ rc = malware(&arg);
-+ break;
-+
-+ case ACLC_SPAM:
-+ rc = spam(&arg);
-+ break;
-+
-+ case ACLC_REGEX:
-+ rc = regex(&arg);
-+ break;
-+
- case ACLC_DOMAINS:
- rc = match_isinlist(addr->domain, &arg, 0, &domainlist_anchor,
- addr->domain_cache, MCL_DOMAIN, TRUE, &deliver_domain_data);
-@@ -1618,6 +1671,10 @@
- return DISCARD;
- }
-
-+/* Remove spooled mbox and demimed files.
-+Will immediately return if no files had been created */
-+unspool_mbox();
-+
- /* Before giving an error response, take a look at the length of any user
- message, and split it up into multiple lines if possible. */
-
-diff -urN exim-4.20-orig/src/configure.default exim-4.20/src/configure.default
---- exim-4.20-orig/src/configure.default Mon May 12 15:39:18 2003
-+++ exim-4.20/src/configure.default Tue May 27 13:32:26 2003
-@@ -108,6 +108,25 @@
-
- # You should not change that setting until you understand how ACLs work.
-
-+# The following ACL entry is used if you want to do content scanning with the
-+# exiscan-acl patch. When you uncomment this line, you must also review the
-+# acl_check_content entry in the ACL section further below.
-+
-+# acl_smtp_data = acl_check_content
-+
-+# This configuration variable defines the virus scanner that is used with
-+# the 'malware' ACL condition of the exiscan acl-patch. If you do not use
-+# virus scanning, leave it commented. Please read doc/exiscan-acl-readme.txt
-+# for a list of supported scanners.
-+
-+# av_scanner = sophie:/var/run/sophie
-+
-+# The following setting is only needed if you use the 'spam' ACL condition
-+# of the exiscan-acl patch. It specifies on which host and port the SpamAssassin
-+# "spamd" daemon is listening. If you do not use this condition, or you use
-+# the default of "127.0.0.1 783", you can omit this option.
-+
-+# spamd_address = 127.0.0.1 783
-
- # Specify the domain you want to be added to all unqualified addresses
- # here. An unqualified address is one that does not contain an "@" character
-@@ -308,6 +327,52 @@
- deny message = relay not permitted
-
-
-+# This access control list is used for content scanning with the exiscan-acl
-+# patch. You must also uncomment the entry for acl_smtp_data (scroll up),
-+# otherwise the ACL will not be used. IMPORTANT: the default entries here
-+# should be treated as EXAMPLES. You MUST read the file doc/exiscan-acl-spec.txt
-+# to fully understand what you are doing ...
-+
-+acl_check_content:
-+
-+ # First unpack MIME containers and reject serious errors.
-+ deny message = This message contains a MIME error ($demime_reason)
-+ demime = *
-+ condition = ${if >{$demime_errorlevel}{2}{1}{0}}
-+
-+ # Reject typically wormish file extensions. There is almost no
-+ # sense in sending such files by email.
-+ deny message = This message contains an unwanted file extension ($found_extension)
-+ demime = scr:vbs:bat:lnk:pif
-+
-+ # Reject virus infested messages.
-+ deny message = This message contains malware ($malware_name)
-+ malware = *
-+
-+ # Reject messages containing "viagra" in all kinds of whitespace/case combinations
-+ # WARNING: this is an example !
-+ deny message = This message matches a blacklisted regular expression ($regex_match_string)
-+ regex = [Vv] *[Ii] *[Aa] *[Gg] *[Rr] *[Aa]
-+
-+ # Always add X-Spam-Score and X-Spam-Report headers, using SA system-wide settings
-+ # (user "nobody"), no matter if over threshold or not.
-+ warn message = X-Spam-Score: $spam_score ($spam_bar)
-+ spam = nobody:true
-+ warn message = X-Spam-Report: $spam_report
-+ spam = nobody:true
-+
-+ # Add X-Spam-Flag if spam is over system-wide threshold
-+ warn message = X-Spam-Flag: YES
-+ spam = nobody
-+
-+ # Reject spam messages with score over 10, using an extra condition.
-+ deny message = This message scored $spam_score points. Congratulations!
-+ spam = nobody:true
-+ condition = ${if >{$spam_score_int}{100}{1}{0}}
-+
-+ # finally accept all the rest
-+ accept
-+
-
- ######################################################################
- # ROUTERS CONFIGURATION #
-diff -urN exim-4.20-orig/src/demime.c exim-4.20/src/demime.c
---- exim-4.20-orig/src/demime.c Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/demime.c Fri May 16 17:08:52 2003
-@@ -0,0 +1,1243 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
-+/* License: GPL */
-+
-+/* Code for unpacking MIME containers. Called from acl.c. */
-+
-+#include "exim.h"
-+#include "demime.h"
-+
-+uschar demime_reason_buffer[1024];
-+int demime_ok = 0;
-+struct file_extension *file_extensions = NULL;
-+
-+int demime(uschar **listptr) {
-+ int sep = 0;
-+ uschar *list = *listptr;
-+ uschar *option;
-+ uschar option_buffer[64];
-+ unsigned long long mbox_size;
-+ FILE *mbox_file;
-+ uschar defer_error_buffer[1024];
-+ int demime_rc;
-+
-+ /* reset found_extension variable */
-+ found_extension = NULL;
-+
-+ /* try to find 1st option */
-+ if ((option = string_nextinlist(&list, &sep,
-+ option_buffer,
-+ sizeof(option_buffer))) != NULL) {
-+
-+ /* parse 1st option */
-+ if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) {
-+ /* explicitly no demimeing */
-+ return FAIL;
-+ };
-+ }
-+ else {
-+ /* no options -> no demimeing */
-+ return FAIL;
-+ };
-+
-+ /* make sure the eml mbox file is spooled up */
-+ mbox_file = spool_mbox(&mbox_size);
-+
-+ if (mbox_file == NULL) {
-+ /* error while spooling */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "demime acl condition: error while creating mbox spool file");
-+ return DEFER;
-+ };
-+
-+ /* call demimer if not already done earlier */
-+ if (!demime_ok)
-+ demime_rc = mime_demux(mbox_file, defer_error_buffer);
-+
-+ fclose(mbox_file);
-+
-+ if (demime_rc == DEFER) {
-+ /* temporary failure (DEFER => DEFER) */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "demime acl condition: %s", defer_error_buffer);
-+ return DEFER;
-+ };
-+
-+ /* set demime_ok to avoid unpacking again */
-+ demime_ok = 1;
-+
-+ /* check for file extensions, if there */
-+ while (option != NULL) {
-+ struct file_extension *this_extension = file_extensions;
-+
-+ /* Look for the wildcard. If it is found, we always return true.
-+ The user must then use a custom condition to evaluate demime_errorlevel */
-+ if (Ustrcmp(option,"*") == 0) {
-+ found_extension = NULL;
-+ return OK;
-+ };
-+
-+ /* loop thru extension list */
-+ while (this_extension != NULL) {
-+ if (strcmpic(option, this_extension->file_extension_string) == 0) {
-+ /* found one */
-+ found_extension = this_extension->file_extension_string;
-+ return OK;
-+ };
-+ this_extension = this_extension->next;
-+ };
-+
-+ /* grab next extension from option list */
-+ option = string_nextinlist(&list, &sep,
-+ option_buffer,
-+ sizeof(option_buffer));
-+ };
-+
-+ /* nothing found */
-+ return FAIL;
-+}
-+
-+
-+/*************************************************
-+* unpack TNEF in given directory *
-+*************************************************/
-+
-+int mime_unpack_tnef(uschar *directory) {
-+ uschar filepath[1024];
-+ int n;
-+ struct dirent *entry;
-+ DIR *tempdir;
-+
-+ /* open the dir */
-+ tempdir = opendir(CS directory);
-+ if (tempdir == NULL) {
-+ return -2;
-+ };
-+
-+ /* loop thru dir */
-+ n = 0;
-+ do {
-+ entry = readdir(tempdir);
-+ /* break on end of list */
-+ if (entry == NULL) break;
-+ snprintf(CS filepath,1024,"%s/%s",directory,entry->d_name);
-+ if ( (Ustrcmp(entry->d_name,"..") != 0) && (Ustrcmp(entry->d_name,".") != 0) ) {
-+ TNEF_set_path(CS directory);
-+ n = TNEF_main(CS filepath);
-+ };
-+ } while (1);
-+
-+ closedir(tempdir);
-+ return 0;
-+}
-+
-+
-+/*************************************************
-+* small hex_str -> integer conversion function *
-+*************************************************/
-+
-+/* needed for quoted-printable
-+*/
-+
-+unsigned int mime_hstr_i(uschar *cptr) {
-+ unsigned int i, j = 0;
-+
-+ while (cptr && *cptr && isxdigit(*cptr)) {
-+ i = *cptr++ - '0';
-+ if (9 < i) i -= 7;
-+ j <<= 4;
-+ j |= (i & 0x0f);
-+ }
-+
-+ return(j);
-+}
-+
-+
-+/*************************************************
-+* decode quoted-printable chars *
-+*************************************************/
-+
-+/* gets called when we hit a =
-+ returns: new pointer position
-+ result code in c:
-+ -2 - decode error
-+ -1 - soft line break, no char
-+ 0-255 - char to write
-+*/
-+
-+uschar *mime_decode_qp(uschar *qp_p,int *c) {
-+ uschar hex[] = {0,0,0};
-+ int nan = 0;
-+ uschar *initial_pos = qp_p;
-+
-+ /* advance one char */
-+ qp_p++;
-+
-+ REPEAT_FIRST:
-+ if ( (*qp_p == '\t') || (*qp_p == ' ') || (*qp_p == '\r') ) {
-+ /* tab or whitespace may follow
-+ just ignore it, but remember
-+ that this is not a valid hex
-+ encoding any more */
-+ nan = 1;
-+ qp_p++;
-+ goto REPEAT_FIRST;
-+ }
-+ else if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
-+ /* this is a valid hex char, if nan is unset */
-+ if (nan) {
-+ /* this is illegal */
-+ *c = -2;
-+ return initial_pos;
-+ }
-+ else {
-+ hex[0] = *qp_p;
-+ qp_p++;
-+ };
-+ }
-+ else if (*qp_p == '\n') {
-+ /* hit soft line break already, continue */
-+ *c = -1;
-+ return qp_p;
-+ }
-+ else {
-+ /* illegal char here */
-+ *c = -2;
-+ return initial_pos;
-+ };
-+
-+ if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
-+ if (hex[0] > 0) {
-+ hex[1] = *qp_p;
-+ /* do hex conversion */
-+ *c = mime_hstr_i(hex);
-+ qp_p++;
-+ return qp_p;
-+ }
-+ else {
-+ /* huh ? */
-+ *c = -2;
-+ return initial_pos;
-+ };
-+ }
-+ else {
-+ /* illegal char */
-+ *c = -2;
-+ return initial_pos;
-+ };
-+
-+}
-+
-+
-+/*************************************************
-+* open new dump file *
-+*************************************************/
-+
-+/* open new dump file
-+ returns: -2 soft error
-+ or file #, FILE * in f
-+*/
-+
-+int mime_get_dump_file(uschar *extension, FILE **f, uschar *info) {
-+ uschar file_name[1024];
-+ int result;
-+ unsigned int file_nr;
-+ uschar default_extension[] = ".com";
-+ uschar *p;
-+
-+ if (extension == NULL)
-+ extension = default_extension;
-+
-+ /* scan the proposed extension.
-+ if it is longer than 4 chars, or
-+ contains exotic chars, use the default extension */
-+
-+/* if (Ustrlen(extension) > 4) {
-+ extension = default_extension;
-+ };
-+*/
-+
-+ p = extension+1;
-+
-+ while (*p != 0) {
-+ *p = (uschar)tolower((uschar)*p);
-+ if ( (*p < 97) || (*p > 122) ) {
-+ extension = default_extension;
-+ break;
-+ };
-+ p++;
-+ };
-+
-+ /* find a new file to write to */
-+ file_nr = 0;
-+ do {
-+ struct stat mystat;
-+
-+ snprintf(CS file_name,1024,"%s/scan/%s/%s-%05u%s",spool_directory,message_id,message_id,file_nr,extension);
-+ file_nr++;
-+ if (file_nr >= MIME_SANITY_MAX_DUMP_FILES) {
-+ /* max parts reached */
-+ mime_trigger_error(MIME_ERRORLEVEL_TOO_MANY_PARTS);
-+ break;
-+ };
-+ result = stat(CS file_name,&mystat);
-+ }
-+ while(result != -1);
-+
-+ *f = fopen(CS file_name,"w");
-+ if (*f == NULL) {
-+ /* cannot open new dump file, disk full ? -> soft error */
-+ snprintf(CS info, 1024,"unable to open dump file");
-+ return -2;
-+ };
-+
-+ return file_nr;
-+}
-+
-+
-+/*************************************************
-+* Find a string in a mime header *
-+*************************************************/
-+
-+/* Find a string in a mime header, and optionally fill in
-+ the value associated with it into *value
-+
-+ returns: 0 - nothing found
-+ 1 - found param
-+ 2 - found param + value
-+*/
-+
-+int mime_header_find(uschar *header, uschar *param, uschar **value) {
-+ uschar *needle;
-+
-+ needle = strstric(header,param,FALSE);
-+ if (needle != NULL) {
-+ if (value != NULL) {
-+ needle += Ustrlen(param);
-+ if (*needle == '=') {
-+ uschar *value_start;
-+ uschar *value_end;
-+
-+ value_start = needle + 1;
-+ value_end = strstric(value_start,US";",FALSE);
-+ if (value_end != NULL) {
-+ /* allocate mem for value */
-+ *value = (uschar *)malloc((value_end - value_start)+1);
-+ if (*value == NULL)
-+ return 0;
-+
-+ Ustrncpy(*value,value_start,(value_end - value_start));
-+ (*value)[(value_end - value_start)] = '\0';
-+ return 2;
-+ };
-+ };
-+ };
-+ return 1;
-+ };
-+ return 0;
-+}
-+
-+
-+/*************************************************
-+* Read a line of MIME input *
-+*************************************************/
-+/* returns status code, one of
-+ MIME_READ_LINE_EOF 0
-+ MIME_READ_LINE_OK 1
-+ MIME_READ_LINE_OVERFLOW 2
-+
-+ In header mode, the line will be "cooked".
-+*/
-+
-+int mime_read_line(FILE *f, int mime_demux_mode, uschar *buffer, long *num_copied) {
-+ int c;
-+ int done = 0;
-+ int header_value_mode = 0;
-+ int header_open_brackets = 0;
-+
-+ *num_copied = 0;
-+
-+ while(!done) {
-+
-+ c = fgetc(f);
-+ if (c == EOF) break;
-+
-+ /* --------- header mode -------------- */
-+ if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) {
-+
-+ /* always skip CRs */
-+ if (c == '\r') continue;
-+
-+ if (c == '\n') {
-+ /* look if next char is '\t' or ' ' */
-+ c = fgetc(f);
-+ if (c == EOF) break;
-+ if ( (c == '\t') || (c == ' ') ) continue;
-+ /* end of the header, terminate with ';' */
-+ ungetc(c,f);
-+ c = ';';
-+ done = 1;
-+ };
-+
-+ /* skip control characters */
-+ if (c < 32) continue;
-+
-+ /* skip whitespace + tabs */
-+ if ( (c == ' ') || (c == '\t') )
-+ continue;
-+
-+ if (header_value_mode) {
-+ /* --------- value mode ----------- */
-+ /* skip quotes */
-+ if (c == '"') continue;
-+
-+ /* leave value mode on ';' */
-+ if (c == ';') {
-+ header_value_mode = 0;
-+ };
-+ /* -------------------------------- */
-+ }
-+ else {
-+ /* -------- non-value mode -------- */
-+ if (c == '\\') {
-+ /* quote next char. can be used
-+ to escape brackets. */
-+ c = fgetc(f);
-+ if (c == EOF) break;
-+ }
-+ else if (c == '(') {
-+ header_open_brackets++;
-+ continue;
-+ }
-+ else if ((c == ')') && header_open_brackets) {
-+ header_open_brackets--;
-+ continue;
-+ }
-+ else if ( (c == '=') && !header_open_brackets ) {
-+ /* enter value mode */
-+ header_value_mode = 1;
-+ };
-+
-+ /* skip chars while we are in a comment */
-+ if (header_open_brackets > 0)
-+ continue;
-+ /* -------------------------------- */
-+ };
-+ }
-+ /* ------------------------------------ */
-+ else {
-+ /* ----------- non-header mode -------- */
-+ /* break on '\n' */
-+ if (c == '\n')
-+ done = 1;
-+ /* ------------------------------------ */
-+ };
-+
-+ /* copy the char to the buffer */
-+ buffer[*num_copied] = (uschar)c;
-+ /* raise counter */
-+ (*num_copied)++;
-+
-+ /* break if buffer is full */
-+ if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1) {
-+ done = 1;
-+ };
-+ }
-+
-+ /* 0-terminate */
-+ buffer[*num_copied] = '\0';
-+
-+ if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1)
-+ return MIME_READ_LINE_OVERFLOW;
-+ else
-+ if (c == EOF)
-+ return MIME_READ_LINE_EOF;
-+ else
-+ return MIME_READ_LINE_OK;
-+}
-+
-+
-+/*************************************************
-+* Check for a MIME boundary *
-+*************************************************/
-+
-+/* returns: 0 - no boundary found
-+ 1 - start boundary found
-+ 2 - end boundary found
-+*/
-+
-+int mime_check_boundary(uschar *line, struct boundary *boundaries) {
-+ struct boundary *thisboundary = boundaries;
-+
-+ /* check for '--' first */
-+ if (Ustrncmp(line,"--",2) == 0) {
-+ while(thisboundary != NULL) {
-+ if (Ustrncmp(&line[2],thisboundary->boundary_string,Ustrlen(thisboundary->boundary_string)) == 0) {
-+ if (Ustrncmp(&line[(2+Ustrlen(thisboundary->boundary_string))],"--",2) == 0) {
-+ /* final boundary found */
-+ return 2;
-+ };
-+ return 1;
-+ };
-+ thisboundary = thisboundary->next;
-+ };
-+ };
-+
-+ return 0;
-+}
-+
-+
-+/*************************************************
-+* Check for start of a UUENCODE block *
-+*************************************************/
-+
-+/* returns 0 for no hit,
-+ >0 for hit
-+*/
-+
-+int mime_check_uu_start(uschar *line, uschar *uu_file_extension, int *has_tnef) {
-+
-+ if ( (strncmpic(line,US"begin ",6) == 0)) {
-+ uschar *uu_filename = &line[6];
-+
-+ /* skip perms, if present */
-+ Ustrtoul(&line[6],&uu_filename,10);
-+
-+ /* advance one char */
-+ uu_filename++;
-+
-+ /* This should be the filename.
-+ Check if winmail.dat is present,
-+ which indicates TNEF. */
-+ if (strncmpic(uu_filename,US"winmail.dat",11) == 0) {
-+ *has_tnef = 1;
-+ };
-+
-+ /* reverse to dot if present,
-+ copy up to 4 chars for the extension */
-+ if (Ustrrchr(uu_filename,'.') != NULL)
-+ uu_filename = Ustrrchr(uu_filename,'.');
-+
-+ return sscanf(CS uu_filename, "%4[.0-9A-Za-z]",CS uu_file_extension);
-+ }
-+ else {
-+ /* nothing found */
-+ return 0;
-+ };
-+}
-+
-+
-+/*************************************************
-+* Decode a uu line *
-+*************************************************/
-+
-+/* returns number of decoded bytes
-+ -2 for soft errors
-+*/
-+
-+int warned_about_uudec_line_sanity_1 = 0;
-+int warned_about_uudec_line_sanity_2 = 0;
-+long uu_decode_line(uschar *line, uschar **data, long line_len, uschar *info) {
-+ uschar *p;
-+ long num_decoded = 0;
-+ uschar tmp_c;
-+ uschar *work;
-+ int uu_decoded_line_len, uu_encoded_line_len;
-+
-+ /* allocate memory for data and work buffer */
-+ *data = (uschar *)malloc(line_len);
-+ if (*data == NULL) {
-+ snprintf(CS info, 1024,"unable to allocate %u bytes",line_len);
-+ return -2;
-+ };
-+
-+ work = (uschar *)malloc(line_len);
-+ if (work == NULL) {
-+ snprintf(CS info, 1024,"unable to allocate %u bytes",line_len);
-+ return -2;
-+ };
-+
-+ memcpy(work,line,line_len);
-+
-+ /* First char is line length
-+ This is microsofts way of getting it. Scary. */
-+ if (work[0] < 32) {
-+ /* ignore this line */
-+ return 0;
-+ }
-+ else {
-+ uu_decoded_line_len = uudec[work[0]];
-+ };
-+
-+ p = &work[1];
-+
-+ while (*p > 32) {
-+ *p = uudec[*p];
-+ p++;
-+ };
-+
-+ uu_encoded_line_len = (p - &work[1]);
-+ p = &work[1];
-+
-+ /* check that resulting line length is a multiple of 4 */
-+ if ( ( uu_encoded_line_len % 4 ) != 0) {
-+ if (!warned_about_uudec_line_sanity_1) {
-+ mime_trigger_error(MIME_ERRORLEVEL_UU_MISALIGNED);
-+ warned_about_uudec_line_sanity_1 = 1;
-+ };
-+ return -1;
-+ };
-+
-+ /* check that the line length matches */
-+ if ( ( (((uu_encoded_line_len/4)*3)-2) > uu_decoded_line_len ) || (((uu_encoded_line_len/4)*3) < uu_decoded_line_len) ) {
-+ if (!warned_about_uudec_line_sanity_2) {
-+ mime_trigger_error(MIME_ERRORLEVEL_UU_LINE_LENGTH);
-+ warned_about_uudec_line_sanity_2 = 1;
-+ };
-+ return -1;
-+ };
-+
-+ while ( ((p - &work[1]) < uu_encoded_line_len) && (num_decoded < uu_decoded_line_len)) {
-+
-+ /* byte 0 ---------------------- */
-+ if ((p - &work[1] + 1) >= uu_encoded_line_len) {
-+ return 0;
-+ }
-+
-+ (*data)[num_decoded] = *p;
-+ (*data)[num_decoded] <<= 2;
-+
-+ tmp_c = *(p+1);
-+ tmp_c >>= 4;
-+ (*data)[num_decoded] |= tmp_c;
-+
-+ num_decoded++;
-+ p++;
-+
-+ /* byte 1 ---------------------- */
-+ if ((p - &work[1] + 1) >= uu_encoded_line_len) {
-+ return 0;
-+ }
-+
-+ (*data)[num_decoded] = *p;
-+ (*data)[num_decoded] <<= 4;
-+
-+ tmp_c = *(p+1);
-+ tmp_c >>= 2;
-+ (*data)[num_decoded] |= tmp_c;
-+
-+ num_decoded++;
-+ p++;
-+
-+ /* byte 2 ---------------------- */
-+ if ((p - &work[1] + 1) >= uu_encoded_line_len) {
-+ return 0;
-+ }
-+
-+ (*data)[num_decoded] = *p;
-+ (*data)[num_decoded] <<= 6;
-+
-+ (*data)[num_decoded] |= *(p+1);
-+
-+ num_decoded++;
-+ p+=2;
-+
-+ };
-+
-+ return uu_decoded_line_len;
-+}
-+
-+
-+/*************************************************
-+* Decode a b64 or qp line *
-+*************************************************/
-+
-+/* returns number of decoded bytes
-+ -1 for hard errors
-+ -2 for soft errors
-+*/
-+
-+int warned_about_b64_line_length = 0;
-+int warned_about_b64_line_sanity = 0;
-+int warned_about_b64_illegal_char = 0;
-+int warned_about_qp_line_sanity = 0;
-+long mime_decode_line(int mime_demux_mode,uschar *line, uschar **data, long max_data_len, uschar *info) {
-+ uschar *p;
-+ long num_decoded = 0;
-+ int offset = 0;
-+ uschar tmp_c;
-+
-+ /* allocate memory for data */
-+ *data = (uschar *)malloc(max_data_len);
-+ if (*data == NULL) {
-+ snprintf(CS info, 1024,"unable to allocate %u bytes",max_data_len);
-+ return -2;
-+ };
-+
-+ if (mime_demux_mode == MIME_DEMUX_MODE_BASE64) {
-+ /* ---------------------------------------------- */
-+
-+ /* NULL out trailing '\r' and '\n' chars */
-+ while (Ustrrchr(line,'\r') != NULL) {
-+ *(Ustrrchr(line,'\r')) = '\0';
-+ };
-+ while (Ustrrchr(line,'\n') != NULL) {
-+ *(Ustrrchr(line,'\n')) = '\0';
-+ };
-+
-+ /* check maximum base 64 line length */
-+ if (Ustrlen(line) > MIME_SANITY_MAX_B64_LINE_LENGTH ) {
-+ if (!warned_about_b64_line_length) {
-+ mime_trigger_error(MIME_ERRORLEVEL_B64_LINE_LENGTH);
-+ warned_about_b64_line_length = 1;
-+ };
-+ };
-+
-+ p = line;
-+ offset = 0;
-+ while (*(p+offset) != '\0') {
-+ /* hit illegal char ? */
-+ if (b64[*(p+offset)] == 128) {
-+ if (!warned_about_b64_illegal_char) {
-+ mime_trigger_error(MIME_ERRORLEVEL_B64_ILLEGAL_CHAR);
-+ warned_about_b64_illegal_char = 1;
-+ };
-+ offset++;
-+ }
-+ else {
-+ *p = b64[*(p+offset)];
-+ p++;
-+ };
-+ };
-+ *p = 255;
-+
-+ /* check that resulting line length is a multiple of 4 */
-+ if ( ( (p - &line[0]) % 4 ) != 0) {
-+ if (!warned_about_b64_line_sanity) {
-+ mime_trigger_error(MIME_ERRORLEVEL_B64_MISALIGNED);
-+ warned_about_b64_line_sanity = 1;
-+ };
-+ };
-+
-+ /* line is translated, start bit shifting */
-+ p = line;
-+ num_decoded = 0;
-+
-+ while(*p != 255) {
-+
-+ /* byte 0 ---------------------- */
-+ if (*(p+1) == 255) {
-+ break;
-+ }
-+
-+ (*data)[num_decoded] = *p;
-+ (*data)[num_decoded] <<= 2;
-+
-+ tmp_c = *(p+1);
-+ tmp_c >>= 4;
-+ (*data)[num_decoded] |= tmp_c;
-+
-+ num_decoded++;
-+ p++;
-+
-+ /* byte 1 ---------------------- */
-+ if (*(p+1) == 255) {
-+ break;
-+ }
-+
-+ (*data)[num_decoded] = *p;
-+ (*data)[num_decoded] <<= 4;
-+
-+ tmp_c = *(p+1);
-+ tmp_c >>= 2;
-+ (*data)[num_decoded] |= tmp_c;
-+
-+ num_decoded++;
-+ p++;
-+
-+ /* byte 2 ---------------------- */
-+ if (*(p+1) == 255) {
-+ break;
-+ }
-+
-+ (*data)[num_decoded] = *p;
-+ (*data)[num_decoded] <<= 6;
-+
-+ (*data)[num_decoded] |= *(p+1);
-+
-+ num_decoded++;
-+ p+=2;
-+
-+ };
-+ return num_decoded;
-+ /* ---------------------------------------------- */
-+ }
-+ else if (mime_demux_mode == MIME_DEMUX_MODE_QP) {
-+ /* ---------------------------------------------- */
-+ p = line;
-+
-+ while (*p != 0) {
-+ if (*p == '=') {
-+ int decode_qp_result;
-+
-+ p = mime_decode_qp(p,&decode_qp_result);
-+
-+ if (decode_qp_result == -2) {
-+ /* Error from decoder. p is unchanged. */
-+ if (!warned_about_qp_line_sanity) {
-+ mime_trigger_error(MIME_ERRORLEVEL_QP_ILLEGAL_CHAR);
-+ warned_about_qp_line_sanity = 1;
-+ };
-+ (*data)[num_decoded] = '=';
-+ num_decoded++;
-+ p++;
-+ }
-+ else if (decode_qp_result == -1) {
-+ /* End of the line with soft line break.
-+ Bail out. */
-+ goto QP_RETURN;
-+ }
-+ else if (decode_qp_result >= 0) {
-+ (*data)[num_decoded] = decode_qp_result;
-+ num_decoded++;
-+ };
-+ }
-+ else {
-+ (*data)[num_decoded] = *p;
-+ num_decoded++;
-+ p++;
-+ };
-+ };
-+ QP_RETURN:
-+ return num_decoded;
-+ /* ---------------------------------------------- */
-+ };
-+
-+ return 0;
-+}
-+
-+
-+
-+/*************************************************
-+* Log demime errors and set mime error level *
-+*************************************************/
-+
-+/* This sets the global demime_reason expansion
-+variable and the demime_errorlevel gauge. */
-+
-+void mime_trigger_error(int level, uschar *format, ...) {
-+ char *f;
-+ va_list ap;
-+
-+ if( (f = malloc(16384+23)) != NULL ) {
-+ /* first log the incident */
-+ sprintf(f,"demime acl condition: ");
-+ f+=22;
-+ va_start(ap, format);
-+ vsnprintf(f, 16383,(char *)format, ap);
-+ va_end(ap);
-+ f-=22;
-+ log_write(0, LOG_MAIN|LOG_PANIC, f);
-+ /* then copy to demime_reason_buffer if new
-+ level is greater than old level */
-+ if (level > demime_errorlevel) {
-+ demime_errorlevel = level;
-+ Ustrcpy(demime_reason_buffer, US f);
-+ demime_reason = demime_reason_buffer;
-+ };
-+ free(f);
-+ };
-+}
-+
-+/*************************************************
-+* Demultiplex MIME stream. *
-+*************************************************/
-+
-+/* We can handle BASE64, QUOTED-PRINTABLE, and UUENCODE.
-+ UUENCODE does not need to have a proper
-+ transfer-encoding header, we detect it with "begin"
-+
-+ This function will report human parsable errors in
-+ *info.
-+
-+ returns DEFER -> soft error (see *info)
-+ OK -> EOF hit, all ok
-+*/
-+
-+int mime_demux(FILE *f, uschar *info) {
-+ int mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
-+ int uu_mode = MIME_UU_MODE_OFF;
-+ FILE *mime_dump_file = NULL;
-+ FILE *uu_dump_file = NULL;
-+ uschar *line;
-+ int mime_read_line_status = MIME_READ_LINE_OK;
-+ long line_len;
-+ struct boundary *boundaries = NULL;
-+ struct mime_part mime_part_p;
-+ int has_tnef = 0;
-+
-+ /* allocate room for our linebuffer */
-+ line = (uschar *)malloc(MIME_SANITY_MAX_LINE_LENGTH);
-+ if (line == NULL) {
-+ snprintf(CS info, 1024,"unable to allocate %u bytes",MIME_SANITY_MAX_LINE_LENGTH);
-+ return DEFER;
-+ };
-+
-+ /* clear MIME header structure */
-+ memset(&mime_part_p,0,sizeof(mime_part));
-+
-+ /* ----------------------- start demux loop --------------------- */
-+ while (mime_read_line_status == MIME_READ_LINE_OK) {
-+
-+ /* read a line of input. Depending on the mode we are in,
-+ the returned format will differ. */
-+ mime_read_line_status = mime_read_line(f,mime_demux_mode,line,&line_len);
-+ if (mime_read_line_status == MIME_READ_LINE_OVERFLOW) {
-+ mime_trigger_error(MIME_ERRORLEVEL_LONG_LINE);
-+ /* despite the error, continue .. */
-+ mime_read_line_status == MIME_READ_LINE_OK;
-+ continue;
-+ }
-+ else if (mime_read_line_status == MIME_READ_LINE_EOF) {
-+ break;
-+ };
-+
-+ if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) {
-+ /* -------------- header mode --------------------- */
-+
-+ /* Check for an empty line, which is the end of the headers.
-+ In HEADER mode, the line is returned "cooked", with the
-+ final '\n' replaced by a ';' */
-+ if (line_len == 1) {
-+ int tmp;
-+
-+ /* We have reached the end of the headers. Start decoding
-+ with the collected settings. */
-+ if (mime_part_p.seen_content_transfer_encoding > 1) {
-+ mime_demux_mode = mime_part_p.seen_content_transfer_encoding;
-+ }
-+ else {
-+ /* default to plain mode if no specific encoding type found */
-+ mime_demux_mode = MIME_DEMUX_MODE_PLAIN;
-+ };
-+
-+ /* open new dump file */
-+ tmp = mime_get_dump_file(mime_part_p.extension, &mime_dump_file, info);
-+ if (tmp < 0) {
-+ return DEFER;
-+ };
-+
-+ /* clear out mime_part */
-+ memset(&mime_part_p,0,sizeof(mime_part));
-+ }
-+ else {
-+ /* Another header to check for file extensions,
-+ encoding type and boundaries */
-+ if (strncmpic(US"content-type:",line,Ustrlen("content-type:")) == 0) {
-+ /* ---------------------------- Content-Type header ------------------------------- */
-+ uschar *value = line;
-+
-+ /* check for message/partial MIME type and reject it */
-+ if (mime_header_find(line,US"message/partial",NULL) > 0)
-+ mime_trigger_error(MIME_ERRORLEVEL_MESSAGE_PARTIAL);
-+
-+ /* check for TNEF content type, remember to unpack TNEF later. */
-+ if (mime_header_find(line,US"application/ms-tnef",NULL) > 0)
-+ has_tnef = 1;
-+
-+ /* find the file extension, but do not fill it in
-+ it is already set, since content-disposition has
-+ precedence. */
-+ if (mime_part_p.extension == NULL) {
-+ if (mime_header_find(line,US"name",&value) == 2) {
-+ if (Ustrlen(value) > MIME_SANITY_MAX_FILENAME)
-+ mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH);
-+ mime_part_p.extension = value;
-+ mime_part_p.extension = Ustrrchr(value,'.');
-+ if (mime_part_p.extension == NULL) {
-+ /* file without extension, setting
-+ NULL will use the default extension later */
-+ mime_part_p.extension = NULL;
-+ }
-+ else {
-+ struct file_extension *this_extension =
-+ (struct file_extension *)malloc(sizeof(file_extension));
-+
-+ this_extension->file_extension_string =
-+ (uschar *)malloc(Ustrlen(mime_part_p.extension)+1);
-+ Ustrcpy(this_extension->file_extension_string,
-+ mime_part_p.extension+1);
-+ this_extension->next = file_extensions;
-+ file_extensions = this_extension;
-+ };
-+ };
-+ };
-+
-+ /* find a boundary and add it to the list, if present */
-+ value = line;
-+ if (mime_header_find(line,US"boundary",&value) == 2) {
-+ struct boundary *thisboundary;
-+
-+ if (Ustrlen(value) > MIME_SANITY_MAX_BOUNDARY_LENGTH) {
-+ mime_trigger_error(MIME_ERRORLEVEL_BOUNDARY_LENGTH);
-+ }
-+ else {
-+ thisboundary = (struct boundary*)malloc(sizeof(boundary));
-+ thisboundary->next = boundaries;
-+ thisboundary->boundary_string = value;
-+ boundaries = thisboundary;
-+ };
-+ };
-+
-+ if (mime_part_p.seen_content_type == 0) {
-+ mime_part_p.seen_content_type = 1;
-+ }
-+ else {
-+ mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
-+ };
-+ /* ---------------------------------------------------------------------------- */
-+ }
-+ else if (strncmpic(US"content-transfer-encoding:",line,Ustrlen("content-transfer-encoding:")) == 0) {
-+ /* ---------------------------- Content-Transfer-Encoding header -------------- */
-+
-+ if (mime_part_p.seen_content_transfer_encoding == 0) {
-+ if (mime_header_find(line,US"base64",NULL) > 0) {
-+ mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_BASE64;
-+ }
-+ else if (mime_header_find(line,US"quoted-printable",NULL) > 0) {
-+ mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_QP;
-+ }
-+ else {
-+ mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_PLAIN;
-+ };
-+ }
-+ else {
-+ mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
-+ };
-+ /* ---------------------------------------------------------------------------- */
-+ }
-+ else if (strncmpic(US"content-disposition:",line,Ustrlen("content-disposition:")) == 0) {
-+ /* ---------------------------- Content-Disposition header -------------------- */
-+ uschar *value = line;
-+
-+ if (mime_part_p.seen_content_disposition == 0) {
-+ mime_part_p.seen_content_disposition = 1;
-+
-+ if (mime_header_find(line,US"filename",&value) == 2) {
-+ if (Ustrlen(value) > MIME_SANITY_MAX_FILENAME)
-+ mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH);
-+ mime_part_p.extension = value;
-+ mime_part_p.extension = Ustrrchr(value,'.');
-+ if (mime_part_p.extension == NULL) {
-+ /* file without extension, setting
-+ NULL will use the default extension later */
-+ mime_part_p.extension = NULL;
-+ }
-+ else {
-+ struct file_extension *this_extension =
-+ (struct file_extension *)malloc(sizeof(file_extension));
-+
-+ this_extension->file_extension_string =
-+ (uschar *)malloc(Ustrlen(mime_part_p.extension)+1);
-+ Ustrcpy(this_extension->file_extension_string,
-+ mime_part_p.extension+1);
-+ this_extension->next = file_extensions;
-+ file_extensions = this_extension;
-+ };
-+ };
-+ }
-+ else {
-+ mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
-+ };
-+ /* ---------------------------------------------------------------------------- */
-+ };
-+ }; /* End of header checks */
-+ /* ------------------------------------------------ */
-+ }
-+ else {
-+ /* -------------- non-header mode ----------------- */
-+ int tmp;
-+
-+ if (uu_mode == MIME_UU_MODE_OFF) {
-+ uschar uu_file_extension[5];
-+ /* We are not currently decoding UUENCODE
-+ Check for possible UUENCODE start tag. */
-+ if (mime_check_uu_start(line,uu_file_extension,&has_tnef)) {
-+ /* possible UUENCODING start detected.
-+ Set unconfirmed mode first. */
-+ uu_mode = MIME_UU_MODE_UNCONFIRMED;
-+ /* open new uu dump file */
-+ tmp = mime_get_dump_file(uu_file_extension, &uu_dump_file, info);
-+ if (tmp < 0) {
-+ free(line);
-+ return DEFER;
-+ };
-+ };
-+ }
-+ else {
-+ uschar *data;
-+ long data_len = 0;
-+
-+ if (uu_mode == MIME_UU_MODE_UNCONFIRMED) {
-+ /* We are in unconfirmed UUENCODE mode. */
-+
-+ data_len = uu_decode_line(line,&data,line_len,info);
-+
-+ if (data_len == -2) {
-+ /* temp error, turn off uudecode mode */
-+ if (uu_dump_file != NULL) {
-+ fclose(uu_dump_file); uu_dump_file = NULL;
-+ };
-+ uu_mode = MIME_UU_MODE_OFF;
-+ return DEFER;
-+ }
-+ else if (data_len == -1) {
-+ if (uu_dump_file != NULL) {
-+ fclose(uu_dump_file); uu_dump_file = NULL;
-+ };
-+ uu_mode = MIME_UU_MODE_OFF;
-+ data_len = 0;
-+ }
-+ else if (data_len > 0) {
-+ /* we have at least decoded a valid byte
-+ turn on confirmed mode */
-+ uu_mode = MIME_UU_MODE_CONFIRMED;
-+ };
-+ }
-+ else if (uu_mode == MIME_UU_MODE_CONFIRMED) {
-+ /* If we are in confirmed UU mode,
-+ check for single "end" tag on line */
-+ if ((strncmpic(line,US"end",3) == 0) && (line[3] < 32)) {
-+ if (uu_dump_file != NULL) {
-+ fclose(uu_dump_file); uu_dump_file = NULL;
-+ };
-+ uu_mode = MIME_UU_MODE_OFF;
-+ }
-+ else {
-+ data_len = uu_decode_line(line,&data,line_len,info);
-+ if (data_len == -2) {
-+ /* temp error, turn off uudecode mode */
-+ if (uu_dump_file != NULL) {
-+ fclose(uu_dump_file); uu_dump_file = NULL;
-+ };
-+ uu_mode = MIME_UU_MODE_OFF;
-+ return DEFER;
-+ }
-+ else if (data_len == -1) {
-+ /* skip this line */
-+ data_len = 0;
-+ };
-+ };
-+ };
-+
-+ /* write data to dump file, if available */
-+ if (data_len > 0) {
-+ if (fwrite(data,1,data_len,uu_dump_file) < data_len) {
-+ /* short write */
-+ snprintf(CS info, 1024,"short write on uudecode dump file");
-+ free(line);
-+ return DEFER;
-+ };
-+ };
-+ };
-+
-+ if (mime_demux_mode != MIME_DEMUX_MODE_SCANNING) {
-+ /* Non-scanning and Non-header mode. That means
-+ we are currently decoding data to the dump
-+ file. */
-+
-+ /* Check for a known boundary. */
-+ tmp = mime_check_boundary(line,boundaries);
-+ if (tmp == 1) {
-+ /* We have hit a known start boundary.
-+ That will put us back in header mode. */
-+ mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
-+ if (mime_dump_file != NULL) {
-+ fclose(mime_dump_file); mime_dump_file = NULL;
-+ };
-+ }
-+ else if (tmp == 2) {
-+ /* We have hit a known end boundary.
-+ That puts us into scanning mode, which will end when we hit another known start boundary */
-+ mime_demux_mode = MIME_DEMUX_MODE_SCANNING;
-+ if (mime_dump_file != NULL) {
-+ fclose(mime_dump_file); mime_dump_file = NULL;
-+ };
-+ }
-+ else {
-+ uschar *data;
-+ long data_len;
-+
-+ /* decode the line with the appropriate method */
-+ if (mime_demux_mode == MIME_DEMUX_MODE_PLAIN) {
-+ /* in plain mode, just dump the line */
-+ data = line;
-+ data_len = line_len;
-+ }
-+ else if ( (mime_demux_mode == MIME_DEMUX_MODE_QP) || (mime_demux_mode == MIME_DEMUX_MODE_BASE64) ) {
-+ data_len = mime_decode_line(mime_demux_mode,line,&data,line_len,info);
-+ if (data_len < 0) {
-+ /* Error reported from the line decoder. */
-+ data_len = 0;
-+ };
-+ };
-+
-+ /* write data to dump file */
-+ if (data_len > 0) {
-+ if (fwrite(data,1,data_len,mime_dump_file) < data_len) {
-+ /* short write */
-+ snprintf(CS info, 1024,"short write on dump file");
-+ free(line);
-+ return DEFER;
-+ };
-+ };
-+
-+ };
-+ }
-+ else {
-+ /* Scanning mode. We end up here after a end boundary.
-+ This will usually be at the end of a message or at
-+ the end of a MIME container.
-+ We need to look for another start boundary to get
-+ back into header mode. */
-+ if (mime_check_boundary(line,boundaries) == 1) {
-+ mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
-+ };
-+
-+ };
-+ /* ------------------------------------------------ */
-+ };
-+ };
-+ /* ----------------------- end demux loop ----------------------- */
-+
-+ /* close files, they could still be open */
-+ if (mime_dump_file != NULL)
-+ fclose(mime_dump_file);
-+ if (uu_dump_file != NULL)
-+ fclose(uu_dump_file);
-+
-+ /* release line buffer */
-+ free(line);
-+
-+ /* FIXME: release boundary buffers.
-+ Not too much of a problem since
-+ this instance of exim is not resident. */
-+
-+ if (has_tnef) {
-+ uschar file_name[1024];
-+ /* at least one file could be TNEF encoded.
-+ attempt to send all decoded files thru the TNEF decoder */
-+
-+ snprintf(CS file_name,1024,"%s/scan/%s",spool_directory,message_id);
-+ mime_unpack_tnef(file_name);
-+ };
-+
-+ return 0;
-+}
-+
-diff -urN exim-4.20-orig/src/demime.h exim-4.20/src/demime.h
---- exim-4.20-orig/src/demime.h Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/demime.h Wed May 14 12:04:24 2003
-@@ -0,0 +1,146 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
-+/* License: GPL */
-+
-+/* demime defines */
-+
-+#define MIME_DEMUX_MODE_SCANNING 0
-+#define MIME_DEMUX_MODE_MIME_HEADERS 1
-+#define MIME_DEMUX_MODE_BASE64 2
-+#define MIME_DEMUX_MODE_QP 3
-+#define MIME_DEMUX_MODE_PLAIN 4
-+
-+#define MIME_UU_MODE_OFF 0
-+#define MIME_UU_MODE_UNCONFIRMED 1
-+#define MIME_UU_MODE_CONFIRMED 2
-+
-+#define MIME_MAX_EXTENSION 128
-+
-+#define MIME_READ_LINE_EOF 0
-+#define MIME_READ_LINE_OK 1
-+#define MIME_READ_LINE_OVERFLOW 2
-+
-+#define MIME_SANITY_MAX_LINE_LENGTH 131071
-+#define MIME_SANITY_MAX_FILENAME 512
-+#define MIME_SANITY_MAX_HEADER_OPTION_VALUE 1024
-+#define MIME_SANITY_MAX_B64_LINE_LENGTH 76
-+#define MIME_SANITY_MAX_BOUNDARY_LENGTH 1024
-+#define MIME_SANITY_MAX_DUMP_FILES 1024
-+
-+
-+
-+/* MIME errorlevel settings */
-+
-+#define MIME_ERRORLEVEL_LONG_LINE 3,US"line length in message or single header size exceeds %u bytes",MIME_SANITY_MAX_LINE_LENGTH
-+#define MIME_ERRORLEVEL_TOO_MANY_PARTS 3,US"too many MIME parts (max %u)",MIME_SANITY_MAX_DUMP_FILES
-+#define MIME_ERRORLEVEL_MESSAGE_PARTIAL 3,US"'message/partial' MIME type"
-+#define MIME_ERRORLEVEL_FILENAME_LENGTH 3,US"proposed filename exceeds %u characters",MIME_SANITY_MAX_FILENAME
-+#define MIME_ERRORLEVEL_BOUNDARY_LENGTH 3,US"boundary length exceeds %u characters",MIME_SANITY_MAX_BOUNDARY_LENGTH
-+#define MIME_ERRORLEVEL_DOUBLE_HEADERS 2,US"double headers (content-type, content-disposition or content-transfer-encoding)"
-+#define MIME_ERRORLEVEL_UU_MISALIGNED 1,US"uuencoded line length is not a multiple of 4 characters"
-+#define MIME_ERRORLEVEL_UU_LINE_LENGTH 1,US"uuencoded line length does not match advertised number of bytes"
-+#define MIME_ERRORLEVEL_B64_LINE_LENGTH 1,US"base64 line length exceeds %u characters",MIME_SANITY_MAX_B64_LINE_LENGTH
-+#define MIME_ERRORLEVEL_B64_ILLEGAL_CHAR 2,US"base64 line contains illegal character"
-+#define MIME_ERRORLEVEL_B64_MISALIGNED 1,US"base64 line length is not a multiple of 4 characters"
-+#define MIME_ERRORLEVEL_QP_ILLEGAL_CHAR 1,US"quoted-printable encoding contains illegal character"
-+
-+
-+/* demime structures */
-+
-+typedef struct mime_part {
-+ /* true if there was a content-type header */
-+ int seen_content_type;
-+ /* true if there was a content-transfer-encoding header
-+ contains the encoding type */
-+ int seen_content_transfer_encoding;
-+ /* true if there was a content-disposition header */
-+ int seen_content_disposition;
-+ /* pointer to a buffer with the proposed file extension */
-+ uschar *extension;
-+} mime_part;
-+
-+typedef struct boundary {
-+ struct boundary *next;
-+ uschar *boundary_string;
-+} boundary;
-+
-+typedef struct file_extension {
-+ struct file_extension *next;
-+ uschar *file_extension_string;
-+} file_extension;
-+
-+/* available functions for the TNEF library (tnef.c & tnef.h) */
-+
-+extern int TNEF_main( char *filename );
-+extern int TNEF_set_verbosity( int level );
-+extern int TNEF_set_debug( int level );
-+extern int TNEF_set_syslogging( int level );
-+extern int TNEF_set_stderrlogging( int level );
-+extern int TNEF_set_path( char *path );
-+
-+
-+
-+/* demime.c prototypes */
-+
-+int mime_unpack_tnef(uschar *);
-+unsigned int mime_hstr_i(uschar *);
-+uschar *mime_decode_qp(uschar *, int *);
-+int mime_get_dump_file(uschar *, FILE **, uschar *);
-+int mime_header_find(uschar *, uschar *, uschar **);
-+int mime_read_line(FILE *, int, uschar *, long *);
-+int mime_check_boundary(uschar *, struct boundary *);
-+int mime_check_uu_start(uschar *, uschar *, int *);
-+long uu_decode_line(uschar *, uschar **, long, uschar *);
-+long mime_decode_line(int ,uschar *, uschar **, long, uschar *);
-+void mime_trigger_error(int, uschar *, ...);
-+int mime_demux(FILE *, uschar *);
-+
-+
-+
-+/* BASE64 decoder matrix */
-+static unsigned char b64[256]={
-+/* 0 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+/* 16 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+/* 32 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 62, 128, 128, 128, 63,
-+/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 255, 128, 128,
-+/* 64 */ 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
-+/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 128, 128, 128, 128, 128,
-+/* 96 */ 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128,
-+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
-+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
-+};
-+
-+
-+/* Microsoft-Style uudecode matrix */
-+static unsigned char uudec[256]={
-+/* 0 */ 0, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-+/* 16 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-+/* 32 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-+/* 48 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-+/* 64 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-+/* 80 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-+/* 96 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-+/* 112 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-+/* 128 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-+/* 144 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-+/* 160 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-+/* 176 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-+/* 192 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-+/* 208 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-+/* 224 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-+/* 240 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
-+};
-+
-diff -urN exim-4.20-orig/src/expand.c exim-4.20/src/expand.c
---- exim-4.20-orig/src/expand.c Mon May 12 15:39:19 2003
-+++ exim-4.20/src/expand.c Wed May 14 12:04:24 2003
-@@ -218,11 +218,14 @@
- { "caller_uid", vtype_int, &real_uid },
- { "compile_date", vtype_stringptr, &version_date },
- { "compile_number", vtype_stringptr, &version_cnumber },
-+ { "demime_errorlevel", vtype_int, &demime_errorlevel },
-+ { "demime_reason", vtype_stringptr, &demime_reason },
- { "dnslist_domain", vtype_stringptr, &dnslist_domain },
- { "dnslist_text", vtype_stringptr, &dnslist_text },
- { "dnslist_value", vtype_stringptr, &dnslist_value },
- { "domain", vtype_stringptr, &deliver_domain },
- { "domain_data", vtype_stringptr, &deliver_domain_data },
-+ { "found_extension", vtype_stringptr, &found_extension },
- { "home", vtype_stringptr, &deliver_home },
- { "host", vtype_stringptr, &deliver_host },
- { "host_address", vtype_stringptr, &deliver_host_address },
-@@ -241,6 +244,7 @@
- { "local_part_suffix", vtype_stringptr, &deliver_localpart_suffix },
- { "local_scan_data", vtype_stringptr, &local_scan_data },
- { "localhost_number", vtype_int, &host_number },
-+ { "malware_name", vtype_stringptr, &malware_name },
- { "message_age", vtype_int, &message_age },
- { "message_body", vtype_msgbody, &message_body },
- { "message_body_end", vtype_msgbody_end, &message_body_end },
-@@ -275,6 +279,7 @@
- { "received_protocol", vtype_stringptr, &received_protocol },
- { "recipients", vtype_recipients, NULL },
- { "recipients_count", vtype_int, &recipients_count },
-+ { "regex_match_string", vtype_stringptr, &regex_match_string },
- { "reply_address", vtype_reply, NULL },
- { "return_path", vtype_stringptr, &return_path },
- { "return_size_limit", vtype_int, &return_size_limit },
-@@ -302,6 +307,10 @@
- { "sn7", vtype_filter_int, &filter_sn[7] },
- { "sn8", vtype_filter_int, &filter_sn[8] },
- { "sn9", vtype_filter_int, &filter_sn[9] },
-+ { "spam_bar", vtype_stringptr, &spam_bar },
-+ { "spam_report", vtype_stringptr, &spam_report },
-+ { "spam_score", vtype_stringptr, &spam_score },
-+ { "spam_score_int", vtype_stringptr, &spam_score_int },
- { "spool_directory", vtype_stringptr, &spool_directory },
- { "thisaddress", vtype_stringptr, &filter_thisaddress },
- { "tls_certificate_verified", vtype_int, &tls_certificate_verified },
-diff -urN exim-4.20-orig/src/functions.h exim-4.20/src/functions.h
---- exim-4.20-orig/src/functions.h Mon May 12 15:39:19 2003
-+++ exim-4.20/src/functions.h Wed May 14 12:04:24 2003
-@@ -64,6 +64,7 @@
- extern void deliver_set_expansions(address_item *);
- extern int deliver_split_address(address_item *);
- extern void deliver_succeeded(address_item *);
-+extern int demime(uschar **);
- extern BOOL directory_make(uschar *, uschar *, int, BOOL);
- extern dns_address *dns_address_from_rr(dns_answer *, dns_record *);
- extern void dns_init(BOOL, BOOL);
-@@ -114,6 +115,7 @@
-
- extern void log_close_all(void);
-
-+extern int malware(uschar **);
- extern int match_address_list(uschar *, BOOL, uschar **, unsigned int *,
- int, int);
- extern int match_check_list(uschar **, int, tree_node **, unsigned int **,
-@@ -227,6 +229,8 @@
- extern BOOL smtp_start_session(void);
- extern int smtp_ungetc(int);
- extern int smtp_write_command(smtp_outblock *, BOOL, char *, ...);
-+extern int spam(uschar **);
-+extern FILE *spool_mbox(unsigned long long *);
- extern BOOL spool_move_message(uschar *, uschar *, uschar *, uschar *);
- extern BOOL spool_open_datafile(uschar *);
- extern int spool_open_temp(uschar *);
-@@ -277,6 +281,8 @@
- extern tree_node *tree_search(tree_node *, uschar *);
- extern void tree_write(tree_node *, FILE *);
-
-+extern void unspool_mbox(void);
-+
- extern int verify_address(address_item *, FILE *, int, int, BOOL *);
- extern int verify_check_dnsbl(uschar **);
- extern int verify_check_header_address(uschar **, uschar **, int);
-diff -urN exim-4.20-orig/src/globals.c exim-4.20/src/globals.c
---- exim-4.20-orig/src/globals.c Mon May 12 15:39:19 2003
-+++ exim-4.20/src/globals.c Fri May 23 11:06:00 2003
-@@ -286,6 +286,7 @@
- uschar *auth_defer_msg = US"reason not recorded";
- uschar *auth_defer_user_msg = US"";
- int auto_thaw = 0;
-+uschar *av_scanner = US"sophie:/var/run/sophie";
-
- BOOL background_daemon = TRUE;
- uschar *base62_chars=
-@@ -400,6 +401,8 @@
- BOOL deliver_selectstring_regex = FALSE;
- uschar *deliver_selectstring_sender = NULL;
- BOOL deliver_selectstring_sender_regex = FALSE;
-+int demime_errorlevel = 0;
-+uschar *demime_reason = NULL;
- BOOL disable_logging = FALSE;
-
- uschar *dns_again_means_nonexist = NULL;
-@@ -443,6 +446,7 @@
- uschar *filter_test = NULL;
- uschar *filter_thisaddress = NULL;
- int finduser_retries = 0;
-+uschar *found_extension = NULL;
- uschar *freeze_tell = NULL;
-
- uschar *gecos_name = NULL;
-@@ -565,6 +569,7 @@
- uschar *lookup_value = NULL;
-
- macro_item *macros = NULL;
-+uschar *malware_name = NULL;
- int max_username_length = 0;
- int message_age = 0;
- uschar *message_body = NULL;
-@@ -680,6 +685,7 @@
- const pcre *regex_PIPELINING = NULL;
- const pcre *regex_SIZE = NULL;
- const pcre *regex_ismsgid = NULL;
-+uschar *regex_match_string = NULL;
- int remote_delivery_count = 0;
- int remote_max_parallel = 2;
- uschar *remote_sort_domains = NULL;
-@@ -846,6 +852,11 @@
- int smtp_rlr_threshold = INT_MAX;
- BOOL smtp_use_pipelining = FALSE;
- BOOL smtp_use_size = FALSE;
-+uschar *spamd_address = US"127.0.0.1 783";
-+uschar *spam_bar = NULL;
-+uschar *spam_report = NULL;
-+uschar *spam_score = NULL;
-+uschar *spam_score_int = NULL;
- BOOL split_spool_directory = FALSE;
- uschar *spool_directory = US SPOOL_DIRECTORY
- "\0<--------------Space to patch spool_directory->";
-diff -urN exim-4.20-orig/src/globals.h exim-4.20/src/globals.h
---- exim-4.20-orig/src/globals.h Mon May 12 15:39:19 2003
-+++ exim-4.20/src/globals.h Wed May 14 12:04:24 2003
-@@ -129,6 +129,7 @@
- extern uschar *auth_defer_msg; /* Error message for log */
- extern uschar *auth_defer_user_msg; /* Error message for user */
- extern int auto_thaw; /* Auto-thaw interval */
-+extern uschar *av_scanner; /* AntiVirus scanner to use for the malware condition */
-
- extern BOOL background_daemon; /* Set FALSE to keep in foreground */
- extern uschar *base62_chars; /* Table of base-62 characters */
-@@ -210,6 +211,8 @@
- extern BOOL deliver_selectstring_regex; /* String is regex */
- extern uschar *deliver_selectstring_sender; /* For selecting by sender */
- extern BOOL deliver_selectstring_sender_regex; /* String is regex */
-+extern int demime_errorlevel; /* Severity of MIME error */
-+extern uschar *demime_reason; /* Reason for broken MIME container */
- extern BOOL disable_logging; /* Disables log writing when TRUE */
-
- extern uschar *dns_again_means_nonexist; /* Domains that are badly set up */
-@@ -250,6 +253,7 @@
- extern uschar *filter_test; /* Run as a filter tester on this file */
- extern uschar *filter_thisaddress; /* For address looping */
- extern int finduser_retries; /* Retry count for getpwnam() */
-+extern uschar *found_extension; /* demime acl condition: file extension found */
- extern uschar *freeze_tell; /* Message on (some) freezings */
-
- extern uschar *gecos_name; /* To be expanded when pattern matches */
-@@ -322,6 +326,7 @@
- extern uschar *lookup_value; /* Value looked up from file */
-
- extern macro_item *macros; /* Configuration macros */
-+extern uschar *malware_name; /* Name of virus or malware ("W32/Klez-H") */
- extern int max_username_length; /* For systems with broken getpwnam() */
- extern int message_age; /* In seconds */
- extern uschar *message_body; /* Start of message body for filter */
-@@ -421,6 +426,7 @@
- extern const pcre *regex_PIPELINING; /* For recognizing PIPELINING */
- extern const pcre *regex_SIZE; /* For recognizing SIZE settings */
- extern const pcre *regex_ismsgid; /* Compiled r.e. for message it */
-+extern uschar *regex_match_string; /* regex that matched a line (regex ACL condition) */
- extern int remote_delivery_count; /* Number of remote addresses */
- extern int remote_max_parallel; /* Maximum parallel delivery */
- extern uschar *remote_sort_domains; /* Remote domain sorting order */
-@@ -511,6 +517,11 @@
- extern BOOL smtp_use_pipelining; /* Global for passed connections */
- extern BOOL smtp_use_size; /* Global for passed connections */
- extern BOOL split_spool_directory; /* TRUE to use multiple subdirs */
-+extern uschar *spamd_address; /* address for the spamassassin daemon */
-+extern uschar *spam_bar; /* the spam "bar" (textual representation of spam_score) */
-+extern uschar *spam_report; /* the spamd report (multiline) */
-+extern uschar *spam_score; /* the spam score (float) */
-+extern uschar *spam_score_int; /* spam_score * 10 (int) */
- extern uschar *spool_directory; /* Name of spool directory */
- extern int string_datestamp_offset;/* After insertion by string_format */
- extern BOOL strip_excess_angle_brackets; /* Surrounding route-addrs */
-diff -urN exim-4.20-orig/src/malware.c exim-4.20/src/malware.c
---- exim-4.20-orig/src/malware.c Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/malware.c Thu Jun 5 09:33:29 2003
-@@ -0,0 +1,635 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
-+/* License: GPL */
-+
-+/* Code for calling virus (malware) scanners. Called from acl.c. */
-+
-+#include "exim.h"
-+
-+/* SHUT_WR seems to be undefined on Unixware ? */
-+#ifndef SHUT_WR
-+#define SHUT_WR 1
-+#endif
-+
-+uschar malware_name_buffer[256];
-+int malware_ok = 0;
-+
-+int malware(uschar **listptr) {
-+ int sep = 0;
-+ uschar *list = *listptr;
-+ uschar *av_scanner_work = av_scanner;
-+ uschar *scanner_name;
-+ uschar scanner_name_buffer[16];
-+ uschar *malware_regex;
-+ uschar malware_regex_buffer[64];
-+ uschar malware_regex_default[] = ".+";
-+ unsigned long long mbox_size;
-+ FILE *mbox_file;
-+ int roffset;
-+ const pcre *re;
-+ const uschar *rerror;
-+
-+ /* make sure the eml mbox file is spooled up */
-+ mbox_file = spool_mbox(&mbox_size);
-+ if (mbox_file == NULL) {
-+ /* error while spooling */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: error while creating mbox spool file");
-+ return DEFER;
-+ };
-+ /* none of our current scanners need the mbox
-+ file as a stream, so we can close it right away */
-+ fclose(mbox_file);
-+
-+ /* extract the malware regex to match against from the option list */
-+ if ((malware_regex = string_nextinlist(&list, &sep,
-+ malware_regex_buffer,
-+ sizeof(malware_regex_buffer))) != NULL) {
-+
-+ /* parse 1st option */
-+ if ( (strcmpic(malware_regex,US"false") == 0) ||
-+ (Ustrcmp(malware_regex,"0") == 0) ) {
-+ /* explicitly no matching */
-+ return FAIL;
-+ };
-+
-+ /* special cases (match anything except empty) */
-+ if ( (strcmpic(malware_regex,US"true") == 0) ||
-+ (Ustrcmp(malware_regex,"*") == 0) ||
-+ (Ustrcmp(malware_regex,"1") == 0) ) {
-+ malware_regex = malware_regex_default;
-+ };
-+ }
-+ else {
-+ /* empty means "don't match anything" */
-+ return FAIL;
-+ };
-+
-+ /* compile the regex, see if it works */
-+ re = pcre_compile(CS malware_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
-+ if (re == NULL) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: regular expression error in '%s': %s at offset %d", malware_regex, rerror, roffset);
-+ return DEFER;
-+ };
-+
-+ /* Do not scan twice. */
-+ if (malware_ok == 0) {
-+
-+ /* find the scanner type from the av_scanner option */
-+ if ((scanner_name = string_nextinlist(&av_scanner_work, &sep,
-+ scanner_name_buffer,
-+ sizeof(scanner_name_buffer))) == NULL) {
-+ /* no scanner given */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: av_scanner configuration variable is empty");
-+ return DEFER;
-+ };
-+
-+
-+
-+ /* "kavdaemon" scanner type ------------------------------------------------ */
-+ if (strcmpic(scanner_name,US"kavdaemon") == 0) {
-+ uschar *kav_options;
-+ uschar kav_options_buffer[1024];
-+ uschar kav_options_default[] = "/var/run/AvpCtl";
-+ struct sockaddr_un server;
-+ int sock;
-+ time_t t;
-+ uschar tmpbuf[1024];
-+ uschar scanrequest[1024];
-+ uschar kav_match_string[128];
-+ int kav_rc;
-+ unsigned long kav_reportlen, bread;
-+ pcre *kav_re;
-+
-+ if ((kav_options = string_nextinlist(&av_scanner_work, &sep,
-+ kav_options_buffer,
-+ sizeof(kav_options_buffer))) == NULL) {
-+ /* no options supplied, use default options */
-+ kav_options = kav_options_default;
-+ };
-+
-+ /* open the kavdaemon socket */
-+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
-+ if (sock < 0) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: can't open UNIX socket.");
-+ return DEFER;
-+ }
-+ server.sun_family = AF_UNIX;
-+ Ustrcpy(server.sun_path, kav_options);
-+ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: unable to connect to kavdaemon UNIX socket (%s). errno=%d", kav_options, errno);
-+ return DEFER;
-+ }
-+
-+ /* get current date and time, build scan request */
-+ time(&t);
-+ strftime(CS tmpbuf, sizeof(tmpbuf), "<0>%d %b %H:%M:%S:%%s/scan/%%s", localtime(&t));
-+ snprintf(CS scanrequest, 1024,CS tmpbuf, spool_directory, message_id);
-+
-+ /* send scan request */
-+ if (send(sock, scanrequest, Ustrlen(scanrequest)+1, 0) < 0) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: unable to write to kavdaemon UNIX socket (%s)", kav_options);
-+ return DEFER;
-+ }
-+
-+ /* wait for result */
-+ if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: unable to read 2 bytes from kavdaemon socket.");
-+ return DEFER;
-+ }
-+
-+ /* get errorcode from lower nibble */
-+ kav_rc = tmpbuf[0] & 0x0F;
-+
-+ /* improper kavdaemon configuration */
-+ if ( (kav_rc == 5) || (kav_rc == 6) ) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: please reconfigure kavdaemon to NOT disinfect or remove infected files.");
-+ return DEFER;
-+ };
-+
-+ if (kav_rc == 1) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: kavdaemon reported 'scanning not completed' (code 1).");
-+ return DEFER;
-+ };
-+
-+ if (kav_rc == 7) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: kavdaemon reported 'kavdaemon damaged' (code 7).");
-+ return DEFER;
-+ };
-+
-+ /* code 8 is not handled, since it is ambigous. It appears mostly on
-+ bounces where part of a file has been cut off */
-+
-+ /* "virus found" return codes (2-4) */
-+ if ((kav_rc > 1) && (kav_rc < 5)) {
-+
-+ /* setup default virus name */
-+ Ustrcpy(malware_name_buffer,"unknown");
-+ malware_name = malware_name_buffer;
-+
-+ /* read the report, if available */
-+ if( tmpbuf[1] == 1 ) {
-+ /* read report size */
-+ if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: cannot read report size from kavdaemon");
-+ return DEFER;
-+ };
-+
-+ /* it's possible that avp returns av_buffer[1] == 1 but the
-+ reportsize is 0 (!?) */
-+ if (kav_reportlen > 0) {
-+ /* set up match regex, depends on retcode */
-+ if( kav_rc == 3 )
-+ Ustrcpy(kav_match_string, "suspicion:\\s*(.+?)\\s*$");
-+ else
-+ Ustrcpy(kav_match_string, "infected:\\s*(.+?)\\s*$");
-+
-+ kav_re = pcre_compile( CS kav_match_string,
-+ PCRE_COPT,
-+ (const char **)&rerror,
-+ &roffset,
-+ NULL );
-+
-+ /* read report, linewise */
-+ while (kav_reportlen > 0) {
-+ int result = 0;
-+ int ovector[30];
-+
-+ bread = 0;
-+ while ( recv(sock, &tmpbuf[bread], 1, 0) == 1 ) {
-+ kav_reportlen--;
-+ if ( (tmpbuf[bread] == '\n') || (bread > 1021) ) break;
-+ bread++;
-+ };
-+ bread++;
-+ tmpbuf[bread] = '\0';
-+
-+ /* try matcher on the line, grab substring */
-+ result = pcre_exec(kav_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30);
-+ if (result >= 2) {
-+ pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS malware_name_buffer, 255);
-+ break;
-+ };
-+ };
-+ };
-+ };
-+ }
-+ else {
-+ /* no virus found */
-+ malware_name = NULL;
-+ };
-+
-+ close(sock);
-+ }
-+ /* ----------------------------------------------------------------------- */
-+
-+
-+ /* "cmdline" scanner type ------------------------------------------------ */
-+ else if (strcmpic(scanner_name,US"cmdline") == 0) {
-+ uschar *cmdline_scanner;
-+ uschar cmdline_scanner_buffer[1024];
-+ uschar *cmdline_trigger;
-+ uschar cmdline_trigger_buffer[1024];
-+ const pcre *cmdline_trigger_re;
-+ uschar *cmdline_regex;
-+ uschar cmdline_regex_buffer[1024];
-+ const pcre *cmdline_regex_re;
-+ uschar file_name[1024];
-+ uschar commandline[1024];
-+ FILE *scanner_out = NULL;
-+ FILE *scanner_record = NULL;
-+ uschar linebuffer[32767];
-+ int trigger = 0;
-+ int result;
-+ int ovector[30];
-+
-+ /* find scanner command line */
-+ if ((cmdline_scanner = string_nextinlist(&av_scanner_work, &sep,
-+ cmdline_scanner_buffer,
-+ sizeof(cmdline_scanner_buffer))) == NULL) {
-+ /* no command line supplied */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: missing commandline specification for cmdline scanner type.");
-+ return DEFER;
-+ };
-+
-+ /* find scanner output trigger */
-+ if ((cmdline_trigger = string_nextinlist(&av_scanner_work, &sep,
-+ cmdline_trigger_buffer,
-+ sizeof(cmdline_trigger_buffer))) == NULL) {
-+ /* no trigger regex supplied */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: missing trigger specification for cmdline scanner type.");
-+ return DEFER;
-+ };
-+
-+ /* precompile trigger regex */
-+ cmdline_trigger_re = pcre_compile(CS cmdline_trigger, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
-+ if (cmdline_trigger_re == NULL) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_trigger_re, rerror, roffset);
-+ return DEFER;
-+ };
-+
-+ /* find scanner name regex */
-+ if ((cmdline_regex = string_nextinlist(&av_scanner_work, &sep,
-+ cmdline_regex_buffer,
-+ sizeof(cmdline_regex_buffer))) == NULL) {
-+ /* no name regex supplied */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: missing virus name regex specification for cmdline scanner type.");
-+ return DEFER;
-+ };
-+
-+ /* precompile name regex */
-+ cmdline_regex_re = pcre_compile(CS cmdline_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
-+ if (cmdline_regex_re == NULL) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_regex_re, rerror, roffset);
-+ return DEFER;
-+ };
-+
-+ /* prepare scanner call */
-+ snprintf(CS file_name,1024,"%s/scan/%s", spool_directory, message_id);
-+ snprintf(CS commandline,1024, CS cmdline_scanner,file_name);
-+ /* redirect STDERR too */
-+ Ustrcat(commandline," 2>&1");
-+
-+ scanner_out = popen(CS commandline,"r");
-+ if (scanner_out == NULL) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: calling cmdline scanner (%s) failed: %s.", commandline, strerror(errno));
-+ return DEFER;
-+ };
-+
-+ snprintf(CS file_name,1024,"%s/scan/%s/%s_scanner_output", spool_directory, message_id, message_id);
-+ scanner_record = fopen(CS file_name,"w");
-+
-+ if (scanner_record == NULL) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: opening scanner output file (%s) failed: %s.", file_name, strerror(errno));
-+ pclose(scanner_out);
-+ return DEFER;
-+ };
-+
-+ /* look for trigger while recording output */
-+ while(fgets(CS linebuffer,32767,scanner_out) != NULL) {
-+ if ( Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record) ) {
-+ /* short write */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: short write on scanner output file (%s).", file_name);
-+ pclose(scanner_out);
-+ return DEFER;
-+ };
-+ /* try trigger match */
-+ if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1))
-+ trigger = 1;
-+ };
-+
-+ fclose(scanner_record);
-+ pclose(scanner_out);
-+
-+ if (trigger) {
-+ /* setup default virus name */
-+ Ustrcpy(malware_name_buffer,"unknown");
-+ malware_name = malware_name_buffer;
-+
-+ /* re-open the scanner output file, look for name match */
-+ scanner_record = fopen(CS file_name,"r");
-+ while(fgets(CS linebuffer,32767,scanner_record) != NULL) {
-+ /* try match */
-+ result = pcre_exec(cmdline_regex_re, NULL, CS linebuffer, Ustrlen(linebuffer), 0, 0, ovector, 30);
-+ if (result >= 2) {
-+ pcre_copy_substring(CS linebuffer, ovector, result, 1, CS malware_name_buffer, 255);
-+ };
-+ };
-+ fclose(scanner_record);
-+ }
-+ else {
-+ /* no virus found */
-+ malware_name = NULL;
-+ };
-+ }
-+ /* ----------------------------------------------------------------------- */
-+
-+
-+ /* "sophie" scanner type ------------------------------------------------- */
-+ else if (strcmpic(scanner_name,US"sophie") == 0) {
-+ uschar *sophie_options;
-+ uschar sophie_options_buffer[1024];
-+ uschar sophie_options_default[] = "/var/run/sophie";
-+ int bread = 0;
-+ struct sockaddr_un server;
-+ int sock;
-+ uschar file_name[1024];
-+ uschar av_buffer[1024];
-+
-+ if ((sophie_options = string_nextinlist(&av_scanner_work, &sep,
-+ sophie_options_buffer,
-+ sizeof(sophie_options_buffer))) == NULL) {
-+ /* no options supplied, use default options */
-+ sophie_options = sophie_options_default;
-+ };
-+
-+ /* open the sophie socket */
-+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
-+ if (sock < 0) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: can't open UNIX socket.");
-+ return DEFER;
-+ }
-+ server.sun_family = AF_UNIX;
-+ Ustrcpy(server.sun_path, sophie_options);
-+ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: unable to connect to sophie UNIX socket (%s). errno=%d", sophie_options, errno);
-+ return DEFER;
-+ }
-+
-+ /* pass the scan directory to sophie */
-+ snprintf(CS file_name,1024,"%s/scan/%s", spool_directory, message_id);
-+ if (write(sock, file_name, Ustrlen(file_name)) < 0) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: unable to write to sophie UNIX socket (%s)", sophie_options);
-+ return DEFER;
-+ };
-+
-+ write(sock, "\n", 1);
-+
-+ /* wait for result */
-+ memset(av_buffer, 0, sizeof(av_buffer));
-+ if ((!(bread = read(sock, av_buffer, sizeof(av_buffer))) > 0)) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: unable to read from sophie UNIX socket (%s)", sophie_options);
-+ return DEFER;
-+ };
-+
-+ close(sock);
-+
-+ /* infected ? */
-+ if (av_buffer[0] == '1') {
-+ if (Ustrchr(av_buffer, '\n')) *Ustrchr(av_buffer, '\n') = '\0';
-+ Ustrcpy(malware_name_buffer,&av_buffer[2]);
-+ malware_name = malware_name_buffer;
-+ }
-+ else if (!strncmp(CS av_buffer, "-1", 2)) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: malware acl condition: sophie reported error");
-+ return DEFER;
-+ }
-+ else {
-+ /* all ok, no virus */
-+ malware_name = NULL;
-+ };
-+ }
-+ /* ----------------------------------------------------------------------- */
-+
-+
-+ /* "clamd" scanner type ------------------------------------------------- */
-+ /* This code was contributed by David Saez <david@ols.es> */
-+ else if (strcmpic(scanner_name,US"clamd") == 0) {
-+ uschar *clamd_options;
-+ uschar clamd_options_buffer[1024];
-+ uschar clamd_options_default[] = "/tmp/clamd";
-+ uschar *p,*vname;
-+ struct sockaddr_un server;
-+ int sock,port,i,offset=0,bread=0;
-+ uschar file_name[1024];
-+ uschar av_buffer[1024];
-+ uschar hostname[256];
-+ struct hostent *he;
-+ struct in_addr in;
-+
-+ if ((clamd_options = string_nextinlist(&av_scanner_work, &sep,
-+ clamd_options_buffer,
-+ sizeof(clamd_options_buffer))) == NULL) {
-+ /* no options supplied, use default options */
-+ clamd_options = clamd_options_default;
-+ }
-+
-+ /* socket does not start with '/' -> network socket */
-+ if (*clamd_options != '/') {
-+
-+ /* extract host and port part */
-+ if( sscanf(CS clamd_options, "%s %u", hostname, &port) != 2 ) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: invalid socket '%s'", clamd_options);
-+ return DEFER;
-+ };
-+
-+ /* Lookup the host */
-+ if((he = gethostbyname(CS hostname)) == 0) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: failed to lookup host '%s'", hostname);
-+ return DEFER;
-+ }
-+
-+ in = *(struct in_addr *) he->h_addr_list[0];
-+
-+ /* Open the ClamAV Socket */
-+ if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: unable to acquire socket (%s)",
-+ strerror(errno));
-+ return DEFER;
-+ }
-+
-+ if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: connection to %s, port %u failed (%s)",
-+ inet_ntoa(in), port, strerror(errno));
-+ return DEFER;
-+ }
-+ }
-+ else {
-+ /* open the local socket */
-+ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: unable to acquire socket (%s)",
-+ strerror(errno));
-+ return DEFER;
-+ }
-+
-+ server.sun_family = AF_UNIX;
-+ Ustrcpy(server.sun_path, clamd_options);
-+
-+ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: unable to connect to UNIX socket %s (%s)",
-+ clamd_options, strerror(errno) );
-+ return DEFER;
-+ }
-+ }
-+
-+ /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
-+
-+ snprintf(CS file_name,1024,"SCAN %s/scan/%s\n", spool_directory, message_id);
-+
-+ if (send(sock, file_name, Ustrlen(file_name), 0) < 0) {
-+ close(sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
-+ strerror(errno));
-+ return DEFER;
-+ }
-+
-+ /* we're done sending, close socket for writing */
-+ shutdown(sock, SHUT_WR);
-+
-+ /* Read the result */
-+ memset(av_buffer, 0, sizeof(av_buffer));
-+ bread = read(sock, av_buffer, sizeof(av_buffer));
-+ close(sock);
-+
-+ if (!(bread > 0)) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: unable to read from socket (%s)",
-+ strerror(errno));
-+ return DEFER;
-+ }
-+
-+ if (bread == sizeof(av_buffer)) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: buffer too small");
-+ return DEFER;
-+ }
-+
-+ /* Check the result. ClamAV Returns
-+ infected: -> "<filename>: <virusname> FOUND"
-+ not-infected: -> "<filename>: OK"
-+ error: -> "<filename>: <errcode> ERROR */
-+
-+ if (!(*av_buffer)) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: ClamAV returned null");
-+ return DEFER;
-+ }
-+
-+ /* colon in returned output? */
-+ if((p = Ustrrchr(av_buffer,':')) == NULL) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: ClamAV returned malformed result: %s",
-+ av_buffer);
-+ return DEFER;
-+ }
-+
-+ /* strip filename strip CR at the end */
-+ vname = ++p;
-+ p = vname + Ustrlen(vname) - 1;
-+ if( *p == '\n' ) *p = '\0';
-+
-+ if ((p = Ustrstr(vname, "FOUND"))!=NULL) {
-+ *p=0;
-+ for (--p;p>vname && *p<=32;p--) *p=0;
-+ Ustrcpy(malware_name_buffer,vname);
-+ malware_name = malware_name_buffer;
-+ }
-+ else {
-+ if (Ustrstr(vname, "ERROR")!=NULL) {
-+ /* ClamAV reports ERROR
-+ Find line start */
-+ for (;*vname!='\n' && vname>av_buffer; vname--);
-+ if (*vname=='\n') vname++;
-+
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware acl condition: clamd: ClamAV returned %s",vname);
-+ return DEFER;
-+ }
-+ else {
-+ /* Everything should be OK */
-+ malware_name = NULL;
-+ }
-+ }
-+ }
-+ /* ----------------------------------------------------------------------- */
-+
-+
-+
-+ /* "unknown" scanner type ------------------------------------------------- */
-+ else {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "malware condition: unknown scanner type '%s'", scanner_name);
-+ return DEFER;
-+ };
-+ /* ----------------------------------------------------------------------- */
-+
-+ /* set "been here, done that" marker */
-+ malware_ok = 1;
-+ };
-+
-+ /* match virus name against pattern (caseless ------->----------v) */
-+ if ( (malware_name != NULL) &&
-+ (regex_match_and_setup(re, malware_name, 0, -1)) ) {
-+ return OK;
-+ }
-+ else {
-+ return FAIL;
-+ };
-+}
-diff -urN exim-4.20-orig/src/readconf.c exim-4.20/src/readconf.c
---- exim-4.20-orig/src/readconf.c Mon May 12 15:39:21 2003
-+++ exim-4.20/src/readconf.c Wed May 14 12:04:24 2003
-@@ -152,6 +152,7 @@
- { "allow_utf8_domains", opt_bool, &allow_utf8_domains },
- { "auth_advertise_hosts", opt_stringptr, &auth_advertise_hosts },
- { "auto_thaw", opt_time, &auto_thaw },
-+ { "av_scanner", opt_stringptr, &av_scanner },
- { "bi_command", opt_stringptr, &bi_command },
- { "bounce_message_file", opt_stringptr, &bounce_message_file },
- { "bounce_message_text", opt_stringptr, &bounce_message_text },
-@@ -297,6 +298,7 @@
- { "smtp_receive_timeout", opt_time, &smtp_receive_timeout },
- { "smtp_reserve_hosts", opt_stringptr, &smtp_reserve_hosts },
- { "smtp_return_error_details",opt_bool, &smtp_return_error_details },
-+ { "spamd_address", opt_stringptr, &spamd_address },
- { "split_spool_directory", opt_bool, &split_spool_directory },
- { "spool_directory", opt_stringptr, &spool_directory },
- { "strip_excess_angle_brackets", opt_bool, &strip_excess_angle_brackets },
-diff -urN exim-4.20-orig/src/regex.c exim-4.20/src/regex.c
---- exim-4.20-orig/src/regex.c Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/regex.c Wed May 14 12:04:24 2003
-@@ -0,0 +1,110 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
-+/* License: GPL */
-+
-+/* Code for matching regular expressions against headers and body.
-+ Called from acl.c. */
-+
-+#include "exim.h"
-+
-+/* Structure to hold a list of Regular expressions */
-+typedef struct pcre_list {
-+ pcre *re;
-+ uschar *pcre_text;
-+ struct pcre_list *next;
-+} pcre_list;
-+
-+uschar regex_match_string_buffer[1024];
-+
-+int regex(uschar **listptr) {
-+ int sep = 0;
-+ uschar *list = *listptr;
-+ uschar *regex_string;
-+ uschar regex_string_buffer[1024];
-+ unsigned long long mbox_size;
-+ FILE *mbox_file;
-+ pcre *re;
-+ pcre_list *re_list_head = NULL;
-+ pcre_list *re_list_item;
-+ const char *pcre_error;
-+ int pcre_erroffset;
-+ uschar *linebuffer;
-+
-+ /* reset expansion variable */
-+ regex_match_string = NULL;
-+
-+ /* make sure the eml mbox file is spooled up */
-+ mbox_file = spool_mbox(&mbox_size);
-+ if (mbox_file == NULL) {
-+ /* error while spooling */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "regex acl condition: error while creating mbox spool file");
-+ return DEFER;
-+ };
-+
-+ /* precompile our regexes */
-+ while ((regex_string = string_nextinlist(&list, &sep,
-+ regex_string_buffer,
-+ sizeof(regex_string_buffer))) != NULL) {
-+
-+ /* parse option */
-+ if ( (strcmpic(regex_string,US"false") == 0) ||
-+ (Ustrcmp(regex_string,"0") == 0) ) {
-+ /* explicitly no matching */
-+ continue;
-+ };
-+
-+ /* compile our regular expression */
-+ re = pcre_compile( CS regex_string,
-+ 0,
-+ &pcre_error,
-+ &pcre_erroffset,
-+ NULL );
-+
-+ if (re == NULL) {
-+ log_write(0, LOG_MAIN,
-+ "regex acl condition warning - error in regex '%s': %s at offset %d, skipped.", regex_string, pcre_error, pcre_erroffset);
-+ continue;
-+ }
-+ else {
-+ re_list_item = store_get(sizeof(pcre_list));
-+ re_list_item->re = re;
-+ re_list_item->pcre_text = string_copy(regex_string);
-+ re_list_item->next = re_list_head;
-+ re_list_head = re_list_item;
-+ };
-+ };
-+
-+ /* no regexes -> nothing to do */
-+ if (re_list_head == NULL) {
-+ return FAIL;
-+ };
-+
-+ /* match each line against all regexes */
-+ linebuffer = store_get(32767);
-+ while (fgets(CS linebuffer, 32767, mbox_file) != NULL) {
-+ re_list_item = re_list_head;
-+ do {
-+ /* try matcher on the line */
-+ if (pcre_exec(re_list_item->re, NULL, CS linebuffer,
-+ (int)Ustrlen(linebuffer), 0, 0, NULL, 0) >= 0) {
-+ Ustrncpy(regex_match_string_buffer, re_list_item->pcre_text, 1023);
-+ regex_match_string = regex_match_string_buffer;
-+ fclose(mbox_file);
-+ return OK;
-+ };
-+ re_list_item = re_list_item->next;
-+ } while (re_list_item != NULL);
-+ };
-+
-+ fclose(mbox_file);
-+
-+ /* no matches ... */
-+ return FAIL;
-+}
-diff -urN exim-4.20-orig/src/spam.c exim-4.20/src/spam.c
---- exim-4.20-orig/src/spam.c Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/spam.c Wed May 21 09:35:15 2003
-@@ -0,0 +1,264 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
-+/* License: GPL */
-+
-+/* Code for calling spamassassin's spamd. Called from acl.c. */
-+
-+#include "exim.h"
-+#include "spam.h"
-+
-+uschar spam_score_buffer[16];
-+uschar spam_score_int_buffer[16];
-+uschar spam_bar_buffer[128];
-+uschar spam_report_buffer[32600];
-+uschar prev_user_name[128];
-+int spam_ok = 0;
-+int spam_rc = 0;
-+
-+int spam(uschar **listptr) {
-+ int sep = 0;
-+ uschar *list = *listptr;
-+ uschar *user_name;
-+ uschar user_name_buffer[128];
-+ unsigned long long mbox_size;
-+ FILE *mbox_file;
-+ int spamd_sock;
-+ uschar tcp_addr[24];
-+ unsigned int tcp_port;
-+ uschar spamd_buffer[32600];
-+ int i, j, offset;
-+ uschar spamd_version[8];
-+ uschar spamd_score_char;
-+ double spamd_threshold, spamd_score;
-+ int spamd_report_offset;
-+ uschar *p,*q;
-+ int override = 0;
-+
-+ /* find the username from the option list */
-+ if ((user_name = string_nextinlist(&list, &sep,
-+ user_name_buffer,
-+ sizeof(user_name_buffer))) == NULL) {
-+ /* no username given, this means no scanning should be done */
-+ return FAIL;
-+ };
-+
-+ /* if username is "0" or "false", do not scan */
-+ if ( (Ustrcmp(user_name,"0") == 0) ||
-+ (strcmpic(user_name,US"false") == 0) ) {
-+ return FAIL;
-+ };
-+
-+ /* if there is an additional option, check if it is "true" */
-+ if (strcmpic(list,US"true") == 0) {
-+ /* in that case, always return true later */
-+ override = 1;
-+ };
-+
-+ /* if we scanned for this username last time, just return */
-+ if ( spam_ok && ( Ustrcmp(prev_user_name, user_name) == 0 ) )
-+ if (override)
-+ return OK;
-+ else
-+ return spam_rc;
-+
-+ /* make sure the eml mbox file is spooled up */
-+ mbox_file = spool_mbox(&mbox_size);
-+
-+ if (mbox_file == NULL) {
-+ /* error while spooling */
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: error while creating mbox spool file");
-+ return DEFER;
-+ };
-+
-+ /* contact spamd */
-+ spamd_sock = ip_socket(SOCK_STREAM, AF_INET);
-+ if (spamd_sock < 0) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: error creating IP socket for spamd");
-+ fclose(mbox_file);
-+ return DEFER;
-+ };
-+
-+ if (ip_bind(spamd_sock, AF_INET, US"0.0.0.0", 0) < 0) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: bind socket for spamd failed: %s",strerror(errno));
-+ fclose(mbox_file);
-+ close(spamd_sock);
-+ return DEFER;
-+ };
-+
-+ /* grok spamd address and port */
-+ if( sscanf(CS spamd_address, "%s %u", tcp_addr, &tcp_port) != 2 ) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: invalid spamd address: '%s'", spamd_address);
-+ fclose(mbox_file);
-+ close(spamd_sock);
-+ return DEFER;
-+ };
-+
-+ if (ip_connect(spamd_sock, AF_INET, tcp_addr, tcp_port, 5) < 0) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: spamd connection to %s, port %u failed: %s", tcp_addr, tcp_port, strerror(errno));
-+ fclose(mbox_file);
-+ close(spamd_sock);
-+ return DEFER;
-+ };
-+
-+ /* now we are connected to spamd on spamd_sock */
-+ snprintf(CS spamd_buffer,
-+ sizeof(spamd_buffer),
-+ "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %lld\r\n\r\n",
-+ user_name,
-+ mbox_size);
-+
-+ /* send our request */
-+ if (send(spamd_sock, spamd_buffer, Ustrlen(spamd_buffer), 0) < 0) {
-+ close(spamd_sock);
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: spamd send failed: %s", strerror(errno));
-+ fclose(mbox_file);
-+ close(spamd_sock);
-+ return DEFER;
-+ };
-+
-+ /* now send the file */
-+ do {
-+ j = fread(spamd_buffer,1,sizeof(spamd_buffer),mbox_file);
-+ if (j > 0) {
-+ i = send(spamd_sock,spamd_buffer,j,0);
-+ if (i != j) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: error/short send to spamd");
-+ close(spamd_sock);
-+ fclose(mbox_file);
-+ return DEFER;
-+ };
-+ };
-+ }
-+ while (j > 0);
-+
-+ fclose(mbox_file);
-+
-+ /* we're done sending, close socket for writing */
-+ shutdown(spamd_sock,SHUT_WR);
-+
-+ /* read spamd response */
-+ memset(spamd_buffer, 0, sizeof(spamd_buffer));
-+ offset = 0;
-+ while((i = ip_recv(spamd_sock,
-+ spamd_buffer + offset,
-+ sizeof(spamd_buffer) - offset - 1,
-+ SPAMD_READ_TIMEOUT)) > 0 ) {
-+ offset += i;
-+ }
-+
-+ /* error handling */
-+ if((i <= 0) && (errno != 0)) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: error reading from spamd socket: %s", strerror(errno));
-+ close(spamd_sock);
-+ return DEFER;
-+ }
-+
-+ /* reading done */
-+ close(spamd_sock);
-+
-+ /* dig in the spamd output and put the report in a multiline header, if requested */
-+ if( sscanf(CS spamd_buffer,"SPAMD/%s 0 EX_OK\r\nContent-length: %*u\r\n\r\n%lf/%lf\r\n%n",
-+ spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
-+
-+ /* try to fall back to pre-2.50 spamd output */
-+ if( sscanf(CS spamd_buffer,"SPAMD/%s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n",
-+ spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
-+ log_write(0, LOG_MAIN|LOG_PANIC,
-+ "spam acl condition: cannot parse spamd output");
-+ return DEFER;
-+ };
-+ };
-+
-+ /* Create report. Since this is a multiline string,
-+ we must hack it into shape first */
-+ p = &spamd_buffer[spamd_report_offset];
-+ q = spam_report_buffer;
-+ while (*p != '\0') {
-+ /* skip \r */
-+ if (*p == '\r') {
-+ p++;
-+ continue;
-+ };
-+ *q = *p;
-+ q++;
-+ if (*p == '\n') {
-+ *q = '\t';
-+ q++;
-+ /* eat whitespace */
-+ while( (*p <= ' ') && (*p != '\0') ) {
-+ p++;
-+ };
-+ p--;
-+ };
-+ p++;
-+ };
-+ /* NULL-terminate */
-+ *q = '\0';
-+ q--;
-+ /* cut off trailing leftovers */
-+ while (*q <= ' ') {
-+ *q = '\0';
-+ q--;
-+ };
-+ spam_report = spam_report_buffer;
-+
-+ /* create spam bar */
-+ spamd_score_char = spamd_score > 0 ? '+' : '-';
-+ j = abs((int)(spamd_score));
-+ i = 0;
-+ if( j != 0 ) {
-+ while((i < j) && (i <= MAX_SPAM_BAR_CHARS))
-+ spam_bar_buffer[i++] = spamd_score_char;
-+ }
-+ else{
-+ spam_bar_buffer[0] = '/';
-+ i = 1;
-+ }
-+ spam_bar_buffer[i] = '\0';
-+ spam_bar = spam_bar_buffer;
-+
-+ /* create "float" spam score */
-+ snprintf(CS spam_score_buffer, sizeof(spam_score_buffer),"%.1f", spamd_score);
-+ spam_score = spam_score_buffer;
-+
-+ /* create "int" spam score */
-+ j = (int)(spamd_score*10);
-+ snprintf(CS spam_score_int_buffer, sizeof(spam_score_int_buffer), "%d", j);
-+ spam_score_int = spam_score_int_buffer;
-+
-+ /* compare threshold against score */
-+ if (spamd_score >= spamd_threshold) {
-+ /* spam as determined by user's threshold */
-+ spam_rc = OK;
-+ }
-+ else {
-+ /* not spam */
-+ spam_rc = FAIL;
-+ };
-+
-+ /* remember user name and "been here" for it */
-+ Ustrcpy(prev_user_name, user_name);
-+ spam_ok = 1;
-+
-+ if (override) {
-+ /* always return OK, no matter what the score */
-+ return OK;
-+ }
-+ else {
-+ return spam_rc;
-+ };
-+}
-diff -urN exim-4.20-orig/src/spam.h exim-4.20/src/spam.h
---- exim-4.20-orig/src/spam.h Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/spam.h Wed May 14 12:04:24 2003
-@@ -0,0 +1,23 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
-+/* License: GPL */
-+
-+/* spam defines */
-+
-+/* timeout for reading from spamd */
-+#define SPAMD_READ_TIMEOUT 3600
-+
-+/* maximum length of the spam bar */
-+#define MAX_SPAM_BAR_CHARS 50
-+
-+/* SHUT_WR seems to be undefined on Unixware ? */
-+#ifndef SHUT_WR
-+#define SHUT_WR 1
-+#endif
-+
-diff -urN exim-4.20-orig/src/spool_in.c exim-4.20/src/spool_in.c
---- exim-4.20-orig/src/spool_in.c Mon May 12 15:39:22 2003
-+++ exim-4.20/src/spool_in.c Wed May 14 12:04:24 2003
-@@ -248,6 +248,7 @@
- interface_port = 0;
- local_error_message = FALSE;
- local_scan_data = NULL;
-+spam_score_int = NULL;
- message_linecount = 0;
- received_protocol = NULL;
- recipients_list = NULL;
-@@ -347,6 +348,8 @@
- local_error_message = TRUE;
- else if (Ustrncmp(big_buffer, "-local_scan ", 12) == 0)
- local_scan_data = string_copy(big_buffer + 12);
-+ else if (Ustrncmp(big_buffer, "-spam_score_int ", 16) == 0)
-+ spam_score_int = string_copy(big_buffer + 16);
- else if (Ustrcmp(big_buffer, "-host_lookup_failed") == 0)
- host_lookup_failed = TRUE;
- else if (Ustrncmp(big_buffer, "-body_linecount", 15) == 0)
-diff -urN exim-4.20-orig/src/spool_mbox.c exim-4.20/src/spool_mbox.c
---- exim-4.20-orig/src/spool_mbox.c Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/spool_mbox.c Tue Jun 10 15:43:43 2003
-@@ -0,0 +1,157 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
-+/* License: GPL */
-+
-+/* Code for setting up a MBOX style spool file inside a /scan/<msgid>
-+sub directory of exim's spool directory. */
-+
-+#include "exim.h"
-+
-+/* externals, we must reset them on unspooling */
-+extern int demime_ok;
-+extern int malware_ok;
-+extern int spam_ok;
-+extern struct file_extension *file_extensions;
-+
-+int spool_mbox_ok = 0;
-+
-+/* returns a pointer to the FILE, and puts the size in bytes into mbox_file_size */
-+
-+FILE *spool_mbox(unsigned long long *mbox_file_size) {
-+ uschar mbox_path[1024];
-+ uschar message_subdir[2];
-+ uschar data_buffer[65535];
-+ FILE *mbox_file;
-+ FILE *data_file;
-+ header_line *my_headerlist;
-+ struct stat statbuf;
-+ int i,j;
-+
-+ if (!spool_mbox_ok) {
-+ /* create scan directory, if not present */
-+ if (!directory_make(spool_directory, US "scan", 0750, FALSE)) {
-+ debug_printf("unable to create directory: %s/scan\n", spool_directory);
-+ return NULL;
-+ };
-+
-+ /* create temp directory inside scan dir */
-+ snprintf(CS mbox_path, 1024, "%s/scan/%s", spool_directory, message_id);
-+ if (!directory_make(NULL, mbox_path, 0750, FALSE)) {
-+ debug_printf("unable to create directory: %s/scan/%s\n", spool_directory, message_id);
-+ return NULL;
-+ };
-+
-+ /* open [message_id].eml file for writing */
-+ snprintf(CS mbox_path, 1024, "%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
-+ mbox_file = Ufopen(mbox_path,"w");
-+
-+ if (mbox_file == NULL) {
-+ debug_printf("unable to open file for writing: %s\n", mbox_path);
-+ return NULL;
-+ };
-+
-+ /* write all header lines to mbox file */
-+ my_headerlist = header_list;
-+ while (my_headerlist != NULL) {
-+
-+ /* skip deleted headers */
-+ if (my_headerlist->type == '*') {
-+ my_headerlist = my_headerlist->next;
-+ continue;
-+ };
-+
-+ i = fwrite(my_headerlist->text, 1, my_headerlist->slen, mbox_file);
-+ if (i != my_headerlist->slen) {
-+ debug_printf("error/short write on writing in: %s", mbox_path);
-+ fclose(mbox_file);
-+ return NULL;
-+ };
-+
-+ my_headerlist = my_headerlist->next;
-+ };
-+
-+ /* copy body file */
-+ message_subdir[1] = '\0';
-+ for (i = 0; i < 2; i++) {
-+ message_subdir[0] = (split_spool_directory == (i == 0))? message_id[5] : 0;
-+ sprintf(CS mbox_path, "%s/input/%s/%s-D", spool_directory, message_subdir, message_id);
-+ data_file = Ufopen(mbox_path,"r");
-+ if (data_file != NULL)
-+ break;
-+ };
-+
-+ fread(data_buffer, 1, 18, data_file);
-+
-+ do {
-+ j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
-+ if (j > 0) {
-+ i = fwrite(data_buffer, 1, j, mbox_file);
-+ if (i != j) {
-+ debug_printf("error/short write on writing in: %s", mbox_path);
-+ fclose(mbox_file);
-+ fclose(data_file);
-+ return NULL;
-+ };
-+ };
-+ } while (j > 0);
-+
-+ fclose(data_file);
-+ fclose(mbox_file);
-+ spool_mbox_ok = 1;
-+ };
-+
-+ snprintf(CS mbox_path, 1024, "%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
-+
-+ /* get the size of the mbox message */
-+ stat(CS mbox_path, &statbuf);
-+ *mbox_file_size = statbuf.st_size;
-+
-+ /* open [message_id].eml file for reading */
-+ mbox_file = Ufopen(mbox_path,"r");
-+
-+ return mbox_file;
-+}
-+
-+/* remove mbox spool file, demimed files and temp directory */
-+void unspool_mbox(void) {
-+
-+ /* reset all exiscan state variables */
-+ demime_ok = 0;
-+ file_extensions = NULL;
-+ spam_ok = 0;
-+ malware_ok = 0;
-+
-+ if (spool_mbox_ok) {
-+ uschar mbox_path[1024];
-+ uschar file_path[1024];
-+ int n;
-+ struct dirent *entry;
-+ DIR *tempdir;
-+
-+ spool_mbox_ok = 0;
-+
-+ snprintf(CS mbox_path, 1024, "%s/scan/%s", spool_directory, message_id);
-+
-+ tempdir = opendir(CS mbox_path);
-+ /* loop thru dir & delete entries */
-+ n = 0;
-+ do {
-+ entry = readdir(tempdir);
-+ if (entry == NULL) break;
-+ snprintf(CS file_path, 1024,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name);
-+ if ( (Ustrcmp(entry->d_name,"..") != 0) && (Ustrcmp(entry->d_name,".") != 0) )
-+ n = unlink(CS file_path);
-+ } while (n > -1);
-+
-+ closedir(tempdir);
-+
-+ /* remove directory */
-+ n = rmdir(CS mbox_path);
-+ };
-+}
-diff -urN exim-4.20-orig/src/spool_out.c exim-4.20/src/spool_out.c
---- exim-4.20-orig/src/spool_out.c Mon May 12 15:39:22 2003
-+++ exim-4.20/src/spool_out.c Wed May 14 12:04:24 2003
-@@ -200,6 +200,7 @@
- if (sender_local) fprintf(f, "-local\n");
- if (local_error_message) fprintf(f, "-localerror\n");
- if (local_scan_data != NULL) fprintf(f, "-local_scan %s\n", local_scan_data);
-+if (spam_score_int != NULL) fprintf(f,"-spam_score_int %s\n", spam_score_int);
- if (deliver_manual_thaw) fprintf(f, "-manual_thaw\n");
- if (sender_set_untrusted) fprintf(f, "-sender_set_untrusted\n");
-
-diff -urN exim-4.20-orig/src/tnef.c exim-4.20/src/tnef.c
---- exim-4.20-orig/src/tnef.c Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/tnef.c Wed May 14 12:04:24 2003
-@@ -0,0 +1,741 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/* Code for unpacking TNEF containers. Called from demime.c. */
-+
-+/***************************************************************************
-+ * tnef2txt
-+* A program to decode application/ms-tnef MIME attachments into text
-+* for those fortunate enough not to be running either a Microsoft
-+* operating system or mailer.
-+*
-+ * 18/10/2001
-+* Brutally cropped by Paul L Daniels (pldaniels@pldaniels.com) in order
-+* to accommodate the needs of ripMIME/Xamime/Inflex without carrying too
-+* much excess baggage.
-+*
-+ * Brandon Long (blong@uiuc.edu), April 1997
-+* 1.0 Version
-+* Supports most types, but doesn't decode properties. Maybe some other
-+* time.
-+*
-+ * 1.1 Version (7/1/97)
-+* Supports saving of attAttachData to a file given by attAttachTitle
-+* start of property decoding support
-+*
-+ * 1.2 Version (7/19/97)
-+* Some architectures don't like reading 16/32 bit data on unaligned
-+* boundaries. Fixed, losing efficiency, but this doesn't really
-+* need efficiency anyways. (Still...)
-+* Also, the #pragma pack from the MSVC include file wasn't liked
-+* by most Unix compilers, replaced with a GCCism. This should work
-+* with GCC, but other compilers I don't know.
-+*
-+ * 1.3 Version (7/22/97)
-+* Ok, take out the DTR over the stream, now uses read_16.
-+*
-+ * NOTE: THIS SOFTWARE IS FOR YOUR PERSONAL GRATIFICATION ONLY. I DON'T
-+* IMPLY IN ANY LEGAL SENSE THAT THIS SOFTWARE DOES ANYTHING OR THAT IT WILL
-+* BE USEFULL IN ANY WAY. But, you can send me fixes to it, I don't mind.
-+***************************************************************************/
-+
-+#include <stdio.h>
-+#include <sys/stat.h>
-+#include <stdlib.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <netinet/in.h>
-+#include "tnef.h"
-+
-+
-+#define VERSION "pldtnef/0.0.1"
-+
-+int _TNEF_syslogging = 0;
-+int _TNEF_stderrlogging = 0;
-+int _TNEF_verbose = 0;
-+int _TNEF_debug = 0;
-+
-+int Verbose = FALSE;
-+int SaveData = FALSE;
-+
-+char _TNEF_path[1024]="";
-+
-+uint8 *tnef_home;
-+uint8 *tnef_limit;
-+
-+/*------------------------------------------------------------------------
-+Procedure: TNEF_set_path ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int TNEF_set_path( char *path )
-+{
-+ snprintf(_TNEF_path,1023,"%s",path);
-+
-+ return 0;
-+}
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: TNEF_set_verbosity ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int TNEF_set_verbosity( int level )
-+{
-+ _TNEF_verbose = level;
-+ return _TNEF_verbose;
-+}
-+
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: TNEF_set_debug ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int TNEF_set_debug( int level )
-+{
-+ _TNEF_debug = level;
-+ TNEF_set_verbosity( level );
-+ return _TNEF_debug;
-+}
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: TNEF_set_syslogging ID:1
-+Purpose: Turns on/off the syslog feature for TNEF error messages
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int TNEF_set_syslogging( int level )
-+{
-+ _TNEF_syslogging = level;
-+ return _TNEF_syslogging;
-+}
-+
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: TNEF_set_stderrlogging ID:1
-+Purpose: Turns on/off the stderr feature for TNEF error messages
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int TNEF_set_stderrlogging( int level )
-+{
-+ _TNEF_stderrlogging = level;
-+ return _TNEF_stderrlogging;
-+}
-+
-+
-+/* Some systems don't like to read unaligned data */
-+/*------------------------------------------------------------------------
-+Procedure: read_32 ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+uint32 read_32(uint8 *tsp)
-+{
-+ uint8 a,b,c,d;
-+ uint32 ret;
-+
-+ if (tsp > tnef_limit)
-+ {
-+ if ((_TNEF_verbose)||(_TNEF_stderrlogging)||(_TNEF_debug)) fprintf(stderr,"TNEF read_32() Attempting to read past end\n");
-+ return -1;
-+ }
-+
-+ a = *tsp;
-+ b = *(tsp+1);
-+ c = *(tsp+2);
-+ d = *(tsp+3);
-+
-+ ret = long_little_endian(a<<24 | b<<16 | c<<8 | d);
-+
-+ return ret;
-+}
-+
-+/*------------------------------------------------------------------------
-+Procedure: read_16 ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+uint16 read_16(uint8 *tsp)
-+{
-+ uint8 a,b;
-+ uint16 ret;
-+
-+ if (tsp > tnef_limit)
-+ {
-+ if ((_TNEF_verbose)||(_TNEF_stderrlogging)||(_TNEF_debug)) fprintf(stderr,"TNEF read_16() Attempting to read past end\n");
-+ return -1;
-+ }
-+
-+
-+ a = *tsp;
-+ b = *(tsp + 1);
-+
-+ ret = little_endian(a<<8 | b);
-+
-+ return ret;
-+}
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: make_string ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+char *make_string(uint8 *tsp, int size)
-+{
-+ static char s[256] = "";
-+ int len = (size>sizeof(s)-1) ? sizeof(s)-1 : size;
-+
-+ strncpy(s,(char *)tsp, len);
-+ s[len] = '\0';
-+ return s;
-+}
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: handle_props ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int handle_props(uint8 *tsp)
-+{
-+ int bytes = 0;
-+ uint32 num_props = 0;
-+ uint32 x = 0;
-+
-+
-+ num_props = read_32(tsp);
-+ bytes += sizeof(num_props);
-+
-+ while (x < num_props)
-+ {
-+ uint32 prop_tag;
-+ uint32 num;
-+ char filename[256];
-+ static int file_num = 0;
-+
-+ prop_tag = read_32(tsp+bytes);
-+ bytes += sizeof(prop_tag);
-+
-+ switch (prop_tag & PROP_TYPE_MASK)
-+ {
-+ case PT_BINARY:
-+ num = read_32(tsp+bytes);
-+ bytes += sizeof(num);
-+ num = read_32(tsp+bytes);
-+ bytes += sizeof(num);
-+ if (prop_tag == PR_RTF_COMPRESSED)
-+ {
-+ sprintf (filename, "XAM_%d.rtf", file_num);
-+ file_num++;
-+ save_attach_data(filename, tsp+bytes, num);
-+ }
-+ /* num + PAD */
-+ bytes += num + ((num % 4) ? (4 - num%4) : 0);
-+ break;
-+ case PT_STRING8:
-+ num = read_32(tsp+bytes);
-+ bytes += sizeof(num);
-+ num = read_32(tsp+bytes);
-+ bytes += sizeof(num);
-+ make_string(tsp+bytes,num);
-+ bytes += num + ((num % 4) ? (4 - num%4) : 0);
-+ break;
-+ case PT_UNICODE:
-+ case PT_OBJECT:
-+ break;
-+ case PT_I2:
-+ bytes += 2;
-+ break;
-+ case PT_LONG:
-+ bytes += 4;
-+ break;
-+ case PT_R4:
-+ bytes += 4;
-+ break;
-+ case PT_DOUBLE:
-+ bytes += 8;
-+ break;
-+ case PT_CURRENCY:
-+ case PT_APPTIME:
-+ case PT_ERROR:
-+ bytes += 4;
-+ break;
-+ case PT_BOOLEAN:
-+ bytes += 4;
-+ break;
-+ case PT_I8:
-+ bytes += 8;
-+ case PT_SYSTIME:
-+ bytes += 8;
-+ break;
-+ }
-+ x++;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: save_attach_data ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int save_attach_data(char *title, uint8 *tsp, uint32 size)
-+{
-+ FILE *out;
-+ char filename[1024];
-+
-+ /*
-+ if ((*tsp +size) > _TNEF_size)
-+ {
-+ return -1;
-+ }
-+ */
-+ snprintf(filename,1023,"%s/%s",_TNEF_path,title);
-+
-+ out = fopen(filename, "w");
-+ if (!out)
-+ {
-+ if (_TNEF_stderrlogging > 0) fprintf(stderr, "Error openning file %s for writing\n", filename);
-+ return -1;
-+ }
-+
-+ fwrite(tsp, sizeof(uint8), size, out);
-+ fclose(out);
-+ return 0;
-+}
-+
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: default_handler ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int default_handler(uint32 attribute, uint8 *tsp, uint32 size)
-+{
-+ uint16 type = ATT_TYPE(attribute);
-+
-+ switch (type) {
-+ case atpTriples:
-+ break;
-+ case atpString:
-+ case atpText:
-+ break;
-+ case atpDate:
-+ break;
-+ case atpShort:
-+ break;
-+ case atpLong:
-+ break;
-+ case atpByte:
-+ break;
-+ case atpWord:
-+ break;
-+ case atpDword:
-+ break;
-+ default:
-+ break;
-+ }
-+ return 0;
-+
-+}
-+
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: read_attribute ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int read_attribute(uint8 *tsp)
-+{
-+
-+ int bytes = 0, header = 0;
-+ uint32 attribute;
-+ uint8 component = 0;
-+ uint32 size = 0;
-+ uint16 checksum = 0;
-+ static char attach_title[256] = {
-+ 0 };
-+ static uint32 attach_size = 0;
-+ static uint32 attach_loc = 0;
-+ uint8 *ptr;
-+
-+ /* What component are we look at? */
-+ component = *tsp;
-+
-+ bytes += sizeof(uint8);
-+
-+ /* Read the attributes of this component */
-+
-+ if (_TNEF_debug) fprintf(stderr,"read_attribute: Reading Attribute...\n");
-+ attribute = read_32(tsp+bytes);
-+ if (attribute == -1) return -1;
-+ bytes += sizeof(attribute);
-+
-+ /* Read the size of the information we have to read */
-+
-+ if (_TNEF_debug) fprintf(stderr,"read_attribute: Reading Size...\n");
-+ size = read_32(tsp+bytes);
-+ if (size == -1) return -1;
-+ bytes += sizeof(size);
-+
-+ /* The header size equals the sum of all the things we've read
-+ so far. */
-+
-+ header = bytes;
-+
-+ /* The is a bit of a tricky one [if you're being slow
-+ it moves the number of bytes ahead by the amount of data of
-+ the attribute we're about to read, so that for next
-+ "read_attribute()"
-+ call starts in the right place.
-+ */
-+
-+ bytes += size;
-+
-+ /* Read in the checksum for this component
-+
-+ AMMENDMENT - 19/07/02 - 17H01
-+ Small code change to deal with strange sitations that occur with non
-+ english characters. - Submitted by wtcheuk@netvigator.com @ 19/07/02
-+ */
-+
-+ if ( bytes < 0 ) return -1;
-+
-+ /* --END of ammendment. */
-+
-+ if (_TNEF_debug) fprintf(stderr,"read_attribute: Reading Checksum...(offset %d, bytes=%d)\n", tsp -tnef_home, bytes);
-+ checksum = read_16(tsp+bytes);
-+ bytes += sizeof(checksum);
-+
-+ if (_TNEF_debug) fprintf(stderr,"Decoding attribute %d\n",attribute);
-+
-+ switch (attribute) {
-+ case attNull:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attFrom:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attSubject:
-+ break;
-+ case attDateSent:
-+ break;
-+ case attDateRecd:
-+ break;
-+ case attMessageStatus:
-+ break;
-+ case attMessageClass:
-+ break;
-+ case attMessageID:
-+ break;
-+ case attParentID:
-+ break;
-+ case attConversationID:
-+ break;
-+ case attBody:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attPriority:
-+ break;
-+ case attAttachData:
-+ attach_size=size;
-+ attach_loc =(int)tsp+header;
-+ if (SaveData && strlen(attach_title)>0 && attach_size > 0) {
-+ if (!save_attach_data(attach_title, (uint8 *)attach_loc,attach_size))
-+ {
-+ if (_TNEF_verbose) fprintf(stdout,"Decoding %s\n", attach_title);
-+ }
-+ else
-+ {
-+ if (_TNEF_syslogging > 0) syslog(1,"TNEF: Error saving attachment %s\n",attach_title);
-+ }
-+ }
-+ break;
-+ case attAttachTitle:
-+ strncpy(attach_title, make_string(tsp+header,size),255);
-+ if (SaveData && strlen(attach_title)>0 && attach_size > 0) {
-+ if (!save_attach_data(attach_title, (uint8 *)attach_loc,attach_size))
-+ {
-+ if (_TNEF_verbose) fprintf(stdout,"Decoding %s\n", attach_title);
-+ }
-+ else
-+ {
-+ if (_TNEF_syslogging > 0) syslog(1,"TNEF: Error saving attachment %s\n",attach_title);
-+ }
-+ }
-+ break;
-+ case attAttachMetaFile:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attAttachCreateDate:
-+ break;
-+ case attAttachModifyDate:
-+ break;
-+ case attDateModified:
-+ break;
-+ case attAttachTransportFilename:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attAttachRenddata:
-+ attach_title[0]=0;
-+ attach_size=0;
-+ attach_loc=0;
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attMAPIProps:
-+ handle_props(tsp+header);
-+ break;
-+ case attRecipTable:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attAttachment:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attTnefVersion:
-+ {
-+ uint32 version;
-+ version = read_32(tsp+header);
-+ if (version == -1) return -1;
-+ }
-+ break;
-+ case attOemCodepage:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attOriginalMessageClass:
-+ break;
-+ case attOwner:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attSentFor:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attDelegate:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attDateStart:
-+ break;
-+ case attDateEnd:
-+ break;
-+ case attAidOwner:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ case attRequestRes:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ default:
-+ default_handler(attribute, tsp+header, size);
-+ break;
-+ }
-+ return bytes;
-+
-+}
-+
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: decode_tnef ID:1
-+Purpose:
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int TNEF_decode_tnef(uint8 *tnef_stream, int size)
-+{
-+
-+ int ra_response;
-+ uint8 *tsp;
-+
-+ if (_TNEF_debug) fprintf(stderr,"TNEF_decode_tnef: Start. Size = %d\n",size);
-+
-+ /* TSP == TNEF Stream Pointer (well memory block actually!)
-+ */
-+ tsp = tnef_stream;
-+
-+ /* Read in the signature of this TNEF
-+ */
-+ if (TNEF_SIGNATURE == read_32(tsp))
-+ {
-+ if (_TNEF_debug) fprintf(stderr,"TNEF signature is good\n");
-+ }
-+ else
-+ {
-+ if (_TNEF_stderrlogging > 0) fprintf(stderr,"TNEF_decode_tnef: Bad TNEF signature, expecting %lx got %lx\n",TNEF_SIGNATURE,read_32(tsp));
-+ }
-+
-+ /* Move tsp pointer along
-+ */
-+ tsp += sizeof(TNEF_SIGNATURE);
-+
-+ if (_TNEF_debug) fprintf(stderr,"TNEF Attach Key: %x\n",read_16(tsp));
-+ /* Move tsp pointer along
-+ */
-+ tsp += sizeof(uint16);
-+
-+ /* While we still have more bytes to process,
-+ go through entire memory block and extract
-+ all the required attributes and files
-+ */
-+ if (_TNEF_debug) fprintf(stderr,"TNEF - Commence reading attributes\n");
-+ while ((tsp - tnef_stream) < size)
-+ {
-+ if (_TNEF_debug) fprintf(stderr,"Offset = %d\n",tsp -tnef_home);
-+ ra_response = read_attribute(tsp);
-+ if ( ra_response > 0 )
-+ {
-+ tsp += ra_response;
-+ } else {
-+
-+ /* Must find out /WHY/ this happens, and, how to rectify the issue. */
-+
-+ tsp++;
-+ if (_TNEF_debug) fprintf(stderr,"TNEF - Attempting to read attribute at %d resulted in a sub-zero response, ending decoding to be safe\n");
-+ break;
-+ }
-+ }
-+
-+ if (_TNEF_debug) fprintf(stderr,"TNEF - DONE.\n");
-+
-+ return 0;
-+}
-+
-+
-+
-+
-+
-+
-+/*------------------------------------------------------------------------
-+Procedure: TNEF_main ID:1
-+Purpose: Decodes a given TNEF encoded file
-+Input:
-+Output:
-+Errors:
-+------------------------------------------------------------------------*/
-+int TNEF_main( char *filename )
-+{
-+ FILE *fp;
-+ struct stat sb;
-+ uint8 *tnef_stream;
-+ int size, nread;
-+ int dump = 0;
-+ int x;
-+
-+ if (_TNEF_debug) fprintf(stderr,"TNEF_main: Start, decoding %s\n",filename);
-+
-+ SaveData = TRUE;
-+
-+ /* Test to see if the file actually exists
-+ */
-+ if (stat(filename,&sb) == -1)
-+ {
-+ if (_TNEF_stderrlogging > 0) fprintf(stderr,"Error stating file %s (%s)\n", filename,strerror(errno));
-+ return -1;
-+ }
-+
-+ /* Get the filesize */
-+
-+ size = sb.st_size;
-+
-+ /* Allocate enough memory to read in the ENTIRE file
-+ FIXME - This could be a real consumer if multiple
-+ instances of TNEF decoding is going on
-+ */
-+
-+ tnef_home = tnef_stream = (uint8 *)malloc(size);
-+ tnef_limit = tnef_home +size;
-+
-+ /* If we were unable to allocate enough memory, then we
-+ should report this */
-+
-+ if (tnef_stream == NULL)
-+ {
-+ if (_TNEF_stderrlogging > 0) fprintf(stderr,"Error allocating %d bytes for loading file (%s)\n", size,strerror(errno));
-+ return -1;
-+ }
-+
-+ /* Attempt to open up the TNEF encoded file... if it fails
-+ then report the failed condition to syslog */
-+
-+ if ((fp = fopen(filename,"r")) == NULL)
-+ {
-+ if (_TNEF_stderrlogging > 0) fprintf(stderr,"Error opening file %s for reading (%s)\n", filename,strerror(errno));
-+ return -1;
-+ }
-+
-+ /* Attempt to read in the entire file */
-+
-+ nread = fread(tnef_stream, sizeof(uint8), size, fp);
-+
-+ if (_TNEF_debug) fprintf(stderr,"TNEF: Read %d bytes\n",nread);
-+
-+ /* If we did not read in all the bytes, then let syslogs know! */
-+
-+ if (nread < size)
-+ {
-+ return -1;
-+ }
-+
-+ /* Close the file */
-+
-+ fclose(fp);
-+
-+ /* Proceed to decode the file */
-+
-+ TNEF_decode_tnef(tnef_stream,size);
-+
-+
-+ if (_TNEF_debug) fprintf(stderr,"TNEF - finished decoding.\n");
-+
-+ return 0;
-+}
-+
-+
-+/* --------------------------END. */
-+
-+
-+
-diff -urN exim-4.20-orig/src/tnef.h exim-4.20/src/tnef.h
---- exim-4.20-orig/src/tnef.h Thu Jan 1 01:00:00 1970
-+++ exim-4.20/src/tnef.h Wed May 14 12:04:24 2003
-@@ -0,0 +1,1839 @@
-+/*************************************************
-+* Exim - an Internet mail transport agent *
-+*************************************************/
-+
-+/* This file is part of the exiscan-acl content scanner
-+patch. It is NOT part of the standard exim distribution. */
-+
-+/***************************************************************************
-+ *
-+ * config.h for tnef decoder by Brandon Long
-+ * Based on config.h from S3MOD by Dan Marks and David Jeske
-+ *
-+ * (C) 1994,1995 By Daniel Marks and David Jeske
-+ *
-+ * While we retain the copyright to this code, this source code is FREE.
-+ * You may use it in any way you wish, in any product you wish. You may
-+ * NOT steal the copyright for this code from us.
-+ *
-+ * We respectfully ask that you email one of us, if possible, if you
-+ * produce something significant with this code, or if you have any bug
-+ * fixes to contribute. We also request that you give credit where
-+ * credit is due if you include part of this code in a program of your own.
-+ *
-+ ***************************************************************************
-+ *
-+ * config.h - compile time configuration options and system specific defines
-+ *
-+ */
-+
-+/* 2003-02-03 Merged all TNEF and MAPI related headers in this file to reduce
-+ clutter
-+ - Tom Kistner
-+*/
-+
-+#ifndef _CONFIG_H
-+#define _CONFIG_H 1
-+
-+/***************************************************************************/
-+/* The following are system specific settings */
-+/***************************************************************************/
-+
-+#if defined(SUN)
-+#define BIT_32
-+#define ___TNEF_BYTE_ORDER 4321
-+#undef NEAR_FAR_PTR
-+
-+#elif defined (HPUX)
-+#define BIT_32
-+#define ___TNEF_BYTE_ORDER 4321
-+#undef NEAR_FAR_PTR
-+
-+#elif defined(DEC)
-+#undef NEAR_FAR_PTR
-+
-+#elif defined(__sgi)
-+#define BIT_32
-+#define ___TNEF_BYTE_ORDER 4321
-+#undef NEAR_FAR_PTR
-+
-+#elif defined(AIX)
-+#undef NEAR_FAR_PTR
-+#define ___TNEF_BYTE_ORDER 4321
-+#define BIT_32
-+
-+#elif defined(LINUX)
-+#define BIT_32
-+#undef NEAR_FAR_PTR
-+
-+#elif defined(MSDOS)
-+#define NEAR_FAR_PTR
-+#undef BIT_32
-+
-+#else
-+#undef NEAR_FAR_PTR
-+#define BIT_32
-+
-+
-+#endif /* OS/MACH TYPE */
-+
-+/***************************************************************************/
-+/* 16/32 Bit and Byte Order hacks */
-+/***************************************************************************/
-+
-+#ifdef BIT_32
-+typedef short int int16;
-+typedef unsigned short int uint16;
-+typedef int int32;
-+typedef unsigned int uint32;
-+typedef char int8;
-+typedef unsigned char uint8;
-+#else
-+typedef int int16;
-+typedef unsigned int uint16;
-+typedef long int int32;
-+typedef unsigned long int uint32;
-+typedef char int8;
-+typedef unsigned char uint8;
-+#endif /* BIT_32 */
-+
-+#ifndef WIN32_TYPES
-+#define ULONG uint32
-+#define SCODE uint32
-+#define FAR
-+#define LPVOID void *
-+#define WORD uint16
-+#define DWORD uint32
-+#define LONG int32
-+#define BYTE uint8
-+#endif /* !WIN32_TYPES */
-+
-+#define endian_switch(x) (((((uint16)(x)) & 0xFF00) >> 8) | \
-+ ((((uint16)(x)) & 0xFF) << 8))
-+
-+#define long_endian_switch(x) ( ((((uint32)(x)) & 0xFF00UL) << 8) | \
-+ ((((uint32)(x)) & 0xFFUL) << 24) | \
-+ ((((uint32)(x)) & 0xFF0000UL) >> 8) | \
-+ ((((uint32)(x)) & 0xFF000000UL) >> 24))
-+
-+#if ___TNEF_BYTE_ORDER == 4321
-+#define big_endian(x) (x)
-+#define long_big_endian(x) (x)
-+#define little_endian(x) (endian_switch(x))
-+#define long_little_endian(x) (long_endian_switch(x))
-+#else
-+#define big_endian(x) (endian_switch(x))
-+#define long_big_endian(x) (long_endian_switch(x))
-+#define little_endian(x) (x)
-+#define long_little_endian(x) (x)
-+#endif /* ___TNEF_BYTE_ORDER */
-+
-+#ifndef TRUE
-+#define TRUE 1
-+#endif
-+#ifndef FALSE
-+#define FALSE 0
-+#endif
-+
-+
-+#endif /* _CONFIG_H */
-+/*
-+ * Taken from the Win32 SDK or the MSVC4 include files, I'm not sure which.
-+ * The document describing the TNEF format alludes to this document for more
-+ * information. This file was stripped a bit to allow it to compile with
-+ * GCC and without random other Windows header files so it could be used
-+ * to decode TNEF bitstreams with tnef2txt.
-+ *
-+ * T N E F . H
-+ *
-+ *
-+ * This file contains structure and function definitions for the
-+ * MAPI implementation of the Transport Neutral Encapsilation Format
-+ * used by MAPI providers for the neutral serialization of a MAPI
-+ * message. This implementation sits on top of the IStream object as
-+ * documented in the OLE 2 Specs.
-+ *
-+ * Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
-+ */
-+
-+#ifndef TNEF_H
-+#define TNEF_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+
-+#ifndef BEGIN_INTERFACE
-+#define BEGIN_INTERFACE
-+#endif
-+
-+#ifndef MAPI_DIM
-+#define MAPI_DIM 1
-+#endif
-+
-+#define TNTNoffsetof(s,m) (unsigned long)&(((s *)0)->m)
-+
-+/* ------------------------------------ */
-+/* TNEF Problem and TNEF Problem Arrays */
-+/* ------------------------------------ */
-+
-+typedef struct _STnefProblem
-+{
-+ ULONG ulComponent;
-+ ULONG ulAttribute;
-+ ULONG ulPropTag;
-+ SCODE scode;
-+} STnefProblem;
-+
-+typedef struct _STnefProblemArray
-+{
-+ ULONG cProblem;
-+ STnefProblem aProblem[MAPI_DIM];
-+} STnefProblemArray, FAR * LPSTnefProblemArray;
-+
-+#if 0
-+#define CbNewSTnefProblemArray(_cprob) \
-+ (TNoffsetof(STnefProblemArray,aProblem) + (_cprob)*sizeof(STnefProblem))
-+#define CbSTnefProblemArray(_lparray) \
-+ (TNoffsetof(STnefProblemArray,aProblem) + \
-+ (UINT) ((_lparray)->cProblem*sizeof(STnefProblem)))
-+#endif
-+
-+/* Pointers to TNEF Interface ---------------------------------------- */
-+
-+#if 0
-+DECLARE_MAPI_INTERFACE_PTR(ITnef, LPITNEF);
-+#endif
-+
-+/* OpenTNEFStream */
-+
-+#define TNEF_DECODE ((ULONG) 0)
-+#define TNEF_ENCODE ((ULONG) 2)
-+
-+#define TNEF_PURE ((ULONG) 0x00010000)
-+#define TNEF_COMPATIBILITY ((ULONG) 0x00020000)
-+#define TNEF_BEST_DATA ((ULONG) 0x00040000)
-+#define TNEF_COMPONENT_ENCODING ((ULONG) 0x80000000)
-+
-+/* AddProps, ExtractProps */
-+
-+#define TNEF_PROP_INCLUDE ((ULONG) 0x00000001)
-+#define TNEF_PROP_EXCLUDE ((ULONG) 0x00000002)
-+#define TNEF_PROP_CONTAINED ((ULONG) 0x00000004)
-+#define TNEF_PROP_MESSAGE_ONLY ((ULONG) 0x00000008)
-+#define TNEF_PROP_ATTACHMENTS_ONLY ((ULONG) 0x00000010)
-+#define TNEF_PROP_CONTAINED_TNEF ((ULONG) 0x00000040)
-+
-+/* FinishComponent */
-+
-+#define TNEF_COMPONENT_MESSAGE ((ULONG) 0x00001000)
-+#define TNEF_COMPONENT_ATTACHMENT ((ULONG) 0x00002000)
-+
-+#if 0
-+#define MAPI_ITNEF_METHODS(IPURE) \
-+ MAPIMETHOD(AddProps) \
-+ (THIS_ ULONG ulFlags, \
-+ ULONG ulElemID, \
-+ LPVOID lpvData, \
-+ LPSPropTagArray lpPropList) IPURE; \
-+ MAPIMETHOD(ExtractProps) \
-+ (THIS_ ULONG ulFlags, \
-+ LPSPropTagArray lpPropList, \
-+ LPSTnefProblemArray FAR * lpProblems) IPURE; \
-+ MAPIMETHOD(Finish) \
-+ (THIS_ ULONG ulFlags, \
-+ WORD FAR * lpKey, \
-+ LPSTnefProblemArray FAR * lpProblems) IPURE; \
-+ MAPIMETHOD(OpenTaggedBody) \
-+ (THIS_ LPMESSAGE lpMessage, \
-+ ULONG ulFlags, \
-+ LPSTREAM FAR * lppStream) IPURE; \
-+ MAPIMETHOD(SetProps) \
-+ (THIS_ ULONG ulFlags, \
-+ ULONG ulElemID, \
-+ ULONG cValues, \
-+ LPSPropValue lpProps) IPURE; \
-+ MAPIMETHOD(EncodeRecips) \
-+ (THIS_ ULONG ulFlags, \
-+ LPMAPITABLE lpRecipientTable) IPURE; \
-+ MAPIMETHOD(FinishComponent) \
-+ (THIS_ ULONG ulFlags, \
-+ ULONG ulComponentID, \
-+ LPSPropTagArray lpCustomPropList, \
-+ LPSPropValue lpCustomProps, \
-+ LPSPropTagArray lpPropList, \
-+ LPSTnefProblemArray FAR * lpProblems) IPURE; \
-+
-+#undef INTERFACE
-+#define INTERFACE ITnef
-+DECLARE_MAPI_INTERFACE_(ITnef, IUnknown)
-+{
-+ BEGIN_INTERFACE
-+ MAPI_IUNKNOWN_METHODS(PURE)
-+ MAPI_ITNEF_METHODS(PURE)
-+};
-+
-+STDMETHODIMP OpenTnefStream(
-+ LPVOID lpvSupport,
-+ LPSTREAM lpStream,
-+ LPTSTR lpszStreamName,
-+ ULONG ulFlags,
-+ LPMESSAGE lpMessage,
-+ WORD wKeyVal,
-+ LPITNEF FAR * lppTNEF);
-+
-+typedef HRESULT (STDMETHODCALLTYPE FAR * LPOPENTNEFSTREAM) (
-+ LPVOID lpvSupport,
-+ LPSTREAM lpStream,
-+ LPTSTR lpszStreamName,
-+ ULONG ulFlags,
-+ LPMESSAGE lpMessage,
-+ WORD wKeyVal,
-+ LPITNEF FAR * lppTNEF);
-+
-+STDMETHODIMP OpenTnefStreamEx(
-+ LPVOID lpvSupport,
-+ LPSTREAM lpStream,
-+ LPTSTR lpszStreamName,
-+ ULONG ulFlags,
-+ LPMESSAGE lpMessage,
-+ WORD wKeyVal,
-+ LPADRBOOK lpAdressBook,
-+ LPITNEF FAR * lppTNEF);
-+
-+typedef HRESULT (STDMETHODCALLTYPE FAR * LPOPENTNEFSTREAMEX) (
-+ LPVOID lpvSupport,
-+ LPSTREAM lpStream,
-+ LPTSTR lpszStreamName,
-+ ULONG ulFlags,
-+ LPMESSAGE lpMessage,
-+ WORD wKeyVal,
-+ LPADRBOOK lpAdressBook,
-+ LPITNEF FAR * lppTNEF);
-+
-+STDMETHODIMP GetTnefStreamCodepage (
-+ LPSTREAM lpStream,
-+ ULONG FAR * lpulCodepage,
-+ ULONG FAR * lpulSubCodepage);
-+
-+typedef HRESULT (STDMETHODCALLTYPE FAR * LPGETTNEFSTREAMCODEPAGE) (
-+ LPSTREAM lpStream,
-+ ULONG FAR * lpulCodepage,
-+ ULONG FAR * lpulSubCodepage);
-+
-+#define OPENTNEFSTREAM "OpenTnefStream"
-+#define OPENTNEFSTREAMEX "OpenTnefStreamEx"
-+#define GETTNEFSTREAMCODEPAGE "GetTnefStreamCodePage"
-+#endif
-+
-+/* -------------------------- */
-+/* TNEF Signature and Version */
-+/* -------------------------- */
-+
-+#define MAKE_TNEF_VERSION(_mj,_mn) (((ULONG)(0x0000FFFF & _mj) << 16) | (ULONG)(0x0000FFFF & _mn))
-+#define TNEF_SIGNATURE ((ULONG) 0x223E9F78)
-+#define TNEF_VERSION ((ULONG) MAKE_TNEF_VERSION(1,0))
-+
-+
-+/* ------------------------------------------- */
-+/* TNEF Down-level Attachment Types/Structures */
-+/* ------------------------------------------- */
-+
-+typedef WORD ATYP;
-+enum { atypNull, atypFile, atypOle, atypPicture, atypMax };
-+
-+#define MAC_BINARY ((DWORD) 0x00000001)
-+
-+typedef struct _renddata
-+{
-+ ATYP atyp;
-+ ULONG ulPosition;
-+ WORD dxWidth;
-+ WORD dyHeight;
-+ DWORD dwFlags;
-+
-+} RENDDATA, *PRENDDATA;
-+
-+/* ----------------------------------- */
-+/* TNEF Down-level Date/Time Structure */
-+/* ----------------------------------- */
-+
-+typedef struct _dtr
-+{
-+ WORD wYear;
-+ WORD wMonth;
-+ WORD wDay;
-+ WORD wHour;
-+ WORD wMinute;
-+ WORD wSecond;
-+ WORD wDayOfWeek;
-+
-+} DTR;
-+
-+
-+/* ----------------------------- */
-+/* TNEF Down-level Message Flags */
-+/* ----------------------------- */
-+
-+#define fmsNull ((BYTE) 0x00)
-+#define fmsModified ((BYTE) 0x01)
-+#define fmsLocal ((BYTE) 0x02)
-+#define fmsSubmitted ((BYTE) 0x04)
-+#define fmsRead ((BYTE) 0x20)
-+#define fmsHasAttach ((BYTE) 0x80)
-+
-+
-+/* ----------------------------------------- */
-+/* TNEF Down-level Triple Address Structures */
-+/* ----------------------------------------- */
-+
-+#define trpidNull ((WORD) 0x0000)
-+#define trpidUnresolved ((WORD) 0x0001)
-+#define trpidResolvedNSID ((WORD) 0x0002)
-+#define trpidResolvedAddress ((WORD) 0x0003)
-+#define trpidOneOff ((WORD) 0x0004)
-+#define trpidGroupNSID ((WORD) 0x0005)
-+#define trpidOffline ((WORD) 0x0006)
-+#define trpidIgnore ((WORD) 0x0007)
-+#define trpidClassEntry ((WORD) 0x0008)
-+#define trpidResolvedGroupAddress ((WORD) 0x0009)
-+typedef struct _trp
-+{
-+ WORD trpid;
-+ WORD cbgrtrp;
-+ WORD cch;
-+ WORD cbRgb;
-+
-+} TRP, *PTRP, *PGRTRP, FAR * LPTRP;
-+#define CbOfTrp(_p) (sizeof(TRP) + (_p)->cch + (_p)->cbRgb)
-+#define LpszOfTrp(_p) ((LPSTR)(((LPTRP) (_p)) + 1))
-+#define LpbOfTrp(_p) (((LPBYTE)(((LPTRP)(_p)) + 1)) + (_p)->cch)
-+#define LptrpNext(_p) ((LPTRP)((LPBYTE)(_p) + CbOfTrp(_p)))
-+
-+typedef DWORD XTYPE;
-+#define xtypeUnknown ((XTYPE) 0)
-+#define xtypeInternet ((XTYPE) 6)
-+
-+#define cbDisplayName 41
-+#define cbEmailName 11
-+#define cbSeverName 12
-+typedef struct _ADDR_ALIAS
-+{
-+ char rgchName[cbDisplayName];
-+ char rgchEName[cbEmailName];
-+ char rgchSrvr[cbSeverName];
-+ ULONG dibDetail;
-+ WORD type;
-+
-+} ADDRALIAS, FAR * LPADDRALIAS;
-+#define cbALIAS sizeof(ALIAS)
-+
-+#define cbTYPE 16
-+#define cbMaxIdData 200
-+typedef struct _NSID
-+{
-+ DWORD dwSize;
-+ unsigned char uchType[cbTYPE];
-+ XTYPE xtype;
-+ LONG lTime;
-+
-+ union
-+ {
-+ ADDRALIAS alias;
-+ char rgchInterNet[1];
-+
-+ } address;
-+
-+} NSID, * LPNSID;
-+#define cbNSID sizeof(NSID)
-+
-+
-+/* -------------------------- */
-+/* TNEF Down-level Priorities */
-+/* -------------------------- */
-+
-+#define prioLow 3
-+#define prioNorm 2
-+#define prioHigh 1
-+
-+
-+/* ------------------------------------- */
-+/* TNEF Down-level Attributes/Properties */
-+/* ------------------------------------- */
-+
-+#define atpTriples ((WORD) 0x0000)
-+#define atpString ((WORD) 0x0001)
-+#define atpText ((WORD) 0x0002)
-+#define atpDate ((WORD) 0x0003)
-+#define atpShort ((WORD) 0x0004)
-+#define atpLong ((WORD) 0x0005)
-+#define atpByte ((WORD) 0x0006)
-+#define atpWord ((WORD) 0x0007)
-+#define atpDword ((WORD) 0x0008)
-+#define atpMax ((WORD) 0x0009)
-+
-+#define LVL_MESSAGE ((BYTE) 0x01)
-+#define LVL_ATTACHMENT ((BYTE) 0x02)
-+
-+#define ATT_ID(_att) ((WORD) ((_att) & 0x0000FFFF))
-+#define ATT_TYPE(_att) ((WORD) (((_att) >> 16) & 0x0000FFFF))
-+#define ATT(_atp, _id) ((((DWORD) (_atp)) << 16) | ((WORD) (_id)))
-+
-+#define attNull ATT( 0, 0x0000)
-+#define attFrom ATT( atpTriples, 0x8000) /* PR_ORIGINATOR_RETURN_ADDRESS */
-+#define attSubject ATT( atpString, 0x8004) /* PR_SUBJECT */
-+#define attDateSent ATT( atpDate, 0x8005) /* PR_CLIENT_SUBMIT_TIME */
-+#define attDateRecd ATT( atpDate, 0x8006) /* PR_MESSAGE_DELIVERY_TIME */
-+#define attMessageStatus ATT( atpByte, 0x8007) /* PR_MESSAGE_FLAGS */
-+#define attMessageClass ATT( atpWord, 0x8008) /* PR_MESSAGE_CLASS */
-+#define attMessageID ATT( atpString, 0x8009) /* PR_MESSAGE_ID */
-+#define attParentID ATT( atpString, 0x800A) /* PR_PARENT_ID */
-+#define attConversationID ATT( atpString, 0x800B) /* PR_CONVERSATION_ID */
-+#define attBody ATT( atpText, 0x800C) /* PR_BODY */
-+#define attPriority ATT( atpShort, 0x800D) /* PR_IMPORTANCE */
-+#define attAttachData ATT( atpByte, 0x800F) /* PR_ATTACH_DATA_xxx */
-+#define attAttachTitle ATT( atpString, 0x8010) /* PR_ATTACH_FILENAME */
-+#define attAttachMetaFile ATT( atpByte, 0x8011) /* PR_ATTACH_RENDERING */
-+#define attAttachCreateDate ATT( atpDate, 0x8012) /* PR_CREATION_TIME */
-+#define attAttachModifyDate ATT( atpDate, 0x8013) /* PR_LAST_MODIFICATION_TIME */
-+#define attDateModified ATT( atpDate, 0x8020) /* PR_LAST_MODIFICATION_TIME */
-+#define attAttachTransportFilename ATT( atpByte, 0x9001) /* PR_ATTACH_TRANSPORT_NAME */
-+#define attAttachRenddata ATT( atpByte, 0x9002)
-+#define attMAPIProps ATT( atpByte, 0x9003)
-+#define attRecipTable ATT( atpByte, 0x9004) /* PR_MESSAGE_RECIPIENTS */
-+#define attAttachment ATT( atpByte, 0x9005)
-+#define attTnefVersion ATT( atpDword, 0x9006)
-+#define attOemCodepage ATT( atpByte, 0x9007)
-+#define attOriginalMessageClass ATT( atpWord, 0x0006) /* PR_ORIG_MESSAGE_CLASS */
-+
-+#define attOwner ATT( atpByte, 0x0000) /* PR_RCVD_REPRESENTING_xxx or
-+ PR_SENT_REPRESENTING_xxx */
-+#define attSentFor ATT( atpByte, 0x0001) /* PR_SENT_REPRESENTING_xxx */
-+#define attDelegate ATT( atpByte, 0x0002) /* PR_RCVD_REPRESENTING_xxx */
-+#define attDateStart ATT( atpDate, 0x0006) /* PR_DATE_START */
-+#define attDateEnd ATT( atpDate, 0x0007) /* PR_DATE_END */
-+#define attAidOwner ATT( atpLong, 0x0008) /* PR_OWNER_APPT_ID */
-+#define attRequestRes ATT( atpShort, 0x0009) /* PR_RESPONSE_REQUESTED */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* defined TNEF_H */
-+/*
-+ * M A P I D E F S . H
-+ *
-+ * Definitions used by MAPI clients and service providers.
-+ *
-+ * Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
-+ */
-+
-+#ifndef MAPIDEFS_H
-+#define MAPIDEFS_H
-+
-+
-+/* Array dimension for structures with variable-sized arrays at the end. */
-+
-+/* Simple data types */
-+
-+
-+typedef WORD WCHAR;
-+
-+#ifdef UNICODE
-+typedef WCHAR TCHAR;
-+#else
-+typedef char TCHAR;
-+#endif
-+
-+typedef WCHAR * LPWSTR;
-+typedef const WCHAR * LPCWSTR;
-+typedef TCHAR * LPTSTR;
-+typedef const TCHAR * LPCTSTR;
-+typedef BYTE * LPBYTE;
-+
-+typedef ULONG * LPULONG;
-+
-+#ifndef __LHANDLE
-+#define __LHANDLE
-+typedef unsigned long LHANDLE, * LPLHANDLE;
-+#endif
-+
-+#if !defined(_WINBASE_) && !defined(_FILETIME_)
-+#define _FILETIME_
-+typedef struct _FILETIME
-+{
-+ DWORD dwLowDateTime;
-+ DWORD dwHighDateTime;
-+} FILETIME, * LPFILETIME;
-+#endif
-+
-+/*
-+ * This flag is used in many different MAPI calls to signify that
-+ * the object opened by the call should be modifiable (MAPI_MODIFY).
-+ * If the flag MAPI_MAX_ACCESS is set, the object returned should be
-+ * returned at the maximum access level allowed. An additional
-+ * property available on the object (PR_ACCESS_LEVEL) uses the same
-+ * MAPI_MODIFY flag to say just what this new access level is.
-+ */
-+
-+#define MAPI_MODIFY ((ULONG) 0x00000001)
-+
-+/*
-+ * The following flags are used to indicate to the client what access
-+ * level is permissible in the object. They appear in PR_ACCESS in
-+ * message and folder objects as well as in contents and associated
-+ * contents tables
-+ */
-+
-+#define MAPI_ACCESS_MODIFY ((ULONG) 0x00000001)
-+#define MAPI_ACCESS_READ ((ULONG) 0x00000002)
-+#define MAPI_ACCESS_DELETE ((ULONG) 0x00000004)
-+#define MAPI_ACCESS_CREATE_HIERARCHY ((ULONG) 0x00000008)
-+#define MAPI_ACCESS_CREATE_CONTENTS ((ULONG) 0x00000010)
-+#define MAPI_ACCESS_CREATE_ASSOCIATED ((ULONG) 0x00000020)
-+
-+/*
-+ * The MAPI_UNICODE flag is used in many different MAPI calls to signify
-+ * that strings passed through the interface are in Unicode (a 16-bit
-+ * character set). The default is an 8-bit character set.
-+ *
-+ * The value fMapiUnicode can be used as the 'normal' value for
-+ * that bit, given the application's default character set.
-+ */
-+
-+#define MAPI_UNICODE ((ULONG) 0x80000000)
-+
-+#ifdef UNICODE
-+#define fMapiUnicode MAPI_UNICODE
-+#else
-+#define fMapiUnicode 0
-+#endif
-+
-+/* successful HRESULT */
-+#define hrSuccess 0
-+
-+
-+
-+/* Recipient types */
-+#ifndef MAPI_ORIG /* also defined in mapi.h */
-+#define MAPI_ORIG 0 /* Recipient is message originator */
-+#define MAPI_TO 1 /* Recipient is a primary recipient */
-+#define MAPI_CC 2 /* Recipient is a copy recipient */
-+#define MAPI_BCC 3 /* Recipient is blind copy recipient */
-+#define MAPI_P1 0x10000000 /* Recipient is a P1 resend recipient */
-+#define MAPI_SUBMITTED 0x80000000 /* Recipient is already processed */
-+/* #define MAPI_AUTHORIZE 4 recipient is a CMC authorizing user */
-+/*#define MAPI_DISCRETE 0x10000000 Recipient is a P1 resend recipient */
-+#endif
-+
-+/* Bit definitions for abFlags[0] of ENTRYID */
-+#define MAPI_SHORTTERM 0x80
-+#define MAPI_NOTRECIP 0x40
-+#define MAPI_THISSESSION 0x20
-+#define MAPI_NOW 0x10
-+#define MAPI_NOTRESERVED 0x08
-+
-+/* Bit definitions for abFlags[1] of ENTRYID */
-+#define MAPI_COMPOUND 0x80
-+
-+/* ENTRYID */
-+typedef struct
-+{
-+ BYTE abFlags[4];
-+ BYTE ab[MAPI_DIM];
-+} ENTRYID, *LPENTRYID;
-+
-+#define CbNewENTRYID(_cb) (offsetof(ENTRYID,ab) + (_cb))
-+#define CbENTRYID(_cb) (offsetof(ENTRYID,ab) + (_cb))
-+
-+/* Byte-order-independent version of GUID (world-unique identifier) */
-+typedef struct _MAPIUID
-+{
-+ BYTE ab[16];
-+} MAPIUID, * LPMAPIUID;
-+
-+/* Note: need to include C run-times (memory.h) to use this macro */
-+
-+#define IsEqualMAPIUID(lpuid1, lpuid2) (!memcmp(lpuid1, lpuid2, sizeof(MAPIUID)))
-+
-+/*
-+ * Constants for one-off entry ID:
-+ * The MAPIUID that identifies the one-off provider;
-+ * the flag that defines whether the embedded strings are Unicode;
-+ * the flag that specifies whether the recipient gets TNEF or not.
-+ */
-+
-+#define MAPI_ONE_OFF_UID { 0x81, 0x2b, 0x1f, 0xa4, 0xbe, 0xa3, 0x10, 0x19, 0x9d, 0x6e, 0x00, 0xdd, 0x01, 0x0f, 0x54, 0x02 }
-+#define MAPI_ONE_OFF_UNICODE 0x8000
-+#define MAPI_ONE_OFF_NO_RICH_INFO 0x0001
-+
-+/* Object type */
-+
-+#define MAPI_STORE ((ULONG) 0x00000001) /* Message Store */
-+#define MAPI_ADDRBOOK ((ULONG) 0x00000002) /* Address Book */
-+#define MAPI_FOLDER ((ULONG) 0x00000003) /* Folder */
-+#define MAPI_ABCONT ((ULONG) 0x00000004) /* Address Book Container */
-+#define MAPI_MESSAGE ((ULONG) 0x00000005) /* Message */
-+#define MAPI_MAILUSER ((ULONG) 0x00000006) /* Individual Recipient */
-+#define MAPI_ATTACH ((ULONG) 0x00000007) /* Attachment */
-+#define MAPI_DISTLIST ((ULONG) 0x00000008) /* Distribution List Recipient */
-+#define MAPI_PROFSECT ((ULONG) 0x00000009) /* Profile Section */
-+#define MAPI_STATUS ((ULONG) 0x0000000A) /* Status Object */
-+#define MAPI_SESSION ((ULONG) 0x0000000B) /* Session */
-+#define MAPI_FORMINFO ((ULONG) 0x0000000C) /* Form Information */
-+
-+
-+/*
-+ * Maximum length of profile names and passwords, not including
-+ * the null termination character.
-+ */
-+#ifndef cchProfileNameMax
-+#define cchProfileNameMax 64
-+#define cchProfilePassMax 64
-+#endif
-+
-+
-+/* Property Types */
-+
-+#define MV_FLAG 0x1000 /* Multi-value flag */
-+
-+#define PT_UNSPECIFIED ((ULONG) 0) /* (Reserved for interface use) type doesn't matter to caller */
-+#define PT_NULL ((ULONG) 1) /* NULL property value */
-+#define PT_I2 ((ULONG) 2) /* Signed 16-bit value */
-+#define PT_LONG ((ULONG) 3) /* Signed 32-bit value */
-+#define PT_R4 ((ULONG) 4) /* 4-byte floating point */
-+#define PT_DOUBLE ((ULONG) 5) /* Floating point double */
-+#define PT_CURRENCY ((ULONG) 6) /* Signed 64-bit int (decimal w/ 4 digits right of decimal pt) */
-+#define PT_APPTIME ((ULONG) 7) /* Application time */
-+#define PT_ERROR ((ULONG) 10) /* 32-bit error value */
-+#define PT_BOOLEAN ((ULONG) 11) /* 16-bit boolean (non-zero true) */
-+#define PT_OBJECT ((ULONG) 13) /* Embedded object in a property */
-+#define PT_I8 ((ULONG) 20) /* 8-byte signed integer */
-+#define PT_STRING8 ((ULONG) 30) /* Null terminated 8-bit character string */
-+#define PT_UNICODE ((ULONG) 31) /* Null terminated Unicode string */
-+#define PT_SYSTIME ((ULONG) 64) /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */
-+#define PT_CLSID ((ULONG) 72) /* OLE GUID */
-+#define PT_BINARY ((ULONG) 258) /* Uninterpreted (counted byte array) */
-+/* Changes are likely to these numbers, and to their structures. */
-+
-+/* Alternate property type names for ease of use */
-+#define PT_SHORT PT_I2
-+#define PT_I4 PT_LONG
-+#define PT_FLOAT PT_R4
-+#define PT_R8 PT_DOUBLE
-+#define PT_LONGLONG PT_I8
-+
-+/*
-+ * The type of a MAPI-defined string property is indirected, so
-+ * that it defaults to Unicode string on a Unicode platform and to
-+ * String8 on an ANSI or DBCS platform.
-+ *
-+ * Macros are defined here both for the property type, and for the
-+ * field of the property value structure which should be
-+ * dereferenced to obtain the string pointer.
-+ */
-+
-+#ifdef UNICODE
-+#define PT_TSTRING PT_UNICODE
-+#define PT_MV_TSTRING (MV_FLAG|PT_UNICODE)
-+#define LPSZ lpszW
-+#define LPPSZ lppszW
-+#define MVSZ MVszW
-+#else
-+#define PT_TSTRING PT_STRING8
-+#define PT_MV_TSTRING (MV_FLAG|PT_STRING8)
-+#define LPSZ lpszA
-+#define LPPSZ lppszA
-+#define MVSZ MVszA
-+#endif
-+
-+
-+/* Property Tags
-+ *
-+ * By convention, MAPI never uses 0 or FFFF as a property ID.
-+ * Use as null values, initializers, sentinels, or what have you.
-+ */
-+
-+#define PROP_TYPE_MASK ((ULONG)0x0000FFFF) /* Mask for Property type */
-+#define PROP_TYPE(ulPropTag) (((ULONG)(ulPropTag))&PROP_TYPE_MASK)
-+#define PROP_ID(ulPropTag) (((ULONG)(ulPropTag))>>16)
-+#define PROP_TAG(ulPropType,ulPropID) ((((ULONG)(ulPropID))<<16)|((ULONG)(ulPropType)))
-+#define PROP_ID_NULL 0
-+#define PROP_ID_INVALID 0xFFFF
-+#define PR_NULL PROP_TAG( PT_NULL, PROP_ID_NULL)
-+#if 0
-+#define CHANGE_PROP_TYPE(ulPropTag, ulPropType) \
-+ (((ULONG)0xFFFF0000 & ulPropTag) | ulPropType)
-+#endif
-+
-+
-+/* Multi-valued Property Types */
-+
-+#define PT_MV_I2 (MV_FLAG|PT_I2)
-+#define PT_MV_LONG (MV_FLAG|PT_LONG)
-+#define PT_MV_R4 (MV_FLAG|PT_R4)
-+#define PT_MV_DOUBLE (MV_FLAG|PT_DOUBLE)
-+#define PT_MV_CURRENCY (MV_FLAG|PT_CURRENCY)
-+#define PT_MV_APPTIME (MV_FLAG|PT_APPTIME)
-+#define PT_MV_SYSTIME (MV_FLAG|PT_SYSTIME)
-+#define PT_MV_STRING8 (MV_FLAG|PT_STRING8)
-+#define PT_MV_BINARY (MV_FLAG|PT_BINARY)
-+#define PT_MV_UNICODE (MV_FLAG|PT_UNICODE)
-+#define PT_MV_CLSID (MV_FLAG|PT_CLSID)
-+#define PT_MV_I8 (MV_FLAG|PT_I8)
-+
-+/* Alternate property type names for ease of use */
-+#define PT_MV_SHORT PT_MV_I2
-+#define PT_MV_I4 PT_MV_LONG
-+#define PT_MV_FLOAT PT_MV_R4
-+#define PT_MV_R8 PT_MV_DOUBLE
-+#define PT_MV_LONGLONG PT_MV_I8
-+
-+/*
-+ * Property type reserved bits
-+ *
-+ * MV_INSTANCE is used as a flag in table operations to request
-+ * that a multi-valued property be presented as a single-valued
-+ * property appearing in multiple rows.
-+ */
-+
-+#define MV_INSTANCE 0x2000
-+#define MVI_FLAG (MV_FLAG | MV_INSTANCE)
-+#define MVI_PROP(tag) ((tag) | MVI_FLAG)
-+
-+
-+
-+#endif /* MAPIDEFS_H */
-+/*
-+ * M A P I T A G S . H
-+ *
-+ * Property tag definitions for standard properties of MAPI
-+ * objects.
-+ *
-+ * The following ranges should be used for all property IDs. Note that
-+ * property IDs for objects other than messages and recipients should
-+ * all fall in the range 0x3000 to 0x3FFF:
-+ *
-+ * From To Kind of property
-+ * --------------------------------
-+ * 0001 0BFF MAPI_defined envelope property
-+ * 0C00 0DFF MAPI_defined per-recipient property
-+ * 0E00 0FFF MAPI_defined non-transmittable property
-+ * 1000 2FFF MAPI_defined message content property
-+ *
-+ * 3000 3FFF MAPI_defined property (usually not message or recipient)
-+ *
-+ * 4000 57FF Transport-defined envelope property
-+ * 5800 5FFF Transport-defined per-recipient property
-+ * 6000 65FF User-defined non-transmittable property
-+ * 6600 67FF Provider-defined internal non-transmittable property
-+ * 6800 7BFF Message class-defined content property
-+ * 7C00 7FFF Message class-defined non-transmittable
-+ * property
-+ *
-+ * 8000 FFFE User-defined Name-to-id mapped property
-+ *
-+ * The 3000-3FFF range is further subdivided as follows:
-+ *
-+ * From To Kind of property
-+ * --------------------------------
-+ * 3000 33FF Common property such as display name, entry ID
-+ * 3400 35FF Message store object
-+ * 3600 36FF Folder or AB container
-+ * 3700 38FF Attachment
-+ * 3900 39FF Address book object
-+ * 3A00 3BFF Mail user
-+ * 3C00 3CFF Distribution list
-+ * 3D00 3DFF Profile section
-+ * 3E00 3FFF Status object
-+ *
-+ * Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
-+ */
-+
-+#ifndef MAPITAGS_H
-+#define MAPITAGS_H
-+
-+/* Determine if a property is transmittable. */
-+
-+#define FIsTransmittable(ulPropTag) \
-+ ((PROP_ID (ulPropTag) < (ULONG)0x0E00) || \
-+ (PROP_ID (ulPropTag) >= (ULONG)0x8000) || \
-+ ((PROP_ID (ulPropTag) >= (ULONG)0x1000) && (PROP_ID (ulPropTag) < (ULONG)0x6000)) || \
-+ ((PROP_ID (ulPropTag) >= (ULONG)0x6800) && (PROP_ID (ulPropTag) < (ULONG)0x7C00)))
-+
-+/*
-+ * Message envelope properties
-+ */
-+
-+#define PR_ACKNOWLEDGEMENT_MODE PROP_TAG( PT_LONG, 0x0001)
-+#define PR_ALTERNATE_RECIPIENT_ALLOWED PROP_TAG( PT_BOOLEAN, 0x0002)
-+#define PR_AUTHORIZING_USERS PROP_TAG( PT_BINARY, 0x0003)
-+#define PR_AUTO_FORWARD_COMMENT PROP_TAG( PT_TSTRING, 0x0004)
-+#define PR_AUTO_FORWARD_COMMENT_W PROP_TAG( PT_UNICODE, 0x0004)
-+#define PR_AUTO_FORWARD_COMMENT_A PROP_TAG( PT_STRING8, 0x0004)
-+#define PR_AUTO_FORWARDED PROP_TAG( PT_BOOLEAN, 0x0005)
-+#define PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID PROP_TAG( PT_BINARY, 0x0006)
-+#define PR_CONTENT_CORRELATOR PROP_TAG( PT_BINARY, 0x0007)
-+#define PR_CONTENT_IDENTIFIER PROP_TAG( PT_TSTRING, 0x0008)
-+#define PR_CONTENT_IDENTIFIER_W PROP_TAG( PT_UNICODE, 0x0008)
-+#define PR_CONTENT_IDENTIFIER_A PROP_TAG( PT_STRING8, 0x0008)
-+#define PR_CONTENT_LENGTH PROP_TAG( PT_LONG, 0x0009)
-+#define PR_CONTENT_RETURN_REQUESTED PROP_TAG( PT_BOOLEAN, 0x000A)
-+
-+
-+
-+#define PR_CONVERSATION_KEY PROP_TAG( PT_BINARY, 0x000B)
-+
-+#define PR_CONVERSION_EITS PROP_TAG( PT_BINARY, 0x000C)
-+#define PR_CONVERSION_WITH_LOSS_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x000D)
-+#define PR_CONVERTED_EITS PROP_TAG( PT_BINARY, 0x000E)
-+#define PR_DEFERRED_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x000F)
-+#define PR_DELIVER_TIME PROP_TAG( PT_SYSTIME, 0x0010)
-+#define PR_DISCARD_REASON PROP_TAG( PT_LONG, 0x0011)
-+#define PR_DISCLOSURE_OF_RECIPIENTS PROP_TAG( PT_BOOLEAN, 0x0012)
-+#define PR_DL_EXPANSION_HISTORY PROP_TAG( PT_BINARY, 0x0013)
-+#define PR_DL_EXPANSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0014)
-+#define PR_EXPIRY_TIME PROP_TAG( PT_SYSTIME, 0x0015)
-+#define PR_IMPLICIT_CONVERSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0016)
-+#define PR_IMPORTANCE PROP_TAG( PT_LONG, 0x0017)
-+#define PR_IPM_ID PROP_TAG( PT_BINARY, 0x0018)
-+#define PR_LATEST_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0019)
-+#define PR_MESSAGE_CLASS PROP_TAG( PT_TSTRING, 0x001A)
-+#define PR_MESSAGE_CLASS_W PROP_TAG( PT_UNICODE, 0x001A)
-+#define PR_MESSAGE_CLASS_A PROP_TAG( PT_STRING8, 0x001A)
-+#define PR_MESSAGE_DELIVERY_ID PROP_TAG( PT_BINARY, 0x001B)
-+
-+
-+
-+
-+
-+#define PR_MESSAGE_SECURITY_LABEL PROP_TAG( PT_BINARY, 0x001E)
-+#define PR_OBSOLETED_IPMS PROP_TAG( PT_BINARY, 0x001F)
-+#define PR_ORIGINALLY_INTENDED_RECIPIENT_NAME PROP_TAG( PT_BINARY, 0x0020)
-+#define PR_ORIGINAL_EITS PROP_TAG( PT_BINARY, 0x0021)
-+#define PR_ORIGINATOR_CERTIFICATE PROP_TAG( PT_BINARY, 0x0022)
-+#define PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0023)
-+#define PR_ORIGINATOR_RETURN_ADDRESS PROP_TAG( PT_BINARY, 0x0024)
-+
-+
-+
-+#define PR_PARENT_KEY PROP_TAG( PT_BINARY, 0x0025)
-+#define PR_PRIORITY PROP_TAG( PT_LONG, 0x0026)
-+
-+
-+
-+#define PR_ORIGIN_CHECK PROP_TAG( PT_BINARY, 0x0027)
-+#define PR_PROOF_OF_SUBMISSION_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0028)
-+#define PR_READ_RECEIPT_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0029)
-+#define PR_RECEIPT_TIME PROP_TAG( PT_SYSTIME, 0x002A)
-+#define PR_RECIPIENT_REASSIGNMENT_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x002B)
-+#define PR_REDIRECTION_HISTORY PROP_TAG( PT_BINARY, 0x002C)
-+#define PR_RELATED_IPMS PROP_TAG( PT_BINARY, 0x002D)
-+#define PR_ORIGINAL_SENSITIVITY PROP_TAG( PT_LONG, 0x002E)
-+#define PR_LANGUAGES PROP_TAG( PT_TSTRING, 0x002F)
-+#define PR_LANGUAGES_W PROP_TAG( PT_UNICODE, 0x002F)
-+#define PR_LANGUAGES_A PROP_TAG( PT_STRING8, 0x002F)
-+#define PR_REPLY_TIME PROP_TAG( PT_SYSTIME, 0x0030)
-+#define PR_REPORT_TAG PROP_TAG( PT_BINARY, 0x0031)
-+#define PR_REPORT_TIME PROP_TAG( PT_SYSTIME, 0x0032)
-+#define PR_RETURNED_IPM PROP_TAG( PT_BOOLEAN, 0x0033)
-+#define PR_SECURITY PROP_TAG( PT_LONG, 0x0034)
-+#define PR_INCOMPLETE_COPY PROP_TAG( PT_BOOLEAN, 0x0035)
-+#define PR_SENSITIVITY PROP_TAG( PT_LONG, 0x0036)
-+#define PR_SUBJECT PROP_TAG( PT_TSTRING, 0x0037)
-+#define PR_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0037)
-+#define PR_SUBJECT_A PROP_TAG( PT_STRING8, 0x0037)
-+#define PR_SUBJECT_IPM PROP_TAG( PT_BINARY, 0x0038)
-+#define PR_CLIENT_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x0039)
-+#define PR_REPORT_NAME PROP_TAG( PT_TSTRING, 0x003A)
-+#define PR_REPORT_NAME_W PROP_TAG( PT_UNICODE, 0x003A)
-+#define PR_REPORT_NAME_A PROP_TAG( PT_STRING8, 0x003A)
-+#define PR_SENT_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x003B)
-+#define PR_X400_CONTENT_TYPE PROP_TAG( PT_BINARY, 0x003C)
-+#define PR_SUBJECT_PREFIX PROP_TAG( PT_TSTRING, 0x003D)
-+#define PR_SUBJECT_PREFIX_W PROP_TAG( PT_UNICODE, 0x003D)
-+#define PR_SUBJECT_PREFIX_A PROP_TAG( PT_STRING8, 0x003D)
-+#define PR_NON_RECEIPT_REASON PROP_TAG( PT_LONG, 0x003E)
-+#define PR_RECEIVED_BY_ENTRYID PROP_TAG( PT_BINARY, 0x003F)
-+#define PR_RECEIVED_BY_NAME PROP_TAG( PT_TSTRING, 0x0040)
-+#define PR_RECEIVED_BY_NAME_W PROP_TAG( PT_UNICODE, 0x0040)
-+#define PR_RECEIVED_BY_NAME_A PROP_TAG( PT_STRING8, 0x0040)
-+#define PR_SENT_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x0041)
-+#define PR_SENT_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x0042)
-+#define PR_SENT_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x0042)
-+#define PR_SENT_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x0042)
-+#define PR_RCVD_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x0043)
-+#define PR_RCVD_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x0044)
-+#define PR_RCVD_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x0044)
-+#define PR_RCVD_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x0044)
-+#define PR_REPORT_ENTRYID PROP_TAG( PT_BINARY, 0x0045)
-+#define PR_READ_RECEIPT_ENTRYID PROP_TAG( PT_BINARY, 0x0046)
-+#define PR_MESSAGE_SUBMISSION_ID PROP_TAG( PT_BINARY, 0x0047)
-+#define PR_PROVIDER_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x0048)
-+#define PR_ORIGINAL_SUBJECT PROP_TAG( PT_TSTRING, 0x0049)
-+#define PR_ORIGINAL_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0049)
-+#define PR_ORIGINAL_SUBJECT_A PROP_TAG( PT_STRING8, 0x0049)
-+#define PR_DISC_VAL PROP_TAG( PT_BOOLEAN, 0x004A)
-+#define PR_ORIG_MESSAGE_CLASS PROP_TAG( PT_TSTRING, 0x004B)
-+#define PR_ORIG_MESSAGE_CLASS_W PROP_TAG( PT_UNICODE, 0x004B)
-+#define PR_ORIG_MESSAGE_CLASS_A PROP_TAG( PT_STRING8, 0x004B)
-+#define PR_ORIGINAL_AUTHOR_ENTRYID PROP_TAG( PT_BINARY, 0x004C)
-+#define PR_ORIGINAL_AUTHOR_NAME PROP_TAG( PT_TSTRING, 0x004D)
-+#define PR_ORIGINAL_AUTHOR_NAME_W PROP_TAG( PT_UNICODE, 0x004D)
-+#define PR_ORIGINAL_AUTHOR_NAME_A PROP_TAG( PT_STRING8, 0x004D)
-+#define PR_ORIGINAL_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x004E)
-+#define PR_REPLY_RECIPIENT_ENTRIES PROP_TAG( PT_BINARY, 0x004F)
-+#define PR_REPLY_RECIPIENT_NAMES PROP_TAG( PT_TSTRING, 0x0050)
-+#define PR_REPLY_RECIPIENT_NAMES_W PROP_TAG( PT_UNICODE, 0x0050)
-+#define PR_REPLY_RECIPIENT_NAMES_A PROP_TAG( PT_STRING8, 0x0050)
-+
-+#define PR_RECEIVED_BY_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0051)
-+#define PR_RCVD_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0052)
-+#define PR_READ_RECEIPT_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0053)
-+#define PR_REPORT_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0054)
-+#define PR_ORIGINAL_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0055)
-+#define PR_ORIGINAL_AUTHOR_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0056)
-+
-+#define PR_MESSAGE_TO_ME PROP_TAG( PT_BOOLEAN, 0x0057)
-+#define PR_MESSAGE_CC_ME PROP_TAG( PT_BOOLEAN, 0x0058)
-+#define PR_MESSAGE_RECIP_ME PROP_TAG( PT_BOOLEAN, 0x0059)
-+
-+#define PR_ORIGINAL_SENDER_NAME PROP_TAG( PT_TSTRING, 0x005A)
-+#define PR_ORIGINAL_SENDER_NAME_W PROP_TAG( PT_UNICODE, 0x005A)
-+#define PR_ORIGINAL_SENDER_NAME_A PROP_TAG( PT_STRING8, 0x005A)
-+#define PR_ORIGINAL_SENDER_ENTRYID PROP_TAG( PT_BINARY, 0x005B)
-+#define PR_ORIGINAL_SENDER_SEARCH_KEY PROP_TAG( PT_BINARY, 0x005C)
-+#define PR_ORIGINAL_SENT_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x005D)
-+#define PR_ORIGINAL_SENT_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x005D)
-+#define PR_ORIGINAL_SENT_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x005D)
-+#define PR_ORIGINAL_SENT_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x005E)
-+#define PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x005F)
-+
-+#define PR_START_DATE PROP_TAG( PT_SYSTIME, 0x0060)
-+#define PR_END_DATE PROP_TAG( PT_SYSTIME, 0x0061)
-+#define PR_OWNER_APPT_ID PROP_TAG( PT_LONG, 0x0062)
-+#define PR_RESPONSE_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0063)
-+
-+#define PR_SENT_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0064)
-+#define PR_SENT_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0064)
-+#define PR_SENT_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0064)
-+#define PR_SENT_REPRESENTING_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0065)
-+#define PR_SENT_REPRESENTING_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0065)
-+#define PR_SENT_REPRESENTING_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0065)
-+
-+#define PR_ORIGINAL_SENDER_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0066)
-+#define PR_ORIGINAL_SENDER_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0066)
-+#define PR_ORIGINAL_SENDER_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0066)
-+#define PR_ORIGINAL_SENDER_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0067)
-+#define PR_ORIGINAL_SENDER_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0067)
-+#define PR_ORIGINAL_SENDER_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0067)
-+
-+#define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0068)
-+#define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0068)
-+#define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0068)
-+#define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0069)
-+#define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0069)
-+#define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0069)
-+
-+#define PR_CONVERSATION_TOPIC PROP_TAG( PT_TSTRING, 0x0070)
-+#define PR_CONVERSATION_TOPIC_W PROP_TAG( PT_UNICODE, 0x0070)
-+#define PR_CONVERSATION_TOPIC_A PROP_TAG( PT_STRING8, 0x0070)
-+#define PR_CONVERSATION_INDEX PROP_TAG( PT_BINARY, 0x0071)
-+
-+#define PR_ORIGINAL_DISPLAY_BCC PROP_TAG( PT_TSTRING, 0x0072)
-+#define PR_ORIGINAL_DISPLAY_BCC_W PROP_TAG( PT_UNICODE, 0x0072)
-+#define PR_ORIGINAL_DISPLAY_BCC_A PROP_TAG( PT_STRING8, 0x0072)
-+#define PR_ORIGINAL_DISPLAY_CC PROP_TAG( PT_TSTRING, 0x0073)
-+#define PR_ORIGINAL_DISPLAY_CC_W PROP_TAG( PT_UNICODE, 0x0073)
-+#define PR_ORIGINAL_DISPLAY_CC_A PROP_TAG( PT_STRING8, 0x0073)
-+#define PR_ORIGINAL_DISPLAY_TO PROP_TAG( PT_TSTRING, 0x0074)
-+#define PR_ORIGINAL_DISPLAY_TO_W PROP_TAG( PT_UNICODE, 0x0074)
-+#define PR_ORIGINAL_DISPLAY_TO_A PROP_TAG( PT_STRING8, 0x0074)
-+
-+#define PR_RECEIVED_BY_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0075)
-+#define PR_RECEIVED_BY_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0075)
-+#define PR_RECEIVED_BY_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0075)
-+#define PR_RECEIVED_BY_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0076)
-+#define PR_RECEIVED_BY_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0076)
-+#define PR_RECEIVED_BY_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0076)
-+
-+#define PR_RCVD_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0077)
-+#define PR_RCVD_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0077)
-+#define PR_RCVD_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0077)
-+#define PR_RCVD_REPRESENTING_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0078)
-+#define PR_RCVD_REPRESENTING_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0078)
-+#define PR_RCVD_REPRESENTING_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0078)
-+
-+#define PR_ORIGINAL_AUTHOR_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0079)
-+#define PR_ORIGINAL_AUTHOR_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0079)
-+#define PR_ORIGINAL_AUTHOR_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0079)
-+#define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x007A)
-+#define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x007A)
-+#define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x007A)
-+
-+#define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE PROP_TAG( PT_TSTRING, 0x007B)
-+#define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x007B)
-+#define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x007B)
-+#define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x007C)
-+#define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x007C)
-+#define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x007C)
-+
-+#define PR_TRANSPORT_MESSAGE_HEADERS PROP_TAG(PT_TSTRING, 0x007D)
-+#define PR_TRANSPORT_MESSAGE_HEADERS_W PROP_TAG(PT_UNICODE, 0x007D)
-+#define PR_TRANSPORT_MESSAGE_HEADERS_A PROP_TAG(PT_STRING8, 0x007D)
-+
-+#define PR_DELEGATION PROP_TAG(PT_BINARY, 0x007E)
-+
-+#define PR_TNEF_CORRELATION_KEY PROP_TAG(PT_BINARY, 0x007F)
-+
-+
-+
-+/*
-+ * Message content properties
-+ */
-+
-+#define PR_BODY PROP_TAG( PT_TSTRING, 0x1000)
-+#define PR_BODY_W PROP_TAG( PT_UNICODE, 0x1000)
-+#define PR_BODY_A PROP_TAG( PT_STRING8, 0x1000)
-+#define PR_REPORT_TEXT PROP_TAG( PT_TSTRING, 0x1001)
-+#define PR_REPORT_TEXT_W PROP_TAG( PT_UNICODE, 0x1001)
-+#define PR_REPORT_TEXT_A PROP_TAG( PT_STRING8, 0x1001)
-+#define PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY PROP_TAG( PT_BINARY, 0x1002)
-+#define PR_REPORTING_DL_NAME PROP_TAG( PT_BINARY, 0x1003)
-+#define PR_REPORTING_MTA_CERTIFICATE PROP_TAG( PT_BINARY, 0x1004)
-+
-+/* Removed PR_REPORT_ORIGIN_AUTHENTICATION_CHECK with DCR 3865, use PR_ORIGIN_CHECK */
-+
-+#define PR_RTF_SYNC_BODY_CRC PROP_TAG( PT_LONG, 0x1006)
-+#define PR_RTF_SYNC_BODY_COUNT PROP_TAG( PT_LONG, 0x1007)
-+#define PR_RTF_SYNC_BODY_TAG PROP_TAG( PT_TSTRING, 0x1008)
-+#define PR_RTF_SYNC_BODY_TAG_W PROP_TAG( PT_UNICODE, 0x1008)
-+#define PR_RTF_SYNC_BODY_TAG_A PROP_TAG( PT_STRING8, 0x1008)
-+#define PR_RTF_COMPRESSED PROP_TAG( PT_BINARY, 0x1009)
-+#define PR_RTF_SYNC_PREFIX_COUNT PROP_TAG( PT_LONG, 0x1010)
-+#define PR_RTF_SYNC_TRAILING_COUNT PROP_TAG( PT_LONG, 0x1011)
-+#define PR_ORIGINALLY_INTENDED_RECIP_ENTRYID PROP_TAG( PT_BINARY, 0x1012)
-+
-+/*
-+ * Reserved 0x1100-0x1200
-+ */
-+
-+
-+/*
-+ * Message recipient properties
-+ */
-+
-+#define PR_CONTENT_INTEGRITY_CHECK PROP_TAG( PT_BINARY, 0x0C00)
-+#define PR_EXPLICIT_CONVERSION PROP_TAG( PT_LONG, 0x0C01)
-+#define PR_IPM_RETURN_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C02)
-+#define PR_MESSAGE_TOKEN PROP_TAG( PT_BINARY, 0x0C03)
-+#define PR_NDR_REASON_CODE PROP_TAG( PT_LONG, 0x0C04)
-+#define PR_NDR_DIAG_CODE PROP_TAG( PT_LONG, 0x0C05)
-+#define PR_NON_RECEIPT_NOTIFICATION_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C06)
-+#define PR_DELIVERY_POINT PROP_TAG( PT_LONG, 0x0C07)
-+
-+#define PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C08)
-+#define PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT PROP_TAG( PT_BINARY, 0x0C09)
-+#define PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY PROP_TAG( PT_BOOLEAN, 0x0C0A)
-+#define PR_PHYSICAL_DELIVERY_MODE PROP_TAG( PT_LONG, 0x0C0B)
-+#define PR_PHYSICAL_DELIVERY_REPORT_REQUEST PROP_TAG( PT_LONG, 0x0C0C)
-+#define PR_PHYSICAL_FORWARDING_ADDRESS PROP_TAG( PT_BINARY, 0x0C0D)
-+#define PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C0E)
-+#define PR_PHYSICAL_FORWARDING_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0C0F)
-+#define PR_PHYSICAL_RENDITION_ATTRIBUTES PROP_TAG( PT_BINARY, 0x0C10)
-+#define PR_PROOF_OF_DELIVERY PROP_TAG( PT_BINARY, 0x0C11)
-+#define PR_PROOF_OF_DELIVERY_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C12)
-+#define PR_RECIPIENT_CERTIFICATE PROP_TAG( PT_BINARY, 0x0C13)
-+#define PR_RECIPIENT_NUMBER_FOR_ADVICE PROP_TAG( PT_TSTRING, 0x0C14)
-+#define PR_RECIPIENT_NUMBER_FOR_ADVICE_W PROP_TAG( PT_UNICODE, 0x0C14)
-+#define PR_RECIPIENT_NUMBER_FOR_ADVICE_A PROP_TAG( PT_STRING8, 0x0C14)
-+#define PR_RECIPIENT_TYPE PROP_TAG( PT_LONG, 0x0C15)
-+#define PR_REGISTERED_MAIL_TYPE PROP_TAG( PT_LONG, 0x0C16)
-+#define PR_REPLY_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C17)
-+#define PR_REQUESTED_DELIVERY_METHOD PROP_TAG( PT_LONG, 0x0C18)
-+#define PR_SENDER_ENTRYID PROP_TAG( PT_BINARY, 0x0C19)
-+#define PR_SENDER_NAME PROP_TAG( PT_TSTRING, 0x0C1A)
-+#define PR_SENDER_NAME_W PROP_TAG( PT_UNICODE, 0x0C1A)
-+#define PR_SENDER_NAME_A PROP_TAG( PT_STRING8, 0x0C1A)
-+#define PR_SUPPLEMENTARY_INFO PROP_TAG( PT_TSTRING, 0x0C1B)
-+#define PR_SUPPLEMENTARY_INFO_W PROP_TAG( PT_UNICODE, 0x0C1B)
-+#define PR_SUPPLEMENTARY_INFO_A PROP_TAG( PT_STRING8, 0x0C1B)
-+#define PR_TYPE_OF_MTS_USER PROP_TAG( PT_LONG, 0x0C1C)
-+#define PR_SENDER_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0C1D)
-+#define PR_SENDER_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0C1E)
-+#define PR_SENDER_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0C1E)
-+#define PR_SENDER_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0C1E)
-+#define PR_SENDER_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0C1F)
-+#define PR_SENDER_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0C1F)
-+#define PR_SENDER_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0C1F)
-+
-+/*
-+ * Message non-transmittable properties
-+ */
-+
-+/*
-+ * The two tags, PR_MESSAGE_RECIPIENTS and PR_MESSAGE_ATTACHMENTS,
-+ * are to be used in the exclude list passed to
-+ * IMessage::CopyTo when the caller wants either the recipients or attachments
-+ * of the message to not get copied. It is also used in the ProblemArray
-+ * return from IMessage::CopyTo when an error is encountered copying them
-+ */
-+
-+#define PR_CURRENT_VERSION PROP_TAG( PT_I8, 0x0E00)
-+#define PR_DELETE_AFTER_SUBMIT PROP_TAG( PT_BOOLEAN, 0x0E01)
-+#define PR_DISPLAY_BCC PROP_TAG( PT_TSTRING, 0x0E02)
-+#define PR_DISPLAY_BCC_W PROP_TAG( PT_UNICODE, 0x0E02)
-+#define PR_DISPLAY_BCC_A PROP_TAG( PT_STRING8, 0x0E02)
-+#define PR_DISPLAY_CC PROP_TAG( PT_TSTRING, 0x0E03)
-+#define PR_DISPLAY_CC_W PROP_TAG( PT_UNICODE, 0x0E03)
-+#define PR_DISPLAY_CC_A PROP_TAG( PT_STRING8, 0x0E03)
-+#define PR_DISPLAY_TO PROP_TAG( PT_TSTRING, 0x0E04)
-+#define PR_DISPLAY_TO_W PROP_TAG( PT_UNICODE, 0x0E04)
-+#define PR_DISPLAY_TO_A PROP_TAG( PT_STRING8, 0x0E04)
-+#define PR_PARENT_DISPLAY PROP_TAG( PT_TSTRING, 0x0E05)
-+#define PR_PARENT_DISPLAY_W PROP_TAG( PT_UNICODE, 0x0E05)
-+#define PR_PARENT_DISPLAY_A PROP_TAG( PT_STRING8, 0x0E05)
-+#define PR_MESSAGE_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0E06)
-+#define PR_MESSAGE_FLAGS PROP_TAG( PT_LONG, 0x0E07)
-+#define PR_MESSAGE_SIZE PROP_TAG( PT_LONG, 0x0E08)
-+#define PR_PARENT_ENTRYID PROP_TAG( PT_BINARY, 0x0E09)
-+#define PR_SENTMAIL_ENTRYID PROP_TAG( PT_BINARY, 0x0E0A)
-+#define PR_CORRELATE PROP_TAG( PT_BOOLEAN, 0x0E0C)
-+#define PR_CORRELATE_MTSID PROP_TAG( PT_BINARY, 0x0E0D)
-+#define PR_DISCRETE_VALUES PROP_TAG( PT_BOOLEAN, 0x0E0E)
-+#define PR_RESPONSIBILITY PROP_TAG( PT_BOOLEAN, 0x0E0F)
-+#define PR_SPOOLER_STATUS PROP_TAG( PT_LONG, 0x0E10)
-+#define PR_TRANSPORT_STATUS PROP_TAG( PT_LONG, 0x0E11)
-+#define PR_MESSAGE_RECIPIENTS PROP_TAG( PT_OBJECT, 0x0E12)
-+#define PR_MESSAGE_ATTACHMENTS PROP_TAG( PT_OBJECT, 0x0E13)
-+#define PR_SUBMIT_FLAGS PROP_TAG( PT_LONG, 0x0E14)
-+#define PR_RECIPIENT_STATUS PROP_TAG( PT_LONG, 0x0E15)
-+#define PR_TRANSPORT_KEY PROP_TAG( PT_LONG, 0x0E16)
-+#define PR_MSG_STATUS PROP_TAG( PT_LONG, 0x0E17)
-+#define PR_MESSAGE_DOWNLOAD_TIME PROP_TAG( PT_LONG, 0x0E18)
-+#define PR_CREATION_VERSION PROP_TAG( PT_I8, 0x0E19)
-+#define PR_MODIFY_VERSION PROP_TAG( PT_I8, 0x0E1A)
-+#define PR_HASATTACH PROP_TAG( PT_BOOLEAN, 0x0E1B)
-+#define PR_BODY_CRC PROP_TAG( PT_LONG, 0x0E1C)
-+#define PR_NORMALIZED_SUBJECT PROP_TAG( PT_TSTRING, 0x0E1D)
-+#define PR_NORMALIZED_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0E1D)
-+#define PR_NORMALIZED_SUBJECT_A PROP_TAG( PT_STRING8, 0x0E1D)
-+#define PR_RTF_IN_SYNC PROP_TAG( PT_BOOLEAN, 0x0E1F)
-+#define PR_ATTACH_SIZE PROP_TAG( PT_LONG, 0x0E20)
-+#define PR_ATTACH_NUM PROP_TAG( PT_LONG, 0x0E21)
-+#define PR_PREPROCESS PROP_TAG( PT_BOOLEAN, 0x0E22)
-+
-+/* PR_ORIGINAL_DISPLAY_TO, _CC, and _BCC moved to transmittible range 03/09/95 */
-+
-+#define PR_ORIGINATING_MTA_CERTIFICATE PROP_TAG( PT_BINARY, 0x0E25)
-+#define PR_PROOF_OF_SUBMISSION PROP_TAG( PT_BINARY, 0x0E26)
-+
-+
-+/*
-+ * The range of non-message and non-recipient property IDs (0x3000 - 0x3FFF) is
-+ * further broken down into ranges to make assigning new property IDs easier.
-+ *
-+ * From To Kind of property
-+ * --------------------------------
-+ * 3000 32FF MAPI_defined common property
-+ * 3200 33FF MAPI_defined form property
-+ * 3400 35FF MAPI_defined message store property
-+ * 3600 36FF MAPI_defined Folder or AB Container property
-+ * 3700 38FF MAPI_defined attachment property
-+ * 3900 39FF MAPI_defined address book property
-+ * 3A00 3BFF MAPI_defined mailuser property
-+ * 3C00 3CFF MAPI_defined DistList property
-+ * 3D00 3DFF MAPI_defined Profile Section property
-+ * 3E00 3EFF MAPI_defined Status property
-+ * 3F00 3FFF MAPI_defined display table property
-+ */
-+
-+/*
-+ * Properties common to numerous MAPI objects.
-+ *
-+ * Those properties that can appear on messages are in the
-+ * non-transmittable range for messages. They start at the high
-+ * end of that range and work down.
-+ *
-+ * Properties that never appear on messages are defined in the common
-+ * property range (see above).
-+ */
-+
-+/*
-+ * properties that are common to multiple objects (including message objects)
-+ * -- these ids are in the non-transmittable range
-+ */
-+
-+#define PR_ENTRYID PROP_TAG( PT_BINARY, 0x0FFF)
-+#define PR_OBJECT_TYPE PROP_TAG( PT_LONG, 0x0FFE)
-+#define PR_ICON PROP_TAG( PT_BINARY, 0x0FFD)
-+#define PR_MINI_ICON PROP_TAG( PT_BINARY, 0x0FFC)
-+#define PR_STORE_ENTRYID PROP_TAG( PT_BINARY, 0x0FFB)
-+#define PR_STORE_RECORD_KEY PROP_TAG( PT_BINARY, 0x0FFA)
-+#define PR_RECORD_KEY PROP_TAG( PT_BINARY, 0x0FF9)
-+#define PR_MAPPING_SIGNATURE PROP_TAG( PT_BINARY, 0x0FF8)
-+#define PR_ACCESS_LEVEL PROP_TAG( PT_LONG, 0x0FF7)
-+#define PR_INSTANCE_KEY PROP_TAG( PT_BINARY, 0x0FF6)
-+#define PR_ROW_TYPE PROP_TAG( PT_LONG, 0x0FF5)
-+#define PR_ACCESS PROP_TAG( PT_LONG, 0x0FF4)
-+
-+/*
-+ * properties that are common to multiple objects (usually not including message objects)
-+ * -- these ids are in the transmittable range
-+ */
-+
-+#define PR_ROWID PROP_TAG( PT_LONG, 0x3000)
-+#define PR_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3001)
-+#define PR_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3001)
-+#define PR_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3001)
-+#define PR_ADDRTYPE PROP_TAG( PT_TSTRING, 0x3002)
-+#define PR_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x3002)
-+#define PR_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x3002)
-+#define PR_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x3003)
-+#define PR_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3003)
-+#define PR_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x3003)
-+#define PR_COMMENT PROP_TAG( PT_TSTRING, 0x3004)
-+#define PR_COMMENT_W PROP_TAG( PT_UNICODE, 0x3004)
-+#define PR_COMMENT_A PROP_TAG( PT_STRING8, 0x3004)
-+#define PR_DEPTH PROP_TAG( PT_LONG, 0x3005)
-+#define PR_PROVIDER_DISPLAY PROP_TAG( PT_TSTRING, 0x3006)
-+#define PR_PROVIDER_DISPLAY_W PROP_TAG( PT_UNICODE, 0x3006)
-+#define PR_PROVIDER_DISPLAY_A PROP_TAG( PT_STRING8, 0x3006)
-+#define PR_CREATION_TIME PROP_TAG( PT_SYSTIME, 0x3007)
-+#define PR_LAST_MODIFICATION_TIME PROP_TAG( PT_SYSTIME, 0x3008)
-+#define PR_RESOURCE_FLAGS PROP_TAG( PT_LONG, 0x3009)
-+#define PR_PROVIDER_DLL_NAME PROP_TAG( PT_TSTRING, 0x300A)
-+#define PR_PROVIDER_DLL_NAME_W PROP_TAG( PT_UNICODE, 0x300A)
-+#define PR_PROVIDER_DLL_NAME_A PROP_TAG( PT_STRING8, 0x300A)
-+#define PR_SEARCH_KEY PROP_TAG( PT_BINARY, 0x300B)
-+#define PR_PROVIDER_UID PROP_TAG( PT_BINARY, 0x300C)
-+#define PR_PROVIDER_ORDINAL PROP_TAG( PT_LONG, 0x300D)
-+
-+/*
-+ * MAPI Form properties
-+ */
-+#define PR_FORM_VERSION PROP_TAG(PT_TSTRING, 0x3301)
-+#define PR_FORM_VERSION_W PROP_TAG(PT_UNICODE, 0x3301)
-+#define PR_FORM_VERSION_A PROP_TAG(PT_STRING8, 0x3301)
-+#define PR_FORM_CLSID PROP_TAG(PT_CLSID, 0x3302)
-+#define PR_FORM_CONTACT_NAME PROP_TAG(PT_TSTRING, 0x3303)
-+#define PR_FORM_CONTACT_NAME_W PROP_TAG(PT_UNICODE, 0x3303)
-+#define PR_FORM_CONTACT_NAME_A PROP_TAG(PT_STRING8, 0x3303)
-+#define PR_FORM_CATEGORY PROP_TAG(PT_TSTRING, 0x3304)
-+#define PR_FORM_CATEGORY_W PROP_TAG(PT_UNICODE, 0x3304)
-+#define PR_FORM_CATEGORY_A PROP_TAG(PT_STRING8, 0x3304)
-+#define PR_FORM_CATEGORY_SUB PROP_TAG(PT_TSTRING, 0x3305)
-+#define PR_FORM_CATEGORY_SUB_W PROP_TAG(PT_UNICODE, 0x3305)
-+#define PR_FORM_CATEGORY_SUB_A PROP_TAG(PT_STRING8, 0x3305)
-+#define PR_FORM_HOST_MAP PROP_TAG(PT_MV_LONG, 0x3306)
-+#define PR_FORM_HIDDEN PROP_TAG(PT_BOOLEAN, 0x3307)
-+#define PR_FORM_DESIGNER_NAME PROP_TAG(PT_TSTRING, 0x3308)
-+#define PR_FORM_DESIGNER_NAME_W PROP_TAG(PT_UNICODE, 0x3308)
-+#define PR_FORM_DESIGNER_NAME_A PROP_TAG(PT_STRING8, 0x3308)
-+#define PR_FORM_DESIGNER_GUID PROP_TAG(PT_CLSID, 0x3309)
-+#define PR_FORM_MESSAGE_BEHAVIOR PROP_TAG(PT_LONG, 0x330A)
-+
-+/*
-+ * Message store properties
-+ */
-+
-+#define PR_DEFAULT_STORE PROP_TAG( PT_BOOLEAN, 0x3400)
-+#define PR_STORE_SUPPORT_MASK PROP_TAG( PT_LONG, 0x340D)
-+#define PR_STORE_STATE PROP_TAG( PT_LONG, 0x340E)
-+
-+#define PR_IPM_SUBTREE_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3410)
-+#define PR_IPM_OUTBOX_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3411)
-+#define PR_IPM_WASTEBASKET_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3412)
-+#define PR_IPM_SENTMAIL_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3413)
-+#define PR_MDB_PROVIDER PROP_TAG( PT_BINARY, 0x3414)
-+#define PR_RECEIVE_FOLDER_SETTINGS PROP_TAG( PT_OBJECT, 0x3415)
-+
-+#define PR_VALID_FOLDER_MASK PROP_TAG( PT_LONG, 0x35DF)
-+#define PR_IPM_SUBTREE_ENTRYID PROP_TAG( PT_BINARY, 0x35E0)
-+
-+#define PR_IPM_OUTBOX_ENTRYID PROP_TAG( PT_BINARY, 0x35E2)
-+#define PR_IPM_WASTEBASKET_ENTRYID PROP_TAG( PT_BINARY, 0x35E3)
-+#define PR_IPM_SENTMAIL_ENTRYID PROP_TAG( PT_BINARY, 0x35E4)
-+#define PR_VIEWS_ENTRYID PROP_TAG( PT_BINARY, 0x35E5)
-+#define PR_COMMON_VIEWS_ENTRYID PROP_TAG( PT_BINARY, 0x35E6)
-+#define PR_FINDER_ENTRYID PROP_TAG( PT_BINARY, 0x35E7)
-+
-+/* Proptags 0x35E8-0x35FF reserved for folders "guaranteed" by PR_VALID_FOLDER_MASK */
-+
-+
-+/*
-+ * Folder and AB Container properties
-+ */
-+
-+#define PR_CONTAINER_FLAGS PROP_TAG( PT_LONG, 0x3600)
-+#define PR_FOLDER_TYPE PROP_TAG( PT_LONG, 0x3601)
-+#define PR_CONTENT_COUNT PROP_TAG( PT_LONG, 0x3602)
-+#define PR_CONTENT_UNREAD PROP_TAG( PT_LONG, 0x3603)
-+#define PR_CREATE_TEMPLATES PROP_TAG( PT_OBJECT, 0x3604)
-+#define PR_DETAILS_TABLE PROP_TAG( PT_OBJECT, 0x3605)
-+#define PR_SEARCH PROP_TAG( PT_OBJECT, 0x3607)
-+#define PR_SELECTABLE PROP_TAG( PT_BOOLEAN, 0x3609)
-+#define PR_SUBFOLDERS PROP_TAG( PT_BOOLEAN, 0x360A)
-+#define PR_STATUS PROP_TAG( PT_LONG, 0x360B)
-+#define PR_ANR PROP_TAG( PT_TSTRING, 0x360C)
-+#define PR_ANR_W PROP_TAG( PT_UNICODE, 0x360C)
-+#define PR_ANR_A PROP_TAG( PT_STRING8, 0x360C)
-+#define PR_CONTENTS_SORT_ORDER PROP_TAG( PT_MV_LONG, 0x360D)
-+#define PR_CONTAINER_HIERARCHY PROP_TAG( PT_OBJECT, 0x360E)
-+#define PR_CONTAINER_CONTENTS PROP_TAG( PT_OBJECT, 0x360F)
-+#define PR_FOLDER_ASSOCIATED_CONTENTS PROP_TAG( PT_OBJECT, 0x3610)
-+#define PR_DEF_CREATE_DL PROP_TAG( PT_BINARY, 0x3611)
-+#define PR_DEF_CREATE_MAILUSER PROP_TAG( PT_BINARY, 0x3612)
-+#define PR_CONTAINER_CLASS PROP_TAG( PT_TSTRING, 0x3613)
-+#define PR_CONTAINER_CLASS_W PROP_TAG( PT_UNICODE, 0x3613)
-+#define PR_CONTAINER_CLASS_A PROP_TAG( PT_STRING8, 0x3613)
-+#define PR_CONTAINER_MODIFY_VERSION PROP_TAG( PT_I8, 0x3614)
-+#define PR_AB_PROVIDER_ID PROP_TAG( PT_BINARY, 0x3615)
-+#define PR_DEFAULT_VIEW_ENTRYID PROP_TAG( PT_BINARY, 0x3616)
-+#define PR_ASSOC_CONTENT_COUNT PROP_TAG( PT_LONG, 0x3617)
-+
-+/* Reserved 0x36C0-0x36FF */
-+
-+/*
-+ * Attachment properties
-+ */
-+
-+#define PR_ATTACHMENT_X400_PARAMETERS PROP_TAG( PT_BINARY, 0x3700)
-+#define PR_ATTACH_DATA_OBJ PROP_TAG( PT_OBJECT, 0x3701)
-+#define PR_ATTACH_DATA_BIN PROP_TAG( PT_BINARY, 0x3701)
-+#define PR_ATTACH_ENCODING PROP_TAG( PT_BINARY, 0x3702)
-+#define PR_ATTACH_EXTENSION PROP_TAG( PT_TSTRING, 0x3703)
-+#define PR_ATTACH_EXTENSION_W PROP_TAG( PT_UNICODE, 0x3703)
-+#define PR_ATTACH_EXTENSION_A PROP_TAG( PT_STRING8, 0x3703)
-+#define PR_ATTACH_FILENAME PROP_TAG( PT_TSTRING, 0x3704)
-+#define PR_ATTACH_FILENAME_W PROP_TAG( PT_UNICODE, 0x3704)
-+#define PR_ATTACH_FILENAME_A PROP_TAG( PT_STRING8, 0x3704)
-+#define PR_ATTACH_METHOD PROP_TAG( PT_LONG, 0x3705)
-+#define PR_ATTACH_LONG_FILENAME PROP_TAG( PT_TSTRING, 0x3707)
-+#define PR_ATTACH_LONG_FILENAME_W PROP_TAG( PT_UNICODE, 0x3707)
-+#define PR_ATTACH_LONG_FILENAME_A PROP_TAG( PT_STRING8, 0x3707)
-+#define PR_ATTACH_PATHNAME PROP_TAG( PT_TSTRING, 0x3708)
-+#define PR_ATTACH_PATHNAME_W PROP_TAG( PT_UNICODE, 0x3708)
-+#define PR_ATTACH_PATHNAME_A PROP_TAG( PT_STRING8, 0x3708)
-+#define PR_ATTACH_RENDERING PROP_TAG( PT_BINARY, 0x3709)
-+#define PR_ATTACH_TAG PROP_TAG( PT_BINARY, 0x370A)
-+#define PR_RENDERING_POSITION PROP_TAG( PT_LONG, 0x370B)
-+#define PR_ATTACH_TRANSPORT_NAME PROP_TAG( PT_TSTRING, 0x370C)
-+#define PR_ATTACH_TRANSPORT_NAME_W PROP_TAG( PT_UNICODE, 0x370C)
-+#define PR_ATTACH_TRANSPORT_NAME_A PROP_TAG( PT_STRING8, 0x370C)
-+#define PR_ATTACH_LONG_PATHNAME PROP_TAG( PT_TSTRING, 0x370D)
-+#define PR_ATTACH_LONG_PATHNAME_W PROP_TAG( PT_UNICODE, 0x370D)
-+#define PR_ATTACH_LONG_PATHNAME_A PROP_TAG( PT_STRING8, 0x370D)
-+#define PR_ATTACH_MIME_TAG PROP_TAG( PT_TSTRING, 0x370E)
-+#define PR_ATTACH_MIME_TAG_W PROP_TAG( PT_UNICODE, 0x370E)
-+#define PR_ATTACH_MIME_TAG_A PROP_TAG( PT_STRING8, 0x370E)
-+#define PR_ATTACH_ADDITIONAL_INFO PROP_TAG( PT_BINARY, 0x370F)
-+
-+/*
-+ * AB Object properties
-+ */
-+
-+#define PR_DISPLAY_TYPE PROP_TAG( PT_LONG, 0x3900)
-+#define PR_TEMPLATEID PROP_TAG( PT_BINARY, 0x3902)
-+#define PR_PRIMARY_CAPABILITY PROP_TAG( PT_BINARY, 0x3904)
-+
-+
-+/*
-+ * Mail user properties
-+ */
-+#define PR_7BIT_DISPLAY_NAME PROP_TAG( PT_STRING8, 0x39FF)
-+#define PR_ACCOUNT PROP_TAG( PT_TSTRING, 0x3A00)
-+#define PR_ACCOUNT_W PROP_TAG( PT_UNICODE, 0x3A00)
-+#define PR_ACCOUNT_A PROP_TAG( PT_STRING8, 0x3A00)
-+#define PR_ALTERNATE_RECIPIENT PROP_TAG( PT_BINARY, 0x3A01)
-+#define PR_CALLBACK_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A02)
-+#define PR_CALLBACK_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A02)
-+#define PR_CALLBACK_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A02)
-+#define PR_CONVERSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x3A03)
-+#define PR_DISCLOSE_RECIPIENTS PROP_TAG( PT_BOOLEAN, 0x3A04)
-+#define PR_GENERATION PROP_TAG( PT_TSTRING, 0x3A05)
-+#define PR_GENERATION_W PROP_TAG( PT_UNICODE, 0x3A05)
-+#define PR_GENERATION_A PROP_TAG( PT_STRING8, 0x3A05)
-+#define PR_GIVEN_NAME PROP_TAG( PT_TSTRING, 0x3A06)
-+#define PR_GIVEN_NAME_W PROP_TAG( PT_UNICODE, 0x3A06)
-+#define PR_GIVEN_NAME_A PROP_TAG( PT_STRING8, 0x3A06)
-+#define PR_GOVERNMENT_ID_NUMBER PROP_TAG( PT_TSTRING, 0x3A07)
-+#define PR_GOVERNMENT_ID_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A07)
-+#define PR_GOVERNMENT_ID_NUMBER_A PROP_TAG( PT_STRING8, 0x3A07)
-+#define PR_BUSINESS_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A08)
-+#define PR_BUSINESS_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A08)
-+#define PR_BUSINESS_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A08)
-+#define PR_OFFICE_TELEPHONE_NUMBER PR_BUSINESS_TELEPHONE_NUMBER
-+#define PR_OFFICE_TELEPHONE_NUMBER_W PR_BUSINESS_TELEPHONE_NUMBER_W
-+#define PR_OFFICE_TELEPHONE_NUMBER_A PR_BUSINESS_TELEPHONE_NUMBER_A
-+#define PR_HOME_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A09)
-+#define PR_HOME_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A09)
-+#define PR_HOME_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A09)
-+#define PR_INITIALS PROP_TAG( PT_TSTRING, 0x3A0A)
-+#define PR_INITIALS_W PROP_TAG( PT_UNICODE, 0x3A0A)
-+#define PR_INITIALS_A PROP_TAG( PT_STRING8, 0x3A0A)
-+#define PR_KEYWORD PROP_TAG( PT_TSTRING, 0x3A0B)
-+#define PR_KEYWORD_W PROP_TAG( PT_UNICODE, 0x3A0B)
-+#define PR_KEYWORD_A PROP_TAG( PT_STRING8, 0x3A0B)
-+#define PR_LANGUAGE PROP_TAG( PT_TSTRING, 0x3A0C)
-+#define PR_LANGUAGE_W PROP_TAG( PT_UNICODE, 0x3A0C)
-+#define PR_LANGUAGE_A PROP_TAG( PT_STRING8, 0x3A0C)
-+#define PR_LOCATION PROP_TAG( PT_TSTRING, 0x3A0D)
-+#define PR_LOCATION_W PROP_TAG( PT_UNICODE, 0x3A0D)
-+#define PR_LOCATION_A PROP_TAG( PT_STRING8, 0x3A0D)
-+#define PR_MAIL_PERMISSION PROP_TAG( PT_BOOLEAN, 0x3A0E)
-+#define PR_MHS_COMMON_NAME PROP_TAG( PT_TSTRING, 0x3A0F)
-+#define PR_MHS_COMMON_NAME_W PROP_TAG( PT_UNICODE, 0x3A0F)
-+#define PR_MHS_COMMON_NAME_A PROP_TAG( PT_STRING8, 0x3A0F)
-+#define PR_ORGANIZATIONAL_ID_NUMBER PROP_TAG( PT_TSTRING, 0x3A10)
-+#define PR_ORGANIZATIONAL_ID_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A10)
-+#define PR_ORGANIZATIONAL_ID_NUMBER_A PROP_TAG( PT_STRING8, 0x3A10)
-+#define PR_SURNAME PROP_TAG( PT_TSTRING, 0x3A11)
-+#define PR_SURNAME_W PROP_TAG( PT_UNICODE, 0x3A11)
-+#define PR_SURNAME_A PROP_TAG( PT_STRING8, 0x3A11)
-+#define PR_ORIGINAL_ENTRYID PROP_TAG( PT_BINARY, 0x3A12)
-+#define PR_ORIGINAL_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3A13)
-+#define PR_ORIGINAL_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3A13)
-+#define PR_ORIGINAL_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3A13)
-+#define PR_ORIGINAL_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3A14)
-+#define PR_POSTAL_ADDRESS PROP_TAG( PT_TSTRING, 0x3A15)
-+#define PR_POSTAL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3A15)
-+#define PR_POSTAL_ADDRESS_A PROP_TAG( PT_STRING8, 0x3A15)
-+#define PR_COMPANY_NAME PROP_TAG( PT_TSTRING, 0x3A16)
-+#define PR_COMPANY_NAME_W PROP_TAG( PT_UNICODE, 0x3A16)
-+#define PR_COMPANY_NAME_A PROP_TAG( PT_STRING8, 0x3A16)
-+#define PR_TITLE PROP_TAG( PT_TSTRING, 0x3A17)
-+#define PR_TITLE_W PROP_TAG( PT_UNICODE, 0x3A17)
-+#define PR_TITLE_A PROP_TAG( PT_STRING8, 0x3A17)
-+#define PR_DEPARTMENT_NAME PROP_TAG( PT_TSTRING, 0x3A18)
-+#define PR_DEPARTMENT_NAME_W PROP_TAG( PT_UNICODE, 0x3A18)
-+#define PR_DEPARTMENT_NAME_A PROP_TAG( PT_STRING8, 0x3A18)
-+#define PR_OFFICE_LOCATION PROP_TAG( PT_TSTRING, 0x3A19)
-+#define PR_OFFICE_LOCATION_W PROP_TAG( PT_UNICODE, 0x3A19)
-+#define PR_OFFICE_LOCATION_A PROP_TAG( PT_STRING8, 0x3A19)
-+#define PR_PRIMARY_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1A)
-+#define PR_PRIMARY_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1A)
-+#define PR_PRIMARY_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1A)
-+#define PR_BUSINESS2_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1B)
-+#define PR_BUSINESS2_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1B)
-+#define PR_BUSINESS2_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1B)
-+#define PR_OFFICE2_TELEPHONE_NUMBER PR_BUSINESS2_TELEPHONE_NUMBER
-+#define PR_OFFICE2_TELEPHONE_NUMBER_W PR_BUSINESS2_TELEPHONE_NUMBER_W
-+#define PR_OFFICE2_TELEPHONE_NUMBER_A PR_BUSINESS2_TELEPHONE_NUMBER_A
-+#define PR_MOBILE_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1C)
-+#define PR_MOBILE_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1C)
-+#define PR_MOBILE_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1C)
-+#define PR_CELLULAR_TELEPHONE_NUMBER PR_MOBILE_TELEPHONE_NUMBER
-+#define PR_CELLULAR_TELEPHONE_NUMBER_W PR_MOBILE_TELEPHONE_NUMBER_W
-+#define PR_CELLULAR_TELEPHONE_NUMBER_A PR_MOBILE_TELEPHONE_NUMBER_A
-+#define PR_RADIO_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1D)
-+#define PR_RADIO_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1D)
-+#define PR_RADIO_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1D)
-+#define PR_CAR_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1E)
-+#define PR_CAR_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1E)
-+#define PR_CAR_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1E)
-+#define PR_OTHER_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1F)
-+#define PR_OTHER_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1F)
-+#define PR_OTHER_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1F)
-+#define PR_TRANSMITABLE_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3A20)
-+#define PR_TRANSMITABLE_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3A20)
-+#define PR_TRANSMITABLE_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3A20)
-+#define PR_PAGER_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A21)
-+#define PR_PAGER_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A21)
-+#define PR_PAGER_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A21)
-+#define PR_BEEPER_TELEPHONE_NUMBER PR_PAGER_TELEPHONE_NUMBER
-+#define PR_BEEPER_TELEPHONE_NUMBER_W PR_PAGER_TELEPHONE_NUMBER_W
-+#define PR_BEEPER_TELEPHONE_NUMBER_A PR_PAGER_TELEPHONE_NUMBER_A
-+#define PR_USER_CERTIFICATE PROP_TAG( PT_BINARY, 0x3A22)
-+#define PR_PRIMARY_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A23)
-+#define PR_PRIMARY_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A23)
-+#define PR_PRIMARY_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A23)
-+#define PR_BUSINESS_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A24)
-+#define PR_BUSINESS_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A24)
-+#define PR_BUSINESS_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A24)
-+#define PR_HOME_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A25)
-+#define PR_HOME_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A25)
-+#define PR_HOME_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A25)
-+#define PR_COUNTRY PROP_TAG( PT_TSTRING, 0x3A26)
-+#define PR_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A26)
-+#define PR_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A26)
-+#define PR_BUSINESS_ADDRESS_COUNTRY PR_COUNTRY
-+#define PR_BUSINESS_ADDRESS_COUNTRY_W PR_COUNTRY_W
-+#define PR_BUSINESS_ADDRESS_COUNTRY_A PR_COUNTRY_A
-+
-+#define PR_LOCALITY PROP_TAG( PT_TSTRING, 0x3A27)
-+#define PR_LOCALITY_W PROP_TAG( PT_UNICODE, 0x3A27)
-+#define PR_LOCALITY_A PROP_TAG( PT_STRING8, 0x3A27)
-+#define PR_BUSINESS_ADDRESS_CITY PR_LOCALITY
-+#define PR_BUSINESS_ADDRESS_CITY_W PR_LOCALITY_W
-+#define PR_BUSINESS_ADDRESS_CITY_A PR_LOCALITY_A
-+
-+#define PR_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A28)
-+#define PR_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A28)
-+#define PR_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A28)
-+#define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE PR_STATE_OR_PROVINCE
-+#define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_W PR_STATE_OR_PROVINCE_W
-+#define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_A PR_STATE_OR_PROVINCE_A
-+
-+#define PR_STREET_ADDRESS PROP_TAG( PT_TSTRING, 0x3A29)
-+#define PR_STREET_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3A29)
-+#define PR_STREET_ADDRESS_A PROP_TAG( PT_STRING8, 0x3A29)
-+#define PR_BUSINESS_ADDRESS_STREET PR_STREET_ADDRESS
-+#define PR_BUSINESS_ADDRESS_STREET_W PR_STREET_ADDRESS_W
-+#define PR_BUSINESS_ADDRESS_STREET_A PR_STREET_ADDRESS_A
-+
-+#define PR_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A2A)
-+#define PR_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A2A)
-+#define PR_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A2A)
-+#define PR_BUSINESS_ADDRESS_POSTAL_CODE PR_POSTAL_CODE
-+#define PR_BUSINESS_ADDRESS_POSTAL_CODE_W PR_POSTAL_CODE_W
-+#define PR_BUSINESS_ADDRESS_POSTAL_CODE_A PR_POSTAL_CODE_A
-+
-+
-+#define PR_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A2B)
-+#define PR_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A2B)
-+#define PR_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A2B)
-+#define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX PR_POST_OFFICE_BOX
-+#define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX_W PR_POST_OFFICE_BOX_W
-+#define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX_A PR_POST_OFFICE_BOX_A
-+
-+
-+#define PR_TELEX_NUMBER PROP_TAG( PT_TSTRING, 0x3A2C)
-+#define PR_TELEX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2C)
-+#define PR_TELEX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2C)
-+#define PR_ISDN_NUMBER PROP_TAG( PT_TSTRING, 0x3A2D)
-+#define PR_ISDN_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2D)
-+#define PR_ISDN_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2D)
-+#define PR_ASSISTANT_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A2E)
-+#define PR_ASSISTANT_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2E)
-+#define PR_ASSISTANT_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2E)
-+#define PR_HOME2_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A2F)
-+#define PR_HOME2_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2F)
-+#define PR_HOME2_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2F)
-+#define PR_ASSISTANT PROP_TAG( PT_TSTRING, 0x3A30)
-+#define PR_ASSISTANT_W PROP_TAG( PT_UNICODE, 0x3A30)
-+#define PR_ASSISTANT_A PROP_TAG( PT_STRING8, 0x3A30)
-+#define PR_SEND_RICH_INFO PROP_TAG( PT_BOOLEAN, 0x3A40)
-+
-+#define PR_WEDDING_ANNIVERSARY PROP_TAG( PT_SYSTIME, 0x3A41)
-+#define PR_BIRTHDAY PROP_TAG( PT_SYSTIME, 0x3A42)
-+
-+
-+#define PR_HOBBIES PROP_TAG( PT_TSTRING, 0x3A43)
-+#define PR_HOBBIES_W PROP_TAG( PT_UNICODE, 0x3A43)
-+#define PR_HOBBIES_A PROP_TAG( PT_STRING8, 0x3A43)
-+
-+#define PR_MIDDLE_NAME PROP_TAG( PT_TSTRING, 0x3A44)
-+#define PR_MIDDLE_NAME_W PROP_TAG( PT_UNICODE, 0x3A44)
-+#define PR_MIDDLE_NAME_A PROP_TAG( PT_STRING8, 0x3A44)
-+
-+#define PR_DISPLAY_NAME_PREFIX PROP_TAG( PT_TSTRING, 0x3A45)
-+#define PR_DISPLAY_NAME_PREFIX_W PROP_TAG( PT_UNICODE, 0x3A45)
-+#define PR_DISPLAY_NAME_PREFIX_A PROP_TAG( PT_STRING8, 0x3A45)
-+
-+#define PR_PROFESSION PROP_TAG( PT_TSTRING, 0x3A46)
-+#define PR_PROFESSION_W PROP_TAG( PT_UNICODE, 0x3A46)
-+#define PR_PROFESSION_A PROP_TAG( PT_STRING8, 0x3A46)
-+
-+#define PR_PREFERRED_BY_NAME PROP_TAG( PT_TSTRING, 0x3A47)
-+#define PR_PREFERRED_BY_NAME_W PROP_TAG( PT_UNICODE, 0x3A47)
-+#define PR_PREFERRED_BY_NAME_A PROP_TAG( PT_STRING8, 0x3A47)
-+
-+#define PR_SPOUSE_NAME PROP_TAG( PT_TSTRING, 0x3A48)
-+#define PR_SPOUSE_NAME_W PROP_TAG( PT_UNICODE, 0x3A48)
-+#define PR_SPOUSE_NAME_A PROP_TAG( PT_STRING8, 0x3A48)
-+
-+#define PR_COMPUTER_NETWORK_NAME PROP_TAG( PT_TSTRING, 0x3A49)
-+#define PR_COMPUTER_NETWORK_NAME_W PROP_TAG( PT_UNICODE, 0x3A49)
-+#define PR_COMPUTER_NETWORK_NAME_A PROP_TAG( PT_STRING8, 0x3A49)
-+
-+#define PR_CUSTOMER_ID PROP_TAG( PT_TSTRING, 0x3A4A)
-+#define PR_CUSTOMER_ID_W PROP_TAG( PT_UNICODE, 0x3A4A)
-+#define PR_CUSTOMER_ID_A PROP_TAG( PT_STRING8, 0x3A4A)
-+
-+#define PR_TTYTDD_PHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A4B)
-+#define PR_TTYTDD_PHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A4B)
-+#define PR_TTYTDD_PHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A4B)
-+
-+#define PR_FTP_SITE PROP_TAG( PT_TSTRING, 0x3A4C)
-+#define PR_FTP_SITE_W PROP_TAG( PT_UNICODE, 0x3A4C)
-+#define PR_FTP_SITE_A PROP_TAG( PT_STRING8, 0x3A4C)
-+
-+#define PR_GENDER PROP_TAG( PT_SHORT, 0x3A4D)
-+
-+#define PR_MANAGER_NAME PROP_TAG( PT_TSTRING, 0x3A4E)
-+#define PR_MANAGER_NAME_W PROP_TAG( PT_UNICODE, 0x3A4E)
-+#define PR_MANAGER_NAME_A PROP_TAG( PT_STRING8, 0x3A4E)
-+
-+#define PR_NICKNAME PROP_TAG( PT_TSTRING, 0x3A4F)
-+#define PR_NICKNAME_W PROP_TAG( PT_UNICODE, 0x3A4F)
-+#define PR_NICKNAME_A PROP_TAG( PT_STRING8, 0x3A4F)
-+
-+#define PR_PERSONAL_HOME_PAGE PROP_TAG( PT_TSTRING, 0x3A50)
-+#define PR_PERSONAL_HOME_PAGE_W PROP_TAG( PT_UNICODE, 0x3A50)
-+#define PR_PERSONAL_HOME_PAGE_A PROP_TAG( PT_STRING8, 0x3A50)
-+
-+
-+#define PR_BUSINESS_HOME_PAGE PROP_TAG( PT_TSTRING, 0x3A51)
-+#define PR_BUSINESS_HOME_PAGE_W PROP_TAG( PT_UNICODE, 0x3A51)
-+#define PR_BUSINESS_HOME_PAGE_A PROP_TAG( PT_STRING8, 0x3A51)
-+
-+#define PR_CONTACT_VERSION PROP_TAG( PT_CLSID, 0x3A52)
-+#define PR_CONTACT_ENTRYIDS PROP_TAG( PT_MV_BINARY, 0x3A53)
-+
-+#define PR_CONTACT_ADDRTYPES PROP_TAG( PT_MV_TSTRING, 0x3A54)
-+#define PR_CONTACT_ADDRTYPES_W PROP_TAG( PT_MV_UNICODE, 0x3A54)
-+#define PR_CONTACT_ADDRTYPES_A PROP_TAG( PT_MV_STRING8, 0x3A54)
-+
-+#define PR_CONTACT_DEFAULT_ADDRESS_INDEX PROP_TAG( PT_LONG, 0x3A55)
-+
-+#define PR_CONTACT_EMAIL_ADDRESSES PROP_TAG( PT_MV_TSTRING, 0x3A56)
-+#define PR_CONTACT_EMAIL_ADDRESSES_W PROP_TAG( PT_MV_UNICODE, 0x3A56)
-+#define PR_CONTACT_EMAIL_ADDRESSES_A PROP_TAG( PT_MV_STRING8, 0x3A56)
-+
-+
-+#define PR_COMPANY_MAIN_PHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A57)
-+#define PR_COMPANY_MAIN_PHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A57)
-+#define PR_COMPANY_MAIN_PHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A57)
-+
-+#define PR_CHILDRENS_NAMES PROP_TAG( PT_MV_TSTRING, 0x3A58)
-+#define PR_CHILDRENS_NAMES_W PROP_TAG( PT_MV_UNICODE, 0x3A58)
-+#define PR_CHILDRENS_NAMES_A PROP_TAG( PT_MV_STRING8, 0x3A58)
-+
-+
-+
-+#define PR_HOME_ADDRESS_CITY PROP_TAG( PT_TSTRING, 0x3A59)
-+#define PR_HOME_ADDRESS_CITY_W PROP_TAG( PT_UNICODE, 0x3A59)
-+#define PR_HOME_ADDRESS_CITY_A PROP_TAG( PT_STRING8, 0x3A59)
-+
-+#define PR_HOME_ADDRESS_COUNTRY PROP_TAG( PT_TSTRING, 0x3A5A)
-+#define PR_HOME_ADDRESS_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A5A)
-+#define PR_HOME_ADDRESS_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A5A)
-+
-+#define PR_HOME_ADDRESS_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A5B)
-+#define PR_HOME_ADDRESS_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A5B)
-+#define PR_HOME_ADDRESS_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A5B)
-+
-+#define PR_HOME_ADDRESS_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A5C)
-+#define PR_HOME_ADDRESS_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A5C)
-+#define PR_HOME_ADDRESS_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A5C)
-+
-+#define PR_HOME_ADDRESS_STREET PROP_TAG( PT_TSTRING, 0x3A5D)
-+#define PR_HOME_ADDRESS_STREET_W PROP_TAG( PT_UNICODE, 0x3A5D)
-+#define PR_HOME_ADDRESS_STREET_A PROP_TAG( PT_STRING8, 0x3A5D)
-+
-+#define PR_HOME_ADDRESS_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A5E)
-+#define PR_HOME_ADDRESS_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A5E)
-+#define PR_HOME_ADDRESS_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A5E)
-+
-+#define PR_OTHER_ADDRESS_CITY PROP_TAG( PT_TSTRING, 0x3A5F)
-+#define PR_OTHER_ADDRESS_CITY_W PROP_TAG( PT_UNICODE, 0x3A5F)
-+#define PR_OTHER_ADDRESS_CITY_A PROP_TAG( PT_STRING8, 0x3A5F)
-+
-+#define PR_OTHER_ADDRESS_COUNTRY PROP_TAG( PT_TSTRING, 0x3A60)
-+#define PR_OTHER_ADDRESS_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A60)
-+#define PR_OTHER_ADDRESS_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A60)
-+
-+#define PR_OTHER_ADDRESS_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A61)
-+#define PR_OTHER_ADDRESS_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A61)
-+#define PR_OTHER_ADDRESS_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A61)
-+
-+#define PR_OTHER_ADDRESS_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A62)
-+#define PR_OTHER_ADDRESS_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A62)
-+#define PR_OTHER_ADDRESS_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A62)
-+
-+#define PR_OTHER_ADDRESS_STREET PROP_TAG( PT_TSTRING, 0x3A63)
-+#define PR_OTHER_ADDRESS_STREET_W PROP_TAG( PT_UNICODE, 0x3A63)
-+#define PR_OTHER_ADDRESS_STREET_A PROP_TAG( PT_STRING8, 0x3A63)
-+
-+#define PR_OTHER_ADDRESS_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A64)
-+#define PR_OTHER_ADDRESS_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A64)
-+#define PR_OTHER_ADDRESS_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A64)
-+
-+
-+/*
-+ * Profile section properties
-+ */
-+
-+#define PR_STORE_PROVIDERS PROP_TAG( PT_BINARY, 0x3D00)
-+#define PR_AB_PROVIDERS PROP_TAG( PT_BINARY, 0x3D01)
-+#define PR_TRANSPORT_PROVIDERS PROP_TAG( PT_BINARY, 0x3D02)
-+
-+#define PR_DEFAULT_PROFILE PROP_TAG( PT_BOOLEAN, 0x3D04)
-+#define PR_AB_SEARCH_PATH PROP_TAG( PT_MV_BINARY, 0x3D05)
-+#define PR_AB_DEFAULT_DIR PROP_TAG( PT_BINARY, 0x3D06)
-+#define PR_AB_DEFAULT_PAB PROP_TAG( PT_BINARY, 0x3D07)
-+
-+#define PR_FILTERING_HOOKS PROP_TAG( PT_BINARY, 0x3D08)
-+#define PR_SERVICE_NAME PROP_TAG( PT_TSTRING, 0x3D09)
-+#define PR_SERVICE_NAME_W PROP_TAG( PT_UNICODE, 0x3D09)
-+#define PR_SERVICE_NAME_A PROP_TAG( PT_STRING8, 0x3D09)
-+#define PR_SERVICE_DLL_NAME PROP_TAG( PT_TSTRING, 0x3D0A)
-+#define PR_SERVICE_DLL_NAME_W PROP_TAG( PT_UNICODE, 0x3D0A)
-+#define PR_SERVICE_DLL_NAME_A PROP_TAG( PT_STRING8, 0x3D0A)
-+#define PR_SERVICE_ENTRY_NAME PROP_TAG( PT_STRING8, 0x3D0B)
-+#define PR_SERVICE_UID PROP_TAG( PT_BINARY, 0x3D0C)
-+#define PR_SERVICE_EXTRA_UIDS PROP_TAG( PT_BINARY, 0x3D0D)
-+#define PR_SERVICES PROP_TAG( PT_BINARY, 0x3D0E)
-+#define PR_SERVICE_SUPPORT_FILES PROP_TAG( PT_MV_TSTRING, 0x3D0F)
-+#define PR_SERVICE_SUPPORT_FILES_W PROP_TAG( PT_MV_UNICODE, 0x3D0F)
-+#define PR_SERVICE_SUPPORT_FILES_A PROP_TAG( PT_MV_STRING8, 0x3D0F)
-+#define PR_SERVICE_DELETE_FILES PROP_TAG( PT_MV_TSTRING, 0x3D10)
-+#define PR_SERVICE_DELETE_FILES_W PROP_TAG( PT_MV_UNICODE, 0x3D10)
-+#define PR_SERVICE_DELETE_FILES_A PROP_TAG( PT_MV_STRING8, 0x3D10)
-+#define PR_AB_SEARCH_PATH_UPDATE PROP_TAG( PT_BINARY, 0x3D11)
-+#define PR_PROFILE_NAME PROP_TAG( PT_TSTRING, 0x3D12)
-+#define PR_PROFILE_NAME_A PROP_TAG( PT_STRING8, 0x3D12)
-+#define PR_PROFILE_NAME_W PROP_TAG( PT_UNICODE, 0x3D12)
-+
-+/*
-+ * Status object properties
-+ */
-+
-+#define PR_IDENTITY_DISPLAY PROP_TAG( PT_TSTRING, 0x3E00)
-+#define PR_IDENTITY_DISPLAY_W PROP_TAG( PT_UNICODE, 0x3E00)
-+#define PR_IDENTITY_DISPLAY_A PROP_TAG( PT_STRING8, 0x3E00)
-+#define PR_IDENTITY_ENTRYID PROP_TAG( PT_BINARY, 0x3E01)
-+#define PR_RESOURCE_METHODS PROP_TAG( PT_LONG, 0x3E02)
-+#define PR_RESOURCE_TYPE PROP_TAG( PT_LONG, 0x3E03)
-+#define PR_STATUS_CODE PROP_TAG( PT_LONG, 0x3E04)
-+#define PR_IDENTITY_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3E05)
-+#define PR_OWN_STORE_ENTRYID PROP_TAG( PT_BINARY, 0x3E06)
-+#define PR_RESOURCE_PATH PROP_TAG( PT_TSTRING, 0x3E07)
-+#define PR_RESOURCE_PATH_W PROP_TAG( PT_UNICODE, 0x3E07)
-+#define PR_RESOURCE_PATH_A PROP_TAG( PT_STRING8, 0x3E07)
-+#define PR_STATUS_STRING PROP_TAG( PT_TSTRING, 0x3E08)
-+#define PR_STATUS_STRING_W PROP_TAG( PT_UNICODE, 0x3E08)
-+#define PR_STATUS_STRING_A PROP_TAG( PT_STRING8, 0x3E08)
-+#define PR_X400_DEFERRED_DELIVERY_CANCEL PROP_TAG( PT_BOOLEAN, 0x3E09)
-+#define PR_HEADER_FOLDER_ENTRYID PROP_TAG( PT_BINARY, 0x3E0A)
-+#define PR_REMOTE_PROGRESS PROP_TAG( PT_LONG, 0x3E0B)
-+#define PR_REMOTE_PROGRESS_TEXT PROP_TAG( PT_TSTRING, 0x3E0C)
-+#define PR_REMOTE_PROGRESS_TEXT_W PROP_TAG( PT_UNICODE, 0x3E0C)
-+#define PR_REMOTE_PROGRESS_TEXT_A PROP_TAG( PT_STRING8, 0x3E0C)
-+#define PR_REMOTE_VALIDATE_OK PROP_TAG( PT_BOOLEAN, 0x3E0D)
-+
-+/*
-+ * Display table properties
-+ */
-+
-+#define PR_CONTROL_FLAGS PROP_TAG( PT_LONG, 0x3F00)
-+#define PR_CONTROL_STRUCTURE PROP_TAG( PT_BINARY, 0x3F01)
-+#define PR_CONTROL_TYPE PROP_TAG( PT_LONG, 0x3F02)
-+#define PR_DELTAX PROP_TAG( PT_LONG, 0x3F03)
-+#define PR_DELTAY PROP_TAG( PT_LONG, 0x3F04)
-+#define PR_XPOS PROP_TAG( PT_LONG, 0x3F05)
-+#define PR_YPOS PROP_TAG( PT_LONG, 0x3F06)
-+#define PR_CONTROL_ID PROP_TAG( PT_BINARY, 0x3F07)
-+#define PR_INITIAL_DETAILS_PANE PROP_TAG( PT_LONG, 0x3F08)
-+
-+/*
-+ * Secure property id range
-+ */
-+
-+#define PROP_ID_SECURE_MIN 0x67F0
-+#define PROP_ID_SECURE_MAX 0x67FF
-+
-+
-+#endif /* MAPITAGS_H */