From afd100f0100b4bf586a0d89935c60f7aa644abbb Mon Sep 17 00:00:00 2001 From: Martin Holzer Date: Sun, 7 Dec 2003 10:56:56 +0000 Subject: cleanup --- net-mail/exim/Manifest | 15 +- net-mail/exim/files/exiscan-acl-4.20-09.patch | 6707 ------------------------- 2 files changed, 7 insertions(+), 6715 deletions(-) delete mode 100644 net-mail/exim/files/exiscan-acl-4.20-09.patch (limited to 'net-mail/exim') 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 -+ -+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 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: -+ -+ /scan//.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 = :::[...] -+ -+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<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 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 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, ®ex_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 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 */ -+ 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: -> ": FOUND" -+ not-infected: -> ": OK" -+ error: -> ": 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 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 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 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 2003-???? */ -+/* License: GPL */ -+ -+/* Code for setting up a MBOX style spool file inside a /scan/ -+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 -+#include -+#include -+#include -+#include -+#include -+#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 */ -- cgit v1.2.3-65-gdbad