1
diff -urN exim-4.34-orig/OS/Makefile-Base exim-4.34/OS/Makefile-Base
2
--- exim-4.34-orig/OS/Makefile-Base Mon May 10 14:31:20 2004
3
+++ exim-4.34/OS/Makefile-Base Mon May 10 16:14:47 2004
5
# Targets for final binaries; the main one has a build number which is
6
# updated each time. We don't bother with that for the auxiliaries.
8
-OBJ_EXIM = acl.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
9
+OBJ_EXIM = acl.o bmi_spam.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o demime.o \
10
directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \
11
filtertest.o globals.o \
12
- header.o host.o ip.o log.o lss.o match.o moan.o \
13
+ header.o host.o ip.o log.o lss.o malware.o match.o mime.o moan.o \
14
os.o parse.o queue.o \
15
- rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
16
- route.o search.o sieve.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
17
- store.o string.o tls.o tod.o transport.o tree.o verify.o \
18
+ rda.o readconf.o receive.o regex.o retry.o rewrite.o rfc2047.o \
19
+ route.o search.o sieve.o smtp_in.o smtp_out.o spam.o spool_in.o spool_mbox.o spool_out.o \
20
+ store.o string.o tls.o tnef.o tod.o transport.o tree.o verify.o \
21
local_scan.o $(EXIM_PERL)
23
exim: pcre/libpcre.a lookups/lookups.a auths/auths.a \
25
# Dependencies for the "ordinary" exim modules
28
+bmi_spam.o: $(HDRS) bmi_spam.c
29
child.o: $(HDRS) child.c
30
crypt16.o: $(HDRS) crypt16.c
31
daemon.o: $(HDRS) daemon.c
32
dbfn.o: $(HDRS) dbfn.c
33
debug.o: $(HDRS) debug.c
34
deliver.o: $(HDRS) deliver.c
35
+demime.o: $(HDRS) demime.c
36
directory.o: $(HDRS) directory.c
43
+malware.o: $(HDRS) malware.c
44
match.o: $(HDRS) match.c
45
+mime.o: $(HDRS) mime.c
46
moan.o: $(HDRS) moan.c
48
parse.o: $(HDRS) parse.c
51
readconf.o: $(HDRS) readconf.c
52
receive.o: $(HDRS) receive.c
53
+regex.o: $(HDRS) regex.c
54
retry.o: $(HDRS) retry.c
55
rewrite.o: $(HDRS) rewrite.c
56
rfc2047.o: $(HDRS) rfc2047.c
58
sieve.o: $(HDRS) sieve.c
59
smtp_in.o: $(HDRS) smtp_in.c
60
smtp_out.o: $(HDRS) smtp_out.c
61
+spam.o: $(HDRS) spam.c
62
spool_in.o: $(HDRS) spool_in.c
63
+spool_mbox.o: $(HDRS) spool_mbox.c
64
spool_out.o: $(HDRS) spool_out.c
65
store.o: $(HDRS) store.c
66
string.o: $(HDRS) string.c
67
tls.o: $(HDRS) tls.c tls-gnu.c tls-openssl.c
68
+tnef.o: $(HDRS) tnef.c
70
transport.o: $(HDRS) transport.c
71
tree.o: $(HDRS) tree.c
72
diff -urN exim-4.34-orig/README.EXISCAN exim-4.34/README.EXISCAN
73
--- exim-4.34-orig/README.EXISCAN Thu Jan 1 01:00:00 1970
74
+++ exim-4.34/README.EXISCAN Mon May 10 16:14:47 2004
76
+Please refer to doc/exiscan-acl-spec.txt
77
diff -urN exim-4.34-orig/doc/exiscan-acl-examples.txt exim-4.34/doc/exiscan-acl-examples.txt
78
--- exim-4.34-orig/doc/exiscan-acl-examples.txt Thu Jan 1 01:00:00 1970
79
+++ exim-4.34/doc/exiscan-acl-examples.txt Mon May 10 16:14:47 2004
81
+--------------------------------------------------------------
82
+exiscan-acl example configurations / FAQ
83
+--------------------------------------------------------------
85
+Author: Tom Kistner <tom@duncanthrax.net>
87
+The exiscan website is at http://duncanthrax.net/exiscan/. You
88
+will find the latest patch versions, as well as links to the
89
+mailing list and its archives there.
91
+This document shows some example configuration snippets:
93
+1. Basic sitewide virus and spam filtering by rejecting
94
+ matching messages after DATA.
95
+2. Adding a cryptographic "checks done" header that will
96
+ prevent re-scanning when the message re-visits one of your
97
+ mail servers, and the body size did not change.
98
+3. Marking spam-suspicious messages with extra headers and a
100
+4. Having more than one spam threshold to act on.
101
+5. Redirecting matching messages to special accounts while
102
+ preserving envelope recipient information.
103
+6. A multi-profile configuration for sites where different
104
+ "customers" (or users) have different content scanning
107
+These examples serve as a guideline and should give you some
108
+pointers that can help you to create your own configuration.
109
+Please do not copy these examples verbatim. You really need to
110
+know what you are doing. The content scanning topic is really
111
+complex and you can screw up your mail server easily if you do
114
+I recommend to read the exiscan documentation on the above
115
+mentioned website before trying to make sense of the following
118
+Each example shows part of a DATA ACL definition, unless
121
+--------------------------------------------------------------
122
+1. Basic setup for simple site-wide filtering
123
+--------------------------------------------------------------
124
+The following example only shows the most basic use of the
125
+exiscan content filtering features. You should see it as a
126
+base that you can build on. However, it may be all you need
127
+for smaller systems with only a few users.
129
+/* -----------------
130
+# Do not scan messages submitted from our own hosts
131
+# and locally submitted messages. Since the DATA ACL
132
+# is not called for messages not submitted via SMTP
133
+# protocols, we do not need to check for an empty
135
+accept hosts = 127.0.0.1:+relay_from_hosts
137
+# Unpack MIME containers and reject file extensions
138
+# used by worms. Note that the extension list may be
140
+deny message = $found_extension files are not accepted here
141
+ demime = com:vbs:bat:pif:scr
143
+# Reject messages that have serious MIME errors.
144
+# This calls the demime condition again, but it
145
+# will return cached results.
146
+deny message = Serious MIME defect detected ($demime_reason)
148
+ condition = ${if >{$demime_errorlevel}{2}{1}{0}}
150
+# Reject messages containing malware.
151
+deny message = This message contains malware ($malware_name)
154
+# Reject spam messages. Remember to tweak your
155
+# site-wide SA profile. Do not spam-scan messages
156
+# larger than eighty kilobytes.
157
+deny message = Classified as spam (score $spam_score)
158
+ condition = ${if <{$message_size}{80k}{1}{0}}
161
+# Finally accept all other messages that have
162
+# made it to this point
164
+------------------ */
168
+--------------------------------------------------------------
169
+2. Adding a cryptographic "scanning done" header
170
+--------------------------------------------------------------
172
+If you have a mail setup where the same message may pass your
173
+server twice (redirects from other servers), or you have
174
+multiple mail servers, you may want to make sure that each
175
+message is only checked once, to save processing time. Here is
178
+At the very beginning of your DATA ACL, put this:
180
+/* -----------------
181
+# Check our crytographic header. If it matches, accept
183
+accept condition = ${if eq {${hmac{md5}\
185
+ {$body_linecount}}}\
186
+ {$h_X-Scan-Signature:} {1}{0}}
187
+------------------ */
189
+At the end, just before the final "accept" verb, put this:
191
+/* -----------------
192
+# Add the cryptographic header.
193
+warn message = X-Scan-Signature: ${hmac{md5}{mysecret}\
195
+------------------ */
197
+Notice the two "mysecret" strings? Replace them with your own
198
+secret, and don't tell anyone :) The hash also includes the
199
+number of lines in the message body, to protect against
200
+message "modifications".
203
+--------------------------------------------------------------
204
+3. Marking Spam messages with extra headers and subject tag
205
+--------------------------------------------------------------
207
+Since the false positive rate with spam scanning is high
208
+compared to virus scanning, it is wise to implement a scheme
209
+with two thresholds, where you reject messages with high
210
+scores and just mark messages with lower scores. End users can
211
+then set up filters in their Mail User Agents (MUAs). Since
212
+many MUAs can not filter on custom headers, it can be
213
+necessary to put a "spam tag" in the subject line. Since it is
214
+not (yet) possible to remove headers in Exims DATA ACL, we
215
+must do this in a system filter. Please see the Exim docs on
216
+how to set up a system filter.
218
+The following example will unconditionally put two spam
219
+information headers in each message, if it is smaller than
222
+/* -----------------
223
+# Always put X-Spam-Score header in the message.
224
+# It looks like this:
225
+# X-Spam-Score: 6.6 (++++++)
226
+# When a MUA cannot match numbers, it can match for an
227
+# equivalent number of '+' signs.
228
+# The 'true' makes sure that the header is always put
229
+# in, no matter what the score.
230
+warn message = X-Spam-Score: $spam_score ($spam_bar)
231
+ condition = ${if <{$message_size}{80k}{1}{0}}
234
+# Always put X-Spam-Report header in the message.
235
+# This is a multiline header that informs the user
236
+# which tests a message has "hit", and how much a
237
+# test has contributed to the score.
238
+warn message = X-Spam-Report: $spam_report
239
+ condition = ${if <{$message_size}{80k}{1}{0}}
241
+------------------ */
243
+For the subject tag, we prepare a new subject header in the
244
+ACL, then swap it with the original Subject in the system
247
+In the DATA ACL, put this:
248
+/* -----------------
249
+warn message = X-New-Subject: *SPAM* $h_subject:
251
+------------------ */
253
+In the system filter, put this:
254
+/* -----------------
255
+if "${if def:header_X-New-Subject: {there}}" is there
257
+ headers remove Subject
258
+ headers add "Subject: $h_X-New-Subject:"
259
+ headers remove X-New-Subject
261
+------------------ */
264
+--------------------------------------------------------------
265
+4. Defining multiple spam thresholds with different actions
266
+--------------------------------------------------------------
267
+If you want to mark messages if they exceed your threshold,
268
+but also have a higher "cutoff" threshold where you reject
269
+messages, use the example above, plus this part:
271
+/* -----------------
272
+deny message = Spam score too high ($spam_score)
273
+ condition = ${if <{$message_size}{80k}{1}{0}}
275
+ condition = ${if >{$spam_score_int}{100}{1}{0}}
276
+------------------ */
278
+The last condition is only true if the spam score exceeds 10.0
279
+points (Keep in mind that $spam_score_int is the messages
280
+score multiplied by ten).
284
+--------------------------------------------------------------
285
+5. Redirect infected or spam messages to special accounts
286
+--------------------------------------------------------------
287
+Sometimes it is desirable not to reject messages, but to stop
288
+them for inspection, and then decide wether to delete, bounce
291
+There are multiple ways to achieve this. The simplest way is
292
+to freeze suspicious messages, and then thaw or bounce them
293
+after a review. Here is a simple example that will freeze spam
294
+suspicious messages when they exceed the SA threshold:
296
+/* -----------------
297
+warn log_message = frozen by spam scanner, score $spam_score
300
+------------------ */
302
+Another way is to redirect suspicious messages to special
303
+postmaster accounts, where they can be reviewed. This involves
304
+setting up a router for these special accounts that acts on a
305
+header set in the DATA ACL.
307
+This is the DATA ACL entry:
309
+/* -----------------
310
+warn message = X-Redirect-To: spambox@mycompany.com
312
+------------------ */
314
+This puts the target address in a special header, which can in
315
+turn be read with this router:
317
+/* -----------------
320
+ condition = ${if def:h_X-Redirect-To: {1}{0}}
321
+ headers_add = X-Original-Recipient: $local_part@$domain
322
+ data = $h_X-Redirect-To:
323
+ headers_remove = X-Redirect-To
324
+ redirect_router = my_second_router
325
+------------------ */
327
+This router should probably be your very first one, and you
328
+need to edit the last line (redirect_router = ) to replace
329
+"my_second_router" with the name of your original first
330
+router. Note that the original message recipient is saved in
331
+the "X-Original-Recipient" header, and the X-Redirect-To
332
+header line is removed.
335
+--------------------------------------------------------------
336
+6. Having multiple content scanning profiles for several
338
+--------------------------------------------------------------
339
+This is one of the most often asked questions, and it also has
340
+the most complicated answer. To understand the difficulties,
341
+you should first remember that the exiscan facilities are run
342
+in the DATA ACL. This ACL is called ONCE per message, after
343
+the sending server has transmitted the end-of-data marker.
344
+This gives us the very cool possibility to reject unwanted
345
+messages with a 5xx error code in response. The big drawback
346
+is that a message can have multiple recipients, and you can
347
+only reject or accept a message for ALL recipients, not
350
+I will first sum up the possible solutions to this dilemma:
352
+ a. Make sure that each incoming message can have only one
353
+ envelope recipient. This is brutal, but effective and
354
+ reliably solves the problem on your end. :) Drawback:
355
+ Incoming mail to multiple recipients is slowed down. The
356
+ exact time depends on the retry strategies of the sending
359
+ b. Offer a limited number of "profiles" that your customers
360
+ can subscribe to. Then, similar to a.), only accept
361
+ recipients with the same profile in a single "batch", and
362
+ defer the others. This does improve on the drawback of
365
+ c. Do scanning as usual, but never reject messages in the
366
+ DATA ACL. Instead put appropriate information in extra
367
+ headers and query those in routers or transports later.
368
+ Drawback: You'll have to send bounces yourself, and your
369
+ queue will fill up with frozen bounces. Advantage: clean
370
+ solution, protocol-wise.
372
+As you see, you can't have your cake and eat it too. Now lets
373
+get into the details of each possible solution.
375
+a.) Making sure each incoming message that will be scanned
376
+ only has one recipient.
378
+ To use this scheme, you must make sure that you do not use
379
+ it on your +relay_from_hosts and authenticated senders.
380
+ Both of these may be MUAs who cannot cope with such a
383
+ Here is a RCPT ACL that implements the behaviour
384
+ (shortened, do not copy 1:1!):
389
+ # accept local, relay-allowed
390
+ # and authenticated sources
393
+ deny local_parts = ^.*[@%!/|]
394
+ accept hosts = 127.0.0.1:+relay_from_hosts
395
+ accept authenticated = *
397
+ # the following treat non-local,
398
+ # non-authenticated sources
400
+ defer message = only one recipient at a time
401
+ condition = ${if def:acl_m0 {1}{0}}
404
+ # put RBLs etc. here
407
+ accept domains = +local_domains
409
+ message = unknown user
411
+ set acl_m0 = $local_part@$domain
413
+ accept domains = +relay_to_domains
415
+ message = unrouteable address
417
+ set acl_m0 = $domain
419
+ deny message = relay not permitted
422
+ The lines which contain acl_m0 are the important ones. The
423
+ $acl_m0 variable gets set when a remote server
424
+ successfully sends one RCPT. Subsequent RCPT commands are
425
+ deferred if this variable is set. The $acl_m0 variable now
426
+ contains the single recipient domain, which you can use in
427
+ the DATA ACL to determine the scanning profile.
429
+ This scheme is only recommended for small servers with a
430
+ low number of possible recipients, where recipients do not
431
+ belong to the same organization. An example would be a
432
+ multiuser shell server.
435
+b.) Having several scanning profiles that "customers" can
438
+ Suppose you want to offer three profiles. Lets call them
439
+ "reject-aggressive", "reject-conservative", and "warn
440
+ -only". Customers can select one of the profiles for each
441
+ of their domains. So you end up with a mapping like this:
443
+ domain-a.com: reject-aggressive
444
+ domain-b.org: warn-only
445
+ domain-c.net: reject-aggressive
446
+ domain-d.com: reject-conservative
449
+ Suppose you put that in a file called /etc/exim/scanprefs
451
+ Now we make a scheme similar to a.), but we do allow more
452
+ than one recipient if they have the same scanning profile
453
+ than the first recipient.
455
+ Here is a RCPT ACL that implements the behaviour
456
+ (shortened, do not copy 1:1!):
461
+ # accept local, relay-allowed and authenticated sources
464
+ deny local_parts = ^.*[@%!/|]
465
+ accept hosts = 127.0.0.1:+relay_from_hosts
466
+ accept authenticated = *
468
+ # the following treat non-local, non-authenticated sources
470
+ defer message = try this address in the next batch
471
+ condition = ${if eq {${acl_m0}}\
472
+ {${lookup{$domain}\
473
+ lsearch{/etc/exim/scanprefs}}}\
477
+ # put RBLs etc. here
480
+ accept domains = +local_domains
482
+ message = unknown user
484
+ set acl_m0 = $local_part@$domain
486
+ accept domains = +relay_to_domains
488
+ message = unrouteable address
490
+ set acl_m0 = ${lookup{$domain}\
491
+ lsearch{/etc/exim/scanprefs}}
493
+ deny message = relay not permitted
496
+ Now a recipient address get deferred if its scan profile
497
+ does not match the current batch profile. The $acl_m0
498
+ variable contains the name of the profile, that can be
499
+ used for processing in the DATA ACL.
501
+ This scheme works pretty well if you keep the number of
502
+ possible profiles low, since that will prevent
503
+ fragmentation of RCPT blocks.
506
+c.) Classic content scanning without the possibility of
507
+ rejects after DATA.
509
+ This emulates the "classic" content scanning in routers
510
+ and transports. The difference is that we still do the
511
+ scan in the DATA ACL, but put the outcome of each facility
512
+ in message headers, that can the be evaluated in special
513
+ routers, individually for each recipient.
515
+ A special approach can be taken for spam scanning, since
516
+ the $spam_score_int variable is also available in routers
517
+ and transports (it gets written to the spool files), so
518
+ you do not need to put that information in a header, but
519
+ rather act on $spam_score_int directly.
521
diff -urN exim-4.34-orig/doc/exiscan-acl-spec.txt exim-4.34/doc/exiscan-acl-spec.txt
522
--- exim-4.34-orig/doc/exiscan-acl-spec.txt Thu Jan 1 01:00:00 1970
523
+++ exim-4.34/doc/exiscan-acl-spec.txt Mon May 10 16:14:47 2004
525
+--------------------------------------------------------------
526
+The exiscan-acl patch for exim4 - Documentation
527
+--------------------------------------------------------------
528
+(c) Tom Kistner <tom@duncanthrax.net> 2003-????
531
+The exiscan-acl patch adds content scanning to the exim4 ACL
532
+system. It supports the following scanning features:
534
+ - MIME ACL that is called for all MIME parts in
535
+ incoming MIME messages.
536
+ - Antivirus using 3rd party scanners.
537
+ - Anti-spam using SpamAssassin.
538
+ - Anti-spam using Brightmail Antispam.
539
+ - Regular expression match against headers, bodies, raw
540
+ MIME parts and decoded MIME parts.
542
+These features are hooked into exim by extending exim's ACL
543
+system. The patch adds expansion variables and ACL conditions.
544
+These conditions are designed to be used in the acl_smtp_data
545
+ACL. It is run when the sending host has completed the DATA
546
+phase and is waiting for our final response to his end-of-data
547
+marker. This allows us to reject messages containing
548
+unwanted content at that stage.
550
+Support for Brightmail AntiSpam requires special compile-time
551
+flags. Please refer to chapter 7 for details.
553
+The default exim configure file contains commented
554
+configuration examples for some features of exiscan-acl.
557
+0. Overall concept / Overview
558
+--------------------------------------------------------------
560
+The exiscan-acl patch extends Exims with mechanisms to
561
+deal with the message body content. Most of these additions
562
+affect the ACL system. The exiscan patch adds
564
+- A new ACL, called 'acl_smtp_mime' (Please see detailed
565
+ chapter on this one below).
566
+- ACL conditions and modifiers
567
+ o malware (attach 3rd party virus/malware scanner)
568
+ o spam (attach SpamAssassin)
569
+ o regex (match regex against message, linewise)
570
+ o decode (decode MIME part to disk)
571
+ o mime_regex (match regex against decoded MIME part)
572
+ o control = fakereject (reject but really accept a message)
573
+- expansion variables
574
+ (see chapters below for names and explanations)
575
+- configuration options in section 1 of Exim's configure file.
576
+ o av_scanner (type and options of the AV scanner)
577
+ o spamd_address (network address / socket of spamd daemon).
579
+All facilites work on a MBOX copy of the message that is
580
+temporarily spooled up in a file called:
582
+ <spool_directory>/scan/<message_id>/<message_id>.eml
584
+The .eml extension is a friendly hint to virus scanners that
585
+they can expect an MBOX-like structure inside that file. The
586
+file is only spooled up once, when the first exiscan facility
587
+is called. Subsequent calls to exiscan conditions will just
588
+open the file again. The directory is recursively removed
589
+when the acl_smtp_data has finished running. When the MIME
590
+ACL decodes files, they will be put into that same folder by
594
+1. The acl_smtp_mime MIME ACL
595
+--------------------------------------------------------------
597
+Note: if you are not familiar with exims ACL system, please go
598
+read the documentation on it, otherwise this chapter will not
599
+make much sense to you.
601
+Here are the facts on acl_smtp_mime:
603
+ - It is called once for each MIME part of a message,
604
+ including multipart types, in the sequence of their
605
+ position in the message.
607
+ - It is called just before the acl_smtp_data ACL. They share
608
+ a result code (the one assed to the remote system after
609
+ DATA). When a call to acl_smtp_mime does not yield
610
+ "accept", ACL processing is aborted and the respective
611
+ result code is sent to the remote mailer. This means that
612
+ the acl_smtp_data is NOT called any more.
614
+ - It is ONLY called if the message has a MIME-Version header.
616
+ - MIME parts will NOT be dumped to disk by default, you have
617
+ to call the "decode" condition to do that (see further
620
+ - For RFC822 attachments (these are messages attached to
621
+ messages, with a content-type of 'message/rfc822'),
622
+ the ACL is called again in the same manner as
623
+ for the "primary" message, only that the $mime_is_rfc822
624
+ expansion variable is set (see below). These messages
625
+ are always decoded to disk before being checked, but
626
+ the files are unlinked once the check is done.
628
+To activate acl_smtp_mime, you need to add assign it the name
629
+of an ACL entry in section 1 of the config file, and then
630
+write that ACL in the ACL section, like:
634
+ # -- section 1 ----
636
+ acl_smtp_mime = my_mime_acl
639
+ # -- acl section ----
650
+ ---------------- */
652
+The following list describes all expansion variables that are
653
+available in the MIME ACL:
657
+ A very important variable. If the MIME part has a "Content
658
+ -Type:" header, this variable will contain its value,
659
+ lowercased, and WITHOUT any options (like "name" or
660
+ "charset", see below for these). Here are some examples of
661
+ popular MIME types, as they may appear in this variable:
665
+ application/octet-stream
669
+ If the MIME part has no "Content-Type:" header, this
670
+ variable is the empty string.
675
+ Another important variable, possibly the most important one.
676
+ It contains a proposed filename for an attachment, if one
677
+ was found in either the "Content-Type:" or "Content
678
+ -Disposition" headers. The filename will be RFC2047
679
+ decoded, however NO additional sanity checks are done. See
680
+ instructions on "decode" further below. If no filename was
681
+ found, this variable is the empty string.
686
+ Contains the charset identifier, if one was found in the
687
+ "Content-Type:" header. Examples for charset identifiers are
693
+ Please note that this value will NOT be normalized, so you
694
+ should do matches case-insensitively.
699
+ If the current part is a multipart (see $mime_is_multipart)
700
+ below, it SHOULD have a boundary string. It is stored in
701
+ this variable. If the current part has no boundary parameter
702
+ in the "Content-Type:" header, this variable contains the
706
+ $mime_content_disposition
707
+ -------------------------
708
+ Contains the normalized content of the "Content
709
+ -Disposition:" header. You can expect strings like
710
+ "attachment" or "inline" here.
713
+ $mime_content_transfer_encoding
714
+ -------------------------------
715
+ Contains the normalized content of the "Content
716
+ -transfer-encoding:" header. This is a symbolic name for
717
+ an encoding type. Typical values are "base64" and "quoted
723
+ Contains the normalized content of the "Content
724
+ -ID:" header. This is a unique ID that can be used to
725
+ reference a part from another part.
728
+ $mime_content_description
729
+ -------------------------
730
+ Contains the normalized content of the "Content
731
+ -Description:" header. It can contain a human-readable
732
+ description of the parts content. Some implementations will
733
+ repeat the filename for attachments here, but they are
734
+ usually only used for display purposes.
739
+ This is a counter that is raised for each processed MIME
740
+ part. It starts at zero for the very first part (which is
741
+ usually a multipart). The counter is per-message, so it is
742
+ reset when processing RFC822 attachments (see
743
+ $mime_is_rfc822). The counter stays set after acl_smtp_mime
744
+ is complete, so you can use it in the DATA ACL to determine
745
+ the number of MIME parts of a message. For non-MIME
746
+ messages, this variable will contain the value -1.
751
+ A "helper" flag that is true (1) when the current
752
+ part has the main type "multipart", for example
753
+ "multipart/alternative" or "multipart/mixed". Since
754
+ multipart entities only serve as containers for other parts,
755
+ you may not want to carry out specific actions on them.
758
+ $mime_is_coverletter
759
+ --------------------
760
+ This flag attempts to differentiate the "cover letter" of an
761
+ e-mail from attached data. It can be used to clamp down on
762
+ "flashy" or unneccessarily encoded content in the
763
+ coverletter, while not restricting attachments at all.
765
+ It returns 1 (true) for a MIME part believed to be part of
766
+ the coverletter, 0 (false) for an attachment. At
767
+ present, the algorithm is as follows:
769
+ 1. The outermost MIME part of a message always coverletter.
770
+ 2. If a multipart/alternative or multipart/related MIME part
771
+ is coverletter, so are all MIME subparts within that
773
+ 3. If any other multipart is coverletter, the first subpart
774
+ is coverletter, the rest are attachments.
775
+ 4. All parts contained within an attachment multipart are
778
+ As an example, the following will ban "HTML mail" (including
779
+ that sent with alternative plain text), while allowing HTML
780
+ files to be attached:
782
+ /* ----------------------
783
+ deny message = HTML mail is not accepted here
784
+ condition = $mime_is_coverletter
785
+ condition = ${if eq{$mime_content_type}{text/html}{1}{0}}
786
+ ----------------------- */
791
+ This flag is true (1) if the current part is NOT a part of
792
+ the checked message itself, but part of an attached message.
793
+ Attached message decoding is fully recursive.
796
+ $mime_decoded_filename
797
+ ----------------------
798
+ This variable is only set after the "decode" condition (see
799
+ below) has been successfully run. It contains the full path
800
+ and file name of the file containing the decoded data.
805
+ This variable is only set after the "decode" condition (see
806
+ below) has been successfully run. It contains the size of
807
+ the decoded part in kilobytes(!). The size is always
808
+ rounded up to full kilobytes, so only a completely empty
809
+ part will have a mime_content_size of 0.
812
+The expansion variables only reflect the content of the MIME
813
+headers for each part. To actually decode the part to disk,
814
+you can use the "decode" condition. The general syntax is
816
+decode = [/<PATH>/]<FILENAME>
818
+The right hand side is expanded before use. After expansion,
821
+ - be '0' or 'false', in which case no decoding is done.
822
+ - be the string 'default'. In that case, the file will be
823
+ put in the temporary "default" directory
824
+ <spool_directory>/scan/<message_id>/
825
+ with a sequential file name, consisting of the message id
826
+ and a sequence number. The full path and name is available
827
+ in $mime_decoded_filename after decoding.
828
+ - start with a slash. If the full name is an existing
829
+ directory, it will be used as a replacement for the
830
+ "default" directory. The filename will then also be
831
+ sequentially assigned. If the name does not exist, it will
832
+ be used as the full path and file name.
833
+ - not start with a slash. It will then be used as the
834
+ filename, and the default path will be used.
836
+You can easily decode a file with its original, proposed
837
+filename using "decode = $mime_filename". However, you should
838
+keep in mind that $mime_filename might contain anything. If
839
+you place files outside of the default path, they will not be
840
+automatically unlinked.
842
+The MIME ACL also supports the regex= and mime_regex=
843
+conditions. You can use those to match regular expressions
844
+against raw and decoded MIME parts, respectively. Read the
845
+next section for more information on these conditions.
849
+2. Match message or MIME parts against regular expressions
850
+--------------------------------------------------------------
852
+The "regex" condition takes one or more regular expressions as
853
+arguments and matches them against the full message (when
854
+called in the DATA ACL) or a raw MIME part (when called in the
855
+MIME ACL). The "regex" condition matches linewise, with a
856
+maximum line length of 32k characters. That means you can't
857
+have multiline matches with the "regex" condition.
859
+The "mime_regex" can only be called in the MIME ACL. It
860
+matches up to 32k of decoded content (the whole content at
861
+once, not linewise). If the part has not been decoded with the
862
+"decode" condition earlier in the ACL, it is decoded
863
+automatically when "mime_regex" is executed (using default
864
+path and filename values). If the decoded data is larger
865
+than 32k, only the first 32k characters will be
868
+The regular expressions are passed as a colon-separated list.
869
+To include a literal colon, you must double it. Since the
870
+whole right-hand side string is expanded before being used,
871
+you must also escape dollar ($) signs with backslashes.
873
+Here is a simple example:
875
+/* ----------------------
876
+deny message = contains blacklisted regex ($regex_match_string)
877
+ regex = [Mm]ortgage : URGENT BUSINESS PROPOSAL
878
+----------------------- */
880
+The conditions returns true if one of the regular
881
+expressions has matched. The $regex_match_string expansion
882
+variable is then set up and contains the matching regular
885
+Warning: With large messages, these conditions can be fairly
890
+3. Antispam measures with SpamAssassin
891
+--------------------------------------------------------------
893
+The "spam" ACL condition calls SpamAssassin's "spamd" daemon
894
+to get a spam-score and a report for the message. You must
895
+first install SpamAssassin. You can get it
896
+at http://www.spamassassin.org, or, if you have a working
897
+Perl installation, you can use CPAN by calling
899
+perl -MCPAN -e 'install Mail::SpamAssassin'
901
+SpamAssassin has its own set of configuration files. Please
902
+review its documentation to see how you can tweak it. The
903
+default installation should work nicely, however.
905
+After having installed and configured SpamAssassin, start the
906
+"spamd" daemon. By default, it listens on 127.0.0.1, TCP port
907
+783. If you use another host or port for spamd, you must set
908
+the spamd_address option in Section 1 of the exim
909
+configuration as follows (example):
911
+spamd_address = 127.0.0.1 783
913
+As of version 2.60, spamd also supports communication over UNIX
914
+sockets. If you want to use these, supply spamd_address with
915
+an absolute file name instead of a address/port pair, like:
917
+spamd_address = /var/run/spamd_socket
919
+If you use the above mentioned default, you do NOT need to set
922
+You can also have multiple spamd servers to improve
923
+scalability. These can also reside on other hardware reachable
924
+over the network. To specify multiple spamd servers, just put
925
+multiple address/port pairs in the spamd_address option,
926
+separated with colons:
928
+spamd_address = 192.168.2.10 783 : 192.168.2.11 783 : 192.168.2.12 783
930
+Up to 32 spamd servers are supported. The servers will be
931
+queried in a random fashion. When a server fails to respond
932
+to the connection attempt, all other servers are tried
933
+until one succeeds. If no server responds, the "spam"
934
+condition will return DEFER. IMPORTANT: It is not possible
935
+to use the UNIX socket connection method with
936
+multiple spamd servers.
938
+To use the antispam facility, put the "spam" condition in a
939
+DATA ACL block. Here is a very simple example:
942
+deny message = This message was classified as SPAM
946
+On the right-hand side of the spam condition, you can put the
947
+username that SpamAssassin should scan for. That allows you to
948
+use per-domain or per-user antispam profiles. The right-hand
949
+side is expanded before being used, so you can put lookups or
950
+conditions there. When the right-hand side evaluates to "0" or
951
+"false", no scanning will be done and the condition will fail
954
+If you do not want to scan for a particular user, but rather
955
+use the SpamAssassin system-wide default profile, you can scan
956
+for an unknown user, or simply use "nobody".
958
+The "spam" condition will return true if the threshold
959
+specified in the user's SpamAssassin profile has been matched
960
+or exceeded. If you want to use the spam condition for its
961
+side effects (see the variables below), you can make it always
962
+return "true" by appending ":true" to the username.
964
+When the condition is run, it sets up the following expansion
967
+ $spam_score The spam score of the message, for example
968
+ "3.4" or "30.5". This is useful for
969
+ inclusion in log or reject messages.
971
+ $spam_score_int The spam score of the message, multiplied
972
+ by ten, as an integer value. For example
973
+ "34" or "305". This is useful for numeric
974
+ comparisons in conditions. See further
975
+ below for a more complicated example. This
976
+ variable is special, since it is written
977
+ to the spool file, so it can be used
978
+ during the whole life of the message on
979
+ your exim system, even in routers
982
+ $spam_bar A string consisting of a number of '+' or
983
+ '-' characters, representing the
984
+ spam_score value. A spam score of "4.4"
985
+ would have a spam_bar of '++++'. This is
986
+ useful for inclusion in warning headers,
987
+ since MUAs can match on such strings.
989
+ $spam_report A multiline text table, containing the
990
+ full SpamAssassin report for the message.
991
+ Useful for inclusion in headers or reject
994
+The spam condition caches its results. If you call it again
995
+with the same user name, it will not really scan again, but
996
+rather return the same values as before.
998
+The spam condition will return DEFER if there is any error
999
+while running the message through SpamAssassin. If you want to
1000
+treat DEFER as FAIL (to pass on to the next ACL statement
1001
+block), append '/defer_ok' to the right hand side of the spam
1002
+condition, like this:
1005
+deny message = This message was classified as SPAM
1006
+ spam = joe/defer_ok
1007
+---------------- */
1009
+This will cause messages to be accepted even if there is a
1010
+problem with spamd.
1012
+Finally, here is a commented example on how to use the spam
1015
+/* ----------------
1016
+# put headers in all messages (no matter if spam or not)
1017
+warn message = X-Spam-Score: $spam_score ($spam_bar)
1018
+ spam = nobody:true
1019
+warn message = X-Spam-Report: $spam_report
1020
+ spam = nobody:true
1022
+# add second subject line with *SPAM* marker when message
1023
+# is over threshold
1024
+warn message = Subject: *SPAM* $h_Subject
1027
+# reject spam at high scores (> 12)
1028
+deny message = This message scored $spam_score spam points.
1029
+ spam = nobody:true
1030
+ condition = ${if >{$spam_score_int}{120}{1}{0}}
1031
+----------------- */
1035
+4. The "malware" facility
1036
+ Scan messages for viruses using an external virus scanner
1037
+--------------------------------------------------------------
1039
+This facility lets you connect virus scanner software to exim.
1040
+It supports a "generic" interface to scanners called via the
1041
+shell, and specialized interfaces for "daemon" type virus
1042
+scanners, who are resident in memory and thus are much faster.
1044
+To use this facility, you MUST set the "av_scanner" option in
1045
+section 1 of the exim config file. It specifies the scanner
1046
+type to use, and any additional options it needs to run. The
1047
+basic syntax is as follows:
1049
+ av_scanner = <scanner-type>:<option1>:<option2>:[...]
1051
+The following scanner-types are supported in this release:
1053
+ sophie Sophie is a daemon that uses Sophos' libsavi
1054
+ library to scan for viruses. You can get Sophie
1055
+ at http://www.vanja.com/tools/sophie/. The only
1056
+ option for this scanner type is the path to the
1057
+ UNIX socket that Sophie uses for client
1058
+ communication. The default path is
1059
+ /var/run/sophie, so if you are using this, you
1060
+ can omit the option. Example:
1062
+ av_scanner = sophie:/tmp/sophie
1065
+ kavdaemon Kapersky's kavdaemon is a daemon-type scanner.
1066
+ You can get a trial version at
1067
+ http://www.kapersky.com. This scanner type takes
1068
+ one option, which is the path to the daemon's
1069
+ UNIX socket. The default is "/var/run/AvpCtl".
1072
+ av_scanner = kavdaemon:/opt/AVP/AvpCtl
1075
+ clamd Another daemon type scanner, this one is GPL and
1076
+ free. Get it at http://clamav.elektrapro.com/.
1077
+ Clamd does not seem to unpack MIME containers,
1078
+ so it is recommended to use the demime facility
1079
+ with it. It takes one option: either the path
1080
+ and name of a UNIX socket file, or a
1081
+ hostname/port pair, separated by space. If
1082
+ unset, the default is "/tmp/clamd". Example:
1084
+ av_scanner = clamd:192.168.2.100 1234
1086
+ av_scanner = clamd:/opt/clamd/socket
1089
+ drweb This one is for the DrWeb (http://www.sald.com/)
1090
+ daemon. It takes one argument, either a full
1091
+ path to a UNIX socket, or an IP address and port
1092
+ separated by whitespace. If you omit the
1093
+ argument, the default
1095
+ /usr/local/drweb/run/drwebd.sock
1099
+ av_scanner = drweb:192.168.2.20 31337
1101
+ av_scanner = drweb:/var/run/drwebd.sock
1103
+ Thanks to Alex Miller <asm@abbyy.com.ua> for
1104
+ contributing the code for this scanner.
1107
+ mksd Yet another daemon type scanner, aimed mainly at
1108
+ Polish users, though some parts of documentation
1109
+ are now avaliable in English. You can get it at
1110
+ http://linux.mks.com.pl/. The only option for
1111
+ this scanner type is the maximum number of
1112
+ processes used simultaneously to scan the
1113
+ attachments, provided that the demime facility
1114
+ is employed and also mksd has been run with
1115
+ at least the same number of child processes.
1116
+ You can safely omit this option, the default
1117
+ value is 1. Example:
1119
+ av_scanner = mksd:2
1122
+ cmdline This is the keyword for the generic command line
1123
+ scanner interface. It can be used to attach
1124
+ virus scanners that are invoked on the shell.
1125
+ This scanner type takes 3 mantadory options:
1127
+ - full path and name of the scanner binary, with
1128
+ all command line options and a placeholder
1129
+ (%s) for the directory to scan.
1131
+ - A regular expression to match against the
1132
+ STDOUT and STDERR output of the virus scanner.
1133
+ If the expression matches, a virus was found.
1134
+ You must make absolutely sure that this
1135
+ expression only matches on "virus found". This
1136
+ is called the "trigger" expression.
1138
+ - Another regular expression, containing exactly
1139
+ ONE pair of braces, to match the name of the
1140
+ virus found in the scanners output. This is
1141
+ called the "name" expression.
1145
+ Sophos Sweep reports a virus on a line like
1148
+ Virus 'W32/Magistr-B' found in file ./those.bat
1150
+ For the "trigger" expression, we just use the
1151
+ "found" word. For the "name" expression, we want
1152
+ to get the W32/Magistr-B string, so we can match
1153
+ for the single quotes left and right of it,
1154
+ resulting in the regex '(.*)' (WITH the quotes!)
1156
+ Altogether, this makes the configuration
1159
+ av_scanner = cmdline:\
1160
+ /path/to/sweep -all -rec -archive %s:\
1164
+When av_scanner is correcly set, you can use the "malware"
1165
+condition in the DATA ACL. The condition takes a right-hand
1166
+argument that is expanded before use. It can then be one of
1168
+ - "true", "*", or "1", in which case the message is scanned
1169
+ for viruses. The condition will succeed if a virus was
1170
+ found, or fail otherwise. This is the recommended usage.
1172
+ - "false" or "0", in which case no scanning is done and the
1173
+ condition will fail immediately.
1175
+ - a regular expression, in which case the message is scanned
1176
+ for viruses. The condition will succeed if a virus found
1177
+ found and its name matches the regular expression. This
1178
+ allows you to take special actions on certain types of
1181
+When a virus was found, the condition sets up an expansion
1182
+variable called $malware_name that contains the name of the
1183
+virus found. You should use it in a "message" modifier that
1184
+contains the error returned to the sender.
1186
+The malware condition caches its results, so when you use it
1187
+multiple times, the actual scanning process is only carried
1190
+If your virus scanner cannot unpack MIME and TNEF containers
1191
+itself, you should use the demime condition prior to the
1194
+Here is a simple example:
1196
+/* ----------------------
1197
+deny message = This message contains malware ($malware_name)
1200
+---------------------- */
1202
+Like with the "spam" condition, you can append '/defer_ok' to
1203
+the malware condition to accept messages even if there is a
1204
+problem with the virus scanner, like this:
1206
+/* ----------------------
1207
+deny message = This message contains malware ($malware_name)
1209
+ malware = */defer_ok
1210
+---------------------- */
1214
+5. The "demime" facility
1215
+ MIME unpacking, sanity checking and file extension blocking
1216
+--------------------------------------------------------------
1218
+* This facility provides a simpler interface to MIME decoding
1219
+* than the MIME ACL functionality. It is kept in exiscan for
1220
+* backward compatability.
1222
+The demime facility unpacks MIME containers in the message. It
1223
+detects errors in MIME containers and can match file
1224
+extensions found in the message against a list. Using this
1225
+facility will produce additional files in the temporary scan
1226
+directory that contain the unpacked MIME parts of the message.
1227
+If you do antivirus scanning, it is recommened to use the
1228
+"demime" condition before the antivirus ("malware") condition.
1230
+The condition name of this facility is "demime". On the right
1231
+hand side, you can pass a colon-separated list of file
1232
+extensions that it should match against. If one of the file
1233
+extensions is found, the condition will return "OK" (or
1234
+"true"), otherwise it will return FAIL (or "false"). If there
1235
+was any TEMPORARY error while demimeing (mostly "disk full"),
1236
+the condition will return DEFER, and the message will be
1237
+temporarily rejected.
1239
+The right-hand side gets "expanded" before being treated as a
1240
+list, so you can have conditions and lookups there. If it
1241
+expands to an empty string, "false", or zero ("0"), no
1242
+demimeing is done and the conditions returns FALSE.
1247
+deny message = Found blacklisted file attachment
1248
+ demime = vbs:com:bat:pif:prf:lnk
1251
+When the condition is run, it sets up the following expansion
1254
+ $demime_errorlevel When an error was detected in a MIME
1255
+ container, this variable contains the
1256
+ "severity" of the error, as an integer
1257
+ number. The higher the value, the
1258
+ more severe the error. If this
1259
+ variable is unset or zero, no error has
1262
+ $demime_reason When $demime_errorlevel is greater than
1263
+ zero, this variable contains a human
1264
+ -readable text string describing the
1265
+ MIME error that occured.
1267
+ $found_extension When the "demime" condition returns
1268
+ "true", this variable contains the file
1269
+ extension it has found.
1271
+Both $demime_errorlevel and $demime_reason are set with the
1272
+first call of the "demime" condition, and are not changed on
1275
+If do not want to check for any file extensions, but rather
1276
+use the demime facility for unpacking or error checking
1277
+purposes, just pass "*" as the right-hand side value.
1279
+Here is a more elaborate example on how to use this facility:
1281
+/* -----------------
1282
+# Reject messages with serious MIME container errors
1283
+deny message = Found MIME error ($demime_reason).
1285
+ condition = ${if >{$demime_errorlevel}{2}{1}{0}}
1287
+# Reject known virus spreading file extensions.
1288
+# Accepting these is pretty much braindead.
1289
+deny message = contains $found_extension file (blacklisted).
1290
+ demime = com:vbs:bat:pif:scr
1292
+# Freeze .exe and .doc files. Postmaster can
1293
+# examine them and eventually thaw them up.
1294
+deny log_message = Another $found_extension file.
1297
+--------------------- */
1301
+6. The "fakereject" control statement
1302
+ Reject a message while really accepting it.
1303
+--------------------------------------------------------------
1305
+When you put "control = fakereject" in an ACL statement, the
1306
+following will happen: If exim would have accepted the
1307
+message, it will tell the remote host that it did not, with a
1310
+550-FAKE_REJECT id=xxxxxx-xxxxxx-xx
1311
+550-Your message has been rejected but is being kept for evaluation.
1312
+550 If it was a legit message, it may still be delivered to the target recipient(s).
1314
+But exim will go on to treat the message as if it had accepted
1315
+it. This should be used with extreme caution, please look into
1316
+the examples document for possible usage.
1320
+7. Brighmail AntiSpam (BMI) suppport
1321
+--------------------------------------------------------------
1323
+Brightmail AntiSpam is a commercial package. Please see
1324
+http://www.brightmail.com for more information on
1325
+the product. For the sake of clarity, we'll refer to it as
1329
+0) BMI concept and implementation overview
1331
+In contrast to how spam-scanning with SpamAssassin is
1332
+implemented in exiscan-acl, BMI is more suited for per
1333
+-recipient scanning of messages. However, each messages is
1334
+scanned only once, but multiple "verdicts" for multiple
1335
+recipients can be returned from the BMI server. The exiscan
1336
+implementation passes the message to the BMI server just
1337
+before accepting it. It then adds the retrieved verdicts to
1338
+the messages header file in the spool. These verdicts can then
1339
+be queried in routers, where operation is per-recipient
1340
+instead of per-message. To use BMI, you need to take the
1343
+ 1) Compile Exim with BMI support
1344
+ 2) Set up main BMI options (top section of exim config file)
1345
+ 3) Set up ACL control statement (ACL section of the config
1347
+ 4) Set up your routers to use BMI verdicts (routers section
1348
+ of the config file).
1349
+ 5) (Optional) Set up per-recipient opt-in information.
1351
+These four steps are explained in more details below.
1353
+1) Adding support for BMI at compile time
1355
+ To compile with BMI support, you need to link Exim against
1356
+ the Brighmail client SDK, consisting of a library
1357
+ (libbmiclient_single.so) and a header file (bmi_api.h).
1358
+ You'll also need to explicitly set a flag in the Makefile to
1359
+ include BMI support in the Exim binary. Both can be achieved
1360
+ with these 2 lines in Local/Makefile:
1362
+ CFLAGS=-DBRIGHTMAIL -I/path/to/the/dir/with/the/includefile
1363
+ EXTRALIBS_EXIM=-L/path/to/the/dir/with/the/library -lbmiclient_single
1365
+ If you use other CFLAGS or EXTRALIBS_EXIM settings then
1366
+ merge the content of these lines with them.
1368
+ You should also include the location of
1369
+ libbmiclient_single.so in your dynamic linker configuration
1370
+ file (usually /etc/ld.so.conf) and run "ldconfig"
1371
+ afterwards, or else the produced Exim binary will not be
1372
+ able to find the library file.
1375
+2) Setting up BMI support in the exim main configuration
1377
+ To enable BMI support in the main exim configuration, you
1378
+ should set the path to the main BMI configuration file with
1379
+ the "bmi_config_file" option, like this:
1381
+ bmi_config_file = /opt/brightmail/etc/brightmail.cfg
1383
+ This must go into section 1 of exims configuration file (You
1384
+ can put it right on top). If you omit this option, it
1385
+ defaults to /opt/brightmail/etc/brightmail.cfg.
1388
+3) Set up ACL control statement
1390
+ To optimize performance, it makes sense only to process
1391
+ messages coming from remote, untrusted sources with the BMI
1392
+ server. To set up a messages for processing by the BMI
1393
+ server, you MUST set the "bmi_run" control statement in any
1394
+ ACL for an incoming message. You will typically do this in
1395
+ an "accept" block in the "acl_check_rcpt" ACL. You should
1396
+ use the "accept" block(s) that accept messages from remote
1397
+ servers for your own domain(s). Here is an example that uses
1398
+ the "accept" blocks from exims default configuration file:
1401
+ accept domains = +local_domains
1403
+ verify = recipient
1406
+ accept domains = +relay_to_domains
1408
+ verify = recipient
1411
+ If bmi_run is not set in any ACL during reception of the
1412
+ message, it will NOT be passed to the BMI server.
1415
+4) Setting up routers to use BMI verdicts
1417
+ When a message has been run through the BMI server, one or
1418
+ more "verdicts" are present. Different recipients can have
1419
+ different verdicts. Each recipient is treated individually
1420
+ during routing, so you can query the verdicts by recipient
1421
+ at that stage. From Exims view, a verdict can have the
1422
+ following outcomes:
1424
+ o deliver the message normally
1425
+ o deliver the message to an alternate location
1426
+ o do not deliver the message
1428
+ To query the verdict for a recipient, the implementation
1429
+ offers the following tools:
1432
+ - Boolean router preconditions. These can be used in any
1433
+ router. For a simple implementation of BMI, these may be
1434
+ all that you need. The following preconditions are
1437
+ o bmi_deliver_default
1439
+ This precondition is TRUE if the verdict for the
1440
+ recipient is to deliver the message normally. If the
1441
+ message has not been processed by the BMI server, this
1442
+ variable defaults to TRUE.
1444
+ o bmi_deliver_alternate
1446
+ This precondition is TRUE if the verdict for the
1447
+ recipient is to deliver the message to an alternate
1448
+ location. You can get the location string from the
1449
+ $bmi_alt_location expansion variable if you need it. See
1450
+ further below. If the message has not been processed by
1451
+ the BMI server, this variable defaults to FALSE.
1453
+ o bmi_dont_deliver
1455
+ This precondition is TRUE if the verdict for the
1456
+ recipient is NOT to deliver the message to the
1457
+ recipient. You will typically use this precondition in a
1458
+ top-level blackhole router, like this:
1460
+ # don't deliver messages handled by the BMI server
1464
+ data = :blackhole:
1466
+ This router should be on top of all others, so messages
1467
+ that should not be delivered do not reach other routers
1468
+ at all. If the message has not been processed by
1469
+ the BMI server, this variable defaults to FALSE.
1472
+ - A list router precondition to query if rules "fired" on
1473
+ the message for the recipient. Its name is "bmi_rule". You
1474
+ use it by passing it a colon-separated list of rule
1475
+ numbers. You can use this condition to route messages that
1476
+ matched specific rules. Here is an example:
1478
+ # special router for BMI rule #5, #8 and #11
1479
+ bmi_rule_redirect:
1482
+ data = postmaster@mydomain.com
1485
+ - Expansion variables. Several expansion variables are set
1486
+ during routing. You can use them in custom router
1487
+ conditions, for example. The following variables are
1490
+ o $bmi_base64_verdict
1492
+ This variable will contain the BASE64 encoded verdict
1493
+ for the recipient being routed. You can use it to add a
1494
+ header to messages for tracking purposes, for example:
1499
+ headers_add = X-Brightmail-Verdict: $bmi_base64_verdict
1500
+ transport = local_delivery
1502
+ If there is no verdict available for the recipient being
1503
+ routed, this variable contains the empty string.
1505
+ o $bmi_base64_tracker_verdict
1507
+ This variable will contain a BASE64 encoded subset of
1508
+ the verdict information concerning the "rules" that
1509
+ fired on the message. You can add this string to a
1510
+ header, commonly named "X-Brightmail-Tracker". Example:
1515
+ headers_add = X-Brightmail-Tracker: $bmi_base64_tracker_verdict
1516
+ transport = local_delivery
1518
+ If there is no verdict available for the recipient being
1519
+ routed, this variable contains the empty string.
1521
+ o $bmi_alt_location
1523
+ If the verdict is to redirect the message to an
1524
+ alternate location, this variable will contain the
1525
+ alternate location string returned by the BMI server. In
1526
+ its default configuration, this is a header-like string
1527
+ that can be added to the message with "headers_add". If
1528
+ there is no verdict available for the recipient being
1529
+ routed, or if the message is to be delivered normally,
1530
+ this variable contains the empty string.
1534
+ This is an additional integer variable that can be used
1535
+ to query if the message should be delivered at all. You
1536
+ should use router preconditions instead if possible.
1538
+ $bmi_deliver is '0': the message should NOT be delivered.
1539
+ $bmi_deliver is '1': the message should be delivered.
1542
+ IMPORTANT NOTE: Verdict inheritance.
1543
+ The message is passed to the BMI server during message
1544
+ reception, using the target addresses from the RCPT TO:
1545
+ commands in the SMTP transaction. If recipients get expanded
1546
+ or re-written (for example by aliasing), the new address(es)
1547
+ inherit the verdict from the original address. This means
1548
+ that verdicts also apply to all "child" addresses generated
1549
+ from top-level addresses that were sent to the BMI server.
1552
+5) Using per-recipient opt-in information (Optional)
1554
+ The BMI server features multiple scanning "profiles" for
1555
+ individual recipients. These are usually stored in a LDAP
1556
+ server and are queried by the BMI server itself. However,
1557
+ you can also pass opt-in data for each recipient from the
1558
+ MTA to the BMI server. This is particularly useful if you
1559
+ already look up recipient data in exim anyway (which can
1560
+ also be stored in a SQL database or other source). This
1561
+ implementation enables you to pass opt-in data to the BMI
1562
+ server in the RCPT ACL. This works by setting the
1563
+ 'bmi_optin' modifier in a block of that ACL. If should be
1564
+ set to a list of comma-separated strings that identify the
1565
+ features which the BMI server should use for that particular
1566
+ recipient. Ideally, you would use the 'bmi_optin' modifier
1567
+ in the same ACL block where you set the 'bmi_run' control
1568
+ flag. Here is an example that will pull opt-in data for each
1569
+ recipient from a flat file called
1570
+ '/etc/exim/bmi_optin_data'.
1574
+ user1@mydomain.com: <OPTIN STRING1>:<OPTIN STRING2>
1575
+ user2@thatdomain.com: <OPTIN STRING3>
1580
+ accept domains = +relay_to_domains
1582
+ verify = recipient
1583
+ bmi_optin = ${lookup{$local_part@$domain}lsearch{/etc/exim/bmi_optin_data}}
1586
+ Of course, you can also use any other lookup method that
1587
+ exim supports, including LDAP, Postgres, MySQL, Oracle etc.,
1588
+ as long as the result is a list of colon-separated opt-in
1591
+ For a list of available opt-in strings, please contact your
1592
+ Brightmail representative.
1594
+--------------------------------------------------------------
1596
+--------------------------------------------------------------
1597
diff -urN exim-4.34-orig/exim_monitor/em_globals.c exim-4.34/exim_monitor/em_globals.c
1598
--- exim-4.34-orig/exim_monitor/em_globals.c Mon May 10 14:31:20 2004
1599
+++ exim-4.34/exim_monitor/em_globals.c Mon May 10 16:14:47 2004
1601
uschar *action_required;
1602
uschar *alternate_config = NULL;
1606
+uschar *bmi_verdicts = NULL;
1608
int body_max = 20000;
1610
uschar *exim_path = US BIN_DIRECTORY "/exim"
1612
BOOL deliver_manual_thaw = FALSE;
1613
BOOL dont_deliver = FALSE;
1615
+BOOL fake_reject = FALSE;
1617
header_line *header_last = NULL;
1618
header_line *header_list = NULL;
1622
BOOL local_error_message = FALSE;
1623
uschar *local_scan_data = NULL;
1624
+uschar *spam_score_int = NULL;
1625
BOOL log_timezone = FALSE;
1626
int message_age = 0;
1628
diff -urN exim-4.34-orig/scripts/MakeLinks exim-4.34/scripts/MakeLinks
1629
--- exim-4.34-orig/scripts/MakeLinks Mon May 10 14:31:20 2004
1630
+++ exim-4.34/scripts/MakeLinks Mon May 10 16:14:47 2004
1631
@@ -170,19 +170,25 @@
1632
# but local_scan.c does not, because its location is taken from the build-time
1633
# configuration. Likewise for the os.c file, which gets build dynamically.
1635
+ln -s ../src/bmi_spam.h bmi_spam.h
1636
ln -s ../src/dbfunctions.h dbfunctions.h
1637
ln -s ../src/dbstuff.h dbstuff.h
1638
+ln -s ../src/demime.h demime.h
1639
ln -s ../src/exim.h exim.h
1640
ln -s ../src/functions.h functions.h
1641
ln -s ../src/globals.h globals.h
1642
ln -s ../src/local_scan.h local_scan.h
1643
ln -s ../src/macros.h macros.h
1644
+ln -s ../src/mime.h mime.h
1645
ln -s ../src/mytypes.h mytypes.h
1646
ln -s ../src/osfunctions.h osfunctions.h
1647
+ln -s ../src/spam.h spam.h
1648
ln -s ../src/store.h store.h
1649
ln -s ../src/structs.h structs.h
1650
+ln -s ../src/tnef.h tnef.h
1652
ln -s ../src/acl.c acl.c
1653
+ln -s ../src/bmi_spam.c bmi_spam.c
1654
ln -s ../src/buildconfig.c buildconfig.c
1655
ln -s ../src/child.c child.c
1656
ln -s ../src/crypt16.c crypt16.c
1658
ln -s ../src/dbfn.c dbfn.c
1659
ln -s ../src/debug.c debug.c
1660
ln -s ../src/deliver.c deliver.c
1661
+ln -s ../src/demime.c demime.c
1662
ln -s ../src/directory.c directory.c
1663
ln -s ../src/dns.c dns.c
1664
ln -s ../src/drtables.c drtables.c
1666
ln -s ../src/ip.c ip.c
1667
ln -s ../src/log.c log.c
1668
ln -s ../src/lss.c lss.c
1669
+ln -s ../src/malware.c malware.c
1670
ln -s ../src/match.c match.c
1671
+ln -s ../src/mime.c mime.c
1672
ln -s ../src/moan.c moan.c
1673
ln -s ../src/parse.c parse.c
1674
ln -s ../src/perl.c perl.c
1676
ln -s ../src/rda.c rda.c
1677
ln -s ../src/readconf.c readconf.c
1678
ln -s ../src/receive.c receive.c
1679
+ln -s ../src/regex.c regex.c
1680
ln -s ../src/retry.c retry.c
1681
ln -s ../src/rewrite.c rewrite.c
1682
ln -s ../src/rfc2047.c rfc2047.c
1683
@@ -224,13 +234,16 @@
1684
ln -s ../src/sieve.c sieve.c
1685
ln -s ../src/smtp_in.c smtp_in.c
1686
ln -s ../src/smtp_out.c smtp_out.c
1687
+ln -s ../src/spam.c spam.c
1688
ln -s ../src/spool_in.c spool_in.c
1689
+ln -s ../src/spool_mbox.c spool_mbox.c
1690
ln -s ../src/spool_out.c spool_out.c
1691
ln -s ../src/store.c store.c
1692
ln -s ../src/string.c string.c
1693
ln -s ../src/tls.c tls.c
1694
ln -s ../src/tls-gnu.c tls-gnu.c
1695
ln -s ../src/tls-openssl.c tls-openssl.c
1696
+ln -s ../src/tnef.c tnef.c
1697
ln -s ../src/tod.c tod.c
1698
ln -s ../src/transport.c transport.c
1699
ln -s ../src/tree.c tree.c
1700
diff -urN exim-4.34-orig/src/acl.c exim-4.34/src/acl.c
1701
--- exim-4.34-orig/src/acl.c Mon May 10 14:31:20 2004
1702
+++ exim-4.34/src/acl.c Mon May 10 16:14:47 2004
1705
/* Code for handling Access Control Lists (ACLs) */
1707
+/* This file has been modified by the exiscan-acl patch. */
1712
+#include "bmi_spam.h"
1715
/* Default callout timeout */
1718
/* ACL condition and modifier codes - keep in step with the table that
1721
-enum { ACLC_ACL, ACLC_AUTHENTICATED, ACLC_CONDITION, ACLC_CONTROL, ACLC_DELAY,
1722
+enum { ACLC_ACL, ACLC_AUTHENTICATED,
1726
+ ACLC_CONDITION, ACLC_CONTROL, ACLC_DECODE, ACLC_DELAY, ACLC_DEMIME,
1727
ACLC_DNSLISTS, ACLC_DOMAINS, ACLC_ENCRYPTED, ACLC_ENDPASS, ACLC_HOSTS,
1728
- ACLC_LOCAL_PARTS, ACLC_LOG_MESSAGE, ACLC_LOGWRITE, ACLC_MESSAGE,
1729
- ACLC_RECIPIENTS, ACLC_SENDER_DOMAINS, ACLC_SENDERS, ACLC_SET, ACLC_VERIFY };
1730
+ ACLC_LOCAL_PARTS, ACLC_LOG_MESSAGE, ACLC_LOGWRITE, ACLC_MALWARE, ACLC_MESSAGE, ACLC_MIME_REGEX,
1731
+ ACLC_RECIPIENTS, ACLC_REGEX, ACLC_SENDER_DOMAINS, ACLC_SENDERS, ACLC_SET, ACLC_SPAM, ACLC_VERIFY };
1733
/* ACL conditions/modifiers: "delay", "control", "endpass", "message",
1734
"log_message", "logwrite", and "set" are modifiers that look like conditions
1735
but always return TRUE. They are used for their side effects. */
1737
-static uschar *conditions[] = { US"acl", US"authenticated", US"condition",
1738
- US"control", US"delay", US"dnslists", US"domains", US"encrypted",
1739
- US"endpass", US"hosts", US"local_parts", US"log_message", US"logwrite",
1740
- US"message", US"recipients", US"sender_domains", US"senders", US"set",
1741
+static uschar *conditions[] = { US"acl", US"authenticated",
1745
+ US"condition", US"control", US"decode", US"delay", US"demime", US"dnslists", US"domains", US"encrypted",
1746
+ US"endpass", US"hosts", US"local_parts", US"log_message", US"logwrite", US"malware",
1747
+ US"message", US"mime_regex", US"recipients", US"regex", US"sender_domains", US"senders", US"set", US"spam",
1750
/* Flags to indicate for which conditions /modifiers a string expansion is done
1752
static uschar cond_expand_at_top[] = {
1754
FALSE, /* authenticated */
1756
+ TRUE, /* bmi_optin */
1758
TRUE, /* condition */
1760
+ TRUE, /* decode */
1762
+ TRUE, /* demime */
1763
TRUE, /* dnslists */
1764
FALSE, /* domains */
1765
FALSE, /* encrypted */
1767
FALSE, /* local_parts */
1768
TRUE, /* log_message */
1769
TRUE, /* logwrite */
1770
+ TRUE, /* malware */
1772
+ TRUE, /* mime_regex */
1773
FALSE, /* recipients */
1775
FALSE, /* sender_domains */
1776
FALSE, /* senders */
1783
static uschar cond_modifiers[] = {
1785
FALSE, /* authenticated */
1787
+ TRUE, /* bmi_optin */
1789
FALSE, /* condition */
1791
+ FALSE, /* decode */
1793
+ FALSE, /* demime */
1794
FALSE, /* dnslists */
1795
FALSE, /* domains */
1796
FALSE, /* encrypted */
1797
@@ -89,11 +115,15 @@
1798
FALSE, /* local_parts */
1799
TRUE, /* log_message */
1800
TRUE, /* log_write */
1801
+ FALSE, /* malware */
1803
+ FALSE, /* mime_regex */
1804
FALSE, /* recipients */
1805
+ FALSE, /* regex */
1806
FALSE, /* sender_domains */
1807
FALSE, /* senders */
1813
@@ -102,8 +132,20 @@
1815
static unsigned int cond_forbids[] = {
1818
(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_CONNECT)| /* authenticated */
1819
(1<<ACL_WHERE_HELO),
1822
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* bmi_optin */
1823
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1824
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
1825
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1826
+ (1<<ACL_WHERE_MAILAUTH)|
1827
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1828
+ (1<<ACL_WHERE_VRFY),
1833
(1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)| /* control */
1834
@@ -112,12 +154,29 @@
1835
(1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1836
(1<<ACL_WHERE_STARTTLS)|(ACL_WHERE_VRFY),
1838
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* decode */
1839
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1840
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_RCPT)|
1841
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1842
+ (1<<ACL_WHERE_MAILAUTH)|
1843
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1844
+ (1<<ACL_WHERE_VRFY),
1848
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* demime */
1849
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1850
+ (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_RCPT)|
1851
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1852
+ (1<<ACL_WHERE_MAILAUTH)|
1853
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1854
+ (1<<ACL_WHERE_VRFY),
1856
(1<<ACL_WHERE_NOTSMTP), /* dnslists */
1858
(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* domains */
1859
(1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1860
- (1<<ACL_WHERE_DATA)|
1861
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
1862
(1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1863
(1<<ACL_WHERE_MAILAUTH)|
1864
(1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1865
@@ -125,29 +184,56 @@
1867
(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_CONNECT)| /* encrypted */
1868
(1<<ACL_WHERE_HELO),
1872
(1<<ACL_WHERE_NOTSMTP), /* hosts */
1874
(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* local_parts */
1875
(1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1876
- (1<<ACL_WHERE_DATA)|
1877
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
1878
(1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1879
(1<<ACL_WHERE_MAILAUTH)|
1880
(1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1881
(1<<ACL_WHERE_VRFY),
1883
0, /* log_message */
1887
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* malware */
1888
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1889
+ (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_RCPT)|
1890
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1891
+ (1<<ACL_WHERE_MAILAUTH)|
1892
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1893
+ (1<<ACL_WHERE_VRFY),
1897
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* mime_regex */
1898
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1899
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_RCPT)|
1900
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1901
+ (1<<ACL_WHERE_MAILAUTH)|
1902
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1903
+ (1<<ACL_WHERE_VRFY),
1905
(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* recipients */
1906
(1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1907
- (1<<ACL_WHERE_DATA)|
1908
+ (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
1909
(1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1910
(1<<ACL_WHERE_MAILAUTH)|
1911
(1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1912
(1<<ACL_WHERE_VRFY),
1914
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* regex */
1915
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1916
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1917
+ (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_RCPT)|
1918
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1919
+ (1<<ACL_WHERE_VRFY),
1921
(1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)| /* sender_domains */
1922
(1<<ACL_WHERE_HELO)|
1923
(1<<ACL_WHERE_MAILAUTH)|
1924
@@ -162,6 +248,14 @@
1928
+ (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_AUTH)| /* spam */
1929
+ (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
1930
+ (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_RCPT)|
1931
+ (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
1932
+ (1<<ACL_WHERE_MAILAUTH)|
1933
+ (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
1934
+ (1<<ACL_WHERE_VRFY),
1936
/* Certain types of verify are always allowed, so we let it through
1937
always and check in the verify function itself */
1940
/* If this isn't a message ACL, we can't do anything with a user message.
1943
-if (where != ACL_WHERE_MAIL && where != ACL_WHERE_RCPT &&
1944
+if (where != ACL_WHERE_MAIL && where != ACL_WHERE_MIME && where != ACL_WHERE_RCPT &&
1945
where != ACL_WHERE_DATA && where != ACL_WHERE_NOTSMTP)
1947
log_write(0, LOG_MAIN|LOG_PANIC, "ACL \"warn\" with \"message\" setting "
1948
@@ -1005,6 +1099,7 @@
1949
uschar *user_message = NULL;
1950
uschar *log_message = NULL;
1954
for (; cb != NULL; cb = cb->next)
1956
@@ -1136,6 +1231,20 @@
1957
deliver_freeze = TRUE;
1958
deliver_frozen_at = time(NULL);
1960
+ else if (Ustrcmp(arg, "fakereject") == 0)
1962
+ fake_reject = TRUE;
1965
+ else if (Ustrcmp(arg, "bmi_run") == 0)
1970
+ else if (Ustrcmp(arg, "no_mbox_unspool") == 0)
1972
+ no_mbox_unspool = TRUE;
1974
else if (Ustrcmp(arg, "queue_only") == 0)
1976
queue_only_policy = TRUE;
1977
@@ -1167,7 +1276,70 @@
1981
- rc = verify_check_dnsbl(&arg);
1982
+ rc = verify_check_dnsbl(&arg);
1986
+ case ACLC_BMI_OPTIN:
1988
+ int old_pool = store_pool;
1989
+ store_pool = POOL_PERM;
1990
+ bmi_current_optin = string_copy(arg);
1991
+ store_pool = old_pool;
1997
+ rc = mime_decode(&arg);
2000
+ case ACLC_MIME_REGEX:
2001
+ rc = mime_regex(&arg);
2005
+ rc = demime(&arg);
2008
+ case ACLC_MALWARE:
2010
+ /* Seperate the regular expression and any optional parameters. */
2011
+ uschar *ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size);
2012
+ /* Run the malware backend. */
2013
+ rc = malware(&ss);
2014
+ /* Modify return code based upon the existance of options. */
2015
+ while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size))
2017
+ if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
2019
+ /* FAIL so that the message is passed to the next ACL */
2028
+ /* Seperate the regular expression and any optional parameters. */
2029
+ uschar *ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size);
2030
+ /* Run the spam backend. */
2032
+ /* Modify return code based upon the existance of options. */
2033
+ while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size))
2035
+ if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
2037
+ /* FAIL so that the message is passed to the next ACL */
2049
@@ -1836,6 +2008,7 @@
2050
if (where != ACL_WHERE_MAIL &&
2051
where != ACL_WHERE_RCPT &&
2052
where != ACL_WHERE_DATA &&
2053
+ where != ACL_WHERE_MIME &&
2054
where != ACL_WHERE_NOTSMTP)
2056
log_write(0, LOG_MAIN|LOG_PANIC, "\"discard\" verb not allowed in %s "
2057
diff -urN exim-4.34-orig/src/bmi_spam.c exim-4.34/src/bmi_spam.c
2058
--- exim-4.34-orig/src/bmi_spam.c Thu Jan 1 01:00:00 1970
2059
+++ exim-4.34/src/bmi_spam.c Mon May 10 16:14:47 2004
2061
+/*************************************************
2062
+* Exim - an Internet mail transport agent *
2063
+*************************************************/
2065
+/* This file is part of the exiscan-acl content scanner
2066
+ patch. It is NOT part of the standard exim distribution. */
2068
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
2071
+/* Code for calling Brightmail AntiSpam. */
2074
+#include "bmi_spam.h"
2078
+uschar *bmi_current_optin = NULL;
2080
+uschar *bmi_process_message(header_line *header_list, int data_fd) {
2081
+ BmiSystem *system = NULL;
2082
+ BmiMessage *message = NULL;
2084
+ BmiErrorLocation err_loc;
2085
+ BmiErrorType err_type;
2086
+ const BmiVerdict *verdict = NULL;
2088
+ uschar data_buffer[4096];
2089
+ uschar localhost[] = "127.0.0.1";
2090
+ uschar *host_address;
2091
+ uschar *verdicts = NULL;
2094
+ err = bmiInitSystem(BMI_VERSION, (char *)bmi_config_file, &system);
2095
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2096
+ err_loc = bmiErrorGetLocation(err);
2097
+ err_type = bmiErrorGetType(err);
2098
+ log_write(0, LOG_PANIC,
2099
+ "bmi error [loc %d type %d]: could not initialize Brightmail system.", (int)err_loc, (int)err_type);
2103
+ err = bmiInitMessage(system, &message);
2104
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2105
+ err_loc = bmiErrorGetLocation(err);
2106
+ err_type = bmiErrorGetType(err);
2107
+ log_write(0, LOG_PANIC,
2108
+ "bmi error [loc %d type %d]: could not initialize Brightmail message.", (int)err_loc, (int)err_type);
2109
+ bmiFreeSystem(system);
2113
+ /* Send IP address of sending host */
2114
+ if (sender_host_address == NULL)
2115
+ host_address = localhost;
2117
+ host_address = sender_host_address;
2118
+ err = bmiProcessConnection((char *)host_address, message);
2119
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2120
+ err_loc = bmiErrorGetLocation(err);
2121
+ err_type = bmiErrorGetType(err);
2122
+ log_write(0, LOG_PANIC,
2123
+ "bmi error [loc %d type %d]: bmiProcessConnection() failed (IP %s).", (int)err_loc, (int)err_type, (char *)host_address);
2124
+ bmiFreeMessage(message);
2125
+ bmiFreeSystem(system);
2129
+ /* Send envelope sender address */
2130
+ err = bmiProcessFROM((char *)sender_address, message);
2131
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2132
+ err_loc = bmiErrorGetLocation(err);
2133
+ err_type = bmiErrorGetType(err);
2134
+ log_write(0, LOG_PANIC,
2135
+ "bmi error [loc %d type %d]: bmiProcessFROM() failed (address %s).", (int)err_loc, (int)err_type, (char *)sender_address);
2136
+ bmiFreeMessage(message);
2137
+ bmiFreeSystem(system);
2141
+ /* Send envelope recipients */
2142
+ for(i=0;i<recipients_count;i++) {
2143
+ recipient_item *r = recipients_list + i;
2144
+ BmiOptin *optin = NULL;
2146
+ /* create optin object if optin string is given */
2147
+ if ((r->bmi_optin != NULL) && (Ustrlen(r->bmi_optin) > 1)) {
2148
+ debug_printf("passing bmiOptin string: %s\n", r->bmi_optin);
2149
+ bmiOptinInit(&optin);
2150
+ err = bmiOptinMset(optin, r->bmi_optin, ':');
2151
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2152
+ log_write(0, LOG_PANIC|LOG_MAIN,
2153
+ "bmi warning: [loc %d type %d]: bmiOptinMSet() failed (address '%s', string '%s').", (int)err_loc, (int)err_type, (char *)r->address, (char *)r->bmi_optin);
2154
+ if (optin != NULL)
2155
+ bmiOptinFree(optin);
2160
+ err = bmiAccumulateTO((char *)r->address, optin, message);
2162
+ if (optin != NULL)
2163
+ bmiOptinFree(optin);
2165
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2166
+ err_loc = bmiErrorGetLocation(err);
2167
+ err_type = bmiErrorGetType(err);
2168
+ log_write(0, LOG_PANIC,
2169
+ "bmi error [loc %d type %d]: bmiAccumulateTO() failed (address %s).", (int)err_loc, (int)err_type, (char *)r->address);
2170
+ bmiFreeMessage(message);
2171
+ bmiFreeSystem(system);
2175
+ err = bmiEndTO(message);
2176
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2177
+ err_loc = bmiErrorGetLocation(err);
2178
+ err_type = bmiErrorGetType(err);
2179
+ log_write(0, LOG_PANIC,
2180
+ "bmi error [loc %d type %d]: bmiEndTO() failed.", (int)err_loc, (int)err_type);
2181
+ bmiFreeMessage(message);
2182
+ bmiFreeSystem(system);
2186
+ /* Send message headers */
2187
+ while (header_list != NULL) {
2188
+ /* skip deleted headers */
2189
+ if (header_list->type == '*') {
2190
+ header_list = header_list->next;
2193
+ err = bmiAccumulateHeaders((const char *)header_list->text, header_list->slen, message);
2194
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2195
+ err_loc = bmiErrorGetLocation(err);
2196
+ err_type = bmiErrorGetType(err);
2197
+ log_write(0, LOG_PANIC,
2198
+ "bmi error [loc %d type %d]: bmiAccumulateHeaders() failed.", (int)err_loc, (int)err_type);
2199
+ bmiFreeMessage(message);
2200
+ bmiFreeSystem(system);
2203
+ header_list = header_list->next;
2205
+ err = bmiEndHeaders(message);
2206
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2207
+ err_loc = bmiErrorGetLocation(err);
2208
+ err_type = bmiErrorGetType(err);
2209
+ log_write(0, LOG_PANIC,
2210
+ "bmi error [loc %d type %d]: bmiEndHeaders() failed.", (int)err_loc, (int)err_type);
2211
+ bmiFreeMessage(message);
2212
+ bmiFreeSystem(system);
2217
+ data_file = fdopen(data_fd,"r");
2219
+ j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
2221
+ err = bmiAccumulateBody((const char *)data_buffer, j, message);
2222
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2223
+ err_loc = bmiErrorGetLocation(err);
2224
+ err_type = bmiErrorGetType(err);
2225
+ log_write(0, LOG_PANIC,
2226
+ "bmi error [loc %d type %d]: bmiAccumulateBody() failed.", (int)err_loc, (int)err_type);
2227
+ bmiFreeMessage(message);
2228
+ bmiFreeSystem(system);
2233
+ err = bmiEndBody(message);
2234
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2235
+ err_loc = bmiErrorGetLocation(err);
2236
+ err_type = bmiErrorGetType(err);
2237
+ log_write(0, LOG_PANIC,
2238
+ "bmi error [loc %d type %d]: bmiEndBody() failed.", (int)err_loc, (int)err_type);
2239
+ bmiFreeMessage(message);
2240
+ bmiFreeSystem(system);
2246
+ err = bmiEndMessage(message);
2247
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2248
+ err_loc = bmiErrorGetLocation(err);
2249
+ err_type = bmiErrorGetType(err);
2250
+ log_write(0, LOG_PANIC,
2251
+ "bmi error [loc %d type %d]: bmiEndMessage() failed.", (int)err_loc, (int)err_type);
2252
+ bmiFreeMessage(message);
2253
+ bmiFreeSystem(system);
2257
+ /* get store for the verdict string */
2258
+ verdicts = store_get(1);
2261
+ for ( err = bmiAccessFirstVerdict(message, &verdict);
2263
+ err = bmiAccessNextVerdict(message, verdict, &verdict) ) {
2264
+ char *verdict_str;
2266
+ err = bmiCreateStrFromVerdict(verdict,&verdict_str);
2267
+ if (!store_extend(verdicts, Ustrlen(verdicts)+1, Ustrlen(verdicts)+1+strlen(verdict_str)+1)) {
2268
+ /* can't allocate more store */
2271
+ if (*verdicts != '\0')
2272
+ Ustrcat(verdicts, US ":");
2273
+ Ustrcat(verdicts, US verdict_str);
2274
+ bmiFreeStr(verdict_str);
2277
+ DEBUG(D_receive) debug_printf("bmi verdicts: %s\n", verdicts);
2279
+ if (Ustrlen(verdicts) == 0)
2286
+int bmi_get_delivery_status(uschar *base64_verdict) {
2288
+ BmiErrorLocation err_loc;
2289
+ BmiErrorType err_type;
2290
+ BmiVerdict *verdict = NULL;
2291
+ int rc = 1; /* deliver by default */
2293
+ /* always deliver when there is no verdict */
2294
+ if (base64_verdict == NULL)
2297
+ /* create verdict from base64 string */
2298
+ err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
2299
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2300
+ err_loc = bmiErrorGetLocation(err);
2301
+ err_type = bmiErrorGetType(err);
2302
+ log_write(0, LOG_PANIC,
2303
+ "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
2307
+ err = bmiVerdictError(verdict);
2308
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2309
+ /* deliver normally due to error */
2312
+ else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
2313
+ /* deliver normally */
2316
+ else if (bmiVerdictAccessDestination(verdict) == NULL) {
2317
+ /* do not deliver */
2321
+ /* deliver to alternate location */
2325
+ bmiFreeVerdict(verdict);
2330
+uschar *bmi_get_alt_location(uschar *base64_verdict) {
2332
+ BmiErrorLocation err_loc;
2333
+ BmiErrorType err_type;
2334
+ BmiVerdict *verdict = NULL;
2335
+ uschar *rc = NULL;
2337
+ /* always deliver when there is no verdict */
2338
+ if (base64_verdict == NULL)
2341
+ /* create verdict from base64 string */
2342
+ err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
2343
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2344
+ err_loc = bmiErrorGetLocation(err);
2345
+ err_type = bmiErrorGetType(err);
2346
+ log_write(0, LOG_PANIC,
2347
+ "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
2351
+ err = bmiVerdictError(verdict);
2352
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2353
+ /* deliver normally due to error */
2356
+ else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
2357
+ /* deliver normally */
2360
+ else if (bmiVerdictAccessDestination(verdict) == NULL) {
2361
+ /* do not deliver */
2365
+ /* deliver to alternate location */
2366
+ rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1);
2367
+ Ustrcpy(rc, bmiVerdictAccessDestination(verdict));
2368
+ rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0';
2371
+ bmiFreeVerdict(verdict);
2375
+uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
2377
+ BmiErrorLocation err_loc;
2378
+ BmiErrorType err_type;
2379
+ BmiVerdict *verdict = NULL;
2380
+ const BmiRecipient *recipient = NULL;
2381
+ const char *verdict_str = NULL;
2382
+ uschar *verdict_ptr;
2383
+ uschar *verdict_buffer = NULL;
2386
+ /* return nothing if there are no verdicts available */
2387
+ if (bmi_verdicts == NULL)
2390
+ /* allocate room for the b64 verdict string */
2391
+ verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1);
2393
+ /* loop through verdicts */
2394
+ verdict_ptr = bmi_verdicts;
2395
+ while ((verdict_str = (const char *)string_nextinlist(&verdict_ptr, &sep,
2397
+ Ustrlen(bmi_verdicts)+1)) != NULL) {
2399
+ /* create verdict from base64 string */
2400
+ err = bmiCreateVerdictFromStr(verdict_str, &verdict);
2401
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2402
+ err_loc = bmiErrorGetLocation(err);
2403
+ err_type = bmiErrorGetType(err);
2404
+ log_write(0, LOG_PANIC,
2405
+ "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, verdict_str);
2409
+ /* loop through rcpts for this verdict */
2410
+ for ( recipient = bmiVerdictAccessFirstRecipient(verdict);
2411
+ recipient != NULL;
2412
+ recipient = bmiVerdictAccessNextRecipient(verdict, recipient)) {
2413
+ uschar *rcpt_local_part;
2414
+ uschar *rcpt_domain;
2416
+ /* compare address against our subject */
2417
+ rcpt_local_part = (unsigned char *)bmiRecipientAccessAddress(recipient);
2418
+ rcpt_domain = Ustrchr(rcpt_local_part,'@');
2419
+ if (rcpt_domain == NULL) {
2420
+ rcpt_domain = US"";
2423
+ *rcpt_domain = '\0';
2427
+ if ( (strcmpic(rcpt_local_part, bmi_local_part) == 0) &&
2428
+ (strcmpic(rcpt_domain, bmi_domain) == 0) ) {
2429
+ /* found verdict */
2430
+ bmiFreeVerdict(verdict);
2431
+ return (uschar *)verdict_str;
2435
+ bmiFreeVerdict(verdict);
2442
+uschar *bmi_get_base64_tracker_verdict(uschar *base64_verdict) {
2444
+ BmiErrorLocation err_loc;
2445
+ BmiErrorType err_type;
2446
+ BmiVerdict *verdict = NULL;
2447
+ uschar *rc = NULL;
2449
+ /* always deliver when there is no verdict */
2450
+ if (base64_verdict == NULL)
2453
+ /* create verdict from base64 string */
2454
+ err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
2455
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2456
+ err_loc = bmiErrorGetLocation(err);
2457
+ err_type = bmiErrorGetType(err);
2458
+ log_write(0, LOG_PANIC,
2459
+ "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
2463
+ /* create old tracker string from verdict */
2464
+ err = bmiCreateOldStrFromVerdict(verdict, &rc);
2465
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2466
+ err_loc = bmiErrorGetLocation(err);
2467
+ err_type = bmiErrorGetType(err);
2468
+ log_write(0, LOG_PANIC,
2469
+ "bmi error [loc %d type %d]: bmiCreateOldStrFromVerdict() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
2473
+ bmiFreeVerdict(verdict);
2478
+int bmi_check_rule(uschar *base64_verdict, uschar *option_list) {
2480
+ BmiErrorLocation err_loc;
2481
+ BmiErrorType err_type;
2482
+ BmiVerdict *verdict = NULL;
2486
+ uschar rule_buffer[32];
2490
+ /* no verdict -> no rule fired */
2491
+ if (base64_verdict == NULL)
2494
+ /* create verdict from base64 string */
2495
+ err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict);
2496
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2497
+ err_loc = bmiErrorGetLocation(err);
2498
+ err_type = bmiErrorGetType(err);
2499
+ log_write(0, LOG_PANIC,
2500
+ "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict);
2504
+ err = bmiVerdictError(verdict);
2505
+ if (bmiErrorIsFatal(err) == BMI_TRUE) {
2506
+ /* error -> no rule fired */
2507
+ bmiFreeVerdict(verdict);
2511
+ /* loop through numbers */
2512
+ rule_ptr = option_list;
2513
+ while ((rule_num = string_nextinlist(&rule_ptr, &sep,
2514
+ rule_buffer, 32)) != NULL) {
2515
+ int rule_int = -1;
2517
+ /* try to translate to int */
2518
+ sscanf(rule_num, "%d", &rule_int);
2519
+ if (rule_int > 0) {
2520
+ debug_printf("checking rule #%d\n", rule_int);
2521
+ /* check if rule fired on the message */
2522
+ if (bmiVerdictRuleFired(verdict, rule_int) == BMI_TRUE) {
2523
+ debug_printf("rule #%d fired\n", rule_int);
2530
+ bmiFreeVerdict(verdict);
2535
diff -urN exim-4.34-orig/src/bmi_spam.h exim-4.34/src/bmi_spam.h
2536
--- exim-4.34-orig/src/bmi_spam.h Thu Jan 1 01:00:00 1970
2537
+++ exim-4.34/src/bmi_spam.h Mon May 10 16:14:47 2004
2539
+/*************************************************
2540
+* Exim - an Internet mail transport agent *
2541
+*************************************************/
2543
+/* This file is part of the exiscan-acl content scanner
2544
+ patch. It is NOT part of the standard exim distribution. */
2546
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
2549
+/* Code for calling Brightmail AntiSpam. */
2553
+#include <bmi_api.h>
2555
+extern uschar *bmi_process_message(header_line *, int);
2556
+extern uschar *bmi_get_base64_verdict(uschar *, uschar *);
2557
+extern uschar *bmi_get_base64_tracker_verdict(uschar *);
2558
+extern int bmi_get_delivery_status(uschar *);
2559
+extern uschar *bmi_get_alt_location(uschar *);
2560
+extern int bmi_check_rule(uschar *,uschar *);
2562
+extern uschar *bmi_current_optin;
2565
diff -urN exim-4.34-orig/src/config.h.defaults exim-4.34/src/config.h.defaults
2566
--- exim-4.34-orig/src/config.h.defaults Mon May 10 14:31:20 2004
2567
+++ exim-4.34/src/config.h.defaults Mon May 10 16:14:47 2004
2569
#define SPOOL_DIRECTORY
2570
#define SPOOL_DIRECTORY_MODE 0750
2571
#define SPOOL_MODE 0640
2572
-#define STRING_SPRINTF_BUFFER_SIZE 8192
2573
+#define STRING_SPRINTF_BUFFER_SIZE (8192 * 4)
2576
#define SUPPORT_CRYPTEQ
2577
diff -urN exim-4.34-orig/src/configure.default exim-4.34/src/configure.default
2578
--- exim-4.34-orig/src/configure.default Mon May 10 14:31:20 2004
2579
+++ exim-4.34/src/configure.default Mon May 10 16:14:47 2004
2580
@@ -108,6 +108,26 @@
2582
# You should not change that setting until you understand how ACLs work.
2584
+# The following ACL entries are used if you want to do content scanning with
2585
+# the exiscan-acl patch. When you uncomment one of these lines, you must also
2586
+# review the respective entries in the ACL section further below.
2588
+# acl_smtp_mime = acl_check_mime
2589
+# acl_smtp_data = acl_check_content
2591
+# This configuration variable defines the virus scanner that is used with
2592
+# the 'malware' ACL condition of the exiscan acl-patch. If you do not use
2593
+# virus scanning, leave it commented. Please read doc/exiscan-acl-readme.txt
2594
+# for a list of supported scanners.
2596
+# av_scanner = sophie:/var/run/sophie
2598
+# The following setting is only needed if you use the 'spam' ACL condition
2599
+# of the exiscan-acl patch. It specifies on which host and port the SpamAssassin
2600
+# "spamd" daemon is listening. If you do not use this condition, or you use
2601
+# the default of "127.0.0.1 783", you can omit this option.
2603
+# spamd_address = 127.0.0.1 783
2605
# Specify the domain you want to be added to all unqualified addresses
2606
# here. An unqualified address is one that does not contain an "@" character
2607
@@ -342,6 +362,56 @@
2608
deny message = relay not permitted
2611
+# These access control lists are used for content scanning with the exiscan-acl
2612
+# patch. You must also uncomment the entries for acl_smtp_data and acl_smtp_mime
2613
+# (scroll up), otherwise the ACLs will not be used. IMPORTANT: the default entries here
2614
+# should be treated as EXAMPLES. You MUST read the file doc/exiscan-acl-spec.txt
2615
+# to fully understand what you are doing ...
2619
+ # Decode MIME parts to disk. This will support virus scanners later.
2620
+ warn decode = default
2622
+ # File extension filtering.
2623
+ deny message = Blacklisted file extension detected
2624
+ condition = ${if match \
2625
+ {${lc:$mime_filename}} \
2626
+ {\N(\.exe|\.pif|\.bat|\.scr|\.lnk|\.com)$\N} \
2629
+ # Reject messages that carry chinese character sets.
2630
+ # WARNING: This is an EXAMPLE.
2631
+ deny message = Sorry, noone speaks chinese here
2632
+ condition = ${if eq{$mime_charset}{gb2312}{1}{0}}
2638
+ # Reject virus infested messages.
2639
+ deny message = This message contains malware ($malware_name)
2642
+ # Always add X-Spam-Score and X-Spam-Report headers, using SA system-wide settings
2643
+ # (user "nobody"), no matter if over threshold or not.
2644
+ warn message = X-Spam-Score: $spam_score ($spam_bar)
2645
+ spam = nobody:true
2646
+ warn message = X-Spam-Report: $spam_report
2647
+ spam = nobody:true
2649
+ # Add X-Spam-Flag if spam is over system-wide threshold
2650
+ warn message = X-Spam-Flag: YES
2653
+ # Reject spam messages with score over 10, using an extra condition.
2654
+ deny message = This message scored $spam_score points. Congratulations!
2655
+ spam = nobody:true
2656
+ condition = ${if >{$spam_score_int}{100}{1}{0}}
2658
+ # finally accept all the rest
2662
######################################################################
2663
# ROUTERS CONFIGURATION #
2664
diff -urN exim-4.34-orig/src/deliver.c exim-4.34/src/deliver.c
2665
--- exim-4.34-orig/src/deliver.c Mon May 10 14:31:20 2004
2666
+++ exim-4.34/src/deliver.c Mon May 10 16:14:47 2004
2672
+#include "bmi_spam.h"
2675
/* Data block for keeping track of subprocesses for parallel remote
2677
@@ -152,6 +155,13 @@
2678
deliver_domain = addr->domain;
2679
self_hostname = addr->self_hostname;
2682
+bmi_deliver = 1; /* deliver by default */
2683
+bmi_alt_location = NULL;
2684
+bmi_base64_verdict = NULL;
2685
+bmi_base64_tracker_verdict = NULL;
2688
/* If there's only one address we can set everything. */
2690
if (addr->next == NULL)
2691
@@ -201,6 +211,19 @@
2692
deliver_localpart_suffix = addr->parent->suffix;
2697
+ /* Set expansion variables related to Brightmail AntiSpam */
2698
+ bmi_base64_verdict = bmi_get_base64_verdict(deliver_localpart_orig, deliver_domain_orig);
2699
+ bmi_base64_tracker_verdict = bmi_get_base64_tracker_verdict(bmi_base64_verdict);
2700
+ /* get message delivery status (0 - don't deliver | 1 - deliver) */
2701
+ bmi_deliver = bmi_get_delivery_status(bmi_base64_verdict);
2702
+ /* if message is to be delivered, get eventual alternate location */
2703
+ if (bmi_deliver == 1) {
2704
+ bmi_alt_location = bmi_get_alt_location(bmi_base64_verdict);
2710
/* For multiple addresses, don't set local part, and leave the domain and
2711
diff -urN exim-4.34-orig/src/demime.c exim-4.34/src/demime.c
2712
--- exim-4.34-orig/src/demime.c Thu Jan 1 01:00:00 1970
2713
+++ exim-4.34/src/demime.c Mon May 10 16:14:47 2004
2715
+/*************************************************
2716
+* Exim - an Internet mail transport agent *
2717
+*************************************************/
2719
+/* This file is part of the exiscan-acl content scanner
2720
+patch. It is NOT part of the standard exim distribution. */
2722
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
2725
+/* Code for unpacking MIME containers. Called from acl.c. */
2728
+#include "demime.h"
2730
+uschar demime_reason_buffer[1024];
2731
+struct file_extension *file_extensions = NULL;
2733
+int demime(uschar **listptr) {
2735
+ uschar *list = *listptr;
2737
+ uschar option_buffer[64];
2738
+ unsigned long long mbox_size;
2740
+ uschar defer_error_buffer[1024];
2741
+ int demime_rc = 0;
2743
+ /* reset found_extension variable */
2744
+ found_extension = NULL;
2746
+ /* try to find 1st option */
2747
+ if ((option = string_nextinlist(&list, &sep,
2749
+ sizeof(option_buffer))) != NULL) {
2751
+ /* parse 1st option */
2752
+ if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) {
2753
+ /* explicitly no demimeing */
2758
+ /* no options -> no demimeing */
2762
+ /* make sure the eml mbox file is spooled up */
2763
+ mbox_file = spool_mbox(&mbox_size);
2765
+ if (mbox_file == NULL) {
2766
+ /* error while spooling */
2767
+ log_write(0, LOG_MAIN|LOG_PANIC,
2768
+ "demime acl condition: error while creating mbox spool file");
2772
+ /* call demimer if not already done earlier */
2774
+ demime_rc = mime_demux(mbox_file, defer_error_buffer);
2776
+ fclose(mbox_file);
2778
+ if (demime_rc == DEFER) {
2779
+ /* temporary failure (DEFER => DEFER) */
2780
+ log_write(0, LOG_MAIN,
2781
+ "demime acl condition: %s", defer_error_buffer);
2785
+ /* set demime_ok to avoid unpacking again */
2788
+ /* check for file extensions, if there */
2789
+ while (option != NULL) {
2790
+ struct file_extension *this_extension = file_extensions;
2792
+ /* Look for the wildcard. If it is found, we always return true.
2793
+ The user must then use a custom condition to evaluate demime_errorlevel */
2794
+ if (Ustrcmp(option,"*") == 0) {
2795
+ found_extension = NULL;
2799
+ /* loop thru extension list */
2800
+ while (this_extension != NULL) {
2801
+ if (strcmpic(option, this_extension->file_extension_string) == 0) {
2803
+ found_extension = this_extension->file_extension_string;
2806
+ this_extension = this_extension->next;
2809
+ /* grab next extension from option list */
2810
+ option = string_nextinlist(&list, &sep,
2812
+ sizeof(option_buffer));
2815
+ /* nothing found */
2820
+/*************************************************
2821
+* unpack TNEF in given directory *
2822
+*************************************************/
2824
+int mime_unpack_tnef(uschar *directory) {
2825
+ uschar filepath[1024];
2827
+ struct dirent *entry;
2830
+ /* open the dir */
2831
+ tempdir = opendir(CS directory);
2832
+ if (tempdir == NULL) {
2836
+ /* loop thru dir */
2839
+ entry = readdir(tempdir);
2840
+ /* break on end of list */
2841
+ if (entry == NULL) break;
2842
+ snprintf(CS filepath,1024,"%s/%s",directory,entry->d_name);
2843
+ if ( (Ustrcmp(entry->d_name,"..") != 0) && (Ustrcmp(entry->d_name,".") != 0) && (Ustrcmp(entry->d_name,"winmail.dat") == 0) ) {
2844
+ TNEF_set_path(CS directory);
2845
+ n = TNEF_main(CS filepath);
2849
+ closedir(tempdir);
2854
+/*************************************************
2855
+* small hex_str -> integer conversion function *
2856
+*************************************************/
2858
+/* needed for quoted-printable
2861
+unsigned int mime_hstr_i(uschar *cptr) {
2862
+ unsigned int i, j = 0;
2864
+ while (cptr && *cptr && isxdigit(*cptr)) {
2865
+ i = *cptr++ - '0';
2866
+ if (9 < i) i -= 7;
2875
+/*************************************************
2876
+* decode quoted-printable chars *
2877
+*************************************************/
2879
+/* gets called when we hit a =
2880
+ returns: new pointer position
2883
+ -1 - soft line break, no char
2884
+ 0-255 - char to write
2887
+uschar *mime_decode_qp(uschar *qp_p,int *c) {
2888
+ uschar hex[] = {0,0,0};
2890
+ uschar *initial_pos = qp_p;
2892
+ /* advance one char */
2896
+ if ( (*qp_p == '\t') || (*qp_p == ' ') || (*qp_p == '\r') ) {
2897
+ /* tab or whitespace may follow
2898
+ just ignore it, but remember
2899
+ that this is not a valid hex
2900
+ encoding any more */
2903
+ goto REPEAT_FIRST;
2905
+ else if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
2906
+ /* this is a valid hex char, if nan is unset */
2908
+ /* this is illegal */
2910
+ return initial_pos;
2917
+ else if (*qp_p == '\n') {
2918
+ /* hit soft line break already, continue */
2923
+ /* illegal char here */
2925
+ return initial_pos;
2928
+ if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
2931
+ /* do hex conversion */
2932
+ *c = mime_hstr_i(hex);
2939
+ return initial_pos;
2943
+ /* illegal char */
2945
+ return initial_pos;
2951
+/*************************************************
2952
+* open new dump file *
2953
+*************************************************/
2955
+/* open new dump file
2956
+ returns: -2 soft error
2957
+ or file #, FILE * in f
2960
+int mime_get_dump_file(uschar *extension, FILE **f, uschar *info) {
2961
+ uschar file_name[1024];
2963
+ unsigned int file_nr;
2964
+ uschar default_extension[] = ".com";
2967
+ if (extension == NULL)
2968
+ extension = default_extension;
2970
+ /* scan the proposed extension.
2971
+ if it is longer than 4 chars, or
2972
+ contains exotic chars, use the default extension */
2974
+/* if (Ustrlen(extension) > 4) {
2975
+ extension = default_extension;
2982
+ *p = (uschar)tolower((uschar)*p);
2983
+ if ( (*p < 97) || (*p > 122) ) {
2984
+ extension = default_extension;
2990
+ /* find a new file to write to */
2993
+ struct stat mystat;
2995
+ snprintf(CS file_name,1024,"%s/scan/%s/%s-%05u%s",spool_directory,message_id,message_id,file_nr,extension);
2997
+ if (file_nr >= MIME_SANITY_MAX_DUMP_FILES) {
2998
+ /* max parts reached */
2999
+ mime_trigger_error(MIME_ERRORLEVEL_TOO_MANY_PARTS);
3002
+ result = stat(CS file_name,&mystat);
3004
+ while(result != -1);
3006
+ *f = fopen(CS file_name,"w+");
3008
+ /* cannot open new dump file, disk full ? -> soft error */
3009
+ snprintf(CS info, 1024,"unable to open dump file");
3017
+/*************************************************
3018
+* Find a string in a mime header *
3019
+*************************************************/
3021
+/* Find a string in a mime header, and optionally fill in
3022
+ the value associated with it into *value
3024
+ returns: 0 - nothing found
3026
+ 2 - found param + value
3029
+int mime_header_find(uschar *header, uschar *param, uschar **value) {
3032
+ needle = strstric(header,param,FALSE);
3033
+ if (needle != NULL) {
3034
+ if (value != NULL) {
3035
+ needle += Ustrlen(param);
3036
+ if (*needle == '=') {
3037
+ uschar *value_start;
3038
+ uschar *value_end;
3040
+ value_start = needle + 1;
3041
+ value_end = strstric(value_start,US";",FALSE);
3042
+ if (value_end != NULL) {
3043
+ /* allocate mem for value */
3044
+ *value = (uschar *)malloc((value_end - value_start)+1);
3045
+ if (*value == NULL)
3048
+ Ustrncpy(*value,value_start,(value_end - value_start));
3049
+ (*value)[(value_end - value_start)] = '\0';
3060
+/*************************************************
3061
+* Read a line of MIME input *
3062
+*************************************************/
3063
+/* returns status code, one of
3064
+ MIME_READ_LINE_EOF 0
3065
+ MIME_READ_LINE_OK 1
3066
+ MIME_READ_LINE_OVERFLOW 2
3068
+ In header mode, the line will be "cooked".
3071
+int mime_read_line(FILE *f, int mime_demux_mode, uschar *buffer, long *num_copied) {
3074
+ int header_value_mode = 0;
3075
+ int header_open_brackets = 0;
3082
+ if (c == EOF) break;
3084
+ /* --------- header mode -------------- */
3085
+ if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) {
3087
+ /* always skip CRs */
3088
+ if (c == '\r') continue;
3091
+ if ((*num_copied) > 0) {
3092
+ /* look if next char is '\t' or ' ' */
3094
+ if (c == EOF) break;
3095
+ if ( (c == '\t') || (c == ' ') ) continue;
3098
+ /* end of the header, terminate with ';' */
3103
+ /* skip control characters */
3104
+ if (c < 32) continue;
3106
+ /* skip whitespace + tabs */
3107
+ if ( (c == ' ') || (c == '\t') )
3110
+ if (header_value_mode) {
3111
+ /* --------- value mode ----------- */
3113
+ if (c == '"') continue;
3115
+ /* leave value mode on ';' */
3117
+ header_value_mode = 0;
3119
+ /* -------------------------------- */
3122
+ /* -------- non-value mode -------- */
3124
+ /* quote next char. can be used
3125
+ to escape brackets. */
3127
+ if (c == EOF) break;
3129
+ else if (c == '(') {
3130
+ header_open_brackets++;
3133
+ else if ((c == ')') && header_open_brackets) {
3134
+ header_open_brackets--;
3137
+ else if ( (c == '=') && !header_open_brackets ) {
3138
+ /* enter value mode */
3139
+ header_value_mode = 1;
3142
+ /* skip chars while we are in a comment */
3143
+ if (header_open_brackets > 0)
3145
+ /* -------------------------------- */
3148
+ /* ------------------------------------ */
3150
+ /* ----------- non-header mode -------- */
3151
+ /* break on '\n' */
3154
+ /* ------------------------------------ */
3157
+ /* copy the char to the buffer */
3158
+ buffer[*num_copied] = (uschar)c;
3159
+ /* raise counter */
3162
+ /* break if buffer is full */
3163
+ if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1) {
3169
+ buffer[*num_copied] = '\0';
3171
+ if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1)
3172
+ return MIME_READ_LINE_OVERFLOW;
3175
+ return MIME_READ_LINE_EOF;
3177
+ return MIME_READ_LINE_OK;
3181
+/*************************************************
3182
+* Check for a MIME boundary *
3183
+*************************************************/
3185
+/* returns: 0 - no boundary found
3186
+ 1 - start boundary found
3187
+ 2 - end boundary found
3190
+int mime_check_boundary(uschar *line, struct boundary *boundaries) {
3191
+ struct boundary *thisboundary = boundaries;
3192
+ uschar workbuf[MIME_SANITY_MAX_LINE_LENGTH+1];
3193
+ unsigned int i,j=0;
3195
+ /* check for '--' first */
3196
+ if (Ustrncmp(line,"--",2) == 0) {
3198
+ /* strip tab and space */
3199
+ for (i = 2; i < Ustrlen(line); i++) {
3200
+ if ((line[i] != ' ') && (line[i] != '\t')) {
3201
+ workbuf[j] = line[i];
3205
+ workbuf[j+1]='\0';
3207
+ while(thisboundary != NULL) {
3208
+ if (Ustrncmp(workbuf,thisboundary->boundary_string,Ustrlen(thisboundary->boundary_string)) == 0) {
3209
+ if (Ustrncmp(&workbuf[Ustrlen(thisboundary->boundary_string)],"--",2) == 0) {
3210
+ /* final boundary found */
3215
+ thisboundary = thisboundary->next;
3223
+/*************************************************
3224
+* Check for start of a UUENCODE block *
3225
+*************************************************/
3227
+/* returns 0 for no hit,
3231
+int mime_check_uu_start(uschar *line, uschar *uu_file_extension, int *has_tnef) {
3233
+ if ( (strncmpic(line,US"begin ",6) == 0)) {
3234
+ uschar *uu_filename = &line[6];
3236
+ /* skip perms, if present */
3237
+ Ustrtoul(&line[6],&uu_filename,10);
3239
+ /* advance one char */
3242
+ /* This should be the filename.
3243
+ Check if winmail.dat is present,
3244
+ which indicates TNEF. */
3245
+ if (strncmpic(uu_filename,US"winmail.dat",11) == 0) {
3249
+ /* reverse to dot if present,
3250
+ copy up to 4 chars for the extension */
3251
+ if (Ustrrchr(uu_filename,'.') != NULL)
3252
+ uu_filename = Ustrrchr(uu_filename,'.');
3254
+ return sscanf(CS uu_filename, "%4[.0-9A-Za-z]",CS uu_file_extension);
3257
+ /* nothing found */
3263
+/*************************************************
3264
+* Decode a uu line *
3265
+*************************************************/
3267
+/* returns number of decoded bytes
3268
+ -2 for soft errors
3271
+int warned_about_uudec_line_sanity_1 = 0;
3272
+int warned_about_uudec_line_sanity_2 = 0;
3273
+long uu_decode_line(uschar *line, uschar **data, long line_len, uschar *info) {
3275
+ long num_decoded = 0;
3278
+ int uu_decoded_line_len, uu_encoded_line_len;
3280
+ /* allocate memory for data and work buffer */
3281
+ *data = (uschar *)malloc(line_len);
3282
+ if (*data == NULL) {
3283
+ snprintf(CS info, 1024,"unable to allocate %lu bytes",line_len);
3287
+ work = (uschar *)malloc(line_len);
3288
+ if (work == NULL) {
3289
+ snprintf(CS info, 1024,"unable to allocate %lu bytes",line_len);
3293
+ memcpy(work,line,line_len);
3295
+ /* First char is line length
3296
+ This is microsofts way of getting it. Scary. */
3297
+ if (work[0] < 32) {
3298
+ /* ignore this line */
3302
+ uu_decoded_line_len = uudec[work[0]];
3312
+ uu_encoded_line_len = (p - &work[1]);
3315
+ /* check that resulting line length is a multiple of 4 */
3316
+ if ( ( uu_encoded_line_len % 4 ) != 0) {
3317
+ if (!warned_about_uudec_line_sanity_1) {
3318
+ mime_trigger_error(MIME_ERRORLEVEL_UU_MISALIGNED);
3319
+ warned_about_uudec_line_sanity_1 = 1;
3324
+ /* check that the line length matches */
3325
+ if ( ( (((uu_encoded_line_len/4)*3)-2) > uu_decoded_line_len ) || (((uu_encoded_line_len/4)*3) < uu_decoded_line_len) ) {
3326
+ if (!warned_about_uudec_line_sanity_2) {
3327
+ mime_trigger_error(MIME_ERRORLEVEL_UU_LINE_LENGTH);
3328
+ warned_about_uudec_line_sanity_2 = 1;
3333
+ while ( ((p - &work[1]) < uu_encoded_line_len) && (num_decoded < uu_decoded_line_len)) {
3335
+ /* byte 0 ---------------------- */
3336
+ if ((p - &work[1] + 1) >= uu_encoded_line_len) {
3340
+ (*data)[num_decoded] = *p;
3341
+ (*data)[num_decoded] <<= 2;
3345
+ (*data)[num_decoded] |= tmp_c;
3350
+ /* byte 1 ---------------------- */
3351
+ if ((p - &work[1] + 1) >= uu_encoded_line_len) {
3355
+ (*data)[num_decoded] = *p;
3356
+ (*data)[num_decoded] <<= 4;
3360
+ (*data)[num_decoded] |= tmp_c;
3365
+ /* byte 2 ---------------------- */
3366
+ if ((p - &work[1] + 1) >= uu_encoded_line_len) {
3370
+ (*data)[num_decoded] = *p;
3371
+ (*data)[num_decoded] <<= 6;
3373
+ (*data)[num_decoded] |= *(p+1);
3380
+ return uu_decoded_line_len;
3384
+/*************************************************
3385
+* Decode a b64 or qp line *
3386
+*************************************************/
3388
+/* returns number of decoded bytes
3389
+ -1 for hard errors
3390
+ -2 for soft errors
3393
+int warned_about_b64_line_length = 0;
3394
+int warned_about_b64_line_sanity = 0;
3395
+int warned_about_b64_illegal_char = 0;
3396
+int warned_about_qp_line_sanity = 0;
3397
+long mime_decode_line(int mime_demux_mode,uschar *line, uschar **data, long max_data_len, uschar *info) {
3399
+ long num_decoded = 0;
3403
+ /* allocate memory for data */
3404
+ *data = (uschar *)malloc(max_data_len);
3405
+ if (*data == NULL) {
3406
+ snprintf(CS info, 1024,"unable to allocate %lu bytes",max_data_len);
3410
+ if (mime_demux_mode == MIME_DEMUX_MODE_BASE64) {
3411
+ /* ---------------------------------------------- */
3413
+ /* NULL out trailing '\r' and '\n' chars */
3414
+ while (Ustrrchr(line,'\r') != NULL) {
3415
+ *(Ustrrchr(line,'\r')) = '\0';
3417
+ while (Ustrrchr(line,'\n') != NULL) {
3418
+ *(Ustrrchr(line,'\n')) = '\0';
3421
+ /* check maximum base 64 line length */
3422
+ if (Ustrlen(line) > MIME_SANITY_MAX_B64_LINE_LENGTH ) {
3423
+ if (!warned_about_b64_line_length) {
3424
+ mime_trigger_error(MIME_ERRORLEVEL_B64_LINE_LENGTH);
3425
+ warned_about_b64_line_length = 1;
3431
+ while (*(p+offset) != '\0') {
3432
+ /* hit illegal char ? */
3433
+ if (b64[*(p+offset)] == 128) {
3434
+ if (!warned_about_b64_illegal_char) {
3435
+ mime_trigger_error(MIME_ERRORLEVEL_B64_ILLEGAL_CHAR);
3436
+ warned_about_b64_illegal_char = 1;
3441
+ *p = b64[*(p+offset)];
3447
+ /* check that resulting line length is a multiple of 4 */
3448
+ if ( ( (p - &line[0]) % 4 ) != 0) {
3449
+ if (!warned_about_b64_line_sanity) {
3450
+ mime_trigger_error(MIME_ERRORLEVEL_B64_MISALIGNED);
3451
+ warned_about_b64_line_sanity = 1;
3455
+ /* line is translated, start bit shifting */
3459
+ while(*p != 255) {
3461
+ /* byte 0 ---------------------- */
3462
+ if (*(p+1) == 255) {
3466
+ (*data)[num_decoded] = *p;
3467
+ (*data)[num_decoded] <<= 2;
3471
+ (*data)[num_decoded] |= tmp_c;
3476
+ /* byte 1 ---------------------- */
3477
+ if (*(p+1) == 255) {
3481
+ (*data)[num_decoded] = *p;
3482
+ (*data)[num_decoded] <<= 4;
3486
+ (*data)[num_decoded] |= tmp_c;
3491
+ /* byte 2 ---------------------- */
3492
+ if (*(p+1) == 255) {
3496
+ (*data)[num_decoded] = *p;
3497
+ (*data)[num_decoded] <<= 6;
3499
+ (*data)[num_decoded] |= *(p+1);
3505
+ return num_decoded;
3506
+ /* ---------------------------------------------- */
3508
+ else if (mime_demux_mode == MIME_DEMUX_MODE_QP) {
3509
+ /* ---------------------------------------------- */
3514
+ int decode_qp_result;
3516
+ p = mime_decode_qp(p,&decode_qp_result);
3518
+ if (decode_qp_result == -2) {
3519
+ /* Error from decoder. p is unchanged. */
3520
+ if (!warned_about_qp_line_sanity) {
3521
+ mime_trigger_error(MIME_ERRORLEVEL_QP_ILLEGAL_CHAR);
3522
+ warned_about_qp_line_sanity = 1;
3524
+ (*data)[num_decoded] = '=';
3528
+ else if (decode_qp_result == -1) {
3529
+ /* End of the line with soft line break.
3533
+ else if (decode_qp_result >= 0) {
3534
+ (*data)[num_decoded] = decode_qp_result;
3539
+ (*data)[num_decoded] = *p;
3545
+ return num_decoded;
3546
+ /* ---------------------------------------------- */
3554
+/*************************************************
3555
+* Log demime errors and set mime error level *
3556
+*************************************************/
3558
+/* This sets the global demime_reason expansion
3559
+variable and the demime_errorlevel gauge. */
3561
+void mime_trigger_error(int level, uschar *format, ...) {
3565
+ if( (f = malloc(16384+23)) != NULL ) {
3566
+ /* first log the incident */
3567
+ sprintf(f,"demime acl condition: ");
3569
+ va_start(ap, format);
3570
+ vsnprintf(f, 16383,(char *)format, ap);
3573
+ log_write(0, LOG_MAIN, f);
3574
+ /* then copy to demime_reason_buffer if new
3575
+ level is greater than old level */
3576
+ if (level > demime_errorlevel) {
3577
+ demime_errorlevel = level;
3578
+ Ustrcpy(demime_reason_buffer, US f);
3579
+ demime_reason = demime_reason_buffer;
3585
+/*************************************************
3586
+* Demultiplex MIME stream. *
3587
+*************************************************/
3589
+/* We can handle BASE64, QUOTED-PRINTABLE, and UUENCODE.
3590
+ UUENCODE does not need to have a proper
3591
+ transfer-encoding header, we detect it with "begin"
3593
+ This function will report human parsable errors in
3596
+ returns DEFER -> soft error (see *info)
3597
+ OK -> EOF hit, all ok
3600
+int mime_demux(FILE *f, uschar *info) {
3601
+ int mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
3602
+ int uu_mode = MIME_UU_MODE_OFF;
3603
+ FILE *mime_dump_file = NULL;
3604
+ FILE *uu_dump_file = NULL;
3606
+ int mime_read_line_status = MIME_READ_LINE_OK;
3608
+ struct boundary *boundaries = NULL;
3609
+ struct mime_part mime_part_p;
3611
+ int has_rfc822 = 0;
3613
+ /* allocate room for our linebuffer */
3614
+ line = (uschar *)malloc(MIME_SANITY_MAX_LINE_LENGTH);
3615
+ if (line == NULL) {
3616
+ snprintf(CS info, 1024,"unable to allocate %u bytes",MIME_SANITY_MAX_LINE_LENGTH);
3620
+ /* clear MIME header structure */
3621
+ memset(&mime_part_p,0,sizeof(mime_part));
3623
+ /* ----------------------- start demux loop --------------------- */
3624
+ while (mime_read_line_status == MIME_READ_LINE_OK) {
3626
+ /* read a line of input. Depending on the mode we are in,
3627
+ the returned format will differ. */
3628
+ mime_read_line_status = mime_read_line(f,mime_demux_mode,line,&line_len);
3630
+ if (mime_read_line_status == MIME_READ_LINE_OVERFLOW) {
3631
+ mime_trigger_error(MIME_ERRORLEVEL_LONG_LINE);
3632
+ /* despite the error, continue .. */
3633
+ mime_read_line_status = MIME_READ_LINE_OK;
3636
+ else if (mime_read_line_status == MIME_READ_LINE_EOF) {
3640
+ if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) {
3641
+ /* -------------- header mode --------------------- */
3643
+ /* Check for an empty line, which is the end of the headers.
3644
+ In HEADER mode, the line is returned "cooked", with the
3645
+ final '\n' replaced by a ';' */
3646
+ if (line_len == 1) {
3649
+ /* We have reached the end of the headers. Start decoding
3650
+ with the collected settings. */
3651
+ if (mime_part_p.seen_content_transfer_encoding > 1) {
3652
+ mime_demux_mode = mime_part_p.seen_content_transfer_encoding;
3655
+ /* default to plain mode if no specific encoding type found */
3656
+ mime_demux_mode = MIME_DEMUX_MODE_PLAIN;
3659
+ /* open new dump file */
3660
+ tmp = mime_get_dump_file(mime_part_p.extension, &mime_dump_file, info);
3665
+ /* clear out mime_part */
3666
+ memset(&mime_part_p,0,sizeof(mime_part));
3669
+ /* Another header to check for file extensions,
3670
+ encoding type and boundaries */
3671
+ if (strncmpic(US"content-type:",line,Ustrlen("content-type:")) == 0) {
3672
+ /* ---------------------------- Content-Type header ------------------------------- */
3673
+ uschar *value = line;
3675
+ /* check for message/partial MIME type and reject it */
3676
+ if (mime_header_find(line,US"message/partial",NULL) > 0)
3677
+ mime_trigger_error(MIME_ERRORLEVEL_MESSAGE_PARTIAL);
3679
+ /* check for TNEF content type, remember to unpack TNEF later. */
3680
+ if (mime_header_find(line,US"application/ms-tnef",NULL) > 0)
3683
+ /* check for message/rfcxxx attachments */
3684
+ if (mime_header_find(line,US"message/rfc822",NULL) > 0)
3687
+ /* find the file extension, but do not fill it in
3688
+ it is already set, since content-disposition has
3690
+ if (mime_part_p.extension == NULL) {
3691
+ if (mime_header_find(line,US"name",&value) == 2) {
3692
+ if (Ustrlen(value) > MIME_SANITY_MAX_FILENAME)
3693
+ mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH);
3694
+ mime_part_p.extension = value;
3695
+ mime_part_p.extension = Ustrrchr(value,'.');
3696
+ if (mime_part_p.extension == NULL) {
3697
+ /* file without extension, setting
3698
+ NULL will use the default extension later */
3699
+ mime_part_p.extension = NULL;
3702
+ struct file_extension *this_extension =
3703
+ (struct file_extension *)malloc(sizeof(file_extension));
3705
+ this_extension->file_extension_string =
3706
+ (uschar *)malloc(Ustrlen(mime_part_p.extension)+1);
3707
+ Ustrcpy(this_extension->file_extension_string,
3708
+ mime_part_p.extension+1);
3709
+ this_extension->next = file_extensions;
3710
+ file_extensions = this_extension;
3715
+ /* find a boundary and add it to the list, if present */
3717
+ if (mime_header_find(line,US"boundary",&value) == 2) {
3718
+ struct boundary *thisboundary;
3720
+ if (Ustrlen(value) > MIME_SANITY_MAX_BOUNDARY_LENGTH) {
3721
+ mime_trigger_error(MIME_ERRORLEVEL_BOUNDARY_LENGTH);
3724
+ thisboundary = (struct boundary*)malloc(sizeof(boundary));
3725
+ thisboundary->next = boundaries;
3726
+ thisboundary->boundary_string = value;
3727
+ boundaries = thisboundary;
3731
+ if (mime_part_p.seen_content_type == 0) {
3732
+ mime_part_p.seen_content_type = 1;
3735
+ mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
3737
+ /* ---------------------------------------------------------------------------- */
3739
+ else if (strncmpic(US"content-transfer-encoding:",line,Ustrlen("content-transfer-encoding:")) == 0) {
3740
+ /* ---------------------------- Content-Transfer-Encoding header -------------- */
3742
+ if (mime_part_p.seen_content_transfer_encoding == 0) {
3743
+ if (mime_header_find(line,US"base64",NULL) > 0) {
3744
+ mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_BASE64;
3746
+ else if (mime_header_find(line,US"quoted-printable",NULL) > 0) {
3747
+ mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_QP;
3750
+ mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_PLAIN;
3754
+ mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
3756
+ /* ---------------------------------------------------------------------------- */
3758
+ else if (strncmpic(US"content-disposition:",line,Ustrlen("content-disposition:")) == 0) {
3759
+ /* ---------------------------- Content-Disposition header -------------------- */
3760
+ uschar *value = line;
3762
+ if (mime_part_p.seen_content_disposition == 0) {
3763
+ mime_part_p.seen_content_disposition = 1;
3765
+ if (mime_header_find(line,US"filename",&value) == 2) {
3766
+ if (Ustrlen(value) > MIME_SANITY_MAX_FILENAME)
3767
+ mime_trigger_error(MIME_ERRORLEVEL_FILENAME_LENGTH);
3768
+ mime_part_p.extension = value;
3769
+ mime_part_p.extension = Ustrrchr(value,'.');
3770
+ if (mime_part_p.extension == NULL) {
3771
+ /* file without extension, setting
3772
+ NULL will use the default extension later */
3773
+ mime_part_p.extension = NULL;
3776
+ struct file_extension *this_extension =
3777
+ (struct file_extension *)malloc(sizeof(file_extension));
3779
+ this_extension->file_extension_string =
3780
+ (uschar *)malloc(Ustrlen(mime_part_p.extension)+1);
3781
+ Ustrcpy(this_extension->file_extension_string,
3782
+ mime_part_p.extension+1);
3783
+ this_extension->next = file_extensions;
3784
+ file_extensions = this_extension;
3789
+ mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
3791
+ /* ---------------------------------------------------------------------------- */
3793
+ }; /* End of header checks */
3794
+ /* ------------------------------------------------ */
3797
+ /* -------------- non-header mode ----------------- */
3800
+ if (uu_mode == MIME_UU_MODE_OFF) {
3801
+ uschar uu_file_extension[5];
3802
+ /* We are not currently decoding UUENCODE
3803
+ Check for possible UUENCODE start tag. */
3804
+ if (mime_check_uu_start(line,uu_file_extension,&has_tnef)) {
3805
+ /* possible UUENCODING start detected.
3806
+ Set unconfirmed mode first. */
3807
+ uu_mode = MIME_UU_MODE_UNCONFIRMED;
3808
+ /* open new uu dump file */
3809
+ tmp = mime_get_dump_file(uu_file_extension, &uu_dump_file, info);
3818
+ long data_len = 0;
3820
+ if (uu_mode == MIME_UU_MODE_UNCONFIRMED) {
3821
+ /* We are in unconfirmed UUENCODE mode. */
3823
+ data_len = uu_decode_line(line,&data,line_len,info);
3825
+ if (data_len == -2) {
3826
+ /* temp error, turn off uudecode mode */
3827
+ if (uu_dump_file != NULL) {
3828
+ fclose(uu_dump_file); uu_dump_file = NULL;
3830
+ uu_mode = MIME_UU_MODE_OFF;
3833
+ else if (data_len == -1) {
3834
+ if (uu_dump_file != NULL) {
3835
+ fclose(uu_dump_file); uu_dump_file = NULL;
3837
+ uu_mode = MIME_UU_MODE_OFF;
3840
+ else if (data_len > 0) {
3841
+ /* we have at least decoded a valid byte
3842
+ turn on confirmed mode */
3843
+ uu_mode = MIME_UU_MODE_CONFIRMED;
3846
+ else if (uu_mode == MIME_UU_MODE_CONFIRMED) {
3847
+ /* If we are in confirmed UU mode,
3848
+ check for single "end" tag on line */
3849
+ if ((strncmpic(line,US"end",3) == 0) && (line[3] < 32)) {
3850
+ if (uu_dump_file != NULL) {
3851
+ fclose(uu_dump_file); uu_dump_file = NULL;
3853
+ uu_mode = MIME_UU_MODE_OFF;
3856
+ data_len = uu_decode_line(line,&data,line_len,info);
3857
+ if (data_len == -2) {
3858
+ /* temp error, turn off uudecode mode */
3859
+ if (uu_dump_file != NULL) {
3860
+ fclose(uu_dump_file); uu_dump_file = NULL;
3862
+ uu_mode = MIME_UU_MODE_OFF;
3865
+ else if (data_len == -1) {
3866
+ /* skip this line */
3872
+ /* write data to dump file, if available */
3873
+ if (data_len > 0) {
3874
+ if (fwrite(data,1,data_len,uu_dump_file) < data_len) {
3876
+ snprintf(CS info, 1024,"short write on uudecode dump file");
3883
+ if (mime_demux_mode != MIME_DEMUX_MODE_SCANNING) {
3884
+ /* Non-scanning and Non-header mode. That means
3885
+ we are currently decoding data to the dump
3888
+ /* Check for a known boundary. */
3889
+ tmp = mime_check_boundary(line,boundaries);
3891
+ /* We have hit a known start boundary.
3892
+ That will put us back in header mode. */
3893
+ mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
3894
+ if (mime_dump_file != NULL) {
3895
+ /* if the attachment was a RFC822 message, recurse into it */
3898
+ rewind(mime_dump_file);
3899
+ mime_demux(mime_dump_file,info);
3902
+ fclose(mime_dump_file); mime_dump_file = NULL;
3905
+ else if (tmp == 2) {
3906
+ /* We have hit a known end boundary.
3907
+ That puts us into scanning mode, which will end when we hit another known start boundary */
3908
+ mime_demux_mode = MIME_DEMUX_MODE_SCANNING;
3909
+ if (mime_dump_file != NULL) {
3910
+ /* if the attachment was a RFC822 message, recurse into it */
3913
+ rewind(mime_dump_file);
3914
+ mime_demux(mime_dump_file,info);
3917
+ fclose(mime_dump_file); mime_dump_file = NULL;
3922
+ long data_len = 0;
3924
+ /* decode the line with the appropriate method */
3925
+ if (mime_demux_mode == MIME_DEMUX_MODE_PLAIN) {
3926
+ /* in plain mode, just dump the line */
3928
+ data_len = line_len;
3930
+ else if ( (mime_demux_mode == MIME_DEMUX_MODE_QP) || (mime_demux_mode == MIME_DEMUX_MODE_BASE64) ) {
3931
+ data_len = mime_decode_line(mime_demux_mode,line,&data,line_len,info);
3932
+ if (data_len < 0) {
3933
+ /* Error reported from the line decoder. */
3938
+ /* write data to dump file */
3939
+ if (data_len > 0) {
3940
+ if (fwrite(data,1,data_len,mime_dump_file) < data_len) {
3942
+ snprintf(CS info, 1024,"short write on dump file");
3951
+ /* Scanning mode. We end up here after a end boundary.
3952
+ This will usually be at the end of a message or at
3953
+ the end of a MIME container.
3954
+ We need to look for another start boundary to get
3955
+ back into header mode. */
3956
+ if (mime_check_boundary(line,boundaries) == 1) {
3957
+ mime_demux_mode = MIME_DEMUX_MODE_MIME_HEADERS;
3961
+ /* ------------------------------------------------ */
3964
+ /* ----------------------- end demux loop ----------------------- */
3966
+ /* close files, they could still be open */
3967
+ if (mime_dump_file != NULL)
3968
+ fclose(mime_dump_file);
3969
+ if (uu_dump_file != NULL)
3970
+ fclose(uu_dump_file);
3972
+ /* release line buffer */
3975
+ /* FIXME: release boundary buffers.
3976
+ Not too much of a problem since
3977
+ this instance of exim is not resident. */
3980
+ uschar file_name[1024];
3981
+ /* at least one file could be TNEF encoded.
3982
+ attempt to send all decoded files thru the TNEF decoder */
3984
+ snprintf(CS file_name,1024,"%s/scan/%s",spool_directory,message_id);
3985
+ mime_unpack_tnef(file_name);
3991
diff -urN exim-4.34-orig/src/demime.h exim-4.34/src/demime.h
3992
--- exim-4.34-orig/src/demime.h Thu Jan 1 01:00:00 1970
3993
+++ exim-4.34/src/demime.h Mon May 10 16:14:47 2004
3995
+/*************************************************
3996
+* Exim - an Internet mail transport agent *
3997
+*************************************************/
3999
+/* This file is part of the exiscan-acl content scanner
4000
+patch. It is NOT part of the standard exim distribution. */
4002
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
4005
+/* demime defines */
4007
+#define MIME_DEMUX_MODE_SCANNING 0
4008
+#define MIME_DEMUX_MODE_MIME_HEADERS 1
4009
+#define MIME_DEMUX_MODE_BASE64 2
4010
+#define MIME_DEMUX_MODE_QP 3
4011
+#define MIME_DEMUX_MODE_PLAIN 4
4013
+#define MIME_UU_MODE_OFF 0
4014
+#define MIME_UU_MODE_UNCONFIRMED 1
4015
+#define MIME_UU_MODE_CONFIRMED 2
4017
+#define MIME_MAX_EXTENSION 128
4019
+#define MIME_READ_LINE_EOF 0
4020
+#define MIME_READ_LINE_OK 1
4021
+#define MIME_READ_LINE_OVERFLOW 2
4023
+#define MIME_SANITY_MAX_LINE_LENGTH 131071
4024
+#define MIME_SANITY_MAX_FILENAME 512
4025
+#define MIME_SANITY_MAX_HEADER_OPTION_VALUE 1024
4026
+#define MIME_SANITY_MAX_B64_LINE_LENGTH 76
4027
+#define MIME_SANITY_MAX_BOUNDARY_LENGTH 1024
4028
+#define MIME_SANITY_MAX_DUMP_FILES 1024
4032
+/* MIME errorlevel settings */
4034
+#define MIME_ERRORLEVEL_LONG_LINE 3,US"line length in message or single header size exceeds %u bytes",MIME_SANITY_MAX_LINE_LENGTH
4035
+#define MIME_ERRORLEVEL_TOO_MANY_PARTS 3,US"too many MIME parts (max %u)",MIME_SANITY_MAX_DUMP_FILES
4036
+#define MIME_ERRORLEVEL_MESSAGE_PARTIAL 3,US"'message/partial' MIME type"
4037
+#define MIME_ERRORLEVEL_FILENAME_LENGTH 3,US"proposed filename exceeds %u characters",MIME_SANITY_MAX_FILENAME
4038
+#define MIME_ERRORLEVEL_BOUNDARY_LENGTH 3,US"boundary length exceeds %u characters",MIME_SANITY_MAX_BOUNDARY_LENGTH
4039
+#define MIME_ERRORLEVEL_DOUBLE_HEADERS 2,US"double headers (content-type, content-disposition or content-transfer-encoding)"
4040
+#define MIME_ERRORLEVEL_UU_MISALIGNED 1,US"uuencoded line length is not a multiple of 4 characters"
4041
+#define MIME_ERRORLEVEL_UU_LINE_LENGTH 1,US"uuencoded line length does not match advertised number of bytes"
4042
+#define MIME_ERRORLEVEL_B64_LINE_LENGTH 1,US"base64 line length exceeds %u characters",MIME_SANITY_MAX_B64_LINE_LENGTH
4043
+#define MIME_ERRORLEVEL_B64_ILLEGAL_CHAR 2,US"base64 line contains illegal character"
4044
+#define MIME_ERRORLEVEL_B64_MISALIGNED 1,US"base64 line length is not a multiple of 4 characters"
4045
+#define MIME_ERRORLEVEL_QP_ILLEGAL_CHAR 1,US"quoted-printable encoding contains illegal character"
4048
+/* demime structures */
4050
+typedef struct mime_part {
4051
+ /* true if there was a content-type header */
4052
+ int seen_content_type;
4053
+ /* true if there was a content-transfer-encoding header
4054
+ contains the encoding type */
4055
+ int seen_content_transfer_encoding;
4056
+ /* true if there was a content-disposition header */
4057
+ int seen_content_disposition;
4058
+ /* pointer to a buffer with the proposed file extension */
4059
+ uschar *extension;
4062
+typedef struct boundary {
4063
+ struct boundary *next;
4064
+ uschar *boundary_string;
4067
+typedef struct file_extension {
4068
+ struct file_extension *next;
4069
+ uschar *file_extension_string;
4072
+/* available functions for the TNEF library (tnef.c & tnef.h) */
4074
+extern int TNEF_main( char *filename );
4075
+extern int TNEF_set_verbosity( int level );
4076
+extern int TNEF_set_debug( int level );
4077
+extern int TNEF_set_syslogging( int level );
4078
+extern int TNEF_set_stderrlogging( int level );
4079
+extern int TNEF_set_path( char *path );
4083
+/* demime.c prototypes */
4085
+int mime_unpack_tnef(uschar *);
4086
+unsigned int mime_hstr_i(uschar *);
4087
+uschar *mime_decode_qp(uschar *, int *);
4088
+int mime_get_dump_file(uschar *, FILE **, uschar *);
4089
+int mime_header_find(uschar *, uschar *, uschar **);
4090
+int mime_read_line(FILE *, int, uschar *, long *);
4091
+int mime_check_boundary(uschar *, struct boundary *);
4092
+int mime_check_uu_start(uschar *, uschar *, int *);
4093
+long uu_decode_line(uschar *, uschar **, long, uschar *);
4094
+long mime_decode_line(int ,uschar *, uschar **, long, uschar *);
4095
+void mime_trigger_error(int, uschar *, ...);
4096
+int mime_demux(FILE *, uschar *);
4100
+/* BASE64 decoder matrix */
4101
+static unsigned char b64[256]={
4102
+/* 0 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4103
+/* 16 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4104
+/* 32 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 62, 128, 128, 128, 63,
4105
+/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 255, 128, 128,
4106
+/* 64 */ 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
4107
+/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 128, 128, 128, 128, 128,
4108
+/* 96 */ 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
4109
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128,
4110
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4111
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4112
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4113
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4114
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4115
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4116
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
4117
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
4121
+/* Microsoft-Style uudecode matrix */
4122
+static unsigned char uudec[256]={
4123
+/* 0 */ 0, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
4124
+/* 16 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
4125
+/* 32 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
4126
+/* 48 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
4127
+/* 64 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
4128
+/* 80 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
4129
+/* 96 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
4130
+/* 112 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
4131
+/* 128 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
4132
+/* 144 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
4133
+/* 160 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
4134
+/* 176 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
4135
+/* 192 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
4136
+/* 208 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
4137
+/* 224 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
4138
+/* 240 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
4141
diff -urN exim-4.34-orig/src/exim.c exim-4.34/src/exim.c
4142
--- exim-4.34-orig/src/exim.c Mon May 10 14:31:20 2004
4143
+++ exim-4.34/src/exim.c Mon May 10 16:14:47 2004
4144
@@ -1530,6 +1530,10 @@
4145
printf("%s\n", CS version_copyright);
4146
version_printed = TRUE;
4147
show_whats_supported(stdout);
4148
+ printf("Contains exiscan-acl patch revision %s (c) Tom Kistner [http://duncanthrax.net/exiscan/]\n", exiscan_version_string);
4150
+ printf("Contains Brightmail AntiSpam support via the exiscan-acl patch.\n");
4155
diff -urN exim-4.34-orig/src/expand.c exim-4.34/src/expand.c
4156
--- exim-4.34-orig/src/expand.c Mon May 10 14:31:20 2004
4157
+++ exim-4.34/src/expand.c Mon May 10 16:14:47 2004
4158
@@ -294,6 +294,12 @@
4159
{ "authenticated_id", vtype_stringptr, &authenticated_id },
4160
{ "authenticated_sender",vtype_stringptr, &authenticated_sender },
4161
{ "authentication_failed",vtype_int, &authentication_failed },
4163
+ { "bmi_alt_location", vtype_stringptr, &bmi_alt_location },
4164
+ { "bmi_base64_tracker_verdict", vtype_stringptr, &bmi_base64_tracker_verdict },
4165
+ { "bmi_base64_verdict", vtype_stringptr, &bmi_base64_verdict },
4166
+ { "bmi_deliver", vtype_int, &bmi_deliver },
4168
{ "body_linecount", vtype_int, &body_linecount },
4169
{ "bounce_recipient", vtype_stringptr, &bounce_recipient },
4170
{ "bounce_return_size_limit", vtype_int, &bounce_return_size_limit },
4172
{ "caller_uid", vtype_uid, &real_uid },
4173
{ "compile_date", vtype_stringptr, &version_date },
4174
{ "compile_number", vtype_stringptr, &version_cnumber },
4175
+ { "demime_errorlevel", vtype_int, &demime_errorlevel },
4176
+ { "demime_reason", vtype_stringptr, &demime_reason },
4177
{ "dnslist_domain", vtype_stringptr, &dnslist_domain },
4178
{ "dnslist_text", vtype_stringptr, &dnslist_text },
4179
{ "dnslist_value", vtype_stringptr, &dnslist_value },
4181
{ "exim_gid", vtype_gid, &exim_gid },
4182
{ "exim_path", vtype_stringptr, &exim_path },
4183
{ "exim_uid", vtype_uid, &exim_uid },
4184
+ { "found_extension", vtype_stringptr, &found_extension },
4185
{ "home", vtype_stringptr, &deliver_home },
4186
{ "host", vtype_stringptr, &deliver_host },
4187
{ "host_address", vtype_stringptr, &deliver_host_address },
4189
{ "local_user_uid", vtype_uid, &local_user_uid },
4190
{ "localhost_number", vtype_int, &host_number },
4191
{ "mailstore_basename", vtype_stringptr, &mailstore_basename },
4192
+ { "malware_name", vtype_stringptr, &malware_name },
4193
{ "message_age", vtype_int, &message_age },
4194
{ "message_body", vtype_msgbody, &message_body },
4195
{ "message_body_end", vtype_msgbody_end, &message_body_end },
4196
@@ -337,6 +347,22 @@
4197
{ "message_headers", vtype_msgheaders, NULL },
4198
{ "message_id", vtype_stringptr, &message_id },
4199
{ "message_size", vtype_int, &message_size },
4200
+ { "mime_anomaly_level", vtype_int, &mime_anomaly_level },
4201
+ { "mime_anomaly_text", vtype_stringptr, &mime_anomaly_text },
4202
+ { "mime_boundary", vtype_stringptr, &mime_boundary },
4203
+ { "mime_charset", vtype_stringptr, &mime_charset },
4204
+ { "mime_content_description", vtype_stringptr, &mime_content_description },
4205
+ { "mime_content_disposition", vtype_stringptr, &mime_content_disposition },
4206
+ { "mime_content_id", vtype_stringptr, &mime_content_id },
4207
+ { "mime_content_size", vtype_int, &mime_content_size },
4208
+ { "mime_content_transfer_encoding",vtype_stringptr, &mime_content_transfer_encoding },
4209
+ { "mime_content_type", vtype_stringptr, &mime_content_type },
4210
+ { "mime_decoded_filename", vtype_stringptr, &mime_decoded_filename },
4211
+ { "mime_filename", vtype_stringptr, &mime_filename },
4212
+ { "mime_is_coverletter", vtype_int, &mime_is_coverletter },
4213
+ { "mime_is_multipart", vtype_int, &mime_is_multipart },
4214
+ { "mime_is_rfc822", vtype_int, &mime_is_rfc822 },
4215
+ { "mime_part_count", vtype_int, &mime_part_count },
4216
{ "n0", vtype_filter_int, &filter_n[0] },
4217
{ "n1", vtype_filter_int, &filter_n[1] },
4218
{ "n2", vtype_filter_int, &filter_n[2] },
4220
{ "recipient_data", vtype_stringptr, &recipient_data },
4221
{ "recipients", vtype_recipients, NULL },
4222
{ "recipients_count", vtype_int, &recipients_count },
4223
+ { "regex_match_string", vtype_stringptr, ®ex_match_string },
4224
{ "reply_address", vtype_reply, NULL },
4225
{ "return_path", vtype_stringptr, &return_path },
4226
{ "return_size_limit", vtype_int, &bounce_return_size_limit },
4227
@@ -394,6 +421,10 @@
4228
{ "sn7", vtype_filter_int, &filter_sn[7] },
4229
{ "sn8", vtype_filter_int, &filter_sn[8] },
4230
{ "sn9", vtype_filter_int, &filter_sn[9] },
4231
+ { "spam_bar", vtype_stringptr, &spam_bar },
4232
+ { "spam_report", vtype_stringptr, &spam_report },
4233
+ { "spam_score", vtype_stringptr, &spam_score },
4234
+ { "spam_score_int", vtype_stringptr, &spam_score_int },
4235
{ "spool_directory", vtype_stringptr, &spool_directory },
4236
{ "thisaddress", vtype_stringptr, &filter_thisaddress },
4237
{ "tls_certificate_verified", vtype_int, &tls_certificate_verified },
4238
diff -urN exim-4.34-orig/src/functions.h exim-4.34/src/functions.h
4239
--- exim-4.34-orig/src/functions.h Mon May 10 14:31:20 2004
4240
+++ exim-4.34/src/functions.h Mon May 10 16:14:47 2004
4242
extern void deliver_set_expansions(address_item *);
4243
extern int deliver_split_address(address_item *);
4244
extern void deliver_succeeded(address_item *);
4245
+extern int demime(uschar **);
4246
extern BOOL directory_make(uschar *, uschar *, int, BOOL);
4247
extern dns_address *dns_address_from_rr(dns_answer *, dns_record *);
4248
extern void dns_build_reverse(uschar *, uschar *);
4251
extern void log_close_all(void);
4253
+extern int malware(uschar **);
4254
extern int match_address_list(uschar *, BOOL, BOOL, uschar **,
4255
unsigned int *, int, int, uschar **);
4256
extern int match_check_list(uschar **, int, tree_node **, unsigned int **,
4257
@@ -132,6 +134,11 @@
4258
extern void md5_mid(md5 *, const uschar *);
4259
extern void md5_start(md5 *);
4260
extern void millisleep(int);
4261
+struct mime_boundary_context;
4262
+extern int mime_acl_check(FILE *f, struct mime_boundary_context *,
4263
+ uschar **, uschar **);
4264
+extern int mime_decode(uschar **);
4265
+extern int mime_regex(uschar **);
4266
extern uschar *moan_check_errorcopy(uschar *);
4267
extern BOOL moan_skipped_syntax_errors(uschar *, error_block *, uschar *,
4270
extern BOOL receive_check_set_sender(uschar *);
4271
extern BOOL receive_msg(BOOL);
4272
extern void receive_swallow_smtp(void);
4273
+extern int regex(uschar **);
4274
extern BOOL regex_match_and_setup(const pcre *, uschar *, int, int);
4275
extern const pcre *regex_must_compile(uschar *, BOOL, BOOL);
4276
extern void retry_add_item(address_item *, uschar *, int);
4278
extern BOOL smtp_start_session(void);
4279
extern int smtp_ungetc(int);
4280
extern int smtp_write_command(smtp_outblock *, BOOL, char *, ...);
4281
+extern int spam(uschar **);
4282
+extern FILE *spool_mbox(unsigned long long *);
4283
extern BOOL spool_move_message(uschar *, uschar *, uschar *, uschar *);
4284
extern BOOL spool_open_datafile(uschar *);
4285
extern int spool_open_temp(uschar *);
4287
extern tree_node *tree_search(tree_node *, uschar *);
4288
extern void tree_write(tree_node *, FILE *);
4290
+extern void unspool_mbox(void);
4292
extern int verify_address(address_item *, FILE *, int, int, BOOL *);
4293
extern int verify_check_dnsbl(uschar **);
4294
extern int verify_check_header_address(uschar **, uschar **, int);
4295
diff -urN exim-4.34-orig/src/globals.c exim-4.34/src/globals.c
4296
--- exim-4.34-orig/src/globals.c Mon May 10 14:31:20 2004
4297
+++ exim-4.34/src/globals.c Mon May 10 16:14:47 2004
4299
uschar *acl_smtp_helo = NULL;
4300
uschar *acl_smtp_mail = NULL;
4301
uschar *acl_smtp_mailauth = NULL;
4302
+uschar *acl_smtp_mime = NULL;
4303
uschar *acl_smtp_rcpt = NULL;
4304
uschar *acl_smtp_starttls = NULL;
4305
uschar *acl_smtp_vrfy = NULL;
4315
550, /* HELO/EHLO */
4317
0, /* MAILAUTH; not relevant */
4323
uschar *auth_defer_msg = US"reason not recorded";
4324
uschar *auth_defer_user_msg = US"";
4326
+uschar *av_scanner = US"sophie:/var/run/sophie";
4328
BOOL background_daemon = TRUE;
4329
uschar *base62_chars=
4330
@@ -303,6 +307,15 @@
4331
uschar *bi_command = NULL;
4332
uschar *big_buffer = NULL;
4333
int big_buffer_size = BIG_BUFFER_SIZE;
4335
+uschar *bmi_alt_location = NULL;
4336
+uschar *bmi_base64_tracker_verdict = NULL;
4337
+uschar *bmi_base64_verdict = NULL;
4338
+uschar *bmi_config_file = US"/opt/brightmail/etc/brightmail.cfg";
4339
+int bmi_deliver = 1;
4341
+uschar *bmi_verdicts = NULL;
4343
int body_linecount = 0;
4344
uschar *bounce_message_file = NULL;
4345
uschar *bounce_message_text = NULL;
4347
BOOL deliver_selectstring_regex = FALSE;
4348
uschar *deliver_selectstring_sender = NULL;
4349
BOOL deliver_selectstring_sender_regex = FALSE;
4350
+int demime_errorlevel = 0;
4352
+uschar *demime_reason = NULL;
4353
BOOL disable_logging = FALSE;
4355
uschar *dns_again_means_nonexist = NULL;
4357
"\0<---------------Space to patch exim_path->";
4358
uid_t exim_uid = EXIM_UID;
4359
BOOL exim_uid_set = TRUE; /* This uid is always set */
4360
+uschar *exiscan_version_string = US"??";
4361
int expand_forbid = 0;
4362
int expand_nlength[EXPAND_MAXN+1];
4363
int expand_nmax = -1;
4364
@@ -450,12 +467,14 @@
4365
BOOL extract_addresses_remove_arguments = TRUE;
4366
uschar *extra_local_interfaces = NULL;
4368
+BOOL fake_reject = FALSE;
4369
int filter_n[FILTER_VARIABLE_COUNT];
4370
BOOL filter_running = FALSE;
4371
int filter_sn[FILTER_VARIABLE_COUNT];
4372
uschar *filter_test = NULL;
4373
uschar *filter_thisaddress = NULL;
4374
int finduser_retries = 0;
4375
+uschar *found_extension = NULL;
4376
uid_t fixed_never_users[] = { FIXED_NEVER_USERS };
4377
uschar *freeze_tell = NULL;
4378
uschar *fudged_queue_times = US"";
4381
macro_item *macros = NULL;
4382
uschar *mailstore_basename = NULL;
4383
+uschar *malware_name = NULL;
4384
int max_username_length = 0;
4385
int message_age = 0;
4386
uschar *message_body = NULL;
4387
@@ -629,8 +649,25 @@
4388
uschar *message_size_limit = US"50M";
4389
uschar message_subdir[2] = { 0, 0 };
4390
uschar *message_reference = NULL;
4391
+uschar *mime_anomaly_level = NULL;
4392
+uschar *mime_anomaly_text = NULL;
4393
+uschar *mime_boundary = NULL;
4394
+uschar *mime_charset = NULL;
4395
+uschar *mime_content_description = NULL;
4396
+uschar *mime_content_disposition = NULL;
4397
+uschar *mime_content_id = NULL;
4398
+unsigned int mime_content_size = 0;
4399
+uschar *mime_content_transfer_encoding = NULL;
4400
+uschar *mime_content_type = NULL;
4401
+uschar *mime_decoded_filename = NULL;
4402
+uschar *mime_filename = NULL;
4403
+int mime_is_multipart = 0;
4404
+int mime_is_coverletter = 0;
4405
+int mime_is_rfc822 = 0;
4406
+int mime_part_count = -1;
4408
uid_t *never_users = NULL;
4409
+BOOL no_mbox_unspool = FALSE;
4411
uid_t original_euid;
4412
gid_t originator_gid;
4414
const pcre *regex_PIPELINING = NULL;
4415
const pcre *regex_SIZE = NULL;
4416
const pcre *regex_ismsgid = NULL;
4417
+uschar *regex_match_string = NULL;
4418
int remote_delivery_count = 0;
4419
int remote_max_parallel = 2;
4420
uschar *remote_sort_domains = NULL;
4422
NULL, /* driver name */
4424
NULL, /* address_data */
4426
+ NULL, /* bmi_rule */
4428
NULL, /* cannot_route_message */
4429
NULL, /* condition */
4430
NULL, /* current_directory */
4431
@@ -781,6 +822,11 @@
4432
NULL, /* transport_name */
4434
TRUE, /* address_test */
4436
+ FALSE, /* bmi_deliver_alternate */
4437
+ FALSE, /* bmi_deliver_default */
4438
+ FALSE, /* bmi_dont_deliver */
4441
FALSE, /* caseful_local_part */
4442
FALSE, /* check_local_user */
4443
@@ -907,6 +953,11 @@
4444
int smtp_rlr_threshold = INT_MAX;
4445
BOOL smtp_use_pipelining = FALSE;
4446
BOOL smtp_use_size = FALSE;
4447
+uschar *spamd_address = US"127.0.0.1 783";
4448
+uschar *spam_bar = NULL;
4449
+uschar *spam_report = NULL;
4450
+uschar *spam_score = NULL;
4451
+uschar *spam_score_int = NULL;
4452
BOOL split_spool_directory = FALSE;
4453
uschar *spool_directory = US SPOOL_DIRECTORY
4454
"\0<--------------Space to patch spool_directory->";
4455
diff -urN exim-4.34-orig/src/globals.h exim-4.34/src/globals.h
4456
--- exim-4.34-orig/src/globals.h Mon May 10 14:31:20 2004
4457
+++ exim-4.34/src/globals.h Mon May 10 16:14:47 2004
4459
extern uschar *acl_smtp_helo; /* ACL run after HELO/EHLO */
4460
extern uschar *acl_smtp_mail; /* ACL run after MAIL */
4461
extern uschar *acl_smtp_mailauth; /* ACL run after MAIL AUTH */
4462
+extern uschar *acl_smtp_mime; /* ACL run after DATA, before acl_smtp_data, for each MIME part */
4463
extern uschar *acl_smtp_rcpt; /* ACL run after RCPT */
4464
extern uschar *acl_smtp_starttls; /* ACL run after STARTTLS */
4465
extern uschar *acl_smtp_vrfy; /* ACL run after VRFY */
4466
@@ -137,12 +138,22 @@
4467
extern uschar *auth_defer_msg; /* Error message for log */
4468
extern uschar *auth_defer_user_msg; /* Error message for user */
4469
extern int auto_thaw; /* Auto-thaw interval */
4470
+extern uschar *av_scanner; /* AntiVirus scanner to use for the malware condition */
4472
extern BOOL background_daemon; /* Set FALSE to keep in foreground */
4473
extern uschar *base62_chars; /* Table of base-62 characters */
4474
extern uschar *bi_command; /* Command for -bi option */
4475
extern uschar *big_buffer; /* Used for various temp things */
4476
extern int big_buffer_size; /* Current size (can expand) */
4478
+extern uschar *bmi_alt_location; /* expansion variable that contains the alternate location for the rcpt (available during routing) */
4479
+extern uschar *bmi_base64_tracker_verdict; /* expansion variable with base-64 encoded OLD verdict string (available during routing) */
4480
+extern uschar *bmi_base64_verdict; /* expansion variable with base-64 encoded verdict string (available during routing) */
4481
+extern uschar *bmi_config_file; /* Brightmail config file */
4482
+extern int bmi_deliver; /* Flag that determines if the message should be delivered to the rcpt (available during routing) */
4483
+extern int bmi_run; /* Flag that determines if message should be run through Brightmail server */
4484
+extern uschar *bmi_verdicts; /* BASE64-encoded verdicts with recipient lists */
4486
extern int body_linecount; /* Line count in body */
4487
extern uschar *bounce_message_file; /* Template file */
4488
extern uschar *bounce_message_text; /* One-liner */
4490
extern BOOL deliver_selectstring_regex; /* String is regex */
4491
extern uschar *deliver_selectstring_sender; /* For selecting by sender */
4492
extern BOOL deliver_selectstring_sender_regex; /* String is regex */
4493
+extern int demime_errorlevel; /* Severity of MIME error */
4494
+extern int demime_ok; /* Nonzero if message has been demimed */
4495
+extern uschar *demime_reason; /* Reason for broken MIME container */
4496
extern BOOL disable_logging; /* Disables log writing when TRUE */
4498
extern uschar *dns_again_means_nonexist; /* Domains that are badly set up */
4500
extern uschar *exim_path; /* Path to exec exim */
4501
extern uid_t exim_uid; /* Non-root uid for exim */
4502
extern BOOL exim_uid_set; /* TRUE if exim_uid set */
4503
+extern uschar *exiscan_version_string; /* Exiscan version string */
4504
extern int expand_forbid; /* RDO flags for forbidding things */
4505
extern int expand_nlength[]; /* Lengths of numbered strings */
4506
extern int expand_nmax; /* Max numerical value */
4508
extern BOOL extract_addresses_remove_arguments; /* Controls -t behaviour */
4509
extern uschar *extra_local_interfaces; /* Local, non-listen interfaces */
4511
+extern BOOL fake_reject; /* TRUE if fake reject is to be given */
4512
extern int filter_n[FILTER_VARIABLE_COUNT]; /* filter variables */
4513
extern BOOL filter_running; /* TRUE while running a filter */
4514
extern int filter_sn[FILTER_VARIABLE_COUNT]; /* variables set by system filter */
4516
extern uschar *filter_thisaddress; /* For address looping */
4517
extern int finduser_retries; /* Retry count for getpwnam() */
4518
extern uid_t fixed_never_users[]; /* Can't be overridden */
4519
+extern uschar *found_extension; /* demime acl condition: file extension found */
4520
extern uschar *freeze_tell; /* Message on (some) freezings */
4521
extern uschar *fudged_queue_times; /* For use in test harness */
4525
extern macro_item *macros; /* Configuration macros */
4526
extern uschar *mailstore_basename; /* For mailstore deliveries */
4527
+extern uschar *malware_name; /* Name of virus or malware ("W32/Klez-H") */
4528
extern int max_username_length; /* For systems with broken getpwnam() */
4529
extern int message_age; /* In seconds */
4530
extern uschar *message_body; /* Start of message body for filter */
4531
@@ -361,8 +379,25 @@
4532
extern uschar *message_size_limit; /* As it says */
4533
extern uschar message_subdir[]; /* Subdirectory for messages */
4534
extern uschar *message_reference; /* Reference for error messages */
4535
+extern uschar *mime_anomaly_level;
4536
+extern uschar *mime_anomaly_text;
4537
+extern uschar *mime_boundary;
4538
+extern uschar *mime_charset;
4539
+extern uschar *mime_content_description;
4540
+extern uschar *mime_content_disposition;
4541
+extern uschar *mime_content_id;
4542
+extern unsigned int mime_content_size;
4543
+extern uschar *mime_content_transfer_encoding;
4544
+extern uschar *mime_content_type;
4545
+extern uschar *mime_decoded_filename;
4546
+extern uschar *mime_filename;
4547
+extern int mime_is_multipart;
4548
+extern int mime_is_coverletter;
4549
+extern int mime_is_rfc822;
4550
+extern int mime_part_count;
4552
extern uid_t *never_users; /* List of uids never to be used */
4553
+extern BOOL no_mbox_unspool; /* don't unspool exiscan files */
4555
extern optionlist optionlist_auths[]; /* These option lists are made */
4556
extern int optionlist_auths_size; /* global so that readconf can */
4558
extern const pcre *regex_PIPELINING; /* For recognizing PIPELINING */
4559
extern const pcre *regex_SIZE; /* For recognizing SIZE settings */
4560
extern const pcre *regex_ismsgid; /* Compiled r.e. for message it */
4561
+extern uschar *regex_match_string; /* regex that matched a line (regex ACL condition) */
4562
extern int remote_delivery_count; /* Number of remote addresses */
4563
extern int remote_max_parallel; /* Maximum parallel delivery */
4564
extern uschar *remote_sort_domains; /* Remote domain sorting order */
4565
@@ -536,6 +572,11 @@
4566
extern BOOL smtp_use_pipelining; /* Global for passed connections */
4567
extern BOOL smtp_use_size; /* Global for passed connections */
4568
extern BOOL split_spool_directory; /* TRUE to use multiple subdirs */
4569
+extern uschar *spamd_address; /* address for the spamassassin daemon */
4570
+extern uschar *spam_bar; /* the spam "bar" (textual representation of spam_score) */
4571
+extern uschar *spam_report; /* the spamd report (multiline) */
4572
+extern uschar *spam_score; /* the spam score (float) */
4573
+extern uschar *spam_score_int; /* spam_score * 10 (int) */
4574
extern uschar *spool_directory; /* Name of spool directory */
4575
extern int string_datestamp_offset;/* After insertion by string_format */
4576
extern BOOL strip_excess_angle_brackets; /* Surrounding route-addrs */
4577
diff -urN exim-4.34-orig/src/local_scan.h exim-4.34/src/local_scan.h
4578
--- exim-4.34-orig/src/local_scan.h Mon May 10 14:31:20 2004
4579
+++ exim-4.34/src/local_scan.h Mon May 10 16:14:47 2004
4581
#include "mytypes.h"
4585
/* The function and its return codes. */
4587
extern int local_scan(int, uschar **);
4589
uschar *address; /* the recipient address */
4590
int pno; /* parent number for "one_time" alias, or -1 */
4591
uschar *errors_to; /* the errors_to address or NULL */
4593
+ uschar *bmi_optin;
4598
diff -urN exim-4.34-orig/src/macros.h exim-4.34/src/macros.h
4599
--- exim-4.34-orig/src/macros.h Mon May 10 14:31:20 2004
4600
+++ exim-4.34/src/macros.h Mon May 10 16:14:47 2004
4603
enum { ACL_WHERE_AUTH, ACL_WHERE_CONNECT, ACL_WHERE_DATA, ACL_WHERE_ETRN,
4604
ACL_WHERE_EXPN, ACL_WHERE_HELO, ACL_WHERE_MAIL,
4605
- ACL_WHERE_MAILAUTH, ACL_WHERE_RCPT,
4606
+ ACL_WHERE_MAILAUTH, ACL_WHERE_MIME, ACL_WHERE_RCPT,
4607
ACL_WHERE_STARTTLS, ACL_WHERE_VRFY, ACL_WHERE_NOTSMTP };
4609
/* Situations for spool_write_header() */
4610
diff -urN exim-4.34-orig/src/malware.c exim-4.34/src/malware.c
4611
--- exim-4.34-orig/src/malware.c Thu Jan 1 01:00:00 1970
4612
+++ exim-4.34/src/malware.c Mon May 10 16:14:47 2004
4614
+/*************************************************
4615
+* Exim - an Internet mail transport agent *
4616
+*************************************************/
4618
+/* This file is part of the exiscan-acl content scanner
4619
+patch. It is NOT part of the standard exim distribution. */
4621
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
4624
+/* Code for calling virus (malware) scanners. Called from acl.c. */
4628
+/* declaration of private routines */
4629
+int mksd_scan_packed(int sock);
4630
+int mksd_scan_unpacked(int sock, int maxproc);
4632
+/* SHUT_WR seems to be undefined on Unixware ? */
4637
+#define DRWEBD_SCAN_CMD 0x0001
4638
+#define DRWEBD_RETURN_VIRUSES 0x0001
4640
+/* Routine to check whether a system is big- or litte-endian.
4641
+ Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html
4642
+ Needed for proper kavdaemon implementation. Sigh. */
4643
+#define BIG_MY_ENDIAN 0
4644
+#define LITTLE_MY_ENDIAN 1
4645
+int test_byte_order(void);
4646
+int test_byte_order() {
4647
+ short int word = 0x0001;
4648
+ char *byte = (char *) &word;
4649
+ return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
4652
+uschar malware_name_buffer[256];
4653
+int malware_ok = 0;
4655
+int malware(uschar **listptr) {
4657
+ uschar *list = *listptr;
4658
+ uschar *av_scanner_work = av_scanner;
4659
+ uschar *scanner_name;
4660
+ uschar scanner_name_buffer[16];
4661
+ uschar *malware_regex;
4662
+ uschar malware_regex_buffer[64];
4663
+ uschar malware_regex_default[] = ".+";
4664
+ unsigned long long mbox_size;
4668
+ const uschar *rerror;
4670
+ /* make sure the eml mbox file is spooled up */
4671
+ mbox_file = spool_mbox(&mbox_size);
4672
+ if (mbox_file == NULL) {
4673
+ /* error while spooling */
4674
+ log_write(0, LOG_MAIN|LOG_PANIC,
4675
+ "malware acl condition: error while creating mbox spool file");
4678
+ /* none of our current scanners need the mbox
4679
+ file as a stream, so we can close it right away */
4680
+ fclose(mbox_file);
4682
+ /* extract the malware regex to match against from the option list */
4683
+ if ((malware_regex = string_nextinlist(&list, &sep,
4684
+ malware_regex_buffer,
4685
+ sizeof(malware_regex_buffer))) != NULL) {
4687
+ /* parse 1st option */
4688
+ if ( (strcmpic(malware_regex,US"false") == 0) ||
4689
+ (Ustrcmp(malware_regex,"0") == 0) ) {
4690
+ /* explicitly no matching */
4694
+ /* special cases (match anything except empty) */
4695
+ if ( (strcmpic(malware_regex,US"true") == 0) ||
4696
+ (Ustrcmp(malware_regex,"*") == 0) ||
4697
+ (Ustrcmp(malware_regex,"1") == 0) ) {
4698
+ malware_regex = malware_regex_default;
4702
+ /* empty means "don't match anything" */
4706
+ /* compile the regex, see if it works */
4707
+ re = pcre_compile(CS malware_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
4709
+ log_write(0, LOG_MAIN|LOG_PANIC,
4710
+ "malware acl condition: regular expression error in '%s': %s at offset %d", malware_regex, rerror, roffset);
4714
+ /* Do not scan twice. */
4715
+ if (malware_ok == 0) {
4717
+ /* find the scanner type from the av_scanner option */
4718
+ if ((scanner_name = string_nextinlist(&av_scanner_work, &sep,
4719
+ scanner_name_buffer,
4720
+ sizeof(scanner_name_buffer))) == NULL) {
4721
+ /* no scanner given */
4722
+ log_write(0, LOG_MAIN|LOG_PANIC,
4723
+ "malware acl condition: av_scanner configuration variable is empty");
4727
+ /* "drweb" scanner type ----------------------------------------------- */
4728
+ /* v0.1 - added support for tcp sockets */
4729
+ /* v0.0 - initial release -- support for unix sockets */
4730
+ if (strcmpic(scanner_name,US"drweb") == 0) {
4731
+ uschar *drweb_options;
4732
+ uschar drweb_options_buffer[1024];
4733
+ uschar drweb_options_default[] = "/usr/local/drweb/run/drwebd.sock";
4734
+ struct sockaddr_un server;
4735
+ int sock, port, result, ovector[30];
4736
+ unsigned int fsize;
4737
+ uschar tmpbuf[1024], *drweb_fbuf;
4738
+ uschar scanrequest[1024];
4739
+ uschar drweb_match_string[128];
4740
+ int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd,
4741
+ drweb_vnum, drweb_slen, drweb_fin = 0x0000;
4742
+ unsigned long bread;
4743
+ uschar hostname[256];
4744
+ struct hostent *he;
4745
+ struct in_addr in;
4748
+ if ((drweb_options = string_nextinlist(&av_scanner_work, &sep,
4749
+ drweb_options_buffer, sizeof(drweb_options_buffer))) == NULL) {
4750
+ /* no options supplied, use default options */
4751
+ drweb_options = drweb_options_default;
4754
+ if (*drweb_options != '/') {
4756
+ /* extract host and port part */
4757
+ if( sscanf(CS drweb_options, "%s %u", hostname, &port) != 2 ) {
4758
+ log_write(0, LOG_MAIN|LOG_PANIC,
4759
+ "malware acl condition: drweb: invalid socket '%s'", drweb_options);
4763
+ /* Lookup the host */
4764
+ if((he = gethostbyname(CS hostname)) == 0) {
4765
+ log_write(0, LOG_MAIN|LOG_PANIC,
4766
+ "malware acl condition: drweb: failed to lookup host '%s'", hostname);
4770
+ in = *(struct in_addr *) he->h_addr_list[0];
4772
+ /* Open the drwebd TCP socket */
4773
+ if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
4774
+ log_write(0, LOG_MAIN|LOG_PANIC,
4775
+ "malware acl condition: drweb: unable to acquire socket (%s)",
4780
+ if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
4782
+ log_write(0, LOG_MAIN|LOG_PANIC,
4783
+ "malware acl condition: drweb: connection to %s, port %u failed (%s)",
4784
+ inet_ntoa(in), port, strerror(errno));
4788
+ /* prepare variables */
4789
+ drweb_cmd = htonl(DRWEBD_SCAN_CMD);
4790
+ drweb_flags = htonl(DRWEBD_RETURN_VIRUSES);
4791
+ snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml",
4792
+ spool_directory, message_id, message_id);
4794
+ /* calc file size */
4795
+ drweb_fd = open(CS scanrequest, O_RDONLY);
4796
+ if (drweb_fd == -1) {
4797
+ log_write(0, LOG_MAIN|LOG_PANIC,
4798
+ "malware acl condition: drweb: can't open spool file %s: %s",
4799
+ scanrequest, strerror(errno));
4802
+ fsize = lseek(drweb_fd, 0, SEEK_END);
4803
+ if (fsize == -1) {
4804
+ log_write(0, LOG_MAIN|LOG_PANIC,
4805
+ "malware acl condition: drweb: can't seek spool file %s: %s",
4806
+ scanrequest, strerror(errno));
4809
+ drweb_slen = htonl(fsize);
4810
+ lseek(drweb_fd, 0, SEEK_SET);
4812
+ /* send scan request */
4813
+ if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
4814
+ (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
4815
+ (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) ||
4816
+ (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0)) {
4819
+ log_write(0, LOG_MAIN|LOG_PANIC,
4820
+ "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options);
4824
+ drweb_fbuf = (uschar *) malloc (fsize);
4825
+ if (!drweb_fbuf) {
4828
+ log_write(0, LOG_MAIN|LOG_PANIC,
4829
+ "malware acl condition: drweb: unable to allocate memory %u for file (%s)",
4830
+ fsize, scanrequest);
4834
+ result = read (drweb_fd, drweb_fbuf, fsize);
4835
+ if (result == -1) {
4838
+ log_write(0, LOG_MAIN|LOG_PANIC,
4839
+ "malware acl condition: drweb: can't read spool file %s: %s",
4840
+ scanrequest, strerror(errno));
4844
+ /* send file body to socket */
4845
+ if (send(sock, drweb_fbuf, fsize, 0) < 0) {
4847
+ log_write(0, LOG_MAIN|LOG_PANIC,
4848
+ "malware acl condition: drweb: unable to send file body to socket (%s)", drweb_options);
4855
+ /* open the drwebd UNIX socket */
4856
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
4858
+ log_write(0, LOG_MAIN|LOG_PANIC,
4859
+ "malware acl condition: drweb: can't open UNIX socket");
4862
+ server.sun_family = AF_UNIX;
4863
+ Ustrcpy(server.sun_path, drweb_options);
4864
+ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
4866
+ log_write(0, LOG_MAIN|LOG_PANIC,
4867
+ "malware acl condition: drweb: unable to connect to socket (%s). errno=%d", drweb_options, errno);
4871
+ /* prepare variables */
4872
+ drweb_cmd = htonl(DRWEBD_SCAN_CMD);
4873
+ drweb_flags = htonl(DRWEBD_RETURN_VIRUSES);
4874
+ snprintf(CS scanrequest, 1024,CS"%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
4875
+ drweb_slen = htonl(Ustrlen(scanrequest));
4877
+ /* send scan request */
4878
+ if ((send(sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) ||
4879
+ (send(sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) ||
4880
+ (send(sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) ||
4881
+ (send(sock, scanrequest, Ustrlen(scanrequest), 0) < 0) ||
4882
+ (send(sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) {
4884
+ log_write(0, LOG_MAIN|LOG_PANIC,
4885
+ "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options);
4890
+ /* wait for result */
4891
+ if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) {
4893
+ log_write(0, LOG_MAIN|LOG_PANIC,
4894
+ "malware acl condition: drweb: unable to read return code");
4897
+ drweb_rc = ntohl(drweb_rc);
4899
+ if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) {
4901
+ log_write(0, LOG_MAIN|LOG_PANIC,
4902
+ "malware acl condition: drweb: unable to read the number of viruses");
4905
+ drweb_vnum = ntohl(drweb_vnum);
4907
+ /* "virus(es) found" if virus number is > 0 */
4911
+ uschar pre_malware_nb[256];
4913
+ malware_name = malware_name_buffer;
4915
+ /* setup default virus name */
4916
+ Ustrcpy(malware_name_buffer,"unknown");
4918
+ /* read and concatenate virus names into one string */
4919
+ for (i=0;i<drweb_vnum;i++)
4921
+ /* read the size of report */
4922
+ if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) {
4924
+ log_write(0, LOG_MAIN|LOG_PANIC,
4925
+ "malware acl condition: drweb: cannot read report size");
4928
+ drweb_slen = ntohl(drweb_slen);
4930
+ /* read report body */
4931
+ if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) {
4933
+ log_write(0, LOG_MAIN|LOG_PANIC,
4934
+ "malware acl condition: drweb: cannot read report string");
4937
+ tmpbuf[drweb_slen] = '\0';
4939
+ /* set up match regex, depends on retcode */
4940
+ Ustrcpy(drweb_match_string, "infected\\swith\\s*(.+?)$");
4942
+ drweb_re = pcre_compile( CS drweb_match_string,
4944
+ (const char **)&rerror,
4948
+ /* try matcher on the line, grab substring */
4949
+ result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30);
4950
+ if (result >= 2) {
4951
+ pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS pre_malware_nb, 255);
4953
+ /* the first name we just copy to malware_name */
4955
+ Ustrcpy(CS malware_name_buffer, CS pre_malware_nb);
4957
+ /* concatenate each new virus name to previous */
4958
+ int slen = Ustrlen(malware_name_buffer);
4959
+ if (slen < (slen+Ustrlen(pre_malware_nb))) {
4960
+ Ustrcat(malware_name_buffer, "/");
4961
+ Ustrcat(malware_name_buffer, pre_malware_nb);
4967
+ /* no virus found */
4968
+ malware_name = NULL;
4972
+ /* ----------------------------------------------------------------------- */
4974
+ /* "kavdaemon" scanner type ------------------------------------------------ */
4975
+ else if (strcmpic(scanner_name,US"kavdaemon") == 0) {
4976
+ uschar *kav_options;
4977
+ uschar kav_options_buffer[1024];
4978
+ uschar kav_options_default[] = "/var/run/AvpCtl";
4979
+ struct sockaddr_un server;
4982
+ uschar tmpbuf[1024];
4983
+ uschar scanrequest[1024];
4984
+ uschar kav_match_string[128];
4986
+ unsigned long kav_reportlen, bread;
4989
+ if ((kav_options = string_nextinlist(&av_scanner_work, &sep,
4990
+ kav_options_buffer,
4991
+ sizeof(kav_options_buffer))) == NULL) {
4992
+ /* no options supplied, use default options */
4993
+ kav_options = kav_options_default;
4996
+ /* open the kavdaemon socket */
4997
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
4999
+ log_write(0, LOG_MAIN|LOG_PANIC,
5000
+ "malware acl condition: can't open UNIX socket.");
5003
+ server.sun_family = AF_UNIX;
5004
+ Ustrcpy(server.sun_path, kav_options);
5005
+ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
5007
+ log_write(0, LOG_MAIN|LOG_PANIC,
5008
+ "malware acl condition: unable to connect to kavdaemon UNIX socket (%s). errno=%d", kav_options, errno);
5012
+ /* get current date and time, build scan request */
5014
+ strftime(CS tmpbuf, sizeof(tmpbuf), "<0>%d %b %H:%M:%S:%%s/scan/%%s", localtime(&t));
5015
+ snprintf(CS scanrequest, 1024,CS tmpbuf, spool_directory, message_id);
5017
+ /* send scan request */
5018
+ if (send(sock, scanrequest, Ustrlen(scanrequest)+1, 0) < 0) {
5020
+ log_write(0, LOG_MAIN|LOG_PANIC,
5021
+ "malware acl condition: unable to write to kavdaemon UNIX socket (%s)", kav_options);
5025
+ /* wait for result */
5026
+ if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) {
5028
+ log_write(0, LOG_MAIN|LOG_PANIC,
5029
+ "malware acl condition: unable to read 2 bytes from kavdaemon socket.");
5033
+ /* get errorcode from one nibble */
5034
+ if (test_byte_order() == LITTLE_MY_ENDIAN) {
5035
+ kav_rc = tmpbuf[0] & 0x0F;
5038
+ kav_rc = tmpbuf[1] & 0x0F;
5041
+ /* improper kavdaemon configuration */
5042
+ if ( (kav_rc == 5) || (kav_rc == 6) ) {
5044
+ log_write(0, LOG_MAIN|LOG_PANIC,
5045
+ "malware acl condition: please reconfigure kavdaemon to NOT disinfect or remove infected files.");
5049
+ if (kav_rc == 1) {
5051
+ log_write(0, LOG_MAIN|LOG_PANIC,
5052
+ "malware acl condition: kavdaemon reported 'scanning not completed' (code 1).");
5056
+ if (kav_rc == 7) {
5058
+ log_write(0, LOG_MAIN|LOG_PANIC,
5059
+ "malware acl condition: kavdaemon reported 'kavdaemon damaged' (code 7).");
5063
+ /* code 8 is not handled, since it is ambigous. It appears mostly on
5064
+ bounces where part of a file has been cut off */
5066
+ /* "virus found" return codes (2-4) */
5067
+ if ((kav_rc > 1) && (kav_rc < 5)) {
5068
+ int report_flag = 0;
5070
+ /* setup default virus name */
5071
+ Ustrcpy(malware_name_buffer,"unknown");
5072
+ malware_name = malware_name_buffer;
5074
+ if (test_byte_order() == LITTLE_MY_ENDIAN) {
5075
+ report_flag = tmpbuf[1];
5078
+ report_flag = tmpbuf[0];
5081
+ /* read the report, if available */
5082
+ if( report_flag == 1 ) {
5083
+ /* read report size */
5084
+ if ((bread = recv(sock, &kav_reportlen, 4, 0)) != 4) {
5086
+ log_write(0, LOG_MAIN|LOG_PANIC,
5087
+ "malware acl condition: cannot read report size from kavdaemon");
5091
+ /* it's possible that avp returns av_buffer[1] == 1 but the
5092
+ reportsize is 0 (!?) */
5093
+ if (kav_reportlen > 0) {
5094
+ /* set up match regex, depends on retcode */
5096
+ Ustrcpy(kav_match_string, "suspicion:\\s*(.+?)\\s*$");
5098
+ Ustrcpy(kav_match_string, "infected:\\s*(.+?)\\s*$");
5100
+ kav_re = pcre_compile( CS kav_match_string,
5102
+ (const char **)&rerror,
5106
+ /* read report, linewise */
5107
+ while (kav_reportlen > 0) {
5112
+ while ( recv(sock, &tmpbuf[bread], 1, 0) == 1 ) {
5114
+ if ( (tmpbuf[bread] == '\n') || (bread > 1021) ) break;
5118
+ tmpbuf[bread] = '\0';
5120
+ /* try matcher on the line, grab substring */
5121
+ result = pcre_exec(kav_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0, ovector, 30);
5122
+ if (result >= 2) {
5123
+ pcre_copy_substring(CS tmpbuf, ovector, result, 1, CS malware_name_buffer, 255);
5131
+ /* no virus found */
5132
+ malware_name = NULL;
5137
+ /* ----------------------------------------------------------------------- */
5140
+ /* "cmdline" scanner type ------------------------------------------------ */
5141
+ else if (strcmpic(scanner_name,US"cmdline") == 0) {
5142
+ uschar *cmdline_scanner;
5143
+ uschar cmdline_scanner_buffer[1024];
5144
+ uschar *cmdline_trigger;
5145
+ uschar cmdline_trigger_buffer[1024];
5146
+ const pcre *cmdline_trigger_re;
5147
+ uschar *cmdline_regex;
5148
+ uschar cmdline_regex_buffer[1024];
5149
+ const pcre *cmdline_regex_re;
5150
+ uschar file_name[1024];
5151
+ uschar commandline[1024];
5152
+ void (*eximsigchld)(int);
5153
+ void (*eximsigpipe)(int);
5154
+ FILE *scanner_out = NULL;
5155
+ FILE *scanner_record = NULL;
5156
+ uschar linebuffer[32767];
5161
+ /* find scanner command line */
5162
+ if ((cmdline_scanner = string_nextinlist(&av_scanner_work, &sep,
5163
+ cmdline_scanner_buffer,
5164
+ sizeof(cmdline_scanner_buffer))) == NULL) {
5165
+ /* no command line supplied */
5166
+ log_write(0, LOG_MAIN|LOG_PANIC,
5167
+ "malware acl condition: missing commandline specification for cmdline scanner type.");
5171
+ /* find scanner output trigger */
5172
+ if ((cmdline_trigger = string_nextinlist(&av_scanner_work, &sep,
5173
+ cmdline_trigger_buffer,
5174
+ sizeof(cmdline_trigger_buffer))) == NULL) {
5175
+ /* no trigger regex supplied */
5176
+ log_write(0, LOG_MAIN|LOG_PANIC,
5177
+ "malware acl condition: missing trigger specification for cmdline scanner type.");
5181
+ /* precompile trigger regex */
5182
+ cmdline_trigger_re = pcre_compile(CS cmdline_trigger, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
5183
+ if (cmdline_trigger_re == NULL) {
5184
+ log_write(0, LOG_MAIN|LOG_PANIC,
5185
+ "malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_trigger_re, rerror, roffset);
5189
+ /* find scanner name regex */
5190
+ if ((cmdline_regex = string_nextinlist(&av_scanner_work, &sep,
5191
+ cmdline_regex_buffer,
5192
+ sizeof(cmdline_regex_buffer))) == NULL) {
5193
+ /* no name regex supplied */
5194
+ log_write(0, LOG_MAIN|LOG_PANIC,
5195
+ "malware acl condition: missing virus name regex specification for cmdline scanner type.");
5199
+ /* precompile name regex */
5200
+ cmdline_regex_re = pcre_compile(CS cmdline_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
5201
+ if (cmdline_regex_re == NULL) {
5202
+ log_write(0, LOG_MAIN|LOG_PANIC,
5203
+ "malware acl condition: regular expression error in '%s': %s at offset %d", cmdline_regex_re, rerror, roffset);
5207
+ /* prepare scanner call */
5208
+ snprintf(CS file_name,1024,"%s/scan/%s", spool_directory, message_id);
5209
+ snprintf(CS commandline,1024, CS cmdline_scanner,file_name);
5210
+ /* redirect STDERR too */
5211
+ Ustrcat(commandline," 2>&1");
5213
+ /* store exims signal handlers */
5214
+ eximsigchld = signal(SIGCHLD,SIG_DFL);
5215
+ eximsigpipe = signal(SIGPIPE,SIG_DFL);
5217
+ scanner_out = popen(CS commandline,"r");
5218
+ if (scanner_out == NULL) {
5219
+ log_write(0, LOG_MAIN|LOG_PANIC,
5220
+ "malware acl condition: calling cmdline scanner (%s) failed: %s.", commandline, strerror(errno));
5221
+ signal(SIGCHLD,eximsigchld);
5222
+ signal(SIGPIPE,eximsigpipe);
5226
+ snprintf(CS file_name,1024,"%s/scan/%s/%s_scanner_output", spool_directory, message_id, message_id);
5227
+ scanner_record = fopen(CS file_name,"w");
5229
+ if (scanner_record == NULL) {
5230
+ log_write(0, LOG_MAIN|LOG_PANIC,
5231
+ "malware acl condition: opening scanner output file (%s) failed: %s.", file_name, strerror(errno));
5232
+ pclose(scanner_out);
5233
+ signal(SIGCHLD,eximsigchld);
5234
+ signal(SIGPIPE,eximsigpipe);
5238
+ /* look for trigger while recording output */
5239
+ while(fgets(CS linebuffer,32767,scanner_out) != NULL) {
5240
+ if ( Ustrlen(linebuffer) > fwrite(linebuffer, 1, Ustrlen(linebuffer), scanner_record) ) {
5242
+ log_write(0, LOG_MAIN|LOG_PANIC,
5243
+ "malware acl condition: short write on scanner output file (%s).", file_name);
5244
+ pclose(scanner_out);
5245
+ signal(SIGCHLD,eximsigchld);
5246
+ signal(SIGPIPE,eximsigpipe);
5249
+ /* try trigger match */
5250
+ if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1))
5254
+ fclose(scanner_record);
5255
+ pclose(scanner_out);
5256
+ signal(SIGCHLD,eximsigchld);
5257
+ signal(SIGPIPE,eximsigpipe);
5260
+ /* setup default virus name */
5261
+ Ustrcpy(malware_name_buffer,"unknown");
5262
+ malware_name = malware_name_buffer;
5264
+ /* re-open the scanner output file, look for name match */
5265
+ scanner_record = fopen(CS file_name,"r");
5266
+ while(fgets(CS linebuffer,32767,scanner_record) != NULL) {
5268
+ result = pcre_exec(cmdline_regex_re, NULL, CS linebuffer, Ustrlen(linebuffer), 0, 0, ovector, 30);
5269
+ if (result >= 2) {
5270
+ pcre_copy_substring(CS linebuffer, ovector, result, 1, CS malware_name_buffer, 255);
5273
+ fclose(scanner_record);
5276
+ /* no virus found */
5277
+ malware_name = NULL;
5280
+ /* ----------------------------------------------------------------------- */
5283
+ /* "sophie" scanner type ------------------------------------------------- */
5284
+ else if (strcmpic(scanner_name,US"sophie") == 0) {
5285
+ uschar *sophie_options;
5286
+ uschar sophie_options_buffer[1024];
5287
+ uschar sophie_options_default[] = "/var/run/sophie";
5289
+ struct sockaddr_un server;
5291
+ uschar file_name[1024];
5292
+ uschar av_buffer[1024];
5294
+ if ((sophie_options = string_nextinlist(&av_scanner_work, &sep,
5295
+ sophie_options_buffer,
5296
+ sizeof(sophie_options_buffer))) == NULL) {
5297
+ /* no options supplied, use default options */
5298
+ sophie_options = sophie_options_default;
5301
+ /* open the sophie socket */
5302
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
5304
+ log_write(0, LOG_MAIN|LOG_PANIC,
5305
+ "malware acl condition: can't open UNIX socket.");
5308
+ server.sun_family = AF_UNIX;
5309
+ Ustrcpy(server.sun_path, sophie_options);
5310
+ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
5312
+ log_write(0, LOG_MAIN|LOG_PANIC,
5313
+ "malware acl condition: unable to connect to sophie UNIX socket (%s). errno=%d", sophie_options, errno);
5317
+ /* pass the scan directory to sophie */
5318
+ snprintf(CS file_name,1024,"%s/scan/%s", spool_directory, message_id);
5319
+ if (write(sock, file_name, Ustrlen(file_name)) < 0) {
5321
+ log_write(0, LOG_MAIN|LOG_PANIC,
5322
+ "malware acl condition: unable to write to sophie UNIX socket (%s)", sophie_options);
5326
+ write(sock, "\n", 1);
5328
+ /* wait for result */
5329
+ memset(av_buffer, 0, sizeof(av_buffer));
5330
+ if ((!(bread = read(sock, av_buffer, sizeof(av_buffer))) > 0)) {
5332
+ log_write(0, LOG_MAIN|LOG_PANIC,
5333
+ "malware acl condition: unable to read from sophie UNIX socket (%s)", sophie_options);
5340
+ if (av_buffer[0] == '1') {
5341
+ if (Ustrchr(av_buffer, '\n')) *Ustrchr(av_buffer, '\n') = '\0';
5342
+ Ustrcpy(malware_name_buffer,&av_buffer[2]);
5343
+ malware_name = malware_name_buffer;
5345
+ else if (!strncmp(CS av_buffer, "-1", 2)) {
5346
+ log_write(0, LOG_MAIN|LOG_PANIC,
5347
+ "malware acl condition: malware acl condition: sophie reported error");
5351
+ /* all ok, no virus */
5352
+ malware_name = NULL;
5355
+ /* ----------------------------------------------------------------------- */
5358
+ /* "clamd" scanner type ------------------------------------------------- */
5359
+ /* This code was contributed by David Saez <david@ols.es> */
5360
+ else if (strcmpic(scanner_name,US"clamd") == 0) {
5361
+ uschar *clamd_options;
5362
+ uschar clamd_options_buffer[1024];
5363
+ uschar clamd_options_default[] = "/tmp/clamd";
5365
+ struct sockaddr_un server;
5366
+ int sock,port,bread=0;
5367
+ uschar file_name[1024];
5368
+ uschar av_buffer[1024];
5369
+ uschar hostname[256];
5370
+ struct hostent *he;
5371
+ struct in_addr in;
5373
+ if ((clamd_options = string_nextinlist(&av_scanner_work, &sep,
5374
+ clamd_options_buffer,
5375
+ sizeof(clamd_options_buffer))) == NULL) {
5376
+ /* no options supplied, use default options */
5377
+ clamd_options = clamd_options_default;
5380
+ /* socket does not start with '/' -> network socket */
5381
+ if (*clamd_options != '/') {
5383
+ /* extract host and port part */
5384
+ if( sscanf(CS clamd_options, "%s %u", hostname, &port) != 2 ) {
5385
+ log_write(0, LOG_MAIN|LOG_PANIC,
5386
+ "malware acl condition: clamd: invalid socket '%s'", clamd_options);
5390
+ /* Lookup the host */
5391
+ if((he = gethostbyname(CS hostname)) == 0) {
5392
+ log_write(0, LOG_MAIN|LOG_PANIC,
5393
+ "malware acl condition: clamd: failed to lookup host '%s'", hostname);
5397
+ in = *(struct in_addr *) he->h_addr_list[0];
5399
+ /* Open the ClamAV Socket */
5400
+ if ( (sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
5401
+ log_write(0, LOG_MAIN|LOG_PANIC,
5402
+ "malware acl condition: clamd: unable to acquire socket (%s)",
5407
+ if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
5409
+ log_write(0, LOG_MAIN|LOG_PANIC,
5410
+ "malware acl condition: clamd: connection to %s, port %u failed (%s)",
5411
+ inet_ntoa(in), port, strerror(errno));
5416
+ /* open the local socket */
5417
+ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
5418
+ log_write(0, LOG_MAIN|LOG_PANIC,
5419
+ "malware acl condition: clamd: unable to acquire socket (%s)",
5424
+ server.sun_family = AF_UNIX;
5425
+ Ustrcpy(server.sun_path, clamd_options);
5427
+ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
5429
+ log_write(0, LOG_MAIN|LOG_PANIC,
5430
+ "malware acl condition: clamd: unable to connect to UNIX socket %s (%s)",
5431
+ clamd_options, strerror(errno) );
5436
+ /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
5438
+ snprintf(CS file_name,1024,"SCAN %s/scan/%s\n", spool_directory, message_id);
5440
+ if (send(sock, file_name, Ustrlen(file_name), 0) < 0) {
5442
+ log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
5448
+ We're done sending, close socket for writing.
5450
+ One user reported that clamd 0.70 does not like this any more ...
5454
+ /* shutdown(sock, SHUT_WR); */
5456
+ /* Read the result */
5457
+ memset(av_buffer, 0, sizeof(av_buffer));
5458
+ bread = read(sock, av_buffer, sizeof(av_buffer));
5461
+ if (!(bread > 0)) {
5462
+ log_write(0, LOG_MAIN|LOG_PANIC,
5463
+ "malware acl condition: clamd: unable to read from socket (%s)",
5468
+ if (bread == sizeof(av_buffer)) {
5469
+ log_write(0, LOG_MAIN|LOG_PANIC,
5470
+ "malware acl condition: clamd: buffer too small");
5474
+ /* Check the result. ClamAV Returns
5475
+ infected: -> "<filename>: <virusname> FOUND"
5476
+ not-infected: -> "<filename>: OK"
5477
+ error: -> "<filename>: <errcode> ERROR */
5479
+ if (!(*av_buffer)) {
5480
+ log_write(0, LOG_MAIN|LOG_PANIC,
5481
+ "malware acl condition: clamd: ClamAV returned null");
5485
+ /* colon in returned output? */
5486
+ if((p = Ustrrchr(av_buffer,':')) == NULL) {
5487
+ log_write(0, LOG_MAIN|LOG_PANIC,
5488
+ "malware acl condition: clamd: ClamAV returned malformed result: %s",
5493
+ /* strip filename strip CR at the end */
5495
+ while (*p == ' ') ++p;
5497
+ p = vname + Ustrlen(vname) - 1;
5498
+ if( *p == '\n' ) *p = '\0';
5500
+ if ((p = Ustrstr(vname, "FOUND"))!=NULL) {
5502
+ for (--p;p>vname && *p<=32;p--) *p=0;
5503
+ for (;*vname==32;vname++);
5504
+ Ustrcpy(malware_name_buffer,vname);
5505
+ malware_name = malware_name_buffer;
5508
+ if (Ustrstr(vname, "ERROR")!=NULL) {
5509
+ /* ClamAV reports ERROR
5510
+ Find line start */
5511
+ for (;*vname!='\n' && vname>av_buffer; vname--);
5512
+ if (*vname=='\n') vname++;
5514
+ log_write(0, LOG_MAIN|LOG_PANIC,
5515
+ "malware acl condition: clamd: ClamAV returned %s",vname);
5519
+ /* Everything should be OK */
5520
+ malware_name = NULL;
5524
+ /* ----------------------------------------------------------------------- */
5527
+ /* "mksd" scanner type --------------------------------------------------- */
5528
+ else if (strcmpic(scanner_name,US"mksd") == 0) {
5529
+ uschar *mksd_options;
5530
+ char *mksd_options_end;
5531
+ uschar mksd_options_buffer[32];
5532
+ int mksd_maxproc = 1; /* default, if no option supplied */
5533
+ struct sockaddr_un server;
5537
+ if ((mksd_options = string_nextinlist(&av_scanner_work, &sep,
5538
+ mksd_options_buffer,
5539
+ sizeof(mksd_options_buffer))) != NULL) {
5540
+ mksd_maxproc = (int) strtol(CS mksd_options, &mksd_options_end, 10);
5541
+ if ((*mksd_options == '\0') || (*mksd_options_end != '\0') ||
5542
+ (mksd_maxproc < 1) || (mksd_maxproc > 32)) {
5543
+ log_write(0, LOG_MAIN|LOG_PANIC,
5544
+ "malware acl condition: mksd: invalid option '%s'", mksd_options);
5549
+ /* open the mksd socket */
5550
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
5552
+ log_write(0, LOG_MAIN|LOG_PANIC,
5553
+ "malware acl condition: can't open UNIX socket.");
5556
+ server.sun_family = AF_UNIX;
5557
+ Ustrcpy(server.sun_path, "/var/run/mksd/socket");
5558
+ if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
5560
+ log_write(0, LOG_MAIN|LOG_PANIC,
5561
+ "malware acl condition: unable to connect to mksd UNIX socket (/var/run/mksd/socket). errno=%d", errno);
5565
+ malware_name = NULL;
5567
+ /* choose the appropriate scan routine */
5568
+ retval = demime_ok ?
5569
+ mksd_scan_unpacked(sock, mksd_maxproc) :
5570
+ mksd_scan_packed(sock);
5575
+ /* ----------------------------------------------------------------------- */
5579
+ /* "unknown" scanner type ------------------------------------------------- */
5581
+ log_write(0, LOG_MAIN|LOG_PANIC,
5582
+ "malware condition: unknown scanner type '%s'", scanner_name);
5585
+ /* ----------------------------------------------------------------------- */
5587
+ /* set "been here, done that" marker */
5591
+ /* match virus name against pattern (caseless ------->----------v) */
5592
+ if ( (malware_name != NULL) &&
5593
+ (regex_match_and_setup(re, malware_name, 0, -1)) ) {
5601
+/* ============= private routines for the "mksd" scanner type ============== */
5603
+#include <sys/uio.h>
5605
+int mksd_writev (int sock, struct iovec *iov, int iovcnt)
5611
+ i = writev (sock, iov, iovcnt);
5612
+ while ((i < 0) && (errno == EINTR));
5615
+ log_write(0, LOG_MAIN|LOG_PANIC,
5616
+ "malware acl condition: unable to write to mksd UNIX socket (/var/run/mksd/socket)");
5621
+ if (i >= iov->iov_len) {
5622
+ if (--iovcnt == 0)
5624
+ i -= iov->iov_len;
5627
+ iov->iov_len -= i;
5628
+ iov->iov_base = CS iov->iov_base + i;
5634
+int mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size)
5640
+ if ((i = recv (sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) {
5642
+ log_write(0, LOG_MAIN|LOG_PANIC,
5643
+ "malware acl condition: unable to read from mksd UNIX socket (/var/run/mksd/socket)");
5648
+ /* offset == av_buffer_size -> buffer full */
5649
+ if (offset == av_buffer_size) {
5651
+ log_write(0, LOG_MAIN|LOG_PANIC,
5652
+ "malware acl condition: malformed reply received from mksd");
5655
+ } while (av_buffer[offset-1] != '\n');
5657
+ av_buffer[offset] = '\0';
5661
+int mksd_parse_line (char *line)
5672
+ if ((p = strchr (line, '\n')) != NULL)
5674
+ log_write(0, LOG_MAIN|LOG_PANIC,
5675
+ "malware acl condition: mksd scanner failed: %s", line);
5679
+ if ((p = strchr (line, '\n')) != NULL) {
5681
+ if (((p-line) > 5) && ((p-line) < sizeof (malware_name_buffer)) && (line[3] == ' '))
5682
+ if (((p = strchr (line+4, ' ')) != NULL) && ((p-line) > 4)) {
5684
+ Ustrcpy (malware_name_buffer, line+4);
5685
+ malware_name = malware_name_buffer;
5689
+ log_write(0, LOG_MAIN|LOG_PANIC,
5690
+ "malware acl condition: malformed reply received from mksd: %s", line);
5695
+int mksd_scan_packed (int sock)
5697
+ struct iovec iov[7];
5698
+ char *cmd = "MSQ/scan/.eml\n";
5699
+ uschar av_buffer[1024];
5701
+ iov[0].iov_base = cmd;
5702
+ iov[0].iov_len = 3;
5703
+ iov[1].iov_base = CS spool_directory;
5704
+ iov[1].iov_len = Ustrlen (spool_directory);
5705
+ iov[2].iov_base = cmd + 3;
5706
+ iov[2].iov_len = 6;
5707
+ iov[3].iov_base = iov[5].iov_base = CS message_id;
5708
+ iov[3].iov_len = iov[5].iov_len = Ustrlen (message_id);
5709
+ iov[4].iov_base = cmd + 3;
5710
+ iov[4].iov_len = 1;
5711
+ iov[6].iov_base = cmd + 9;
5712
+ iov[6].iov_len = 5;
5714
+ if (mksd_writev (sock, iov, 7) < 0)
5717
+ if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer)) < 0)
5722
+ return mksd_parse_line (CS av_buffer);
5725
+int mksd_scan_unpacked (int sock, int maxproc)
5727
+ struct iovec iov[5];
5728
+ char *cmd = "\nSQ/";
5730
+ struct dirent *entry;
5734
+ uschar mbox_name[1024];
5735
+ uschar unpackdir[1024];
5736
+ uschar av_buffer[16384];
5738
+ snprintf (CS mbox_name, sizeof (mbox_name), "%s.eml", CS message_id);
5739
+ snprintf (CS unpackdir, sizeof (unpackdir), "%s/scan/%s", CS spool_directory, CS message_id);
5741
+ if ((unpdir = opendir (CS unpackdir)) == NULL) {
5743
+ log_write(0, LOG_MAIN|LOG_PANIC,
5744
+ "malware acl condition: unable to scan spool directory");
5748
+ iov[0].iov_base = cmd;
5749
+ iov[0].iov_len = 3;
5750
+ iov[1].iov_base = CS unpackdir;
5751
+ iov[1].iov_len = Ustrlen (unpackdir);
5752
+ iov[2].iov_base = cmd + 3;
5753
+ iov[2].iov_len = 1;
5754
+ iov[4].iov_base = cmd;
5755
+ iov[4].iov_len = 1;
5758
+ while ((unpdir != NULL) || (pending > 0)) {
5761
+ while ((pending < maxproc) && (unpdir != NULL)) {
5762
+ if ((entry = readdir (unpdir)) != NULL) {
5763
+ if ((Ustrcmp (entry->d_name, ".") != 0) &&
5764
+ (Ustrcmp (entry->d_name, "..") != 0) &&
5765
+ (Ustrcmp (entry->d_name, mbox_name) != 0)) {
5766
+ iov[3].iov_base = entry->d_name;
5767
+ iov[3].iov_len = strlen (entry->d_name);
5768
+ if (mksd_writev (sock, iov, 5) < 0) {
5769
+ closedir (unpdir);
5772
+ iov[0].iov_base = cmd + 1;
5773
+ iov[0].iov_len = 2;
5777
+ closedir (unpdir);
5782
+ /* read and parse */
5783
+ if (pending > 0) {
5784
+ if ((offset = mksd_read_lines (sock, av_buffer, sizeof (av_buffer))) < 0) {
5785
+ if (unpdir != NULL)
5786
+ closedir (unpdir);
5791
+ if (((i = mksd_parse_line (CS line)) != OK) || (malware_name != NULL)) {
5793
+ if (unpdir != NULL)
5794
+ closedir (unpdir);
5798
+ if ((line = Ustrchr (line, '\n')) == NULL) {
5800
+ if (unpdir != NULL)
5801
+ closedir (unpdir);
5802
+ log_write(0, LOG_MAIN|LOG_PANIC,
5803
+ "malware acl condition: unterminated line received from mksd");
5806
+ } while (++line != (av_buffer + offset));
5814
diff -urN exim-4.34-orig/src/mime.c exim-4.34/src/mime.c
5815
--- exim-4.34-orig/src/mime.c Thu Jan 1 01:00:00 1970
5816
+++ exim-4.34/src/mime.c Mon May 10 16:14:47 2004
5818
+/*************************************************
5819
+* Exim - an Internet mail transport agent *
5820
+*************************************************/
5822
+/* This file is part of the exiscan-acl content scanner
5823
+patch. It is NOT part of the standard exim distribution. */
5825
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 */
5830
+#include <sys/stat.h>
5832
+FILE *mime_stream = NULL;
5833
+uschar *mime_current_boundary = NULL;
5836
+/*************************************************
5837
+* decode quoted-printable chars *
5838
+*************************************************/
5840
+/* gets called when we hit a =
5841
+ returns: new pointer position
5844
+ -1 - soft line break, no char
5845
+ 0-255 - char to write
5848
+unsigned int mime_qp_hstr_i(uschar *cptr) {
5849
+ unsigned int i, j = 0;
5850
+ while (cptr && *cptr && isxdigit(*cptr)) {
5851
+ i = *cptr++ - '0';
5852
+ if (9 < i) i -= 7;
5859
+uschar *mime_decode_qp_char(uschar *qp_p,int *c) {
5860
+ uschar hex[] = {0,0,0};
5862
+ uschar *initial_pos = qp_p;
5864
+ /* advance one char */
5868
+ if ( (*qp_p == '\t') || (*qp_p == ' ') || (*qp_p == '\r') ) {
5869
+ /* tab or whitespace may follow
5870
+ just ignore it, but remember
5871
+ that this is not a valid hex
5872
+ encoding any more */
5875
+ goto REPEAT_FIRST;
5877
+ else if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
5878
+ /* this is a valid hex char, if nan is unset */
5880
+ /* this is illegal */
5882
+ return initial_pos;
5889
+ else if (*qp_p == '\n') {
5890
+ /* hit soft line break already, continue */
5895
+ /* illegal char here */
5897
+ return initial_pos;
5900
+ if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
5903
+ /* do hex conversion */
5904
+ *c = mime_qp_hstr_i(hex);
5911
+ return initial_pos;
5915
+ /* illegal char */
5917
+ return initial_pos;
5922
+uschar *mime_parse_line(uschar *buffer, uschar *encoding, int *num_decoded) {
5923
+ uschar *data = NULL;
5925
+ data = (uschar *)malloc(Ustrlen(buffer)+2);
5927
+ if (encoding == NULL) {
5928
+ /* no encoding type at all */
5930
+ memcpy(data, buffer, Ustrlen(buffer));
5931
+ data[(Ustrlen(buffer))] = 0;
5932
+ *num_decoded = Ustrlen(data);
5935
+ else if (Ustrcmp(encoding,"base64") == 0) {
5936
+ uschar *p = buffer;
5939
+ /* ----- BASE64 ---------------------------------------------------- */
5940
+ /* NULL out '\r' and '\n' chars */
5941
+ while (Ustrrchr(p,'\r') != NULL) {
5942
+ *(Ustrrchr(p,'\r')) = '\0';
5944
+ while (Ustrrchr(p,'\n') != NULL) {
5945
+ *(Ustrrchr(p,'\n')) = '\0';
5948
+ while (*(p+offset) != '\0') {
5949
+ /* hit illegal char ? */
5950
+ if (mime_b64[*(p+offset)] == 128) {
5954
+ *p = mime_b64[*(p+offset)];
5960
+ /* line is translated, start bit shifting */
5963
+ while(*p != 255) {
5966
+ /* byte 0 ---------------------- */
5967
+ if (*(p+1) == 255) {
5970
+ data[(*num_decoded)] = *p;
5971
+ data[(*num_decoded)] <<= 2;
5974
+ data[(*num_decoded)] |= tmp_c;
5977
+ /* byte 1 ---------------------- */
5978
+ if (*(p+1) == 255) {
5981
+ data[(*num_decoded)] = *p;
5982
+ data[(*num_decoded)] <<= 4;
5985
+ data[(*num_decoded)] |= tmp_c;
5988
+ /* byte 2 ---------------------- */
5989
+ if (*(p+1) == 255) {
5992
+ data[(*num_decoded)] = *p;
5993
+ data[(*num_decoded)] <<= 6;
5994
+ data[(*num_decoded)] |= *(p+1);
6000
+ /* ----------------------------------------------------------------- */
6002
+ else if (Ustrcmp(encoding,"quoted-printable") == 0) {
6003
+ uschar *p = buffer;
6005
+ /* ----- QP -------------------------------------------------------- */
6009
+ int decode_qp_result;
6011
+ p = mime_decode_qp_char(p,&decode_qp_result);
6013
+ if (decode_qp_result == -2) {
6014
+ /* Error from decoder. p is unchanged. */
6015
+ data[(*num_decoded)] = '=';
6019
+ else if (decode_qp_result == -1) {
6022
+ else if (decode_qp_result >= 0) {
6023
+ data[(*num_decoded)] = decode_qp_result;
6028
+ data[(*num_decoded)] = *p;
6034
+ /* ----------------------------------------------------------------- */
6036
+ /* unknown encoding type, just dump as-is */
6037
+ else goto NO_DECODING;
6041
+FILE *mime_get_decode_file(uschar *pname, uschar *fname) {
6045
+ filename = (uschar *)malloc(2048);
6047
+ if ((pname != NULL) && (fname != NULL)) {
6048
+ snprintf(CS filename, 2048, "%s/%s", pname, fname);
6049
+ f = fopen(CS filename,"w+");
6051
+ else if (pname == NULL) {
6052
+ f = fopen(CS fname,"w+");
6054
+ else if (fname == NULL) {
6058
+ /* must find first free sequential filename */
6060
+ struct stat mystat;
6061
+ snprintf(CS filename,2048,"%s/%s-%05u", pname, message_id, file_nr);
6063
+ /* security break */
6064
+ if (file_nr >= 1024)
6066
+ result = stat(CS filename,&mystat);
6068
+ while(result != -1);
6069
+ f = fopen(CS filename,"w+");
6072
+ /* set expansion variable */
6073
+ mime_decoded_filename = filename;
6079
+int mime_decode(uschar **listptr) {
6081
+ uschar *list = *listptr;
6083
+ uschar option_buffer[1024];
6084
+ uschar decode_path[1024];
6085
+ FILE *decode_file = NULL;
6086
+ uschar *buffer = NULL;
6088
+ unsigned int size_counter = 0;
6090
+ if (mime_stream == NULL)
6093
+ f_pos = ftell(mime_stream);
6095
+ /* build default decode path (will exist since MBOX must be spooled up) */
6096
+ snprintf(CS decode_path,1024,"%s/scan/%s",spool_directory,message_id);
6098
+ /* reserve a line buffer to work in */
6099
+ buffer = (uschar *)malloc(MIME_MAX_LINE_LENGTH+1);
6100
+ if (buffer == NULL) {
6101
+ log_write(0, LOG_PANIC,
6102
+ "decode ACL condition: can't allocate %d bytes of memory.", MIME_MAX_LINE_LENGTH+1);
6106
+ /* try to find 1st option */
6107
+ if ((option = string_nextinlist(&list, &sep,
6109
+ sizeof(option_buffer))) != NULL) {
6111
+ /* parse 1st option */
6112
+ if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) {
6113
+ /* explicitly no decoding */
6117
+ if (Ustrcmp(option,"default") == 0) {
6118
+ /* explicit default path + file names */
6119
+ goto DEFAULT_PATH;
6122
+ if (option[0] == '/') {
6123
+ struct stat statbuf;
6125
+ memset(&statbuf,0,sizeof(statbuf));
6127
+ /* assume either path or path+file name */
6128
+ if ( (stat(CS option, &statbuf) == 0) && S_ISDIR(statbuf.st_mode) )
6129
+ /* is directory, use it as decode_path */
6130
+ decode_file = mime_get_decode_file(option, NULL);
6132
+ /* does not exist or is a file, use as full file name */
6133
+ decode_file = mime_get_decode_file(NULL, option);
6136
+ /* assume file name only, use default path */
6137
+ decode_file = mime_get_decode_file(decode_path, option);
6140
+ /* no option? patch default path */
6141
+ DEFAULT_PATH: decode_file = mime_get_decode_file(decode_path, NULL);
6143
+ if (decode_file == NULL)
6146
+ /* read data linewise and dump it to the file,
6147
+ while looking for the current boundary */
6148
+ while(fgets(CS buffer, MIME_MAX_LINE_LENGTH, mime_stream) != NULL) {
6149
+ uschar *decoded_line = NULL;
6150
+ int decoded_line_length = 0;
6152
+ if (mime_current_boundary != NULL) {
6153
+ /* boundary line must start with 2 dashes */
6154
+ if (Ustrncmp(buffer,"--",2) == 0) {
6155
+ if (Ustrncmp((buffer+2),mime_current_boundary,Ustrlen(mime_current_boundary)) == 0)
6160
+ decoded_line = mime_parse_line(buffer, mime_content_transfer_encoding, &decoded_line_length);
6161
+ /* write line to decode file */
6162
+ if (fwrite(decoded_line, 1, decoded_line_length, decode_file) < decoded_line_length) {
6163
+ /* error/short write */
6164
+ clearerr(mime_stream);
6165
+ fseek(mime_stream,f_pos,SEEK_SET);
6168
+ size_counter += decoded_line_length;
6170
+ if (size_counter > 1023) {
6171
+ if ((mime_content_size + (size_counter / 1024)) < 65535)
6172
+ mime_content_size += (size_counter / 1024);
6174
+ mime_content_size = 65535;
6175
+ size_counter = (size_counter % 1024);
6178
+ free(decoded_line);
6181
+ fclose(decode_file);
6183
+ clearerr(mime_stream);
6184
+ fseek(mime_stream,f_pos,SEEK_SET);
6186
+ /* round up remaining size bytes to one k */
6187
+ if (size_counter) {
6188
+ mime_content_size++;
6194
+int mime_get_header(FILE *f, uschar *header) {
6197
+ int header_value_mode = 0;
6198
+ int header_open_brackets = 0;
6199
+ int num_copied = 0;
6204
+ if (c == EOF) break;
6206
+ /* always skip CRs */
6207
+ if (c == '\r') continue;
6210
+ if (num_copied > 0) {
6211
+ /* look if next char is '\t' or ' ' */
6213
+ if (c == EOF) break;
6214
+ if ( (c == '\t') || (c == ' ') ) continue;
6217
+ /* end of the header, terminate with ';' */
6222
+ /* skip control characters */
6223
+ if (c < 32) continue;
6225
+ if (header_value_mode) {
6226
+ /* --------- value mode ----------- */
6227
+ /* skip leading whitespace */
6228
+ if ( ((c == '\t') || (c == ' ')) && (header_value_mode == 1) )
6231
+ /* we have hit a non-whitespace char, start copying value data */
6232
+ header_value_mode = 2;
6235
+ if (c == '"') continue;
6237
+ /* leave value mode on ';' */
6239
+ header_value_mode = 0;
6241
+ /* -------------------------------- */
6244
+ /* -------- non-value mode -------- */
6245
+ /* skip whitespace + tabs */
6246
+ if ( (c == ' ') || (c == '\t') )
6249
+ /* quote next char. can be used
6250
+ to escape brackets. */
6252
+ if (c == EOF) break;
6254
+ else if (c == '(') {
6255
+ header_open_brackets++;
6258
+ else if ((c == ')') && header_open_brackets) {
6259
+ header_open_brackets--;
6262
+ else if ( (c == '=') && !header_open_brackets ) {
6263
+ /* enter value mode */
6264
+ header_value_mode = 1;
6267
+ /* skip chars while we are in a comment */
6268
+ if (header_open_brackets > 0)
6270
+ /* -------------------------------- */
6273
+ /* copy the char to the buffer */
6274
+ header[num_copied] = (uschar)c;
6275
+ /* raise counter */
6278
+ /* break if header buffer is full */
6279
+ if (num_copied > MIME_MAX_HEADER_SIZE-1) {
6284
+ if (header[num_copied-1] != ';') {
6285
+ header[num_copied-1] = ';';
6289
+ header[num_copied] = '\0';
6291
+ /* return 0 for EOF or empty line */
6292
+ if ((c == EOF) || (num_copied == 1))
6299
+int mime_acl_check(FILE *f, struct mime_boundary_context *context, uschar
6300
+ **user_msgptr, uschar **log_msgptr) {
6302
+ uschar *header = NULL;
6303
+ struct mime_boundary_context nested_context;
6305
+ /* reserve a line buffer to work in */
6306
+ header = (uschar *)malloc(MIME_MAX_HEADER_SIZE+1);
6307
+ if (header == NULL) {
6308
+ log_write(0, LOG_PANIC,
6309
+ "acl_smtp_mime: can't allocate %d bytes of memory.", MIME_MAX_HEADER_SIZE+1);
6313
+ /* Not actually used at the moment, but will be vital to fixing
6314
+ * some RFC 2046 nonconformance later... */
6315
+ nested_context.parent = context;
6317
+ /* loop through parts */
6320
+ /* reset all per-part mime variables */
6321
+ mime_anomaly_level = NULL;
6322
+ mime_anomaly_text = NULL;
6323
+ mime_boundary = NULL;
6324
+ mime_charset = NULL;
6325
+ mime_decoded_filename = NULL;
6326
+ mime_filename = NULL;
6327
+ mime_content_description = NULL;
6328
+ mime_content_disposition = NULL;
6329
+ mime_content_id = NULL;
6330
+ mime_content_transfer_encoding = NULL;
6331
+ mime_content_type = NULL;
6332
+ mime_is_multipart = 0;
6333
+ mime_content_size = 0;
6336
+ If boundary is null, we assume that *f is positioned on the start of headers (for example,
6337
+ at the very beginning of a message.
6338
+ If a boundary is given, we must first advance to it to reach the start of the next header
6342
+ /* NOTE -- there's an error here -- RFC2046 specifically says to
6343
+ * check for outer boundaries. This code doesn't do that, and
6344
+ * I haven't fixed this.
6346
+ * (I have moved partway towards adding support, however, by adding
6347
+ * a "parent" field to my new boundary-context structure.)
6349
+ if (context != NULL) {
6350
+ while(fgets(CS header, MIME_MAX_HEADER_SIZE, f) != NULL) {
6351
+ /* boundary line must start with 2 dashes */
6352
+ if (Ustrncmp(header,"--",2) == 0) {
6353
+ if (Ustrncmp((header+2),context->boundary,Ustrlen(context->boundary)) == 0) {
6354
+ /* found boundary */
6355
+ if (Ustrncmp((header+2+Ustrlen(context->boundary)),"--",2) == 0) {
6356
+ /* END boundary found */
6357
+ debug_printf("End boundary found %s\n", context->boundary);
6361
+ debug_printf("Next part with boundary %s\n", context->boundary);
6363
+ /* can't use break here */
6364
+ goto DECODE_HEADERS;
6368
+ /* Hit EOF or read error. Ugh. */
6369
+ debug_printf("Hit EOF ...\n");
6374
+ /* parse headers, set up expansion variables */
6375
+ while(mime_get_header(f,header)) {
6377
+ /* loop through header list */
6378
+ for (i = 0; i < mime_header_list_size; i++) {
6379
+ uschar *header_value = NULL;
6380
+ int header_value_len = 0;
6382
+ /* found an interesting header? */
6383
+ if (strncmpic(mime_header_list[i].name,header,mime_header_list[i].namelen) == 0) {
6384
+ uschar *p = header + mime_header_list[i].namelen;
6385
+ /* yes, grab the value (normalize to lower case)
6386
+ and copy to its corresponding expansion variable */
6387
+ while(*p != ';') {
6391
+ header_value_len = (p - (header + mime_header_list[i].namelen));
6392
+ header_value = (uschar *)malloc(header_value_len+1);
6393
+ memset(header_value,0,header_value_len+1);
6394
+ p = header + mime_header_list[i].namelen;
6395
+ Ustrncpy(header_value, p, header_value_len);
6396
+ debug_printf("Found %s MIME header, value is '%s'\n", mime_header_list[i].name, header_value);
6397
+ *((uschar **)(mime_header_list[i].value)) = header_value;
6399
+ /* make p point to the next character after the closing ';' */
6400
+ p += (header_value_len+1);
6402
+ /* grab all param=value tags on the remaining line, check if they are interesting */
6403
+ NEXT_PARAM_SEARCH: while (*p != 0) {
6405
+ for (j = 0; j < mime_parameter_list_size; j++) {
6406
+ uschar *param_value = NULL;
6407
+ int param_value_len = 0;
6409
+ /* found an interesting parameter? */
6410
+ if (strncmpic(mime_parameter_list[j].name,p,mime_parameter_list[j].namelen) == 0) {
6411
+ uschar *q = p + mime_parameter_list[j].namelen;
6412
+ /* yes, grab the value and copy to its corresponding expansion variable */
6413
+ while(*q != ';') q++;
6414
+ param_value_len = (q - (p + mime_parameter_list[j].namelen));
6415
+ param_value = (uschar *)malloc(param_value_len+1);
6416
+ memset(param_value,0,param_value_len+1);
6417
+ q = p + mime_parameter_list[j].namelen;
6418
+ Ustrncpy(param_value, q, param_value_len);
6419
+ param_value = rfc2047_decode(param_value, TRUE, NULL, 32, ¶m_value_len, &q);
6420
+ debug_printf("Found %s MIME parameter in %s header, value is '%s'\n", mime_parameter_list[j].name, mime_header_list[i].name, param_value);
6421
+ *((uschar **)(mime_parameter_list[j].value)) = param_value;
6422
+ p += (mime_parameter_list[j].namelen + param_value_len + 1);
6423
+ goto NEXT_PARAM_SEARCH;
6426
+ /* There is something, but not one of our interesting parameters.
6427
+ Advance to the next semicolon */
6428
+ while(*p != ';') p++;
6435
+ /* set additional flag variables (easier access) */
6436
+ if ( (mime_content_type != NULL) &&
6437
+ (Ustrncmp(mime_content_type,"multipart",9) == 0) )
6438
+ mime_is_multipart = 1;
6440
+ /* Make a copy of the boundary pointer.
6441
+ Required since mime_boundary is global
6442
+ and can be overwritten further down in recursion */
6443
+ nested_context.boundary = mime_boundary;
6445
+ /* raise global counter */
6446
+ mime_part_count++;
6448
+ /* copy current file handle to global variable */
6450
+ mime_current_boundary = context ? context->boundary : 0;
6452
+ /* Note the context */
6453
+ mime_is_coverletter = !(context && context->context == MBC_ATTACHMENT);
6455
+ /* call ACL handling function */
6456
+ rc = acl_check(ACL_WHERE_MIME, NULL, acl_smtp_mime, user_msgptr, log_msgptr);
6458
+ mime_stream = NULL;
6459
+ mime_current_boundary = NULL;
6461
+ if (rc != OK) break;
6463
+ /* If we have a multipart entity and a boundary, go recursive */
6464
+ if ( (mime_content_type != NULL) &&
6465
+ (nested_context.boundary != NULL) &&
6466
+ (Ustrncmp(mime_content_type,"multipart",9) == 0) ) {
6467
+ debug_printf("Entering multipart recursion, boundary '%s'\n", nested_context.boundary);
6469
+ if (context && context->context == MBC_ATTACHMENT)
6470
+ nested_context.context = MBC_ATTACHMENT;
6471
+ else if (!Ustrcmp(mime_content_type,"multipart/alternative")
6472
+ || !Ustrcmp(mime_content_type,"multipart/related"))
6473
+ nested_context.context = MBC_COVERLETTER_ALL;
6475
+ nested_context.context = MBC_COVERLETTER_ONESHOT;
6477
+ rc = mime_acl_check(f, &nested_context, user_msgptr, log_msgptr);
6478
+ if (rc != OK) break;
6480
+ else if ( (mime_content_type != NULL) &&
6481
+ (Ustrncmp(mime_content_type,"message/rfc822",14) == 0) ) {
6482
+ uschar *rfc822name = NULL;
6483
+ uschar filename[2048];
6487
+ /* must find first free sequential filename */
6489
+ struct stat mystat;
6490
+ snprintf(CS filename,2048,"%s/scan/%s/__rfc822_%05u", spool_directory, message_id, file_nr);
6492
+ /* security break */
6493
+ if (file_nr >= 128)
6495
+ result = stat(CS filename,&mystat);
6497
+ while(result != -1);
6499
+ rfc822name = filename;
6501
+ /* decode RFC822 attachment */
6502
+ mime_decoded_filename = NULL;
6504
+ mime_current_boundary = context ? context->boundary : NULL;
6505
+ mime_decode(&rfc822name);
6506
+ mime_stream = NULL;
6507
+ mime_current_boundary = NULL;
6508
+ if (mime_decoded_filename == NULL) {
6509
+ /* decoding failed */
6510
+ log_write(0, LOG_MAIN,
6511
+ "mime_regex acl condition warning - could not decode RFC822 MIME part to file.");
6514
+ mime_decoded_filename = NULL;
6518
+ /* If the boundary of this instance is NULL, we are finished here */
6519
+ if (context == NULL) break;
6521
+ if (context->context == MBC_COVERLETTER_ONESHOT)
6522
+ context->context = MBC_ATTACHMENT;
6530
diff -urN exim-4.34-orig/src/mime.h exim-4.34/src/mime.h
6531
--- exim-4.34-orig/src/mime.h Thu Jan 1 01:00:00 1970
6532
+++ exim-4.34/src/mime.h Mon May 10 16:14:47 2004
6534
+/*************************************************
6535
+* Exim - an Internet mail transport agent *
6536
+*************************************************/
6538
+/* This file is part of the exiscan-acl content scanner
6539
+patch. It is NOT part of the standard exim distribution. */
6541
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 */
6545
+#define MIME_MAX_HEADER_SIZE 8192
6546
+#define MIME_MAX_LINE_LENGTH 32768
6548
+#define MBC_ATTACHMENT 0
6549
+#define MBC_COVERLETTER_ONESHOT 1
6550
+#define MBC_COVERLETTER_ALL 2
6552
+struct mime_boundary_context
6554
+ struct mime_boundary_context *parent;
6555
+ unsigned char *boundary;
6559
+typedef struct mime_header {
6565
+static mime_header mime_header_list[] = {
6566
+ { US"content-type:", 13, &mime_content_type },
6567
+ { US"content-disposition:", 20, &mime_content_disposition },
6568
+ { US"content-transfer-encoding:", 26, &mime_content_transfer_encoding },
6569
+ { US"content-id:", 11, &mime_content_id },
6570
+ { US"content-description:", 20 , &mime_content_description }
6573
+static int mime_header_list_size = sizeof(mime_header_list)/sizeof(mime_header);
6577
+typedef struct mime_parameter {
6583
+static mime_parameter mime_parameter_list[] = {
6584
+ { US"name=", 5, &mime_filename },
6585
+ { US"filename=", 9, &mime_filename },
6586
+ { US"charset=", 8, &mime_charset },
6587
+ { US"boundary=", 9, &mime_boundary }
6590
+static int mime_parameter_list_size = sizeof(mime_parameter_list)/sizeof(mime_parameter);
6592
+/* BASE64 decoder matrix */
6593
+static unsigned char mime_b64[256]={
6594
+/* 0 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6595
+/* 16 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6596
+/* 32 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 62, 128, 128, 128, 63,
6597
+/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 255, 128, 128,
6598
+/* 64 */ 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
6599
+/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 128, 128, 128, 128, 128,
6600
+/* 96 */ 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
6601
+/* 112 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128,
6602
+/* 128 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6603
+/* 144 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6604
+/* 160 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6605
+/* 176 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6606
+/* 192 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6607
+/* 208 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6608
+/* 224 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
6609
+/* 240 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
6611
diff -urN exim-4.34-orig/src/readconf.c exim-4.34/src/readconf.c
6612
--- exim-4.34-orig/src/readconf.c Mon May 10 14:31:20 2004
6613
+++ exim-4.34/src/readconf.c Mon May 10 16:14:47 2004
6615
{ "acl_smtp_helo", opt_stringptr, &acl_smtp_helo },
6616
{ "acl_smtp_mail", opt_stringptr, &acl_smtp_mail },
6617
{ "acl_smtp_mailauth", opt_stringptr, &acl_smtp_mailauth },
6618
+ { "acl_smtp_mime", opt_stringptr, &acl_smtp_mime },
6619
{ "acl_smtp_rcpt", opt_stringptr, &acl_smtp_rcpt },
6621
{ "acl_smtp_starttls", opt_stringptr, &acl_smtp_starttls },
6622
@@ -152,7 +153,11 @@
6623
{ "allow_utf8_domains", opt_bool, &allow_utf8_domains },
6624
{ "auth_advertise_hosts", opt_stringptr, &auth_advertise_hosts },
6625
{ "auto_thaw", opt_time, &auto_thaw },
6626
+ { "av_scanner", opt_stringptr, &av_scanner },
6627
{ "bi_command", opt_stringptr, &bi_command },
6629
+ { "bmi_config_file", opt_stringptr, &bmi_config_file },
6631
{ "bounce_message_file", opt_stringptr, &bounce_message_file },
6632
{ "bounce_message_text", opt_stringptr, &bounce_message_text },
6633
{ "bounce_return_body", opt_bool, &bounce_return_body },
6635
{ "smtp_receive_timeout", opt_time, &smtp_receive_timeout },
6636
{ "smtp_reserve_hosts", opt_stringptr, &smtp_reserve_hosts },
6637
{ "smtp_return_error_details",opt_bool, &smtp_return_error_details },
6638
+ { "spamd_address", opt_stringptr, &spamd_address },
6639
{ "split_spool_directory", opt_bool, &split_spool_directory },
6640
{ "spool_directory", opt_stringptr, &spool_directory },
6641
{ "strip_excess_angle_brackets", opt_bool, &strip_excess_angle_brackets },
6642
diff -urN exim-4.34-orig/src/receive.c exim-4.34/src/receive.c
6643
--- exim-4.34-orig/src/receive.c Mon May 10 14:31:20 2004
6644
+++ exim-4.34/src/receive.c Mon May 10 16:14:47 2004
6651
+#include "bmi_spam.h"
6654
/*************************************************
6655
* Local static variables *
6656
@@ -436,6 +438,13 @@
6658
recipients_list[recipients_count].address = recipient;
6659
recipients_list[recipients_count].pno = pno;
6662
+recipients_list[recipients_count].bmi_optin = bmi_current_optin;
6663
+/* reset optin string pointer for next recipient */
6664
+bmi_current_optin = NULL;
6667
recipients_list[recipients_count++].errors_to = NULL;
6670
@@ -2530,6 +2539,124 @@
6672
if (smtp_input && !smtp_batched_input)
6674
+ if (acl_smtp_mime != NULL && recipients_count > 0)
6677
+ uschar rfc822_file_path[2048];
6678
+ unsigned long long mbox_size;
6679
+ header_line *my_headerlist;
6680
+ uschar *user_msg, *log_msg;
6681
+ int mime_part_count_buffer = -1;
6683
+ memset(CS rfc822_file_path,0,2048);
6685
+ /* check if it is a MIME message */
6686
+ my_headerlist = header_list;
6687
+ while (my_headerlist != NULL) {
6688
+ /* skip deleted headers */
6689
+ if (my_headerlist->type == '*') {
6690
+ my_headerlist = my_headerlist->next;
6693
+ if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0) {
6694
+ DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n");
6697
+ my_headerlist = my_headerlist->next;
6700
+ DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
6704
+ /* make sure the eml mbox file is spooled up */
6705
+ mbox_file = spool_mbox(&mbox_size);
6706
+ if (mbox_file == NULL) {
6707
+ /* error while spooling */
6708
+ log_write(0, LOG_MAIN|LOG_PANIC,
6709
+ "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected.");
6710
+ Uunlink(spool_name);
6712
+ smtp_respond(451, TRUE, US"temporary local problem");
6713
+ message_id[0] = 0; /* Indicate no message accepted */
6714
+ smtp_reply = US""; /* Indicate reply already sent */
6715
+ goto TIDYUP; /* Skip to end of function */
6718
+ mime_is_rfc822 = 0;
6721
+ mime_part_count = -1;
6722
+ rc = mime_acl_check(mbox_file, NULL, &user_msg, &log_msg);
6723
+ fclose(mbox_file);
6725
+ if (Ustrlen(rfc822_file_path) > 0) {
6726
+ mime_part_count = mime_part_count_buffer;
6728
+ if (unlink(CS rfc822_file_path) == -1) {
6729
+ log_write(0, LOG_PANIC,
6730
+ "acl_smtp_mime: can't unlink RFC822 spool file, skipping.");
6731
+ goto END_MIME_ACL;
6735
+ /* check if we must check any message/rfc822 attachments */
6737
+ uschar temp_path[1024];
6739
+ struct dirent *entry;
6742
+ snprintf(CS temp_path, 1024, "%s/scan/%s", spool_directory, message_id);
6744
+ tempdir = opendir(CS temp_path);
6747
+ entry = readdir(tempdir);
6748
+ if (entry == NULL) break;
6749
+ if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0) {
6750
+ snprintf(CS rfc822_file_path, 2048,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name);
6751
+ debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path);
6755
+ closedir(tempdir);
6757
+ if (entry != NULL) {
6758
+ mbox_file = Ufopen(rfc822_file_path,"r");
6759
+ if (mbox_file == NULL) {
6760
+ log_write(0, LOG_PANIC,
6761
+ "acl_smtp_mime: can't open RFC822 spool file, skipping.");
6762
+ unlink(CS rfc822_file_path);
6763
+ goto END_MIME_ACL;
6765
+ /* set RFC822 expansion variable */
6766
+ mime_is_rfc822 = 1;
6767
+ mime_part_count_buffer = mime_part_count;
6768
+ goto MIME_ACL_CHECK;
6773
+ add_acl_headers(US"MIME");
6774
+ if (rc == DISCARD)
6776
+ recipients_count = 0;
6777
+ blackholed_by = US"MIME ACL";
6779
+ else if (rc != OK)
6781
+ Uunlink(spool_name);
6783
+ if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0)
6784
+ smtp_yield = FALSE; /* No more messsages after dropped connection */
6785
+ smtp_reply = US""; /* Indicate reply already sent */
6786
+ message_id[0] = 0; /* Indicate no message accepted */
6787
+ goto TIDYUP; /* Skip to end of function */
6792
if (acl_smtp_data != NULL && recipients_count > 0)
6794
uschar *user_msg, *log_msg;
6795
@@ -2543,6 +2670,7 @@
6798
Uunlink(spool_name);
6800
if (smtp_handle_acl_fail(ACL_WHERE_DATA, rc, user_msg, log_msg) != 0)
6801
smtp_yield = FALSE; /* No more messsages after dropped connection */
6802
smtp_reply = US""; /* Indicate reply already sent */
6803
@@ -2552,6 +2680,7 @@
6808
/* Handle non-SMTP and batch SMTP (i.e. non-interactive) messages. Note that
6809
we cannot take different actions for permanent and temporary rejections. */
6811
@@ -2592,6 +2721,8 @@
6812
enable_dollar_recipients = FALSE;
6817
/* The final check on the message is to run the scan_local() function. The
6818
version supplied with Exim always accepts, but this is a hook for sysadmins to
6819
supply their own checking code. The local_scan() function is run even when all
6820
@@ -2769,6 +2900,16 @@
6821
timestamp = expand_string(US"${tod_full}");
6822
memcpy(header_list->text + received_length + 2, timestamp, Ustrlen(timestamp));
6826
+if (bmi_run == 1) {
6827
+ /* rewind data file */
6828
+ lseek(data_fd, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
6829
+ bmi_verdicts = bmi_process_message(header_list, data_fd);
6834
/* Keep the data file open until we have written the header file, in order to
6835
hold onto the lock. In a -bh run, or if the message is to be blackholed, we
6836
don't write the header file, and we unlink the data file. If writing the header
6837
@@ -3011,6 +3152,7 @@
6842
process_info[process_info_len] = 0; /* Remove message id */
6843
if (data_file != NULL) fclose(data_file); /* Frees the lock */
6845
@@ -3037,12 +3179,31 @@
6847
if (smtp_reply == NULL)
6849
- smtp_printf("250 OK id=%s\r\n", message_id);
6852
+ smtp_printf("550-FAKE_REJECT id=%s\r\n", message_id);
6853
+ smtp_printf("550-Your message has been rejected but is being kept for evaluation.\r\n");
6854
+ smtp_printf("550 If it was a legit message, it may still be delivered to the target recipient(s).\r\n");
6857
+ smtp_printf("250 OK id=%s\r\n", message_id);
6861
"\n**** SMTP testing: that is not a real message id!\n\n");
6864
- else if (smtp_reply[0] != 0) smtp_printf("%.1024s\r\n", smtp_reply);
6865
+ else if (smtp_reply[0] != 0)
6867
+ if (fake_reject && (smtp_reply[0] == '2'))
6869
+ smtp_printf("550-FAKE_REJECT id=%s\r\n", message_id);
6870
+ smtp_printf("550-Your message has been rejected but is being kept for evaluation.\r\n");
6871
+ smtp_printf("550 If it was a legit message, it may still be delivered to the target recipient(s).\r\n");
6874
+ smtp_printf("%.1024s\r\n", smtp_reply);
6878
/* For batched SMTP, generate an error message on failure, and do
6879
diff -urN exim-4.34-orig/src/regex.c exim-4.34/src/regex.c
6880
--- exim-4.34-orig/src/regex.c Thu Jan 1 01:00:00 1970
6881
+++ exim-4.34/src/regex.c Mon May 10 16:14:47 2004
6883
+/*************************************************
6884
+* Exim - an Internet mail transport agent *
6885
+*************************************************/
6887
+/* This file is part of the exiscan-acl content scanner
6888
+patch. It is NOT part of the standard exim distribution. */
6890
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
6893
+/* Code for matching regular expressions against headers and body.
6894
+ Called from acl.c. */
6897
+#include <unistd.h>
6898
+#include <sys/mman.h>
6900
+/* Structure to hold a list of Regular expressions */
6901
+typedef struct pcre_list {
6903
+ uschar *pcre_text;
6904
+ struct pcre_list *next;
6907
+uschar regex_match_string_buffer[1024];
6909
+extern FILE *mime_stream;
6910
+extern uschar *mime_current_boundary;
6912
+int regex(uschar **listptr) {
6914
+ uschar *list = *listptr;
6915
+ uschar *regex_string;
6916
+ uschar regex_string_buffer[1024];
6917
+ unsigned long long mbox_size;
6920
+ pcre_list *re_list_head = NULL;
6921
+ pcre_list *re_list_item;
6922
+ const char *pcre_error;
6923
+ int pcre_erroffset;
6924
+ uschar *linebuffer;
6927
+ /* reset expansion variable */
6928
+ regex_match_string = NULL;
6930
+ if (mime_stream == NULL) {
6931
+ /* We are in the DATA ACL */
6932
+ mbox_file = spool_mbox(&mbox_size);
6933
+ if (mbox_file == NULL) {
6934
+ /* error while spooling */
6935
+ log_write(0, LOG_MAIN|LOG_PANIC,
6936
+ "regex acl condition: error while creating mbox spool file");
6941
+ f_pos = ftell(mime_stream);
6942
+ mbox_file = mime_stream;
6945
+ /* precompile our regexes */
6946
+ while ((regex_string = string_nextinlist(&list, &sep,
6947
+ regex_string_buffer,
6948
+ sizeof(regex_string_buffer))) != NULL) {
6950
+ /* parse option */
6951
+ if ( (strcmpic(regex_string,US"false") == 0) ||
6952
+ (Ustrcmp(regex_string,"0") == 0) ) {
6953
+ /* explicitly no matching */
6957
+ /* compile our regular expression */
6958
+ re = pcre_compile( CS regex_string,
6965
+ log_write(0, LOG_MAIN,
6966
+ "regex acl condition warning - error in regex '%s': %s at offset %d, skipped.", regex_string, pcre_error, pcre_erroffset);
6970
+ re_list_item = store_get(sizeof(pcre_list));
6971
+ re_list_item->re = re;
6972
+ re_list_item->pcre_text = string_copy(regex_string);
6973
+ re_list_item->next = re_list_head;
6974
+ re_list_head = re_list_item;
6978
+ /* no regexes -> nothing to do */
6979
+ if (re_list_head == NULL) {
6983
+ /* match each line against all regexes */
6984
+ linebuffer = store_get(32767);
6985
+ while (fgets(CS linebuffer, 32767, mbox_file) != NULL) {
6986
+ if ( (mime_stream != NULL) && (mime_current_boundary != NULL) ) {
6987
+ /* check boundary */
6988
+ if (Ustrncmp(linebuffer,"--",2) == 0) {
6989
+ if (Ustrncmp((linebuffer+2),mime_current_boundary,Ustrlen(mime_current_boundary)) == 0)
6990
+ /* found boundary */
6994
+ re_list_item = re_list_head;
6996
+ /* try matcher on the line */
6997
+ if (pcre_exec(re_list_item->re, NULL, CS linebuffer,
6998
+ (int)Ustrlen(linebuffer), 0, 0, NULL, 0) >= 0) {
6999
+ Ustrncpy(regex_match_string_buffer, re_list_item->pcre_text, 1023);
7000
+ regex_match_string = regex_match_string_buffer;
7001
+ if (mime_stream == NULL)
7002
+ fclose(mbox_file);
7004
+ clearerr(mime_stream);
7005
+ fseek(mime_stream,f_pos,SEEK_SET);
7009
+ re_list_item = re_list_item->next;
7010
+ } while (re_list_item != NULL);
7013
+ if (mime_stream == NULL)
7014
+ fclose(mbox_file);
7016
+ clearerr(mime_stream);
7017
+ fseek(mime_stream,f_pos,SEEK_SET);
7020
+ /* no matches ... */
7025
+int mime_regex(uschar **listptr) {
7027
+ uschar *list = *listptr;
7028
+ uschar *regex_string;
7029
+ uschar regex_string_buffer[1024];
7031
+ pcre_list *re_list_head = NULL;
7032
+ pcre_list *re_list_item;
7033
+ const char *pcre_error;
7034
+ int pcre_erroffset;
7036
+ uschar *mime_subject = NULL;
7037
+ int mime_subject_len = 0;
7039
+ /* reset expansion variable */
7040
+ regex_match_string = NULL;
7042
+ /* precompile our regexes */
7043
+ while ((regex_string = string_nextinlist(&list, &sep,
7044
+ regex_string_buffer,
7045
+ sizeof(regex_string_buffer))) != NULL) {
7047
+ /* parse option */
7048
+ if ( (strcmpic(regex_string,US"false") == 0) ||
7049
+ (Ustrcmp(regex_string,"0") == 0) ) {
7050
+ /* explicitly no matching */
7054
+ /* compile our regular expression */
7055
+ re = pcre_compile( CS regex_string,
7062
+ log_write(0, LOG_MAIN,
7063
+ "regex acl condition warning - error in regex '%s': %s at offset %d, skipped.", regex_string, pcre_error, pcre_erroffset);
7067
+ re_list_item = store_get(sizeof(pcre_list));
7068
+ re_list_item->re = re;
7069
+ re_list_item->pcre_text = string_copy(regex_string);
7070
+ re_list_item->next = re_list_head;
7071
+ re_list_head = re_list_item;
7075
+ /* no regexes -> nothing to do */
7076
+ if (re_list_head == NULL) {
7080
+ /* check if the file is already decoded */
7081
+ if (mime_decoded_filename == NULL) {
7082
+ uschar *empty = US"";
7083
+ /* no, decode it first */
7084
+ mime_decode(&empty);
7085
+ if (mime_decoded_filename == NULL) {
7086
+ /* decoding failed */
7087
+ log_write(0, LOG_MAIN,
7088
+ "mime_regex acl condition warning - could not decode MIME part to file.");
7095
+ f = fopen(CS mime_decoded_filename, "r");
7098
+ log_write(0, LOG_MAIN,
7099
+ "mime_regex acl condition warning - can't open '%s' for reading.", mime_decoded_filename);
7103
+ /* get 32k memory */
7104
+ mime_subject = (uschar *)store_get(32767);
7106
+ /* read max 32k chars from file */
7107
+ mime_subject_len = fread(mime_subject, 1, 32766, f);
7109
+ re_list_item = re_list_head;
7111
+ /* try matcher on the mmapped file */
7112
+ debug_printf("Matching '%s'\n", re_list_item->pcre_text);
7113
+ if (pcre_exec(re_list_item->re, NULL, CS mime_subject,
7114
+ mime_subject_len, 0, 0, NULL, 0) >= 0) {
7115
+ Ustrncpy(regex_match_string_buffer, re_list_item->pcre_text, 1023);
7116
+ regex_match_string = regex_match_string_buffer;
7120
+ re_list_item = re_list_item->next;
7121
+ } while (re_list_item != NULL);
7125
+ /* no matches ... */
7129
diff -urN exim-4.34-orig/src/route.c exim-4.34/src/route.c
7130
--- exim-4.34-orig/src/route.c Mon May 10 14:31:20 2004
7131
+++ exim-4.34/src/route.c Mon May 10 16:14:47 2004
7137
+#include "bmi_spam.h"
7141
/* Generic options for routers, all of which live inside router_instance
7143
(void *)(offsetof(router_instance, address_data)) },
7144
{ "address_test", opt_bool|opt_public,
7145
(void *)(offsetof(router_instance, address_test)) },
7147
+ { "bmi_deliver_alternate", opt_bool | opt_public,
7148
+ (void *)(offsetof(router_instance, bmi_deliver_alternate)) },
7149
+ { "bmi_deliver_default", opt_bool | opt_public,
7150
+ (void *)(offsetof(router_instance, bmi_deliver_default)) },
7151
+ { "bmi_dont_deliver", opt_bool | opt_public,
7152
+ (void *)(offsetof(router_instance, bmi_dont_deliver)) },
7153
+ { "bmi_rule", opt_stringptr|opt_public,
7154
+ (void *)(offsetof(router_instance, bmi_rule)) },
7156
{ "cannot_route_message", opt_stringptr | opt_public,
7157
(void *)(offsetof(router_instance, cannot_route_message)) },
7158
{ "caseful_local_part", opt_bool | opt_public,
7159
@@ -980,6 +993,49 @@
7165
+/* check if a specific Brightmail AntiSpam rule fired on the message */
7166
+if (r->bmi_rule != NULL) {
7167
+ DEBUG(D_route) debug_printf("checking bmi_rule\n");
7168
+ if (bmi_check_rule(bmi_base64_verdict, r->bmi_rule) == 0) {
7169
+ /* none of the rules fired */
7171
+ debug_printf("%s router skipped: none of bmi_rule rules fired\n", r->name);
7176
+/* check if message should not be delivered */
7177
+if (r->bmi_dont_deliver) {
7178
+ if (bmi_deliver == 1) {
7180
+ debug_printf("%s router skipped: bmi_dont_deliver is FALSE\n", r->name);
7185
+/* check if message should go to an alternate location */
7186
+if (r->bmi_deliver_alternate) {
7187
+ if ((bmi_deliver == 0) || (bmi_alt_location == NULL)) {
7189
+ debug_printf("%s router skipped: bmi_deliver_alternate is FALSE\n", r->name);
7194
+/* check if message should go to default location */
7195
+if (r->bmi_deliver_default) {
7196
+ if ((bmi_deliver == 0) || (bmi_alt_location != NULL)) {
7198
+ debug_printf("%s router skipped: bmi_deliver_default is FALSE\n", r->name);
7206
/* All the checks passed. */
7209
diff -urN exim-4.34-orig/src/smtp_in.c exim-4.34/src/smtp_in.c
7210
--- exim-4.34-orig/src/smtp_in.c Mon May 10 14:31:20 2004
7211
+++ exim-4.34/src/smtp_in.c Mon May 10 16:14:47 2004
7213
acl_warn_headers = NULL;
7214
queue_only_policy = FALSE;
7215
deliver_freeze = FALSE; /* Can be set by ACL */
7216
+fake_reject = FALSE; /* Can be set by ACL */
7217
+no_mbox_unspool = FALSE; /* Can be set by ACL */
7218
sender_address = NULL;
7219
raw_sender = NULL; /* After SMTP rewrite, before qualifying */
7220
sender_address_unrewritten = NULL; /* Set only after verify rewrite */
7221
@@ -797,6 +799,10 @@
7222
memset(sender_address_cache, 0, sizeof(sender_address_cache));
7223
memset(sender_domain_cache, 0, sizeof(sender_domain_cache));
7224
authenticated_sender = NULL;
7227
+bmi_verdicts = NULL;
7230
for (i = 0; i < ACL_M_MAX; i++) acl_var[ACL_C_MAX + i] = NULL;
7232
@@ -1747,8 +1753,10 @@
7233
BOOL drop = rc == FAIL_DROP;
7235
uschar *sender_info = US"";
7236
-uschar *what = (where == ACL_WHERE_DATA)? US"after DATA" :
7237
- string_sprintf("%s %s", acl_wherenames[where], smtp_data);
7238
+uschar *what = string_sprintf("%s %s", acl_wherenames[where], smtp_data);
7240
+if (where == ACL_WHERE_DATA) what = US"after DATA";
7241
+if (where == ACL_WHERE_MIME) what = US"during MIME ACL checks";
7243
if (drop) rc = FAIL;
7245
@@ -1758,7 +1766,7 @@
7246
this is what should be logged, so I've changed to logging the unrewritten
7247
address to retain backward compatibility. */
7249
-if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA)
7250
+if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA || where == ACL_WHERE_MIME)
7252
sender_info = string_sprintf("F=<%s> ", (sender_address_unrewritten != NULL)?
7253
sender_address_unrewritten : sender_address);
7254
diff -urN exim-4.34-orig/src/spam.c exim-4.34/src/spam.c
7255
--- exim-4.34-orig/src/spam.c Thu Jan 1 01:00:00 1970
7256
+++ exim-4.34/src/spam.c Mon May 10 16:14:47 2004
7258
+/*************************************************
7259
+* Exim - an Internet mail transport agent *
7260
+*************************************************/
7262
+/* This file is part of the exiscan-acl content scanner
7263
+patch. It is NOT part of the standard exim distribution. */
7265
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
7268
+/* Code for calling spamassassin's spamd. Called from acl.c. */
7273
+uschar spam_score_buffer[16];
7274
+uschar spam_score_int_buffer[16];
7275
+uschar spam_bar_buffer[128];
7276
+uschar spam_report_buffer[32600];
7277
+uschar prev_user_name[128] = "";
7281
+int spam(uschar **listptr) {
7283
+ uschar *list = *listptr;
7284
+ uschar *user_name;
7285
+ uschar user_name_buffer[128];
7286
+ unsigned long long mbox_size;
7289
+ uschar spamd_buffer[32600];
7291
+ uschar spamd_version[8];
7292
+ uschar spamd_score_char;
7293
+ double spamd_threshold, spamd_score;
7294
+ int spamd_report_offset;
7297
+ struct sockaddr_un server;
7299
+ /* find the username from the option list */
7300
+ if ((user_name = string_nextinlist(&list, &sep,
7302
+ sizeof(user_name_buffer))) == NULL) {
7303
+ /* no username given, this means no scanning should be done */
7307
+ /* if username is "0" or "false", do not scan */
7308
+ if ( (Ustrcmp(user_name,"0") == 0) ||
7309
+ (strcmpic(user_name,US"false") == 0) ) {
7313
+ /* if there is an additional option, check if it is "true" */
7314
+ if (strcmpic(list,US"true") == 0) {
7315
+ /* in that case, always return true later */
7319
+ /* if we scanned for this username last time, just return */
7320
+ if ( spam_ok && ( Ustrcmp(prev_user_name, user_name) == 0 ) ) {
7327
+ /* make sure the eml mbox file is spooled up */
7328
+ mbox_file = spool_mbox(&mbox_size);
7330
+ if (mbox_file == NULL) {
7331
+ /* error while spooling */
7332
+ log_write(0, LOG_MAIN|LOG_PANIC,
7333
+ "spam acl condition: error while creating mbox spool file");
7337
+ /* socket does not start with '/' -> network socket */
7338
+ if (*spamd_address != '/') {
7339
+ time_t now = time(NULL);
7340
+ int num_servers = 0;
7341
+ int current_server = 0;
7342
+ int start_server = 0;
7343
+ uschar *address = NULL;
7344
+ uschar *spamd_address_list_ptr = spamd_address;
7345
+ uschar address_buffer[256];
7346
+ spamd_address_container * spamd_address_vector[32];
7348
+ /* Check how many spamd servers we have
7349
+ and register their addresses */
7350
+ while ((address = string_nextinlist(&spamd_address_list_ptr, &sep,
7352
+ sizeof(address_buffer))) != NULL) {
7354
+ spamd_address_container *this_spamd =
7355
+ (spamd_address_container *)store_get(sizeof(spamd_address_container));
7357
+ /* grok spamd address and port */
7358
+ if( sscanf(CS address, "%s %u", this_spamd->tcp_addr, &(this_spamd->tcp_port)) != 2 ) {
7359
+ log_write(0, LOG_MAIN,
7360
+ "spam acl condition: warning - invalid spamd address: '%s'", address);
7364
+ spamd_address_vector[num_servers] = this_spamd;
7366
+ if (num_servers > 31)
7370
+ /* check if we have at least one server */
7371
+ if (!num_servers) {
7372
+ log_write(0, LOG_MAIN|LOG_PANIC,
7373
+ "spam acl condition: no useable spamd server addresses in spamd_address configuration option.");
7374
+ fclose(mbox_file);
7378
+ current_server = start_server = (int)now % num_servers;
7382
+ debug_printf("trying server %s, port %u\n",
7383
+ spamd_address_vector[current_server]->tcp_addr,
7384
+ spamd_address_vector[current_server]->tcp_port);
7386
+ /* contact a spamd */
7387
+ if ( (spamd_sock = ip_socket(SOCK_STREAM, AF_INET)) < 0) {
7388
+ log_write(0, LOG_MAIN|LOG_PANIC,
7389
+ "spam acl condition: error creating IP socket for spamd");
7390
+ fclose(mbox_file);
7394
+ if (ip_connect( spamd_sock,
7396
+ spamd_address_vector[current_server]->tcp_addr,
7397
+ spamd_address_vector[current_server]->tcp_port,
7399
+ /* connection OK */
7403
+ log_write(0, LOG_MAIN|LOG_PANIC,
7404
+ "spam acl condition: warning - spamd connection to %s, port %u failed: %s",
7405
+ spamd_address_vector[current_server]->tcp_addr,
7406
+ spamd_address_vector[current_server]->tcp_port,
7409
+ if (current_server >= num_servers)
7410
+ current_server = 0;
7411
+ if (current_server == start_server) {
7412
+ log_write(0, LOG_MAIN|LOG_PANIC, "spam acl condition: all spamd servers failed");
7413
+ fclose(mbox_file);
7414
+ close(spamd_sock);
7421
+ /* open the local socket */
7423
+ if ((spamd_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
7424
+ log_write(0, LOG_MAIN|LOG_PANIC,
7425
+ "malware acl condition: spamd: unable to acquire socket (%s)",
7427
+ fclose(mbox_file);
7431
+ server.sun_family = AF_UNIX;
7432
+ Ustrcpy(server.sun_path, spamd_address);
7434
+ if (connect(spamd_sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
7435
+ log_write(0, LOG_MAIN|LOG_PANIC,
7436
+ "malware acl condition: spamd: unable to connect to UNIX socket %s (%s)",
7437
+ spamd_address, strerror(errno) );
7438
+ fclose(mbox_file);
7439
+ close(spamd_sock);
7445
+ /* now we are connected to spamd on spamd_sock */
7446
+ snprintf(CS spamd_buffer,
7447
+ sizeof(spamd_buffer),
7448
+ "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %lld\r\n\r\n",
7452
+ /* send our request */
7453
+ if (send(spamd_sock, spamd_buffer, Ustrlen(spamd_buffer), 0) < 0) {
7454
+ close(spamd_sock);
7455
+ log_write(0, LOG_MAIN|LOG_PANIC,
7456
+ "spam acl condition: spamd send failed: %s", strerror(errno));
7457
+ fclose(mbox_file);
7458
+ close(spamd_sock);
7462
+ /* now send the file */
7464
+ j = fread(spamd_buffer,1,sizeof(spamd_buffer),mbox_file);
7466
+ i = send(spamd_sock,spamd_buffer,j,0);
7468
+ log_write(0, LOG_MAIN|LOG_PANIC,
7469
+ "spam acl condition: error/short send to spamd");
7470
+ close(spamd_sock);
7471
+ fclose(mbox_file);
7478
+ fclose(mbox_file);
7480
+ /* we're done sending, close socket for writing */
7481
+ shutdown(spamd_sock,SHUT_WR);
7483
+ /* read spamd response */
7484
+ memset(spamd_buffer, 0, sizeof(spamd_buffer));
7486
+ while((i = ip_recv(spamd_sock,
7487
+ spamd_buffer + offset,
7488
+ sizeof(spamd_buffer) - offset - 1,
7489
+ SPAMD_READ_TIMEOUT)) > 0 ) {
7493
+ /* error handling */
7494
+ if((i <= 0) && (errno != 0)) {
7495
+ log_write(0, LOG_MAIN|LOG_PANIC,
7496
+ "spam acl condition: error reading from spamd socket: %s", strerror(errno));
7497
+ close(spamd_sock);
7501
+ /* reading done */
7502
+ close(spamd_sock);
7504
+ /* dig in the spamd output and put the report in a multiline header, if requested */
7505
+ if( sscanf(CS spamd_buffer,"SPAMD/%s 0 EX_OK\r\nContent-length: %*u\r\n\r\n%lf/%lf\r\n%n",
7506
+ spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
7508
+ /* try to fall back to pre-2.50 spamd output */
7509
+ if( sscanf(CS spamd_buffer,"SPAMD/%s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n",
7510
+ spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3 ) {
7511
+ log_write(0, LOG_MAIN|LOG_PANIC,
7512
+ "spam acl condition: cannot parse spamd output");
7517
+ /* Create report. Since this is a multiline string,
7518
+ we must hack it into shape first */
7519
+ p = &spamd_buffer[spamd_report_offset];
7520
+ q = spam_report_buffer;
7521
+ while (*p != '\0') {
7532
+ /* eat whitespace */
7533
+ while( (*p <= ' ') && (*p != '\0') ) {
7540
+ /* NULL-terminate */
7543
+ /* cut off trailing leftovers */
7544
+ while (*q <= ' ') {
7548
+ spam_report = spam_report_buffer;
7550
+ /* create spam bar */
7551
+ spamd_score_char = spamd_score > 0 ? '+' : '-';
7552
+ j = abs((int)(spamd_score));
7555
+ while((i < j) && (i <= MAX_SPAM_BAR_CHARS))
7556
+ spam_bar_buffer[i++] = spamd_score_char;
7559
+ spam_bar_buffer[0] = '/';
7562
+ spam_bar_buffer[i] = '\0';
7563
+ spam_bar = spam_bar_buffer;
7565
+ /* create "float" spam score */
7566
+ snprintf(CS spam_score_buffer, sizeof(spam_score_buffer),"%.1f", spamd_score);
7567
+ spam_score = spam_score_buffer;
7569
+ /* create "int" spam score */
7570
+ j = (int)((spamd_score + 0.001)*10);
7571
+ snprintf(CS spam_score_int_buffer, sizeof(spam_score_int_buffer), "%d", j);
7572
+ spam_score_int = spam_score_int_buffer;
7574
+ /* compare threshold against score */
7575
+ if (spamd_score >= spamd_threshold) {
7576
+ /* spam as determined by user's threshold */
7584
+ /* remember user name and "been here" for it */
7585
+ Ustrcpy(prev_user_name, user_name);
7589
+ /* always return OK, no matter what the score */
7596
diff -urN exim-4.34-orig/src/spam.h exim-4.34/src/spam.h
7597
--- exim-4.34-orig/src/spam.h Thu Jan 1 01:00:00 1970
7598
+++ exim-4.34/src/spam.h Mon May 10 16:14:47 2004
7600
+/*************************************************
7601
+* Exim - an Internet mail transport agent *
7602
+*************************************************/
7604
+/* This file is part of the exiscan-acl content scanner
7605
+patch. It is NOT part of the standard exim distribution. */
7607
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
7612
+/* timeout for reading from spamd */
7613
+#define SPAMD_READ_TIMEOUT 3600
7615
+/* maximum length of the spam bar */
7616
+#define MAX_SPAM_BAR_CHARS 50
7618
+/* SHUT_WR seems to be undefined on Unixware ? */
7623
+typedef struct spamd_address_container {
7624
+ uschar tcp_addr[24];
7625
+ unsigned int tcp_port;
7626
+} spamd_address_container;
7630
diff -urN exim-4.34-orig/src/spool_in.c exim-4.34/src/spool_in.c
7631
--- exim-4.34-orig/src/spool_in.c Mon May 10 14:31:20 2004
7632
+++ exim-4.34/src/spool_in.c Mon May 10 16:14:47 2004
7635
deliver_firsttime = FALSE;
7636
deliver_freeze = FALSE;
7637
+fake_reject = FALSE;
7638
deliver_frozen_at = 0;
7639
deliver_manual_thaw = FALSE;
7640
/* dont_deliver must NOT be reset */
7643
local_error_message = FALSE;
7644
local_scan_data = NULL;
7645
+spam_score_int = NULL;
7646
message_linecount = 0;
7647
received_protocol = NULL;
7649
@@ -266,6 +268,11 @@
7650
sender_set_untrusted = FALSE;
7651
tree_nonrecipients = NULL;
7655
+bmi_verdicts = NULL;
7659
tls_certificate_verified = FALSE;
7661
@@ -364,6 +371,12 @@
7662
local_error_message = TRUE;
7663
else if (Ustrncmp(big_buffer, "-local_scan ", 12) == 0)
7664
local_scan_data = string_copy(big_buffer + 12);
7665
+ else if (Ustrncmp(big_buffer, "-spam_score_int ", 16) == 0)
7666
+ spam_score_int = string_copy(big_buffer + 16);
7668
+ else if (Ustrncmp(big_buffer, "-bmi_verdicts ", 14) == 0)
7669
+ bmi_verdicts = string_copy(big_buffer + 14);
7671
else if (Ustrcmp(big_buffer, "-host_lookup_failed") == 0)
7672
host_lookup_failed = TRUE;
7673
else if (Ustrncmp(big_buffer, "-body_linecount", 15) == 0)
7674
diff -urN exim-4.34-orig/src/spool_mbox.c exim-4.34/src/spool_mbox.c
7675
--- exim-4.34-orig/src/spool_mbox.c Thu Jan 1 01:00:00 1970
7676
+++ exim-4.34/src/spool_mbox.c Mon May 10 16:14:47 2004
7678
+/*************************************************
7679
+* Exim - an Internet mail transport agent *
7680
+*************************************************/
7682
+/* This file is part of the exiscan-acl content scanner
7683
+patch. It is NOT part of the standard exim distribution. */
7685
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
7688
+/* Code for setting up a MBOX style spool file inside a /scan/<msgid>
7689
+sub directory of exim's spool directory. */
7693
+/* externals, we must reset them on unspooling */
7694
+extern int demime_ok;
7695
+extern int malware_ok;
7696
+extern int spam_ok;
7697
+extern struct file_extension *file_extensions;
7699
+int spool_mbox_ok = 0;
7700
+uschar spooled_message_id[17];
7702
+/* returns a pointer to the FILE, and puts the size in bytes into mbox_file_size */
7704
+FILE *spool_mbox(unsigned long long *mbox_file_size) {
7705
+ uschar mbox_path[1024];
7706
+ uschar message_subdir[2];
7707
+ uschar data_buffer[65535];
7709
+ FILE *data_file = NULL;
7710
+ header_line *my_headerlist;
7711
+ struct stat statbuf;
7716
+ uschar *timestamp;
7719
+ if (!spool_mbox_ok) {
7720
+ /* create scan directory, if not present */
7721
+ if (!directory_make(spool_directory, US "scan", 0750, FALSE)) {
7722
+ debug_printf("unable to create directory: %s/scan\n", spool_directory);
7726
+ /* create temp directory inside scan dir */
7727
+ snprintf(CS mbox_path, 1024, "%s/scan/%s", spool_directory, message_id);
7728
+ if (!directory_make(NULL, mbox_path, 0750, FALSE)) {
7729
+ debug_printf("unable to create directory: %s/scan/%s\n", spool_directory, message_id);
7733
+ /* open [message_id].eml file for writing */
7734
+ snprintf(CS mbox_path, 1024, "%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
7735
+ mbox_file = Ufopen(mbox_path,"w");
7737
+ if (mbox_file == NULL) {
7738
+ debug_printf("unable to open file for writing: %s\n", mbox_path);
7742
+ /* Generate a preliminary Received: header and put it in the file.
7743
+ We need to do this so SA can do DNS list checks */
7745
+ /* removed for 4.34
7747
+ timestamp = expand_string(US"${tod_full}");
7748
+ received = expand_string(received_header_text);
7749
+ if (received != NULL) {
7750
+ uschar *my_received;
7751
+ if (received[0] == 0) {
7752
+ my_received = string_sprintf("Received: ; %s\n", timestamp);
7755
+ my_received = string_sprintf("%s; %s\n", received, timestamp);
7757
+ i = fwrite(my_received, 1, Ustrlen(my_received), mbox_file);
7758
+ if (i != Ustrlen(my_received)) {
7759
+ debug_printf("error/short write on writing in: %s", mbox_path);
7760
+ fclose(mbox_file);
7767
+ /* write all header lines to mbox file */
7768
+ my_headerlist = header_list;
7769
+ while (my_headerlist != NULL) {
7771
+ /* skip deleted headers */
7772
+ if (my_headerlist->type == '*') {
7773
+ my_headerlist = my_headerlist->next;
7777
+ i = fwrite(my_headerlist->text, 1, my_headerlist->slen, mbox_file);
7778
+ if (i != my_headerlist->slen) {
7779
+ debug_printf("error/short write on writing in: %s", mbox_path);
7780
+ fclose(mbox_file);
7784
+ my_headerlist = my_headerlist->next;
7787
+ /* copy body file */
7788
+ message_subdir[1] = '\0';
7789
+ for (i = 0; i < 2; i++) {
7790
+ message_subdir[0] = (split_spool_directory == (i == 0))? message_id[5] : 0;
7791
+ sprintf(CS mbox_path, "%s/input/%s/%s-D", spool_directory, message_subdir, message_id);
7792
+ data_file = Ufopen(mbox_path,"r");
7793
+ if (data_file != NULL)
7797
+ fread(data_buffer, 1, 18, data_file);
7800
+ j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
7802
+ i = fwrite(data_buffer, 1, j, mbox_file);
7804
+ debug_printf("error/short write on writing in: %s", mbox_path);
7805
+ fclose(mbox_file);
7806
+ fclose(data_file);
7812
+ fclose(data_file);
7813
+ fclose(mbox_file);
7814
+ Ustrcpy(spooled_message_id, message_id);
7815
+ spool_mbox_ok = 1;
7818
+ snprintf(CS mbox_path, 1024, "%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
7820
+ /* get the size of the mbox message */
7821
+ stat(CS mbox_path, &statbuf);
7822
+ *mbox_file_size = statbuf.st_size;
7824
+ /* open [message_id].eml file for reading */
7825
+ mbox_file = Ufopen(mbox_path,"r");
7830
+/* remove mbox spool file, demimed files and temp directory */
7831
+void unspool_mbox(void) {
7833
+ /* reset all exiscan state variables */
7835
+ demime_errorlevel = 0;
7836
+ demime_reason = NULL;
7837
+ file_extensions = NULL;
7841
+ if (spool_mbox_ok) {
7843
+ spool_mbox_ok = 0;
7845
+ if (!no_mbox_unspool) {
7846
+ uschar mbox_path[1024];
7847
+ uschar file_path[1024];
7849
+ struct dirent *entry;
7852
+ snprintf(CS mbox_path, 1024, "%s/scan/%s", spool_directory, spooled_message_id);
7854
+ tempdir = opendir(CS mbox_path);
7855
+ /* loop thru dir & delete entries */
7858
+ entry = readdir(tempdir);
7859
+ if (entry == NULL) break;
7860
+ snprintf(CS file_path, 1024,"%s/scan/%s/%s", spool_directory, spooled_message_id, entry->d_name);
7861
+ if ( (Ustrcmp(entry->d_name,"..") != 0) && (Ustrcmp(entry->d_name,".") != 0) ) {
7862
+ debug_printf("unspool_mbox(): unlinking '%s'\n", file_path);
7863
+ n = unlink(CS file_path);
7867
+ closedir(tempdir);
7869
+ /* remove directory */
7870
+ n = rmdir(CS mbox_path);
7874
diff -urN exim-4.34-orig/src/spool_out.c exim-4.34/src/spool_out.c
7875
--- exim-4.34-orig/src/spool_out.c Mon May 10 14:31:20 2004
7876
+++ exim-4.34/src/spool_out.c Mon May 10 16:14:47 2004
7877
@@ -209,9 +209,14 @@
7878
if (sender_local) fprintf(f, "-local\n");
7879
if (local_error_message) fprintf(f, "-localerror\n");
7880
if (local_scan_data != NULL) fprintf(f, "-local_scan %s\n", local_scan_data);
7881
+if (spam_score_int != NULL) fprintf(f,"-spam_score_int %s\n", spam_score_int);
7882
if (deliver_manual_thaw) fprintf(f, "-manual_thaw\n");
7883
if (sender_set_untrusted) fprintf(f, "-sender_set_untrusted\n");
7886
+if (bmi_verdicts != NULL) fprintf(f, "-bmi_verdicts %s\n", bmi_verdicts);
7890
if (tls_certificate_verified) fprintf(f, "-tls_certificate_verified\n");
7891
if (tls_cipher != NULL) fprintf(f, "-tls_cipher %s\n", tls_cipher);
7892
diff -urN exim-4.34-orig/src/structs.h exim-4.34/src/structs.h
7893
--- exim-4.34-orig/src/structs.h Mon May 10 14:31:20 2004
7894
+++ exim-4.34/src/structs.h Mon May 10 16:14:47 2004
7896
uschar *driver_name; /* Must be first */
7898
uschar *address_data; /* Arbitrary data */
7900
+ uschar *bmi_rule; /* Brightmail AntiSpam rule checking */
7902
uschar *cannot_route_message; /* Used when routing fails */
7903
uschar *condition; /* General condition */
7904
uschar *current_directory; /* For use during delivery */
7905
@@ -247,6 +250,11 @@
7906
uschar *transport_name; /* Transport name */
7908
BOOL address_test; /* Use this router when testing addresses */
7910
+ BOOL bmi_deliver_alternate; /* TRUE => BMI said that message should be delivered to alternate location */
7911
+ BOOL bmi_deliver_default; /* TRUE => BMI said that message should be delivered to default location */
7912
+ BOOL bmi_dont_deliver; /* TRUE => BMI said that message should not be delivered at all */
7914
BOOL expn; /* Use this router when processing EXPN */
7915
BOOL caseful_local_part; /* TRUE => don't lowercase */
7916
BOOL check_local_user; /* TRUE => check local user */
7917
diff -urN exim-4.34-orig/src/tnef.c exim-4.34/src/tnef.c
7918
--- exim-4.34-orig/src/tnef.c Thu Jan 1 01:00:00 1970
7919
+++ exim-4.34/src/tnef.c Mon May 10 16:14:47 2004
7921
+/*************************************************
7922
+* Exim - an Internet mail transport agent *
7923
+*************************************************/
7925
+/* This file is part of the exiscan-acl content scanner
7926
+patch. It is NOT part of the standard exim distribution. */
7928
+/* Code for unpacking TNEF containers. Called from demime.c. */
7930
+/***************************************************************************
7932
+* A program to decode application/ms-tnef MIME attachments into text
7933
+* for those fortunate enough not to be running either a Microsoft
7934
+* operating system or mailer.
7937
+* Brutally cropped by Paul L Daniels (pldaniels@pldaniels.com) in order
7938
+* to accommodate the needs of ripMIME/Xamime/Inflex without carrying too
7939
+* much excess baggage.
7941
+ * Brandon Long (blong@uiuc.edu), April 1997
7943
+* Supports most types, but doesn't decode properties. Maybe some other
7946
+ * 1.1 Version (7/1/97)
7947
+* Supports saving of attAttachData to a file given by attAttachTitle
7948
+* start of property decoding support
7950
+ * 1.2 Version (7/19/97)
7951
+* Some architectures don't like reading 16/32 bit data on unaligned
7952
+* boundaries. Fixed, losing efficiency, but this doesn't really
7953
+* need efficiency anyways. (Still...)
7954
+* Also, the #pragma pack from the MSVC include file wasn't liked
7955
+* by most Unix compilers, replaced with a GCCism. This should work
7956
+* with GCC, but other compilers I don't know.
7958
+ * 1.3 Version (7/22/97)
7959
+* Ok, take out the DTR over the stream, now uses read_16.
7961
+ * NOTE: THIS SOFTWARE IS FOR YOUR PERSONAL GRATIFICATION ONLY. I DON'T
7962
+* IMPLY IN ANY LEGAL SENSE THAT THIS SOFTWARE DOES ANYTHING OR THAT IT WILL
7963
+* BE USEFULL IN ANY WAY. But, you can send me fixes to it, I don't mind.
7964
+***************************************************************************/
7967
+#include <sys/stat.h>
7968
+#include <stdlib.h>
7970
+#include <string.h>
7971
+#include <netinet/in.h>
7975
+#define VERSION "pldtnef/0.0.1"
7977
+int _TNEF_syslogging = 0;
7978
+int _TNEF_stderrlogging = 0;
7979
+int _TNEF_verbose = 0;
7980
+int _TNEF_debug = 0;
7982
+int Verbose = FALSE;
7983
+int SaveData = FALSE;
7985
+char _TNEF_path[1024]="";
7990
+/*------------------------------------------------------------------------
7991
+Procedure: TNEF_set_path ID:1
7996
+------------------------------------------------------------------------*/
7997
+int TNEF_set_path( char *path )
7999
+ snprintf(_TNEF_path,1023,"%s",path);
8005
+/*------------------------------------------------------------------------
8006
+Procedure: TNEF_set_verbosity ID:1
8011
+------------------------------------------------------------------------*/
8012
+int TNEF_set_verbosity( int level )
8014
+ _TNEF_verbose = level;
8015
+ return _TNEF_verbose;
8021
+/*------------------------------------------------------------------------
8022
+Procedure: TNEF_set_debug ID:1
8027
+------------------------------------------------------------------------*/
8028
+int TNEF_set_debug( int level )
8030
+ _TNEF_debug = level;
8031
+ TNEF_set_verbosity( level );
8032
+ return _TNEF_debug;
8037
+/*------------------------------------------------------------------------
8038
+Procedure: TNEF_set_syslogging ID:1
8039
+Purpose: Turns on/off the syslog feature for TNEF error messages
8043
+------------------------------------------------------------------------*/
8044
+int TNEF_set_syslogging( int level )
8046
+ _TNEF_syslogging = level;
8047
+ return _TNEF_syslogging;
8053
+/*------------------------------------------------------------------------
8054
+Procedure: TNEF_set_stderrlogging ID:1
8055
+Purpose: Turns on/off the stderr feature for TNEF error messages
8059
+------------------------------------------------------------------------*/
8060
+int TNEF_set_stderrlogging( int level )
8062
+ _TNEF_stderrlogging = level;
8063
+ return _TNEF_stderrlogging;
8067
+/* Some systems don't like to read unaligned data */
8068
+/*------------------------------------------------------------------------
8069
+Procedure: read_32 ID:1
8074
+------------------------------------------------------------------------*/
8075
+uint32 read_32(uint8 *tsp)
8080
+ if (tsp+4 > tnef_limit)
8082
+ if ((_TNEF_verbose)||(_TNEF_stderrlogging)||(_TNEF_debug)) fprintf(stderr,"TNEF read_32() Attempting to read past end\n");
8091
+ ret = long_little_endian(a<<24 | b<<16 | c<<8 | d);
8096
+/*------------------------------------------------------------------------
8097
+Procedure: read_16 ID:1
8102
+------------------------------------------------------------------------*/
8103
+uint16 read_16(uint8 *tsp)
8108
+ if (tsp+2 > tnef_limit)
8110
+ if ((_TNEF_verbose)||(_TNEF_stderrlogging)||(_TNEF_debug)) fprintf(stderr,"TNEF read_16() Attempting to read past end\n");
8118
+ ret = little_endian(a<<8 | b);
8125
+/*------------------------------------------------------------------------
8126
+Procedure: make_string ID:1
8131
+------------------------------------------------------------------------*/
8132
+char *make_string(uint8 *tsp, int size)
8134
+ static char s[256] = "";
8135
+ int len = (size>sizeof(s)-1) ? sizeof(s)-1 : size;
8137
+ strncpy(s,(char *)tsp, len);
8143
+/*------------------------------------------------------------------------
8144
+Procedure: handle_props ID:1
8149
+------------------------------------------------------------------------*/
8151
+int save_attach_data(char *, uint8 *, uint32);
8153
+int handle_props(uint8 *tsp)
8156
+ uint32 num_props = 0;
8160
+ num_props = read_32(tsp);
8161
+ bytes += sizeof(num_props);
8163
+ while (x < num_props)
8167
+ char filename[256];
8168
+ static int file_num = 0;
8170
+ prop_tag = read_32(tsp+bytes);
8171
+ bytes += sizeof(prop_tag);
8173
+ switch (prop_tag & PROP_TYPE_MASK)
8176
+ num = read_32(tsp+bytes);
8177
+ bytes += sizeof(num);
8178
+ num = read_32(tsp+bytes);
8179
+ bytes += sizeof(num);
8180
+ if (prop_tag == PR_RTF_COMPRESSED)
8182
+ sprintf (filename, "XAM_%d.rtf", file_num);
8184
+ save_attach_data(filename, tsp+bytes, num);
8187
+ bytes += num + ((num % 4) ? (4 - num%4) : 0);
8190
+ num = read_32(tsp+bytes);
8191
+ bytes += sizeof(num);
8192
+ num = read_32(tsp+bytes);
8193
+ bytes += sizeof(num);
8194
+ make_string(tsp+bytes,num);
8195
+ bytes += num + ((num % 4) ? (4 - num%4) : 0);
8235
+/*------------------------------------------------------------------------
8236
+Procedure: save_attach_data ID:1
8241
+------------------------------------------------------------------------*/
8242
+int save_attach_data(char *title, uint8 *tsp, uint32 size)
8245
+ char filename[1024];
8248
+ if ((*tsp +size) > _TNEF_size)
8253
+ snprintf(filename,1023,"%s/%s",_TNEF_path,title);
8255
+ out = fopen(filename, "w");
8258
+ if (_TNEF_stderrlogging > 0) fprintf(stderr, "Error openning file %s for writing\n", filename);
8262
+ fwrite(tsp, sizeof(uint8), size, out);
8270
+/*------------------------------------------------------------------------
8271
+Procedure: default_handler ID:1
8276
+------------------------------------------------------------------------*/
8277
+int default_handler(uint32 attribute, uint8 *tsp, uint32 size)
8279
+ uint16 type = ATT_TYPE(attribute);
8309
+/*------------------------------------------------------------------------
8310
+Procedure: read_attribute ID:1
8315
+------------------------------------------------------------------------*/
8316
+int read_attribute(uint8 *tsp)
8319
+ int bytes = 0, header = 0;
8321
+ uint8 component = 0;
8323
+ uint16 checksum = 0;
8324
+ static char attach_title[256] = {
8326
+ static uint32 attach_size = 0;
8327
+ static uint32 attach_loc = 0;
8329
+ /* What component are we look at? */
8332
+ bytes += sizeof(uint8);
8334
+ /* Read the attributes of this component */
8336
+ if (_TNEF_debug) fprintf(stderr,"read_attribute: Reading Attribute...\n");
8337
+ attribute = read_32(tsp+bytes);
8338
+ if (attribute == -1) return -1;
8339
+ bytes += sizeof(attribute);
8341
+ /* Read the size of the information we have to read */
8343
+ if (_TNEF_debug) fprintf(stderr,"read_attribute: Reading Size...\n");
8344
+ size = read_32(tsp+bytes);
8345
+ if (size == -1) return -1;
8346
+ bytes += sizeof(size);
8348
+ /* The header size equals the sum of all the things we've read
8353
+ /* The is a bit of a tricky one [if you're being slow
8354
+ it moves the number of bytes ahead by the amount of data of
8355
+ the attribute we're about to read, so that for next
8356
+ "read_attribute()"
8357
+ call starts in the right place.
8362
+ /* Read in the checksum for this component
8364
+ AMMENDMENT - 19/07/02 - 17H01
8365
+ Small code change to deal with strange sitations that occur with non
8366
+ english characters. - Submitted by wtcheuk@netvigator.com @ 19/07/02
8369
+ if ( bytes < 0 ) return -1;
8371
+ /* --END of ammendment. */
8373
+ if (_TNEF_debug) fprintf(stderr,"read_attribute: Reading Checksum...(offset %d, bytes=%d)\n", tsp -tnef_home, bytes);
8374
+ checksum = read_16(tsp+bytes);
8375
+ bytes += sizeof(checksum);
8377
+ if (_TNEF_debug) fprintf(stderr,"Decoding attribute %d\n",attribute);
8379
+ switch (attribute) {
8381
+ default_handler(attribute, tsp+header, size);
8384
+ default_handler(attribute, tsp+header, size);
8392
+ case attMessageStatus:
8394
+ case attMessageClass:
8396
+ case attMessageID:
8400
+ case attConversationID:
8403
+ default_handler(attribute, tsp+header, size);
8407
+ case attAttachData:
8409
+ attach_loc =(int)tsp+header;
8410
+ if (SaveData && strlen(attach_title)>0 && attach_size > 0) {
8411
+ if (!save_attach_data(attach_title, (uint8 *)attach_loc,attach_size))
8413
+ if (_TNEF_verbose) fprintf(stdout,"Decoding %s\n", attach_title);
8417
+ if (_TNEF_syslogging > 0) syslog(1,"TNEF: Error saving attachment %s\n",attach_title);
8421
+ case attAttachTitle:
8422
+ strncpy(attach_title, make_string(tsp+header,size),255);
8423
+ if (SaveData && strlen(attach_title)>0 && attach_size > 0) {
8424
+ if (!save_attach_data(attach_title, (uint8 *)attach_loc,attach_size))
8426
+ if (_TNEF_verbose) fprintf(stdout,"Decoding %s\n", attach_title);
8430
+ if (_TNEF_syslogging > 0) syslog(1,"TNEF: Error saving attachment %s\n",attach_title);
8434
+ case attAttachMetaFile:
8435
+ default_handler(attribute, tsp+header, size);
8437
+ case attAttachCreateDate:
8439
+ case attAttachModifyDate:
8441
+ case attDateModified:
8443
+ case attAttachTransportFilename:
8444
+ default_handler(attribute, tsp+header, size);
8446
+ case attAttachRenddata:
8447
+ attach_title[0]=0;
8450
+ default_handler(attribute, tsp+header, size);
8452
+ case attMAPIProps:
8453
+ handle_props(tsp+header);
8455
+ case attRecipTable:
8456
+ default_handler(attribute, tsp+header, size);
8458
+ case attAttachment:
8459
+ default_handler(attribute, tsp+header, size);
8461
+ case attTnefVersion:
8464
+ version = read_32(tsp+header);
8465
+ if (version == -1) return -1;
8468
+ case attOemCodepage:
8469
+ default_handler(attribute, tsp+header, size);
8471
+ case attOriginalMessageClass:
8474
+ default_handler(attribute, tsp+header, size);
8477
+ default_handler(attribute, tsp+header, size);
8480
+ default_handler(attribute, tsp+header, size);
8482
+ case attDateStart:
8487
+ default_handler(attribute, tsp+header, size);
8489
+ case attRequestRes:
8490
+ default_handler(attribute, tsp+header, size);
8493
+ default_handler(attribute, tsp+header, size);
8503
+/*------------------------------------------------------------------------
8504
+Procedure: decode_tnef ID:1
8509
+------------------------------------------------------------------------*/
8510
+int TNEF_decode_tnef(uint8 *tnef_stream, int size)
8516
+ if (_TNEF_debug) fprintf(stderr,"TNEF_decode_tnef: Start. Size = %d\n",size);
8520
+ if (_TNEF_debug) fprintf(stderr,"TNEF_decode_tnef: Skipping short file\n");
8524
+ /* TSP == TNEF Stream Pointer (well memory block actually!)
8526
+ tsp = tnef_stream;
8528
+ /* Read in the signature of this TNEF
8530
+ if (TNEF_SIGNATURE == read_32(tsp))
8532
+ if (_TNEF_debug) fprintf(stderr,"TNEF signature is good\n");
8536
+ if (_TNEF_stderrlogging > 0) fprintf(stderr,"TNEF_decode_tnef: Bad TNEF signature, expecting %x got %lx\n",TNEF_SIGNATURE,read_32(tsp));
8539
+ /* Move tsp pointer along
8541
+ tsp += sizeof(TNEF_SIGNATURE);
8543
+ /* This extra check is here just in case we're running with
8544
+ * _TNEF_debug set and try to calculate TNEF Attach Key
8545
+ * when we shouldn't.
8547
+ if (tsp + sizeof(uint16) - tnef_stream > size)
8549
+ if (_TNEF_debug) fprintf(stderr,"TNEF_decode_tnef: Skipping short file\n");
8553
+ if (_TNEF_debug) fprintf(stderr,"TNEF Attach Key: %x\n",read_16(tsp));
8554
+ /* Move tsp pointer along
8556
+ tsp += sizeof(uint16);
8558
+ /* While we still have more bytes to process,
8559
+ go through entire memory block and extract
8560
+ all the required attributes and files
8562
+ if (_TNEF_debug) fprintf(stderr,"TNEF - Commence reading attributes\n");
8563
+ while ((tsp - tnef_stream) < size)
8565
+ if (_TNEF_debug) fprintf(stderr,"Offset = %d\n",tsp -tnef_home);
8566
+ ra_response = read_attribute(tsp);
8567
+ if ( ra_response > 0 )
8569
+ tsp += ra_response;
8572
+ /* Must find out /WHY/ this happens, and, how to rectify the issue. */
8575
+ if (_TNEF_debug) fprintf(stderr,"TNEF - Attempting to read attribute resulted in a sub-zero response, ending decoding to be safe\n");
8580
+ if (_TNEF_debug) fprintf(stderr,"TNEF - DONE.\n");
8590
+/*------------------------------------------------------------------------
8591
+Procedure: TNEF_main ID:1
8592
+Purpose: Decodes a given TNEF encoded file
8596
+------------------------------------------------------------------------*/
8597
+int TNEF_main( char *filename )
8601
+ uint8 *tnef_stream;
8604
+ if (_TNEF_debug) fprintf(stderr,"TNEF_main: Start, decoding %s\n",filename);
8608
+ /* Test to see if the file actually exists
8610
+ if (stat(filename,&sb) == -1)
8612
+ if (_TNEF_stderrlogging > 0) fprintf(stderr,"Error stating file %s (%s)\n", filename,strerror(errno));
8616
+ /* Get the filesize */
8618
+ size = sb.st_size;
8620
+ /* Allocate enough memory to read in the ENTIRE file
8621
+ FIXME - This could be a real consumer if multiple
8622
+ instances of TNEF decoding is going on
8625
+ tnef_home = tnef_stream = (uint8 *)malloc(size);
8626
+ tnef_limit = tnef_home +size;
8628
+ /* If we were unable to allocate enough memory, then we
8629
+ should report this */
8631
+ if (tnef_stream == NULL)
8633
+ if (_TNEF_stderrlogging > 0) fprintf(stderr,"Error allocating %d bytes for loading file (%s)\n", size,strerror(errno));
8637
+ /* Attempt to open up the TNEF encoded file... if it fails
8638
+ then report the failed condition to syslog */
8640
+ if ((fp = fopen(filename,"r")) == NULL)
8642
+ if (_TNEF_stderrlogging > 0) fprintf(stderr,"Error opening file %s for reading (%s)\n", filename,strerror(errno));
8646
+ /* Attempt to read in the entire file */
8648
+ nread = fread(tnef_stream, sizeof(uint8), size, fp);
8650
+ if (_TNEF_debug) fprintf(stderr,"TNEF: Read %d bytes\n",nread);
8652
+ /* If we did not read in all the bytes, then let syslogs know! */
8659
+ /* Close the file */
8663
+ /* Proceed to decode the file */
8665
+ TNEF_decode_tnef(tnef_stream,size);
8668
+ if (_TNEF_debug) fprintf(stderr,"TNEF - finished decoding.\n");
8674
+/* --------------------------END. */
8678
diff -urN exim-4.34-orig/src/tnef.h exim-4.34/src/tnef.h
8679
--- exim-4.34-orig/src/tnef.h Thu Jan 1 01:00:00 1970
8680
+++ exim-4.34/src/tnef.h Mon May 10 16:14:47 2004
8682
+/*************************************************
8683
+* Exim - an Internet mail transport agent *
8684
+*************************************************/
8686
+/* This file is part of the exiscan-acl content scanner
8687
+patch. It is NOT part of the standard exim distribution. */
8689
+/***************************************************************************
8691
+ * config.h for tnef decoder by Brandon Long
8692
+ * Based on config.h from S3MOD by Dan Marks and David Jeske
8694
+ * (C) 1994,1995 By Daniel Marks and David Jeske
8696
+ * While we retain the copyright to this code, this source code is FREE.
8697
+ * You may use it in any way you wish, in any product you wish. You may
8698
+ * NOT steal the copyright for this code from us.
8700
+ * We respectfully ask that you email one of us, if possible, if you
8701
+ * produce something significant with this code, or if you have any bug
8702
+ * fixes to contribute. We also request that you give credit where
8703
+ * credit is due if you include part of this code in a program of your own.
8705
+ ***************************************************************************
8707
+ * config.h - compile time configuration options and system specific defines
8711
+/* 2003-02-03 Merged all TNEF and MAPI related headers in this file to reduce
8719
+#define _CONFIG_H 1
8721
+/***************************************************************************/
8722
+/* The following are system specific settings */
8723
+/***************************************************************************/
8727
+#define ___TNEF_BYTE_ORDER 4321
8728
+#undef NEAR_FAR_PTR
8730
+#elif defined (HPUX)
8732
+#define ___TNEF_BYTE_ORDER 4321
8733
+#undef NEAR_FAR_PTR
8736
+#undef NEAR_FAR_PTR
8738
+#elif defined(__sgi)
8740
+#define ___TNEF_BYTE_ORDER 4321
8741
+#undef NEAR_FAR_PTR
8744
+#undef NEAR_FAR_PTR
8745
+#define ___TNEF_BYTE_ORDER 4321
8748
+#elif defined(LINUX)
8750
+#undef NEAR_FAR_PTR
8752
+#elif defined(MSDOS)
8753
+#define NEAR_FAR_PTR
8757
+#undef NEAR_FAR_PTR
8761
+#endif /* OS/MACH TYPE */
8763
+/***************************************************************************/
8764
+/* 16/32 Bit and Byte Order hacks */
8765
+/***************************************************************************/
8768
+typedef short int int16;
8769
+typedef unsigned short int uint16;
8771
+typedef unsigned int uint32;
8772
+/* typedef char int8; */
8773
+typedef unsigned char uint8;
8776
+typedef unsigned int uint16;
8777
+typedef long int int32;
8778
+typedef unsigned long int uint32;
8780
+typedef unsigned char uint8;
8781
+#endif /* BIT_32 */
8783
+#ifndef WIN32_TYPES
8784
+#define ULONG uint32
8785
+#define SCODE uint32
8787
+#define LPVOID void *
8788
+#define WORD uint16
8789
+#define DWORD uint32
8792
+#endif /* !WIN32_TYPES */
8794
+#define endian_switch(x) (((((uint16)(x)) & 0xFF00) >> 8) | \
8795
+ ((((uint16)(x)) & 0xFF) << 8))
8797
+#define long_endian_switch(x) ( ((((uint32)(x)) & 0xFF00UL) << 8) | \
8798
+ ((((uint32)(x)) & 0xFFUL) << 24) | \
8799
+ ((((uint32)(x)) & 0xFF0000UL) >> 8) | \
8800
+ ((((uint32)(x)) & 0xFF000000UL) >> 24))
8802
+#if ___TNEF_BYTE_ORDER == 4321
8803
+#define big_endian(x) (x)
8804
+#define long_big_endian(x) (x)
8805
+#define little_endian(x) (endian_switch(x))
8806
+#define long_little_endian(x) (long_endian_switch(x))
8808
+#define big_endian(x) (endian_switch(x))
8809
+#define long_big_endian(x) (long_endian_switch(x))
8810
+#define little_endian(x) (x)
8811
+#define long_little_endian(x) (x)
8812
+#endif /* ___TNEF_BYTE_ORDER */
8822
+#endif /* _CONFIG_H */
8824
+ * Taken from the Win32 SDK or the MSVC4 include files, I'm not sure which.
8825
+ * The document describing the TNEF format alludes to this document for more
8826
+ * information. This file was stripped a bit to allow it to compile with
8827
+ * GCC and without random other Windows header files so it could be used
8828
+ * to decode TNEF bitstreams with tnef2txt.
8833
+ * This file contains structure and function definitions for the
8834
+ * MAPI implementation of the Transport Neutral Encapsilation Format
8835
+ * used by MAPI providers for the neutral serialization of a MAPI
8836
+ * message. This implementation sits on top of the IStream object as
8837
+ * documented in the OLE 2 Specs.
8839
+ * Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
8850
+#ifndef BEGIN_INTERFACE
8851
+#define BEGIN_INTERFACE
8858
+#define TNTNoffsetof(s,m) (unsigned long)&(((s *)0)->m)
8860
+/* ------------------------------------ */
8861
+/* TNEF Problem and TNEF Problem Arrays */
8862
+/* ------------------------------------ */
8864
+typedef struct _STnefProblem
8866
+ ULONG ulComponent;
8867
+ ULONG ulAttribute;
8872
+typedef struct _STnefProblemArray
8875
+ STnefProblem aProblem[MAPI_DIM];
8876
+} STnefProblemArray, FAR * LPSTnefProblemArray;
8879
+#define CbNewSTnefProblemArray(_cprob) \
8880
+ (TNoffsetof(STnefProblemArray,aProblem) + (_cprob)*sizeof(STnefProblem))
8881
+#define CbSTnefProblemArray(_lparray) \
8882
+ (TNoffsetof(STnefProblemArray,aProblem) + \
8883
+ (UINT) ((_lparray)->cProblem*sizeof(STnefProblem)))
8886
+/* Pointers to TNEF Interface ---------------------------------------- */
8889
+DECLARE_MAPI_INTERFACE_PTR(ITnef, LPITNEF);
8892
+/* OpenTNEFStream */
8894
+#define TNEF_DECODE ((ULONG) 0)
8895
+#define TNEF_ENCODE ((ULONG) 2)
8897
+#define TNEF_PURE ((ULONG) 0x00010000)
8898
+#define TNEF_COMPATIBILITY ((ULONG) 0x00020000)
8899
+#define TNEF_BEST_DATA ((ULONG) 0x00040000)
8900
+#define TNEF_COMPONENT_ENCODING ((ULONG) 0x80000000)
8902
+/* AddProps, ExtractProps */
8904
+#define TNEF_PROP_INCLUDE ((ULONG) 0x00000001)
8905
+#define TNEF_PROP_EXCLUDE ((ULONG) 0x00000002)
8906
+#define TNEF_PROP_CONTAINED ((ULONG) 0x00000004)
8907
+#define TNEF_PROP_MESSAGE_ONLY ((ULONG) 0x00000008)
8908
+#define TNEF_PROP_ATTACHMENTS_ONLY ((ULONG) 0x00000010)
8909
+#define TNEF_PROP_CONTAINED_TNEF ((ULONG) 0x00000040)
8911
+/* FinishComponent */
8913
+#define TNEF_COMPONENT_MESSAGE ((ULONG) 0x00001000)
8914
+#define TNEF_COMPONENT_ATTACHMENT ((ULONG) 0x00002000)
8917
+#define MAPI_ITNEF_METHODS(IPURE) \
8918
+ MAPIMETHOD(AddProps) \
8919
+ (THIS_ ULONG ulFlags, \
8922
+ LPSPropTagArray lpPropList) IPURE; \
8923
+ MAPIMETHOD(ExtractProps) \
8924
+ (THIS_ ULONG ulFlags, \
8925
+ LPSPropTagArray lpPropList, \
8926
+ LPSTnefProblemArray FAR * lpProblems) IPURE; \
8927
+ MAPIMETHOD(Finish) \
8928
+ (THIS_ ULONG ulFlags, \
8929
+ WORD FAR * lpKey, \
8930
+ LPSTnefProblemArray FAR * lpProblems) IPURE; \
8931
+ MAPIMETHOD(OpenTaggedBody) \
8932
+ (THIS_ LPMESSAGE lpMessage, \
8934
+ LPSTREAM FAR * lppStream) IPURE; \
8935
+ MAPIMETHOD(SetProps) \
8936
+ (THIS_ ULONG ulFlags, \
8939
+ LPSPropValue lpProps) IPURE; \
8940
+ MAPIMETHOD(EncodeRecips) \
8941
+ (THIS_ ULONG ulFlags, \
8942
+ LPMAPITABLE lpRecipientTable) IPURE; \
8943
+ MAPIMETHOD(FinishComponent) \
8944
+ (THIS_ ULONG ulFlags, \
8945
+ ULONG ulComponentID, \
8946
+ LPSPropTagArray lpCustomPropList, \
8947
+ LPSPropValue lpCustomProps, \
8948
+ LPSPropTagArray lpPropList, \
8949
+ LPSTnefProblemArray FAR * lpProblems) IPURE; \
8952
+#define INTERFACE ITnef
8953
+DECLARE_MAPI_INTERFACE_(ITnef, IUnknown)
8956
+ MAPI_IUNKNOWN_METHODS(PURE)
8957
+ MAPI_ITNEF_METHODS(PURE)
8960
+STDMETHODIMP OpenTnefStream(
8961
+ LPVOID lpvSupport,
8962
+ LPSTREAM lpStream,
8963
+ LPTSTR lpszStreamName,
8965
+ LPMESSAGE lpMessage,
8967
+ LPITNEF FAR * lppTNEF);
8969
+typedef HRESULT (STDMETHODCALLTYPE FAR * LPOPENTNEFSTREAM) (
8970
+ LPVOID lpvSupport,
8971
+ LPSTREAM lpStream,
8972
+ LPTSTR lpszStreamName,
8974
+ LPMESSAGE lpMessage,
8976
+ LPITNEF FAR * lppTNEF);
8978
+STDMETHODIMP OpenTnefStreamEx(
8979
+ LPVOID lpvSupport,
8980
+ LPSTREAM lpStream,
8981
+ LPTSTR lpszStreamName,
8983
+ LPMESSAGE lpMessage,
8985
+ LPADRBOOK lpAdressBook,
8986
+ LPITNEF FAR * lppTNEF);
8988
+typedef HRESULT (STDMETHODCALLTYPE FAR * LPOPENTNEFSTREAMEX) (
8989
+ LPVOID lpvSupport,
8990
+ LPSTREAM lpStream,
8991
+ LPTSTR lpszStreamName,
8993
+ LPMESSAGE lpMessage,
8995
+ LPADRBOOK lpAdressBook,
8996
+ LPITNEF FAR * lppTNEF);
8998
+STDMETHODIMP GetTnefStreamCodepage (
8999
+ LPSTREAM lpStream,
9000
+ ULONG FAR * lpulCodepage,
9001
+ ULONG FAR * lpulSubCodepage);
9003
+typedef HRESULT (STDMETHODCALLTYPE FAR * LPGETTNEFSTREAMCODEPAGE) (
9004
+ LPSTREAM lpStream,
9005
+ ULONG FAR * lpulCodepage,
9006
+ ULONG FAR * lpulSubCodepage);
9008
+#define OPENTNEFSTREAM "OpenTnefStream"
9009
+#define OPENTNEFSTREAMEX "OpenTnefStreamEx"
9010
+#define GETTNEFSTREAMCODEPAGE "GetTnefStreamCodePage"
9013
+/* -------------------------- */
9014
+/* TNEF Signature and Version */
9015
+/* -------------------------- */
9017
+#define MAKE_TNEF_VERSION(_mj,_mn) (((ULONG)(0x0000FFFF & _mj) << 16) | (ULONG)(0x0000FFFF & _mn))
9018
+#define TNEF_SIGNATURE ((ULONG) 0x223E9F78)
9019
+#define TNEF_VERSION ((ULONG) MAKE_TNEF_VERSION(1,0))
9022
+/* ------------------------------------------- */
9023
+/* TNEF Down-level Attachment Types/Structures */
9024
+/* ------------------------------------------- */
9027
+enum { atypNull, atypFile, atypOle, atypPicture, atypMax };
9029
+#define MAC_BINARY ((DWORD) 0x00000001)
9031
+typedef struct _renddata
9039
+} RENDDATA, *PRENDDATA;
9041
+/* ----------------------------------- */
9042
+/* TNEF Down-level Date/Time Structure */
9043
+/* ----------------------------------- */
9045
+typedef struct _dtr
9058
+/* ----------------------------- */
9059
+/* TNEF Down-level Message Flags */
9060
+/* ----------------------------- */
9062
+#define fmsNull ((BYTE) 0x00)
9063
+#define fmsModified ((BYTE) 0x01)
9064
+#define fmsLocal ((BYTE) 0x02)
9065
+#define fmsSubmitted ((BYTE) 0x04)
9066
+#define fmsRead ((BYTE) 0x20)
9067
+#define fmsHasAttach ((BYTE) 0x80)
9070
+/* ----------------------------------------- */
9071
+/* TNEF Down-level Triple Address Structures */
9072
+/* ----------------------------------------- */
9074
+#define trpidNull ((WORD) 0x0000)
9075
+#define trpidUnresolved ((WORD) 0x0001)
9076
+#define trpidResolvedNSID ((WORD) 0x0002)
9077
+#define trpidResolvedAddress ((WORD) 0x0003)
9078
+#define trpidOneOff ((WORD) 0x0004)
9079
+#define trpidGroupNSID ((WORD) 0x0005)
9080
+#define trpidOffline ((WORD) 0x0006)
9081
+#define trpidIgnore ((WORD) 0x0007)
9082
+#define trpidClassEntry ((WORD) 0x0008)
9083
+#define trpidResolvedGroupAddress ((WORD) 0x0009)
9084
+typedef struct _trp
9091
+} TRP, *PTRP, *PGRTRP, FAR * LPTRP;
9092
+#define CbOfTrp(_p) (sizeof(TRP) + (_p)->cch + (_p)->cbRgb)
9093
+#define LpszOfTrp(_p) ((LPSTR)(((LPTRP) (_p)) + 1))
9094
+#define LpbOfTrp(_p) (((LPBYTE)(((LPTRP)(_p)) + 1)) + (_p)->cch)
9095
+#define LptrpNext(_p) ((LPTRP)((LPBYTE)(_p) + CbOfTrp(_p)))
9097
+typedef DWORD XTYPE;
9098
+#define xtypeUnknown ((XTYPE) 0)
9099
+#define xtypeInternet ((XTYPE) 6)
9101
+#define cbDisplayName 41
9102
+#define cbEmailName 11
9103
+#define cbSeverName 12
9104
+typedef struct _ADDR_ALIAS
9106
+ char rgchName[cbDisplayName];
9107
+ char rgchEName[cbEmailName];
9108
+ char rgchSrvr[cbSeverName];
9112
+} ADDRALIAS, FAR * LPADDRALIAS;
9113
+#define cbALIAS sizeof(ALIAS)
9116
+#define cbMaxIdData 200
9117
+typedef struct _NSID
9120
+ unsigned char uchType[cbTYPE];
9127
+ char rgchInterNet[1];
9132
+#define cbNSID sizeof(NSID)
9135
+/* -------------------------- */
9136
+/* TNEF Down-level Priorities */
9137
+/* -------------------------- */
9144
+/* ------------------------------------- */
9145
+/* TNEF Down-level Attributes/Properties */
9146
+/* ------------------------------------- */
9148
+#define atpTriples ((WORD) 0x0000)
9149
+#define atpString ((WORD) 0x0001)
9150
+#define atpText ((WORD) 0x0002)
9151
+#define atpDate ((WORD) 0x0003)
9152
+#define atpShort ((WORD) 0x0004)
9153
+#define atpLong ((WORD) 0x0005)
9154
+#define atpByte ((WORD) 0x0006)
9155
+#define atpWord ((WORD) 0x0007)
9156
+#define atpDword ((WORD) 0x0008)
9157
+#define atpMax ((WORD) 0x0009)
9159
+#define LVL_MESSAGE ((BYTE) 0x01)
9160
+#define LVL_ATTACHMENT ((BYTE) 0x02)
9162
+#define ATT_ID(_att) ((WORD) ((_att) & 0x0000FFFF))
9163
+#define ATT_TYPE(_att) ((WORD) (((_att) >> 16) & 0x0000FFFF))
9164
+#define ATT(_atp, _id) ((((DWORD) (_atp)) << 16) | ((WORD) (_id)))
9166
+#define attNull ATT( 0, 0x0000)
9167
+#define attFrom ATT( atpTriples, 0x8000) /* PR_ORIGINATOR_RETURN_ADDRESS */
9168
+#define attSubject ATT( atpString, 0x8004) /* PR_SUBJECT */
9169
+#define attDateSent ATT( atpDate, 0x8005) /* PR_CLIENT_SUBMIT_TIME */
9170
+#define attDateRecd ATT( atpDate, 0x8006) /* PR_MESSAGE_DELIVERY_TIME */
9171
+#define attMessageStatus ATT( atpByte, 0x8007) /* PR_MESSAGE_FLAGS */
9172
+#define attMessageClass ATT( atpWord, 0x8008) /* PR_MESSAGE_CLASS */
9173
+#define attMessageID ATT( atpString, 0x8009) /* PR_MESSAGE_ID */
9174
+#define attParentID ATT( atpString, 0x800A) /* PR_PARENT_ID */
9175
+#define attConversationID ATT( atpString, 0x800B) /* PR_CONVERSATION_ID */
9176
+#define attBody ATT( atpText, 0x800C) /* PR_BODY */
9177
+#define attPriority ATT( atpShort, 0x800D) /* PR_IMPORTANCE */
9178
+#define attAttachData ATT( atpByte, 0x800F) /* PR_ATTACH_DATA_xxx */
9179
+#define attAttachTitle ATT( atpString, 0x8010) /* PR_ATTACH_FILENAME */
9180
+#define attAttachMetaFile ATT( atpByte, 0x8011) /* PR_ATTACH_RENDERING */
9181
+#define attAttachCreateDate ATT( atpDate, 0x8012) /* PR_CREATION_TIME */
9182
+#define attAttachModifyDate ATT( atpDate, 0x8013) /* PR_LAST_MODIFICATION_TIME */
9183
+#define attDateModified ATT( atpDate, 0x8020) /* PR_LAST_MODIFICATION_TIME */
9184
+#define attAttachTransportFilename ATT( atpByte, 0x9001) /* PR_ATTACH_TRANSPORT_NAME */
9185
+#define attAttachRenddata ATT( atpByte, 0x9002)
9186
+#define attMAPIProps ATT( atpByte, 0x9003)
9187
+#define attRecipTable ATT( atpByte, 0x9004) /* PR_MESSAGE_RECIPIENTS */
9188
+#define attAttachment ATT( atpByte, 0x9005)
9189
+#define attTnefVersion ATT( atpDword, 0x9006)
9190
+#define attOemCodepage ATT( atpByte, 0x9007)
9191
+#define attOriginalMessageClass ATT( atpWord, 0x0006) /* PR_ORIG_MESSAGE_CLASS */
9193
+#define attOwner ATT( atpByte, 0x0000) /* PR_RCVD_REPRESENTING_xxx or
9194
+ PR_SENT_REPRESENTING_xxx */
9195
+#define attSentFor ATT( atpByte, 0x0001) /* PR_SENT_REPRESENTING_xxx */
9196
+#define attDelegate ATT( atpByte, 0x0002) /* PR_RCVD_REPRESENTING_xxx */
9197
+#define attDateStart ATT( atpDate, 0x0006) /* PR_DATE_START */
9198
+#define attDateEnd ATT( atpDate, 0x0007) /* PR_DATE_END */
9199
+#define attAidOwner ATT( atpLong, 0x0008) /* PR_OWNER_APPT_ID */
9200
+#define attRequestRes ATT( atpShort, 0x0009) /* PR_RESPONSE_REQUESTED */
9206
+#endif /* defined TNEF_H */
9208
+ * M A P I D E F S . H
9210
+ * Definitions used by MAPI clients and service providers.
9212
+ * Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
9219
+/* Array dimension for structures with variable-sized arrays at the end. */
9221
+/* Simple data types */
9224
+typedef WORD WCHAR;
9227
+typedef WCHAR TCHAR;
9229
+typedef char TCHAR;
9232
+typedef WCHAR * LPWSTR;
9233
+typedef const WCHAR * LPCWSTR;
9234
+typedef TCHAR * LPTSTR;
9235
+typedef const TCHAR * LPCTSTR;
9236
+typedef BYTE * LPBYTE;
9238
+typedef ULONG * LPULONG;
9242
+typedef unsigned long LHANDLE, * LPLHANDLE;
9245
+#if !defined(_WINBASE_) && !defined(_FILETIME_)
9247
+typedef struct _FILETIME
9249
+ DWORD dwLowDateTime;
9250
+ DWORD dwHighDateTime;
9251
+} FILETIME, * LPFILETIME;
9255
+ * This flag is used in many different MAPI calls to signify that
9256
+ * the object opened by the call should be modifiable (MAPI_MODIFY).
9257
+ * If the flag MAPI_MAX_ACCESS is set, the object returned should be
9258
+ * returned at the maximum access level allowed. An additional
9259
+ * property available on the object (PR_ACCESS_LEVEL) uses the same
9260
+ * MAPI_MODIFY flag to say just what this new access level is.
9263
+#define MAPI_MODIFY ((ULONG) 0x00000001)
9266
+ * The following flags are used to indicate to the client what access
9267
+ * level is permissible in the object. They appear in PR_ACCESS in
9268
+ * message and folder objects as well as in contents and associated
9272
+#define MAPI_ACCESS_MODIFY ((ULONG) 0x00000001)
9273
+#define MAPI_ACCESS_READ ((ULONG) 0x00000002)
9274
+#define MAPI_ACCESS_DELETE ((ULONG) 0x00000004)
9275
+#define MAPI_ACCESS_CREATE_HIERARCHY ((ULONG) 0x00000008)
9276
+#define MAPI_ACCESS_CREATE_CONTENTS ((ULONG) 0x00000010)
9277
+#define MAPI_ACCESS_CREATE_ASSOCIATED ((ULONG) 0x00000020)
9280
+ * The MAPI_UNICODE flag is used in many different MAPI calls to signify
9281
+ * that strings passed through the interface are in Unicode (a 16-bit
9282
+ * character set). The default is an 8-bit character set.
9284
+ * The value fMapiUnicode can be used as the 'normal' value for
9285
+ * that bit, given the application's default character set.
9288
+#define MAPI_UNICODE ((ULONG) 0x80000000)
9291
+#define fMapiUnicode MAPI_UNICODE
9293
+#define fMapiUnicode 0
9296
+/* successful HRESULT */
9297
+#define hrSuccess 0
9301
+/* Recipient types */
9302
+#ifndef MAPI_ORIG /* also defined in mapi.h */
9303
+#define MAPI_ORIG 0 /* Recipient is message originator */
9304
+#define MAPI_TO 1 /* Recipient is a primary recipient */
9305
+#define MAPI_CC 2 /* Recipient is a copy recipient */
9306
+#define MAPI_BCC 3 /* Recipient is blind copy recipient */
9307
+#define MAPI_P1 0x10000000 /* Recipient is a P1 resend recipient */
9308
+#define MAPI_SUBMITTED 0x80000000 /* Recipient is already processed */
9309
+/* #define MAPI_AUTHORIZE 4 recipient is a CMC authorizing user */
9310
+/*#define MAPI_DISCRETE 0x10000000 Recipient is a P1 resend recipient */
9313
+/* Bit definitions for abFlags[0] of ENTRYID */
9314
+#define MAPI_SHORTTERM 0x80
9315
+#define MAPI_NOTRECIP 0x40
9316
+#define MAPI_THISSESSION 0x20
9317
+#define MAPI_NOW 0x10
9318
+#define MAPI_NOTRESERVED 0x08
9320
+/* Bit definitions for abFlags[1] of ENTRYID */
9321
+#define MAPI_COMPOUND 0x80
9327
+ BYTE ab[MAPI_DIM];
9328
+} ENTRYID, *LPENTRYID;
9330
+#define CbNewENTRYID(_cb) (offsetof(ENTRYID,ab) + (_cb))
9331
+#define CbENTRYID(_cb) (offsetof(ENTRYID,ab) + (_cb))
9333
+/* Byte-order-independent version of GUID (world-unique identifier) */
9334
+typedef struct _MAPIUID
9337
+} MAPIUID, * LPMAPIUID;
9339
+/* Note: need to include C run-times (memory.h) to use this macro */
9341
+#define IsEqualMAPIUID(lpuid1, lpuid2) (!memcmp(lpuid1, lpuid2, sizeof(MAPIUID)))
9344
+ * Constants for one-off entry ID:
9345
+ * The MAPIUID that identifies the one-off provider;
9346
+ * the flag that defines whether the embedded strings are Unicode;
9347
+ * the flag that specifies whether the recipient gets TNEF or not.
9350
+#define MAPI_ONE_OFF_UID { 0x81, 0x2b, 0x1f, 0xa4, 0xbe, 0xa3, 0x10, 0x19, 0x9d, 0x6e, 0x00, 0xdd, 0x01, 0x0f, 0x54, 0x02 }
9351
+#define MAPI_ONE_OFF_UNICODE 0x8000
9352
+#define MAPI_ONE_OFF_NO_RICH_INFO 0x0001
9356
+#define MAPI_STORE ((ULONG) 0x00000001) /* Message Store */
9357
+#define MAPI_ADDRBOOK ((ULONG) 0x00000002) /* Address Book */
9358
+#define MAPI_FOLDER ((ULONG) 0x00000003) /* Folder */
9359
+#define MAPI_ABCONT ((ULONG) 0x00000004) /* Address Book Container */
9360
+#define MAPI_MESSAGE ((ULONG) 0x00000005) /* Message */
9361
+#define MAPI_MAILUSER ((ULONG) 0x00000006) /* Individual Recipient */
9362
+#define MAPI_ATTACH ((ULONG) 0x00000007) /* Attachment */
9363
+#define MAPI_DISTLIST ((ULONG) 0x00000008) /* Distribution List Recipient */
9364
+#define MAPI_PROFSECT ((ULONG) 0x00000009) /* Profile Section */
9365
+#define MAPI_STATUS ((ULONG) 0x0000000A) /* Status Object */
9366
+#define MAPI_SESSION ((ULONG) 0x0000000B) /* Session */
9367
+#define MAPI_FORMINFO ((ULONG) 0x0000000C) /* Form Information */
9371
+ * Maximum length of profile names and passwords, not including
9372
+ * the null termination character.
9374
+#ifndef cchProfileNameMax
9375
+#define cchProfileNameMax 64
9376
+#define cchProfilePassMax 64
9380
+/* Property Types */
9382
+#define MV_FLAG 0x1000 /* Multi-value flag */
9384
+#define PT_UNSPECIFIED ((ULONG) 0) /* (Reserved for interface use) type doesn't matter to caller */
9385
+#define PT_NULL ((ULONG) 1) /* NULL property value */
9386
+#define PT_I2 ((ULONG) 2) /* Signed 16-bit value */
9387
+#define PT_LONG ((ULONG) 3) /* Signed 32-bit value */
9388
+#define PT_R4 ((ULONG) 4) /* 4-byte floating point */
9389
+#define PT_DOUBLE ((ULONG) 5) /* Floating point double */
9390
+#define PT_CURRENCY ((ULONG) 6) /* Signed 64-bit int (decimal w/ 4 digits right of decimal pt) */
9391
+#define PT_APPTIME ((ULONG) 7) /* Application time */
9392
+#define PT_ERROR ((ULONG) 10) /* 32-bit error value */
9393
+#define PT_BOOLEAN ((ULONG) 11) /* 16-bit boolean (non-zero true) */
9394
+#define PT_OBJECT ((ULONG) 13) /* Embedded object in a property */
9395
+#define PT_I8 ((ULONG) 20) /* 8-byte signed integer */
9396
+#define PT_STRING8 ((ULONG) 30) /* Null terminated 8-bit character string */
9397
+#define PT_UNICODE ((ULONG) 31) /* Null terminated Unicode string */
9398
+#define PT_SYSTIME ((ULONG) 64) /* FILETIME 64-bit int w/ number of 100ns periods since Jan 1,1601 */
9399
+#define PT_CLSID ((ULONG) 72) /* OLE GUID */
9400
+#define PT_BINARY ((ULONG) 258) /* Uninterpreted (counted byte array) */
9401
+/* Changes are likely to these numbers, and to their structures. */
9403
+/* Alternate property type names for ease of use */
9404
+#define PT_SHORT PT_I2
9405
+#define PT_I4 PT_LONG
9406
+#define PT_FLOAT PT_R4
9407
+#define PT_R8 PT_DOUBLE
9408
+#define PT_LONGLONG PT_I8
9411
+ * The type of a MAPI-defined string property is indirected, so
9412
+ * that it defaults to Unicode string on a Unicode platform and to
9413
+ * String8 on an ANSI or DBCS platform.
9415
+ * Macros are defined here both for the property type, and for the
9416
+ * field of the property value structure which should be
9417
+ * dereferenced to obtain the string pointer.
9421
+#define PT_TSTRING PT_UNICODE
9422
+#define PT_MV_TSTRING (MV_FLAG|PT_UNICODE)
9424
+#define LPPSZ lppszW
9427
+#define PT_TSTRING PT_STRING8
9428
+#define PT_MV_TSTRING (MV_FLAG|PT_STRING8)
9430
+#define LPPSZ lppszA
9437
+ * By convention, MAPI never uses 0 or FFFF as a property ID.
9438
+ * Use as null values, initializers, sentinels, or what have you.
9441
+#define PROP_TYPE_MASK ((ULONG)0x0000FFFF) /* Mask for Property type */
9442
+#define PROP_TYPE(ulPropTag) (((ULONG)(ulPropTag))&PROP_TYPE_MASK)
9443
+#define PROP_ID(ulPropTag) (((ULONG)(ulPropTag))>>16)
9444
+#define PROP_TAG(ulPropType,ulPropID) ((((ULONG)(ulPropID))<<16)|((ULONG)(ulPropType)))
9445
+#define PROP_ID_NULL 0
9446
+#define PROP_ID_INVALID 0xFFFF
9447
+#define PR_NULL PROP_TAG( PT_NULL, PROP_ID_NULL)
9449
+#define CHANGE_PROP_TYPE(ulPropTag, ulPropType) \
9450
+ (((ULONG)0xFFFF0000 & ulPropTag) | ulPropType)
9454
+/* Multi-valued Property Types */
9456
+#define PT_MV_I2 (MV_FLAG|PT_I2)
9457
+#define PT_MV_LONG (MV_FLAG|PT_LONG)
9458
+#define PT_MV_R4 (MV_FLAG|PT_R4)
9459
+#define PT_MV_DOUBLE (MV_FLAG|PT_DOUBLE)
9460
+#define PT_MV_CURRENCY (MV_FLAG|PT_CURRENCY)
9461
+#define PT_MV_APPTIME (MV_FLAG|PT_APPTIME)
9462
+#define PT_MV_SYSTIME (MV_FLAG|PT_SYSTIME)
9463
+#define PT_MV_STRING8 (MV_FLAG|PT_STRING8)
9464
+#define PT_MV_BINARY (MV_FLAG|PT_BINARY)
9465
+#define PT_MV_UNICODE (MV_FLAG|PT_UNICODE)
9466
+#define PT_MV_CLSID (MV_FLAG|PT_CLSID)
9467
+#define PT_MV_I8 (MV_FLAG|PT_I8)
9469
+/* Alternate property type names for ease of use */
9470
+#define PT_MV_SHORT PT_MV_I2
9471
+#define PT_MV_I4 PT_MV_LONG
9472
+#define PT_MV_FLOAT PT_MV_R4
9473
+#define PT_MV_R8 PT_MV_DOUBLE
9474
+#define PT_MV_LONGLONG PT_MV_I8
9477
+ * Property type reserved bits
9479
+ * MV_INSTANCE is used as a flag in table operations to request
9480
+ * that a multi-valued property be presented as a single-valued
9481
+ * property appearing in multiple rows.
9484
+#define MV_INSTANCE 0x2000
9485
+#define MVI_FLAG (MV_FLAG | MV_INSTANCE)
9486
+#define MVI_PROP(tag) ((tag) | MVI_FLAG)
9490
+#endif /* MAPIDEFS_H */
9492
+ * M A P I T A G S . H
9494
+ * Property tag definitions for standard properties of MAPI
9497
+ * The following ranges should be used for all property IDs. Note that
9498
+ * property IDs for objects other than messages and recipients should
9499
+ * all fall in the range 0x3000 to 0x3FFF:
9501
+ * From To Kind of property
9502
+ * --------------------------------
9503
+ * 0001 0BFF MAPI_defined envelope property
9504
+ * 0C00 0DFF MAPI_defined per-recipient property
9505
+ * 0E00 0FFF MAPI_defined non-transmittable property
9506
+ * 1000 2FFF MAPI_defined message content property
9508
+ * 3000 3FFF MAPI_defined property (usually not message or recipient)
9510
+ * 4000 57FF Transport-defined envelope property
9511
+ * 5800 5FFF Transport-defined per-recipient property
9512
+ * 6000 65FF User-defined non-transmittable property
9513
+ * 6600 67FF Provider-defined internal non-transmittable property
9514
+ * 6800 7BFF Message class-defined content property
9515
+ * 7C00 7FFF Message class-defined non-transmittable
9518
+ * 8000 FFFE User-defined Name-to-id mapped property
9520
+ * The 3000-3FFF range is further subdivided as follows:
9522
+ * From To Kind of property
9523
+ * --------------------------------
9524
+ * 3000 33FF Common property such as display name, entry ID
9525
+ * 3400 35FF Message store object
9526
+ * 3600 36FF Folder or AB container
9527
+ * 3700 38FF Attachment
9528
+ * 3900 39FF Address book object
9529
+ * 3A00 3BFF Mail user
9530
+ * 3C00 3CFF Distribution list
9531
+ * 3D00 3DFF Profile section
9532
+ * 3E00 3FFF Status object
9534
+ * Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
9540
+/* Determine if a property is transmittable. */
9542
+#define FIsTransmittable(ulPropTag) \
9543
+ ((PROP_ID (ulPropTag) < (ULONG)0x0E00) || \
9544
+ (PROP_ID (ulPropTag) >= (ULONG)0x8000) || \
9545
+ ((PROP_ID (ulPropTag) >= (ULONG)0x1000) && (PROP_ID (ulPropTag) < (ULONG)0x6000)) || \
9546
+ ((PROP_ID (ulPropTag) >= (ULONG)0x6800) && (PROP_ID (ulPropTag) < (ULONG)0x7C00)))
9549
+ * Message envelope properties
9552
+#define PR_ACKNOWLEDGEMENT_MODE PROP_TAG( PT_LONG, 0x0001)
9553
+#define PR_ALTERNATE_RECIPIENT_ALLOWED PROP_TAG( PT_BOOLEAN, 0x0002)
9554
+#define PR_AUTHORIZING_USERS PROP_TAG( PT_BINARY, 0x0003)
9555
+#define PR_AUTO_FORWARD_COMMENT PROP_TAG( PT_TSTRING, 0x0004)
9556
+#define PR_AUTO_FORWARD_COMMENT_W PROP_TAG( PT_UNICODE, 0x0004)
9557
+#define PR_AUTO_FORWARD_COMMENT_A PROP_TAG( PT_STRING8, 0x0004)
9558
+#define PR_AUTO_FORWARDED PROP_TAG( PT_BOOLEAN, 0x0005)
9559
+#define PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID PROP_TAG( PT_BINARY, 0x0006)
9560
+#define PR_CONTENT_CORRELATOR PROP_TAG( PT_BINARY, 0x0007)
9561
+#define PR_CONTENT_IDENTIFIER PROP_TAG( PT_TSTRING, 0x0008)
9562
+#define PR_CONTENT_IDENTIFIER_W PROP_TAG( PT_UNICODE, 0x0008)
9563
+#define PR_CONTENT_IDENTIFIER_A PROP_TAG( PT_STRING8, 0x0008)
9564
+#define PR_CONTENT_LENGTH PROP_TAG( PT_LONG, 0x0009)
9565
+#define PR_CONTENT_RETURN_REQUESTED PROP_TAG( PT_BOOLEAN, 0x000A)
9569
+#define PR_CONVERSATION_KEY PROP_TAG( PT_BINARY, 0x000B)
9571
+#define PR_CONVERSION_EITS PROP_TAG( PT_BINARY, 0x000C)
9572
+#define PR_CONVERSION_WITH_LOSS_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x000D)
9573
+#define PR_CONVERTED_EITS PROP_TAG( PT_BINARY, 0x000E)
9574
+#define PR_DEFERRED_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x000F)
9575
+#define PR_DELIVER_TIME PROP_TAG( PT_SYSTIME, 0x0010)
9576
+#define PR_DISCARD_REASON PROP_TAG( PT_LONG, 0x0011)
9577
+#define PR_DISCLOSURE_OF_RECIPIENTS PROP_TAG( PT_BOOLEAN, 0x0012)
9578
+#define PR_DL_EXPANSION_HISTORY PROP_TAG( PT_BINARY, 0x0013)
9579
+#define PR_DL_EXPANSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0014)
9580
+#define PR_EXPIRY_TIME PROP_TAG( PT_SYSTIME, 0x0015)
9581
+#define PR_IMPLICIT_CONVERSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0016)
9582
+#define PR_IMPORTANCE PROP_TAG( PT_LONG, 0x0017)
9583
+#define PR_IPM_ID PROP_TAG( PT_BINARY, 0x0018)
9584
+#define PR_LATEST_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0019)
9585
+#define PR_MESSAGE_CLASS PROP_TAG( PT_TSTRING, 0x001A)
9586
+#define PR_MESSAGE_CLASS_W PROP_TAG( PT_UNICODE, 0x001A)
9587
+#define PR_MESSAGE_CLASS_A PROP_TAG( PT_STRING8, 0x001A)
9588
+#define PR_MESSAGE_DELIVERY_ID PROP_TAG( PT_BINARY, 0x001B)
9594
+#define PR_MESSAGE_SECURITY_LABEL PROP_TAG( PT_BINARY, 0x001E)
9595
+#define PR_OBSOLETED_IPMS PROP_TAG( PT_BINARY, 0x001F)
9596
+#define PR_ORIGINALLY_INTENDED_RECIPIENT_NAME PROP_TAG( PT_BINARY, 0x0020)
9597
+#define PR_ORIGINAL_EITS PROP_TAG( PT_BINARY, 0x0021)
9598
+#define PR_ORIGINATOR_CERTIFICATE PROP_TAG( PT_BINARY, 0x0022)
9599
+#define PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0023)
9600
+#define PR_ORIGINATOR_RETURN_ADDRESS PROP_TAG( PT_BINARY, 0x0024)
9604
+#define PR_PARENT_KEY PROP_TAG( PT_BINARY, 0x0025)
9605
+#define PR_PRIORITY PROP_TAG( PT_LONG, 0x0026)
9609
+#define PR_ORIGIN_CHECK PROP_TAG( PT_BINARY, 0x0027)
9610
+#define PR_PROOF_OF_SUBMISSION_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0028)
9611
+#define PR_READ_RECEIPT_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0029)
9612
+#define PR_RECEIPT_TIME PROP_TAG( PT_SYSTIME, 0x002A)
9613
+#define PR_RECIPIENT_REASSIGNMENT_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x002B)
9614
+#define PR_REDIRECTION_HISTORY PROP_TAG( PT_BINARY, 0x002C)
9615
+#define PR_RELATED_IPMS PROP_TAG( PT_BINARY, 0x002D)
9616
+#define PR_ORIGINAL_SENSITIVITY PROP_TAG( PT_LONG, 0x002E)
9617
+#define PR_LANGUAGES PROP_TAG( PT_TSTRING, 0x002F)
9618
+#define PR_LANGUAGES_W PROP_TAG( PT_UNICODE, 0x002F)
9619
+#define PR_LANGUAGES_A PROP_TAG( PT_STRING8, 0x002F)
9620
+#define PR_REPLY_TIME PROP_TAG( PT_SYSTIME, 0x0030)
9621
+#define PR_REPORT_TAG PROP_TAG( PT_BINARY, 0x0031)
9622
+#define PR_REPORT_TIME PROP_TAG( PT_SYSTIME, 0x0032)
9623
+#define PR_RETURNED_IPM PROP_TAG( PT_BOOLEAN, 0x0033)
9624
+#define PR_SECURITY PROP_TAG( PT_LONG, 0x0034)
9625
+#define PR_INCOMPLETE_COPY PROP_TAG( PT_BOOLEAN, 0x0035)
9626
+#define PR_SENSITIVITY PROP_TAG( PT_LONG, 0x0036)
9627
+#define PR_SUBJECT PROP_TAG( PT_TSTRING, 0x0037)
9628
+#define PR_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0037)
9629
+#define PR_SUBJECT_A PROP_TAG( PT_STRING8, 0x0037)
9630
+#define PR_SUBJECT_IPM PROP_TAG( PT_BINARY, 0x0038)
9631
+#define PR_CLIENT_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x0039)
9632
+#define PR_REPORT_NAME PROP_TAG( PT_TSTRING, 0x003A)
9633
+#define PR_REPORT_NAME_W PROP_TAG( PT_UNICODE, 0x003A)
9634
+#define PR_REPORT_NAME_A PROP_TAG( PT_STRING8, 0x003A)
9635
+#define PR_SENT_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x003B)
9636
+#define PR_X400_CONTENT_TYPE PROP_TAG( PT_BINARY, 0x003C)
9637
+#define PR_SUBJECT_PREFIX PROP_TAG( PT_TSTRING, 0x003D)
9638
+#define PR_SUBJECT_PREFIX_W PROP_TAG( PT_UNICODE, 0x003D)
9639
+#define PR_SUBJECT_PREFIX_A PROP_TAG( PT_STRING8, 0x003D)
9640
+#define PR_NON_RECEIPT_REASON PROP_TAG( PT_LONG, 0x003E)
9641
+#define PR_RECEIVED_BY_ENTRYID PROP_TAG( PT_BINARY, 0x003F)
9642
+#define PR_RECEIVED_BY_NAME PROP_TAG( PT_TSTRING, 0x0040)
9643
+#define PR_RECEIVED_BY_NAME_W PROP_TAG( PT_UNICODE, 0x0040)
9644
+#define PR_RECEIVED_BY_NAME_A PROP_TAG( PT_STRING8, 0x0040)
9645
+#define PR_SENT_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x0041)
9646
+#define PR_SENT_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x0042)
9647
+#define PR_SENT_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x0042)
9648
+#define PR_SENT_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x0042)
9649
+#define PR_RCVD_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x0043)
9650
+#define PR_RCVD_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x0044)
9651
+#define PR_RCVD_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x0044)
9652
+#define PR_RCVD_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x0044)
9653
+#define PR_REPORT_ENTRYID PROP_TAG( PT_BINARY, 0x0045)
9654
+#define PR_READ_RECEIPT_ENTRYID PROP_TAG( PT_BINARY, 0x0046)
9655
+#define PR_MESSAGE_SUBMISSION_ID PROP_TAG( PT_BINARY, 0x0047)
9656
+#define PR_PROVIDER_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x0048)
9657
+#define PR_ORIGINAL_SUBJECT PROP_TAG( PT_TSTRING, 0x0049)
9658
+#define PR_ORIGINAL_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0049)
9659
+#define PR_ORIGINAL_SUBJECT_A PROP_TAG( PT_STRING8, 0x0049)
9660
+#define PR_DISC_VAL PROP_TAG( PT_BOOLEAN, 0x004A)
9661
+#define PR_ORIG_MESSAGE_CLASS PROP_TAG( PT_TSTRING, 0x004B)
9662
+#define PR_ORIG_MESSAGE_CLASS_W PROP_TAG( PT_UNICODE, 0x004B)
9663
+#define PR_ORIG_MESSAGE_CLASS_A PROP_TAG( PT_STRING8, 0x004B)
9664
+#define PR_ORIGINAL_AUTHOR_ENTRYID PROP_TAG( PT_BINARY, 0x004C)
9665
+#define PR_ORIGINAL_AUTHOR_NAME PROP_TAG( PT_TSTRING, 0x004D)
9666
+#define PR_ORIGINAL_AUTHOR_NAME_W PROP_TAG( PT_UNICODE, 0x004D)
9667
+#define PR_ORIGINAL_AUTHOR_NAME_A PROP_TAG( PT_STRING8, 0x004D)
9668
+#define PR_ORIGINAL_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x004E)
9669
+#define PR_REPLY_RECIPIENT_ENTRIES PROP_TAG( PT_BINARY, 0x004F)
9670
+#define PR_REPLY_RECIPIENT_NAMES PROP_TAG( PT_TSTRING, 0x0050)
9671
+#define PR_REPLY_RECIPIENT_NAMES_W PROP_TAG( PT_UNICODE, 0x0050)
9672
+#define PR_REPLY_RECIPIENT_NAMES_A PROP_TAG( PT_STRING8, 0x0050)
9674
+#define PR_RECEIVED_BY_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0051)
9675
+#define PR_RCVD_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0052)
9676
+#define PR_READ_RECEIPT_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0053)
9677
+#define PR_REPORT_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0054)
9678
+#define PR_ORIGINAL_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0055)
9679
+#define PR_ORIGINAL_AUTHOR_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0056)
9681
+#define PR_MESSAGE_TO_ME PROP_TAG( PT_BOOLEAN, 0x0057)
9682
+#define PR_MESSAGE_CC_ME PROP_TAG( PT_BOOLEAN, 0x0058)
9683
+#define PR_MESSAGE_RECIP_ME PROP_TAG( PT_BOOLEAN, 0x0059)
9685
+#define PR_ORIGINAL_SENDER_NAME PROP_TAG( PT_TSTRING, 0x005A)
9686
+#define PR_ORIGINAL_SENDER_NAME_W PROP_TAG( PT_UNICODE, 0x005A)
9687
+#define PR_ORIGINAL_SENDER_NAME_A PROP_TAG( PT_STRING8, 0x005A)
9688
+#define PR_ORIGINAL_SENDER_ENTRYID PROP_TAG( PT_BINARY, 0x005B)
9689
+#define PR_ORIGINAL_SENDER_SEARCH_KEY PROP_TAG( PT_BINARY, 0x005C)
9690
+#define PR_ORIGINAL_SENT_REPRESENTING_NAME PROP_TAG( PT_TSTRING, 0x005D)
9691
+#define PR_ORIGINAL_SENT_REPRESENTING_NAME_W PROP_TAG( PT_UNICODE, 0x005D)
9692
+#define PR_ORIGINAL_SENT_REPRESENTING_NAME_A PROP_TAG( PT_STRING8, 0x005D)
9693
+#define PR_ORIGINAL_SENT_REPRESENTING_ENTRYID PROP_TAG( PT_BINARY, 0x005E)
9694
+#define PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY PROP_TAG( PT_BINARY, 0x005F)
9696
+#define PR_START_DATE PROP_TAG( PT_SYSTIME, 0x0060)
9697
+#define PR_END_DATE PROP_TAG( PT_SYSTIME, 0x0061)
9698
+#define PR_OWNER_APPT_ID PROP_TAG( PT_LONG, 0x0062)
9699
+#define PR_RESPONSE_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0063)
9701
+#define PR_SENT_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0064)
9702
+#define PR_SENT_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0064)
9703
+#define PR_SENT_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0064)
9704
+#define PR_SENT_REPRESENTING_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0065)
9705
+#define PR_SENT_REPRESENTING_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0065)
9706
+#define PR_SENT_REPRESENTING_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0065)
9708
+#define PR_ORIGINAL_SENDER_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0066)
9709
+#define PR_ORIGINAL_SENDER_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0066)
9710
+#define PR_ORIGINAL_SENDER_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0066)
9711
+#define PR_ORIGINAL_SENDER_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0067)
9712
+#define PR_ORIGINAL_SENDER_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0067)
9713
+#define PR_ORIGINAL_SENDER_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0067)
9715
+#define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0068)
9716
+#define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0068)
9717
+#define PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0068)
9718
+#define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0069)
9719
+#define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0069)
9720
+#define PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0069)
9722
+#define PR_CONVERSATION_TOPIC PROP_TAG( PT_TSTRING, 0x0070)
9723
+#define PR_CONVERSATION_TOPIC_W PROP_TAG( PT_UNICODE, 0x0070)
9724
+#define PR_CONVERSATION_TOPIC_A PROP_TAG( PT_STRING8, 0x0070)
9725
+#define PR_CONVERSATION_INDEX PROP_TAG( PT_BINARY, 0x0071)
9727
+#define PR_ORIGINAL_DISPLAY_BCC PROP_TAG( PT_TSTRING, 0x0072)
9728
+#define PR_ORIGINAL_DISPLAY_BCC_W PROP_TAG( PT_UNICODE, 0x0072)
9729
+#define PR_ORIGINAL_DISPLAY_BCC_A PROP_TAG( PT_STRING8, 0x0072)
9730
+#define PR_ORIGINAL_DISPLAY_CC PROP_TAG( PT_TSTRING, 0x0073)
9731
+#define PR_ORIGINAL_DISPLAY_CC_W PROP_TAG( PT_UNICODE, 0x0073)
9732
+#define PR_ORIGINAL_DISPLAY_CC_A PROP_TAG( PT_STRING8, 0x0073)
9733
+#define PR_ORIGINAL_DISPLAY_TO PROP_TAG( PT_TSTRING, 0x0074)
9734
+#define PR_ORIGINAL_DISPLAY_TO_W PROP_TAG( PT_UNICODE, 0x0074)
9735
+#define PR_ORIGINAL_DISPLAY_TO_A PROP_TAG( PT_STRING8, 0x0074)
9737
+#define PR_RECEIVED_BY_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0075)
9738
+#define PR_RECEIVED_BY_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0075)
9739
+#define PR_RECEIVED_BY_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0075)
9740
+#define PR_RECEIVED_BY_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0076)
9741
+#define PR_RECEIVED_BY_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0076)
9742
+#define PR_RECEIVED_BY_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0076)
9744
+#define PR_RCVD_REPRESENTING_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0077)
9745
+#define PR_RCVD_REPRESENTING_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0077)
9746
+#define PR_RCVD_REPRESENTING_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0077)
9747
+#define PR_RCVD_REPRESENTING_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0078)
9748
+#define PR_RCVD_REPRESENTING_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0078)
9749
+#define PR_RCVD_REPRESENTING_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0078)
9751
+#define PR_ORIGINAL_AUTHOR_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0079)
9752
+#define PR_ORIGINAL_AUTHOR_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0079)
9753
+#define PR_ORIGINAL_AUTHOR_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0079)
9754
+#define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x007A)
9755
+#define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x007A)
9756
+#define PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x007A)
9758
+#define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE PROP_TAG( PT_TSTRING, 0x007B)
9759
+#define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x007B)
9760
+#define PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x007B)
9761
+#define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x007C)
9762
+#define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x007C)
9763
+#define PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x007C)
9765
+#define PR_TRANSPORT_MESSAGE_HEADERS PROP_TAG(PT_TSTRING, 0x007D)
9766
+#define PR_TRANSPORT_MESSAGE_HEADERS_W PROP_TAG(PT_UNICODE, 0x007D)
9767
+#define PR_TRANSPORT_MESSAGE_HEADERS_A PROP_TAG(PT_STRING8, 0x007D)
9769
+#define PR_DELEGATION PROP_TAG(PT_BINARY, 0x007E)
9771
+#define PR_TNEF_CORRELATION_KEY PROP_TAG(PT_BINARY, 0x007F)
9776
+ * Message content properties
9779
+#define PR_BODY PROP_TAG( PT_TSTRING, 0x1000)
9780
+#define PR_BODY_W PROP_TAG( PT_UNICODE, 0x1000)
9781
+#define PR_BODY_A PROP_TAG( PT_STRING8, 0x1000)
9782
+#define PR_REPORT_TEXT PROP_TAG( PT_TSTRING, 0x1001)
9783
+#define PR_REPORT_TEXT_W PROP_TAG( PT_UNICODE, 0x1001)
9784
+#define PR_REPORT_TEXT_A PROP_TAG( PT_STRING8, 0x1001)
9785
+#define PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY PROP_TAG( PT_BINARY, 0x1002)
9786
+#define PR_REPORTING_DL_NAME PROP_TAG( PT_BINARY, 0x1003)
9787
+#define PR_REPORTING_MTA_CERTIFICATE PROP_TAG( PT_BINARY, 0x1004)
9789
+/* Removed PR_REPORT_ORIGIN_AUTHENTICATION_CHECK with DCR 3865, use PR_ORIGIN_CHECK */
9791
+#define PR_RTF_SYNC_BODY_CRC PROP_TAG( PT_LONG, 0x1006)
9792
+#define PR_RTF_SYNC_BODY_COUNT PROP_TAG( PT_LONG, 0x1007)
9793
+#define PR_RTF_SYNC_BODY_TAG PROP_TAG( PT_TSTRING, 0x1008)
9794
+#define PR_RTF_SYNC_BODY_TAG_W PROP_TAG( PT_UNICODE, 0x1008)
9795
+#define PR_RTF_SYNC_BODY_TAG_A PROP_TAG( PT_STRING8, 0x1008)
9796
+#define PR_RTF_COMPRESSED PROP_TAG( PT_BINARY, 0x1009)
9797
+#define PR_RTF_SYNC_PREFIX_COUNT PROP_TAG( PT_LONG, 0x1010)
9798
+#define PR_RTF_SYNC_TRAILING_COUNT PROP_TAG( PT_LONG, 0x1011)
9799
+#define PR_ORIGINALLY_INTENDED_RECIP_ENTRYID PROP_TAG( PT_BINARY, 0x1012)
9802
+ * Reserved 0x1100-0x1200
9807
+ * Message recipient properties
9810
+#define PR_CONTENT_INTEGRITY_CHECK PROP_TAG( PT_BINARY, 0x0C00)
9811
+#define PR_EXPLICIT_CONVERSION PROP_TAG( PT_LONG, 0x0C01)
9812
+#define PR_IPM_RETURN_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C02)
9813
+#define PR_MESSAGE_TOKEN PROP_TAG( PT_BINARY, 0x0C03)
9814
+#define PR_NDR_REASON_CODE PROP_TAG( PT_LONG, 0x0C04)
9815
+#define PR_NDR_DIAG_CODE PROP_TAG( PT_LONG, 0x0C05)
9816
+#define PR_NON_RECEIPT_NOTIFICATION_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C06)
9817
+#define PR_DELIVERY_POINT PROP_TAG( PT_LONG, 0x0C07)
9819
+#define PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C08)
9820
+#define PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT PROP_TAG( PT_BINARY, 0x0C09)
9821
+#define PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY PROP_TAG( PT_BOOLEAN, 0x0C0A)
9822
+#define PR_PHYSICAL_DELIVERY_MODE PROP_TAG( PT_LONG, 0x0C0B)
9823
+#define PR_PHYSICAL_DELIVERY_REPORT_REQUEST PROP_TAG( PT_LONG, 0x0C0C)
9824
+#define PR_PHYSICAL_FORWARDING_ADDRESS PROP_TAG( PT_BINARY, 0x0C0D)
9825
+#define PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C0E)
9826
+#define PR_PHYSICAL_FORWARDING_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x0C0F)
9827
+#define PR_PHYSICAL_RENDITION_ATTRIBUTES PROP_TAG( PT_BINARY, 0x0C10)
9828
+#define PR_PROOF_OF_DELIVERY PROP_TAG( PT_BINARY, 0x0C11)
9829
+#define PR_PROOF_OF_DELIVERY_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C12)
9830
+#define PR_RECIPIENT_CERTIFICATE PROP_TAG( PT_BINARY, 0x0C13)
9831
+#define PR_RECIPIENT_NUMBER_FOR_ADVICE PROP_TAG( PT_TSTRING, 0x0C14)
9832
+#define PR_RECIPIENT_NUMBER_FOR_ADVICE_W PROP_TAG( PT_UNICODE, 0x0C14)
9833
+#define PR_RECIPIENT_NUMBER_FOR_ADVICE_A PROP_TAG( PT_STRING8, 0x0C14)
9834
+#define PR_RECIPIENT_TYPE PROP_TAG( PT_LONG, 0x0C15)
9835
+#define PR_REGISTERED_MAIL_TYPE PROP_TAG( PT_LONG, 0x0C16)
9836
+#define PR_REPLY_REQUESTED PROP_TAG( PT_BOOLEAN, 0x0C17)
9837
+#define PR_REQUESTED_DELIVERY_METHOD PROP_TAG( PT_LONG, 0x0C18)
9838
+#define PR_SENDER_ENTRYID PROP_TAG( PT_BINARY, 0x0C19)
9839
+#define PR_SENDER_NAME PROP_TAG( PT_TSTRING, 0x0C1A)
9840
+#define PR_SENDER_NAME_W PROP_TAG( PT_UNICODE, 0x0C1A)
9841
+#define PR_SENDER_NAME_A PROP_TAG( PT_STRING8, 0x0C1A)
9842
+#define PR_SUPPLEMENTARY_INFO PROP_TAG( PT_TSTRING, 0x0C1B)
9843
+#define PR_SUPPLEMENTARY_INFO_W PROP_TAG( PT_UNICODE, 0x0C1B)
9844
+#define PR_SUPPLEMENTARY_INFO_A PROP_TAG( PT_STRING8, 0x0C1B)
9845
+#define PR_TYPE_OF_MTS_USER PROP_TAG( PT_LONG, 0x0C1C)
9846
+#define PR_SENDER_SEARCH_KEY PROP_TAG( PT_BINARY, 0x0C1D)
9847
+#define PR_SENDER_ADDRTYPE PROP_TAG( PT_TSTRING, 0x0C1E)
9848
+#define PR_SENDER_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x0C1E)
9849
+#define PR_SENDER_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x0C1E)
9850
+#define PR_SENDER_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x0C1F)
9851
+#define PR_SENDER_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x0C1F)
9852
+#define PR_SENDER_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x0C1F)
9855
+ * Message non-transmittable properties
9859
+ * The two tags, PR_MESSAGE_RECIPIENTS and PR_MESSAGE_ATTACHMENTS,
9860
+ * are to be used in the exclude list passed to
9861
+ * IMessage::CopyTo when the caller wants either the recipients or attachments
9862
+ * of the message to not get copied. It is also used in the ProblemArray
9863
+ * return from IMessage::CopyTo when an error is encountered copying them
9866
+#define PR_CURRENT_VERSION PROP_TAG( PT_I8, 0x0E00)
9867
+#define PR_DELETE_AFTER_SUBMIT PROP_TAG( PT_BOOLEAN, 0x0E01)
9868
+#define PR_DISPLAY_BCC PROP_TAG( PT_TSTRING, 0x0E02)
9869
+#define PR_DISPLAY_BCC_W PROP_TAG( PT_UNICODE, 0x0E02)
9870
+#define PR_DISPLAY_BCC_A PROP_TAG( PT_STRING8, 0x0E02)
9871
+#define PR_DISPLAY_CC PROP_TAG( PT_TSTRING, 0x0E03)
9872
+#define PR_DISPLAY_CC_W PROP_TAG( PT_UNICODE, 0x0E03)
9873
+#define PR_DISPLAY_CC_A PROP_TAG( PT_STRING8, 0x0E03)
9874
+#define PR_DISPLAY_TO PROP_TAG( PT_TSTRING, 0x0E04)
9875
+#define PR_DISPLAY_TO_W PROP_TAG( PT_UNICODE, 0x0E04)
9876
+#define PR_DISPLAY_TO_A PROP_TAG( PT_STRING8, 0x0E04)
9877
+#define PR_PARENT_DISPLAY PROP_TAG( PT_TSTRING, 0x0E05)
9878
+#define PR_PARENT_DISPLAY_W PROP_TAG( PT_UNICODE, 0x0E05)
9879
+#define PR_PARENT_DISPLAY_A PROP_TAG( PT_STRING8, 0x0E05)
9880
+#define PR_MESSAGE_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0E06)
9881
+#define PR_MESSAGE_FLAGS PROP_TAG( PT_LONG, 0x0E07)
9882
+#define PR_MESSAGE_SIZE PROP_TAG( PT_LONG, 0x0E08)
9883
+#define PR_PARENT_ENTRYID PROP_TAG( PT_BINARY, 0x0E09)
9884
+#define PR_SENTMAIL_ENTRYID PROP_TAG( PT_BINARY, 0x0E0A)
9885
+#define PR_CORRELATE PROP_TAG( PT_BOOLEAN, 0x0E0C)
9886
+#define PR_CORRELATE_MTSID PROP_TAG( PT_BINARY, 0x0E0D)
9887
+#define PR_DISCRETE_VALUES PROP_TAG( PT_BOOLEAN, 0x0E0E)
9888
+#define PR_RESPONSIBILITY PROP_TAG( PT_BOOLEAN, 0x0E0F)
9889
+#define PR_SPOOLER_STATUS PROP_TAG( PT_LONG, 0x0E10)
9890
+#define PR_TRANSPORT_STATUS PROP_TAG( PT_LONG, 0x0E11)
9891
+#define PR_MESSAGE_RECIPIENTS PROP_TAG( PT_OBJECT, 0x0E12)
9892
+#define PR_MESSAGE_ATTACHMENTS PROP_TAG( PT_OBJECT, 0x0E13)
9893
+#define PR_SUBMIT_FLAGS PROP_TAG( PT_LONG, 0x0E14)
9894
+#define PR_RECIPIENT_STATUS PROP_TAG( PT_LONG, 0x0E15)
9895
+#define PR_TRANSPORT_KEY PROP_TAG( PT_LONG, 0x0E16)
9896
+#define PR_MSG_STATUS PROP_TAG( PT_LONG, 0x0E17)
9897
+#define PR_MESSAGE_DOWNLOAD_TIME PROP_TAG( PT_LONG, 0x0E18)
9898
+#define PR_CREATION_VERSION PROP_TAG( PT_I8, 0x0E19)
9899
+#define PR_MODIFY_VERSION PROP_TAG( PT_I8, 0x0E1A)
9900
+#define PR_HASATTACH PROP_TAG( PT_BOOLEAN, 0x0E1B)
9901
+#define PR_BODY_CRC PROP_TAG( PT_LONG, 0x0E1C)
9902
+#define PR_NORMALIZED_SUBJECT PROP_TAG( PT_TSTRING, 0x0E1D)
9903
+#define PR_NORMALIZED_SUBJECT_W PROP_TAG( PT_UNICODE, 0x0E1D)
9904
+#define PR_NORMALIZED_SUBJECT_A PROP_TAG( PT_STRING8, 0x0E1D)
9905
+#define PR_RTF_IN_SYNC PROP_TAG( PT_BOOLEAN, 0x0E1F)
9906
+#define PR_ATTACH_SIZE PROP_TAG( PT_LONG, 0x0E20)
9907
+#define PR_ATTACH_NUM PROP_TAG( PT_LONG, 0x0E21)
9908
+#define PR_PREPROCESS PROP_TAG( PT_BOOLEAN, 0x0E22)
9910
+/* PR_ORIGINAL_DISPLAY_TO, _CC, and _BCC moved to transmittible range 03/09/95 */
9912
+#define PR_ORIGINATING_MTA_CERTIFICATE PROP_TAG( PT_BINARY, 0x0E25)
9913
+#define PR_PROOF_OF_SUBMISSION PROP_TAG( PT_BINARY, 0x0E26)
9917
+ * The range of non-message and non-recipient property IDs (0x3000 - 0x3FFF) is
9918
+ * further broken down into ranges to make assigning new property IDs easier.
9920
+ * From To Kind of property
9921
+ * --------------------------------
9922
+ * 3000 32FF MAPI_defined common property
9923
+ * 3200 33FF MAPI_defined form property
9924
+ * 3400 35FF MAPI_defined message store property
9925
+ * 3600 36FF MAPI_defined Folder or AB Container property
9926
+ * 3700 38FF MAPI_defined attachment property
9927
+ * 3900 39FF MAPI_defined address book property
9928
+ * 3A00 3BFF MAPI_defined mailuser property
9929
+ * 3C00 3CFF MAPI_defined DistList property
9930
+ * 3D00 3DFF MAPI_defined Profile Section property
9931
+ * 3E00 3EFF MAPI_defined Status property
9932
+ * 3F00 3FFF MAPI_defined display table property
9936
+ * Properties common to numerous MAPI objects.
9938
+ * Those properties that can appear on messages are in the
9939
+ * non-transmittable range for messages. They start at the high
9940
+ * end of that range and work down.
9942
+ * Properties that never appear on messages are defined in the common
9943
+ * property range (see above).
9947
+ * properties that are common to multiple objects (including message objects)
9948
+ * -- these ids are in the non-transmittable range
9951
+#define PR_ENTRYID PROP_TAG( PT_BINARY, 0x0FFF)
9952
+#define PR_OBJECT_TYPE PROP_TAG( PT_LONG, 0x0FFE)
9953
+#define PR_ICON PROP_TAG( PT_BINARY, 0x0FFD)
9954
+#define PR_MINI_ICON PROP_TAG( PT_BINARY, 0x0FFC)
9955
+#define PR_STORE_ENTRYID PROP_TAG( PT_BINARY, 0x0FFB)
9956
+#define PR_STORE_RECORD_KEY PROP_TAG( PT_BINARY, 0x0FFA)
9957
+#define PR_RECORD_KEY PROP_TAG( PT_BINARY, 0x0FF9)
9958
+#define PR_MAPPING_SIGNATURE PROP_TAG( PT_BINARY, 0x0FF8)
9959
+#define PR_ACCESS_LEVEL PROP_TAG( PT_LONG, 0x0FF7)
9960
+#define PR_INSTANCE_KEY PROP_TAG( PT_BINARY, 0x0FF6)
9961
+#define PR_ROW_TYPE PROP_TAG( PT_LONG, 0x0FF5)
9962
+#define PR_ACCESS PROP_TAG( PT_LONG, 0x0FF4)
9965
+ * properties that are common to multiple objects (usually not including message objects)
9966
+ * -- these ids are in the transmittable range
9969
+#define PR_ROWID PROP_TAG( PT_LONG, 0x3000)
9970
+#define PR_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3001)
9971
+#define PR_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3001)
9972
+#define PR_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3001)
9973
+#define PR_ADDRTYPE PROP_TAG( PT_TSTRING, 0x3002)
9974
+#define PR_ADDRTYPE_W PROP_TAG( PT_UNICODE, 0x3002)
9975
+#define PR_ADDRTYPE_A PROP_TAG( PT_STRING8, 0x3002)
9976
+#define PR_EMAIL_ADDRESS PROP_TAG( PT_TSTRING, 0x3003)
9977
+#define PR_EMAIL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3003)
9978
+#define PR_EMAIL_ADDRESS_A PROP_TAG( PT_STRING8, 0x3003)
9979
+#define PR_COMMENT PROP_TAG( PT_TSTRING, 0x3004)
9980
+#define PR_COMMENT_W PROP_TAG( PT_UNICODE, 0x3004)
9981
+#define PR_COMMENT_A PROP_TAG( PT_STRING8, 0x3004)
9982
+#define PR_DEPTH PROP_TAG( PT_LONG, 0x3005)
9983
+#define PR_PROVIDER_DISPLAY PROP_TAG( PT_TSTRING, 0x3006)
9984
+#define PR_PROVIDER_DISPLAY_W PROP_TAG( PT_UNICODE, 0x3006)
9985
+#define PR_PROVIDER_DISPLAY_A PROP_TAG( PT_STRING8, 0x3006)
9986
+#define PR_CREATION_TIME PROP_TAG( PT_SYSTIME, 0x3007)
9987
+#define PR_LAST_MODIFICATION_TIME PROP_TAG( PT_SYSTIME, 0x3008)
9988
+#define PR_RESOURCE_FLAGS PROP_TAG( PT_LONG, 0x3009)
9989
+#define PR_PROVIDER_DLL_NAME PROP_TAG( PT_TSTRING, 0x300A)
9990
+#define PR_PROVIDER_DLL_NAME_W PROP_TAG( PT_UNICODE, 0x300A)
9991
+#define PR_PROVIDER_DLL_NAME_A PROP_TAG( PT_STRING8, 0x300A)
9992
+#define PR_SEARCH_KEY PROP_TAG( PT_BINARY, 0x300B)
9993
+#define PR_PROVIDER_UID PROP_TAG( PT_BINARY, 0x300C)
9994
+#define PR_PROVIDER_ORDINAL PROP_TAG( PT_LONG, 0x300D)
9997
+ * MAPI Form properties
9999
+#define PR_FORM_VERSION PROP_TAG(PT_TSTRING, 0x3301)
10000
+#define PR_FORM_VERSION_W PROP_TAG(PT_UNICODE, 0x3301)
10001
+#define PR_FORM_VERSION_A PROP_TAG(PT_STRING8, 0x3301)
10002
+#define PR_FORM_CLSID PROP_TAG(PT_CLSID, 0x3302)
10003
+#define PR_FORM_CONTACT_NAME PROP_TAG(PT_TSTRING, 0x3303)
10004
+#define PR_FORM_CONTACT_NAME_W PROP_TAG(PT_UNICODE, 0x3303)
10005
+#define PR_FORM_CONTACT_NAME_A PROP_TAG(PT_STRING8, 0x3303)
10006
+#define PR_FORM_CATEGORY PROP_TAG(PT_TSTRING, 0x3304)
10007
+#define PR_FORM_CATEGORY_W PROP_TAG(PT_UNICODE, 0x3304)
10008
+#define PR_FORM_CATEGORY_A PROP_TAG(PT_STRING8, 0x3304)
10009
+#define PR_FORM_CATEGORY_SUB PROP_TAG(PT_TSTRING, 0x3305)
10010
+#define PR_FORM_CATEGORY_SUB_W PROP_TAG(PT_UNICODE, 0x3305)
10011
+#define PR_FORM_CATEGORY_SUB_A PROP_TAG(PT_STRING8, 0x3305)
10012
+#define PR_FORM_HOST_MAP PROP_TAG(PT_MV_LONG, 0x3306)
10013
+#define PR_FORM_HIDDEN PROP_TAG(PT_BOOLEAN, 0x3307)
10014
+#define PR_FORM_DESIGNER_NAME PROP_TAG(PT_TSTRING, 0x3308)
10015
+#define PR_FORM_DESIGNER_NAME_W PROP_TAG(PT_UNICODE, 0x3308)
10016
+#define PR_FORM_DESIGNER_NAME_A PROP_TAG(PT_STRING8, 0x3308)
10017
+#define PR_FORM_DESIGNER_GUID PROP_TAG(PT_CLSID, 0x3309)
10018
+#define PR_FORM_MESSAGE_BEHAVIOR PROP_TAG(PT_LONG, 0x330A)
10021
+ * Message store properties
10024
+#define PR_DEFAULT_STORE PROP_TAG( PT_BOOLEAN, 0x3400)
10025
+#define PR_STORE_SUPPORT_MASK PROP_TAG( PT_LONG, 0x340D)
10026
+#define PR_STORE_STATE PROP_TAG( PT_LONG, 0x340E)
10028
+#define PR_IPM_SUBTREE_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3410)
10029
+#define PR_IPM_OUTBOX_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3411)
10030
+#define PR_IPM_WASTEBASKET_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3412)
10031
+#define PR_IPM_SENTMAIL_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3413)
10032
+#define PR_MDB_PROVIDER PROP_TAG( PT_BINARY, 0x3414)
10033
+#define PR_RECEIVE_FOLDER_SETTINGS PROP_TAG( PT_OBJECT, 0x3415)
10035
+#define PR_VALID_FOLDER_MASK PROP_TAG( PT_LONG, 0x35DF)
10036
+#define PR_IPM_SUBTREE_ENTRYID PROP_TAG( PT_BINARY, 0x35E0)
10038
+#define PR_IPM_OUTBOX_ENTRYID PROP_TAG( PT_BINARY, 0x35E2)
10039
+#define PR_IPM_WASTEBASKET_ENTRYID PROP_TAG( PT_BINARY, 0x35E3)
10040
+#define PR_IPM_SENTMAIL_ENTRYID PROP_TAG( PT_BINARY, 0x35E4)
10041
+#define PR_VIEWS_ENTRYID PROP_TAG( PT_BINARY, 0x35E5)
10042
+#define PR_COMMON_VIEWS_ENTRYID PROP_TAG( PT_BINARY, 0x35E6)
10043
+#define PR_FINDER_ENTRYID PROP_TAG( PT_BINARY, 0x35E7)
10045
+/* Proptags 0x35E8-0x35FF reserved for folders "guaranteed" by PR_VALID_FOLDER_MASK */
10049
+ * Folder and AB Container properties
10052
+#define PR_CONTAINER_FLAGS PROP_TAG( PT_LONG, 0x3600)
10053
+#define PR_FOLDER_TYPE PROP_TAG( PT_LONG, 0x3601)
10054
+#define PR_CONTENT_COUNT PROP_TAG( PT_LONG, 0x3602)
10055
+#define PR_CONTENT_UNREAD PROP_TAG( PT_LONG, 0x3603)
10056
+#define PR_CREATE_TEMPLATES PROP_TAG( PT_OBJECT, 0x3604)
10057
+#define PR_DETAILS_TABLE PROP_TAG( PT_OBJECT, 0x3605)
10058
+#define PR_SEARCH PROP_TAG( PT_OBJECT, 0x3607)
10059
+#define PR_SELECTABLE PROP_TAG( PT_BOOLEAN, 0x3609)
10060
+#define PR_SUBFOLDERS PROP_TAG( PT_BOOLEAN, 0x360A)
10061
+#define PR_STATUS PROP_TAG( PT_LONG, 0x360B)
10062
+#define PR_ANR PROP_TAG( PT_TSTRING, 0x360C)
10063
+#define PR_ANR_W PROP_TAG( PT_UNICODE, 0x360C)
10064
+#define PR_ANR_A PROP_TAG( PT_STRING8, 0x360C)
10065
+#define PR_CONTENTS_SORT_ORDER PROP_TAG( PT_MV_LONG, 0x360D)
10066
+#define PR_CONTAINER_HIERARCHY PROP_TAG( PT_OBJECT, 0x360E)
10067
+#define PR_CONTAINER_CONTENTS PROP_TAG( PT_OBJECT, 0x360F)
10068
+#define PR_FOLDER_ASSOCIATED_CONTENTS PROP_TAG( PT_OBJECT, 0x3610)
10069
+#define PR_DEF_CREATE_DL PROP_TAG( PT_BINARY, 0x3611)
10070
+#define PR_DEF_CREATE_MAILUSER PROP_TAG( PT_BINARY, 0x3612)
10071
+#define PR_CONTAINER_CLASS PROP_TAG( PT_TSTRING, 0x3613)
10072
+#define PR_CONTAINER_CLASS_W PROP_TAG( PT_UNICODE, 0x3613)
10073
+#define PR_CONTAINER_CLASS_A PROP_TAG( PT_STRING8, 0x3613)
10074
+#define PR_CONTAINER_MODIFY_VERSION PROP_TAG( PT_I8, 0x3614)
10075
+#define PR_AB_PROVIDER_ID PROP_TAG( PT_BINARY, 0x3615)
10076
+#define PR_DEFAULT_VIEW_ENTRYID PROP_TAG( PT_BINARY, 0x3616)
10077
+#define PR_ASSOC_CONTENT_COUNT PROP_TAG( PT_LONG, 0x3617)
10079
+/* Reserved 0x36C0-0x36FF */
10082
+ * Attachment properties
10085
+#define PR_ATTACHMENT_X400_PARAMETERS PROP_TAG( PT_BINARY, 0x3700)
10086
+#define PR_ATTACH_DATA_OBJ PROP_TAG( PT_OBJECT, 0x3701)
10087
+#define PR_ATTACH_DATA_BIN PROP_TAG( PT_BINARY, 0x3701)
10088
+#define PR_ATTACH_ENCODING PROP_TAG( PT_BINARY, 0x3702)
10089
+#define PR_ATTACH_EXTENSION PROP_TAG( PT_TSTRING, 0x3703)
10090
+#define PR_ATTACH_EXTENSION_W PROP_TAG( PT_UNICODE, 0x3703)
10091
+#define PR_ATTACH_EXTENSION_A PROP_TAG( PT_STRING8, 0x3703)
10092
+#define PR_ATTACH_FILENAME PROP_TAG( PT_TSTRING, 0x3704)
10093
+#define PR_ATTACH_FILENAME_W PROP_TAG( PT_UNICODE, 0x3704)
10094
+#define PR_ATTACH_FILENAME_A PROP_TAG( PT_STRING8, 0x3704)
10095
+#define PR_ATTACH_METHOD PROP_TAG( PT_LONG, 0x3705)
10096
+#define PR_ATTACH_LONG_FILENAME PROP_TAG( PT_TSTRING, 0x3707)
10097
+#define PR_ATTACH_LONG_FILENAME_W PROP_TAG( PT_UNICODE, 0x3707)
10098
+#define PR_ATTACH_LONG_FILENAME_A PROP_TAG( PT_STRING8, 0x3707)
10099
+#define PR_ATTACH_PATHNAME PROP_TAG( PT_TSTRING, 0x3708)
10100
+#define PR_ATTACH_PATHNAME_W PROP_TAG( PT_UNICODE, 0x3708)
10101
+#define PR_ATTACH_PATHNAME_A PROP_TAG( PT_STRING8, 0x3708)
10102
+#define PR_ATTACH_RENDERING PROP_TAG( PT_BINARY, 0x3709)
10103
+#define PR_ATTACH_TAG PROP_TAG( PT_BINARY, 0x370A)
10104
+#define PR_RENDERING_POSITION PROP_TAG( PT_LONG, 0x370B)
10105
+#define PR_ATTACH_TRANSPORT_NAME PROP_TAG( PT_TSTRING, 0x370C)
10106
+#define PR_ATTACH_TRANSPORT_NAME_W PROP_TAG( PT_UNICODE, 0x370C)
10107
+#define PR_ATTACH_TRANSPORT_NAME_A PROP_TAG( PT_STRING8, 0x370C)
10108
+#define PR_ATTACH_LONG_PATHNAME PROP_TAG( PT_TSTRING, 0x370D)
10109
+#define PR_ATTACH_LONG_PATHNAME_W PROP_TAG( PT_UNICODE, 0x370D)
10110
+#define PR_ATTACH_LONG_PATHNAME_A PROP_TAG( PT_STRING8, 0x370D)
10111
+#define PR_ATTACH_MIME_TAG PROP_TAG( PT_TSTRING, 0x370E)
10112
+#define PR_ATTACH_MIME_TAG_W PROP_TAG( PT_UNICODE, 0x370E)
10113
+#define PR_ATTACH_MIME_TAG_A PROP_TAG( PT_STRING8, 0x370E)
10114
+#define PR_ATTACH_ADDITIONAL_INFO PROP_TAG( PT_BINARY, 0x370F)
10117
+ * AB Object properties
10120
+#define PR_DISPLAY_TYPE PROP_TAG( PT_LONG, 0x3900)
10121
+#define PR_TEMPLATEID PROP_TAG( PT_BINARY, 0x3902)
10122
+#define PR_PRIMARY_CAPABILITY PROP_TAG( PT_BINARY, 0x3904)
10126
+ * Mail user properties
10128
+#define PR_7BIT_DISPLAY_NAME PROP_TAG( PT_STRING8, 0x39FF)
10129
+#define PR_ACCOUNT PROP_TAG( PT_TSTRING, 0x3A00)
10130
+#define PR_ACCOUNT_W PROP_TAG( PT_UNICODE, 0x3A00)
10131
+#define PR_ACCOUNT_A PROP_TAG( PT_STRING8, 0x3A00)
10132
+#define PR_ALTERNATE_RECIPIENT PROP_TAG( PT_BINARY, 0x3A01)
10133
+#define PR_CALLBACK_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A02)
10134
+#define PR_CALLBACK_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A02)
10135
+#define PR_CALLBACK_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A02)
10136
+#define PR_CONVERSION_PROHIBITED PROP_TAG( PT_BOOLEAN, 0x3A03)
10137
+#define PR_DISCLOSE_RECIPIENTS PROP_TAG( PT_BOOLEAN, 0x3A04)
10138
+#define PR_GENERATION PROP_TAG( PT_TSTRING, 0x3A05)
10139
+#define PR_GENERATION_W PROP_TAG( PT_UNICODE, 0x3A05)
10140
+#define PR_GENERATION_A PROP_TAG( PT_STRING8, 0x3A05)
10141
+#define PR_GIVEN_NAME PROP_TAG( PT_TSTRING, 0x3A06)
10142
+#define PR_GIVEN_NAME_W PROP_TAG( PT_UNICODE, 0x3A06)
10143
+#define PR_GIVEN_NAME_A PROP_TAG( PT_STRING8, 0x3A06)
10144
+#define PR_GOVERNMENT_ID_NUMBER PROP_TAG( PT_TSTRING, 0x3A07)
10145
+#define PR_GOVERNMENT_ID_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A07)
10146
+#define PR_GOVERNMENT_ID_NUMBER_A PROP_TAG( PT_STRING8, 0x3A07)
10147
+#define PR_BUSINESS_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A08)
10148
+#define PR_BUSINESS_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A08)
10149
+#define PR_BUSINESS_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A08)
10150
+#define PR_OFFICE_TELEPHONE_NUMBER PR_BUSINESS_TELEPHONE_NUMBER
10151
+#define PR_OFFICE_TELEPHONE_NUMBER_W PR_BUSINESS_TELEPHONE_NUMBER_W
10152
+#define PR_OFFICE_TELEPHONE_NUMBER_A PR_BUSINESS_TELEPHONE_NUMBER_A
10153
+#define PR_HOME_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A09)
10154
+#define PR_HOME_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A09)
10155
+#define PR_HOME_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A09)
10156
+#define PR_INITIALS PROP_TAG( PT_TSTRING, 0x3A0A)
10157
+#define PR_INITIALS_W PROP_TAG( PT_UNICODE, 0x3A0A)
10158
+#define PR_INITIALS_A PROP_TAG( PT_STRING8, 0x3A0A)
10159
+#define PR_KEYWORD PROP_TAG( PT_TSTRING, 0x3A0B)
10160
+#define PR_KEYWORD_W PROP_TAG( PT_UNICODE, 0x3A0B)
10161
+#define PR_KEYWORD_A PROP_TAG( PT_STRING8, 0x3A0B)
10162
+#define PR_LANGUAGE PROP_TAG( PT_TSTRING, 0x3A0C)
10163
+#define PR_LANGUAGE_W PROP_TAG( PT_UNICODE, 0x3A0C)
10164
+#define PR_LANGUAGE_A PROP_TAG( PT_STRING8, 0x3A0C)
10165
+#define PR_LOCATION PROP_TAG( PT_TSTRING, 0x3A0D)
10166
+#define PR_LOCATION_W PROP_TAG( PT_UNICODE, 0x3A0D)
10167
+#define PR_LOCATION_A PROP_TAG( PT_STRING8, 0x3A0D)
10168
+#define PR_MAIL_PERMISSION PROP_TAG( PT_BOOLEAN, 0x3A0E)
10169
+#define PR_MHS_COMMON_NAME PROP_TAG( PT_TSTRING, 0x3A0F)
10170
+#define PR_MHS_COMMON_NAME_W PROP_TAG( PT_UNICODE, 0x3A0F)
10171
+#define PR_MHS_COMMON_NAME_A PROP_TAG( PT_STRING8, 0x3A0F)
10172
+#define PR_ORGANIZATIONAL_ID_NUMBER PROP_TAG( PT_TSTRING, 0x3A10)
10173
+#define PR_ORGANIZATIONAL_ID_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A10)
10174
+#define PR_ORGANIZATIONAL_ID_NUMBER_A PROP_TAG( PT_STRING8, 0x3A10)
10175
+#define PR_SURNAME PROP_TAG( PT_TSTRING, 0x3A11)
10176
+#define PR_SURNAME_W PROP_TAG( PT_UNICODE, 0x3A11)
10177
+#define PR_SURNAME_A PROP_TAG( PT_STRING8, 0x3A11)
10178
+#define PR_ORIGINAL_ENTRYID PROP_TAG( PT_BINARY, 0x3A12)
10179
+#define PR_ORIGINAL_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3A13)
10180
+#define PR_ORIGINAL_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3A13)
10181
+#define PR_ORIGINAL_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3A13)
10182
+#define PR_ORIGINAL_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3A14)
10183
+#define PR_POSTAL_ADDRESS PROP_TAG( PT_TSTRING, 0x3A15)
10184
+#define PR_POSTAL_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3A15)
10185
+#define PR_POSTAL_ADDRESS_A PROP_TAG( PT_STRING8, 0x3A15)
10186
+#define PR_COMPANY_NAME PROP_TAG( PT_TSTRING, 0x3A16)
10187
+#define PR_COMPANY_NAME_W PROP_TAG( PT_UNICODE, 0x3A16)
10188
+#define PR_COMPANY_NAME_A PROP_TAG( PT_STRING8, 0x3A16)
10189
+#define PR_TITLE PROP_TAG( PT_TSTRING, 0x3A17)
10190
+#define PR_TITLE_W PROP_TAG( PT_UNICODE, 0x3A17)
10191
+#define PR_TITLE_A PROP_TAG( PT_STRING8, 0x3A17)
10192
+#define PR_DEPARTMENT_NAME PROP_TAG( PT_TSTRING, 0x3A18)
10193
+#define PR_DEPARTMENT_NAME_W PROP_TAG( PT_UNICODE, 0x3A18)
10194
+#define PR_DEPARTMENT_NAME_A PROP_TAG( PT_STRING8, 0x3A18)
10195
+#define PR_OFFICE_LOCATION PROP_TAG( PT_TSTRING, 0x3A19)
10196
+#define PR_OFFICE_LOCATION_W PROP_TAG( PT_UNICODE, 0x3A19)
10197
+#define PR_OFFICE_LOCATION_A PROP_TAG( PT_STRING8, 0x3A19)
10198
+#define PR_PRIMARY_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1A)
10199
+#define PR_PRIMARY_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1A)
10200
+#define PR_PRIMARY_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1A)
10201
+#define PR_BUSINESS2_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1B)
10202
+#define PR_BUSINESS2_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1B)
10203
+#define PR_BUSINESS2_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1B)
10204
+#define PR_OFFICE2_TELEPHONE_NUMBER PR_BUSINESS2_TELEPHONE_NUMBER
10205
+#define PR_OFFICE2_TELEPHONE_NUMBER_W PR_BUSINESS2_TELEPHONE_NUMBER_W
10206
+#define PR_OFFICE2_TELEPHONE_NUMBER_A PR_BUSINESS2_TELEPHONE_NUMBER_A
10207
+#define PR_MOBILE_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1C)
10208
+#define PR_MOBILE_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1C)
10209
+#define PR_MOBILE_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1C)
10210
+#define PR_CELLULAR_TELEPHONE_NUMBER PR_MOBILE_TELEPHONE_NUMBER
10211
+#define PR_CELLULAR_TELEPHONE_NUMBER_W PR_MOBILE_TELEPHONE_NUMBER_W
10212
+#define PR_CELLULAR_TELEPHONE_NUMBER_A PR_MOBILE_TELEPHONE_NUMBER_A
10213
+#define PR_RADIO_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1D)
10214
+#define PR_RADIO_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1D)
10215
+#define PR_RADIO_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1D)
10216
+#define PR_CAR_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1E)
10217
+#define PR_CAR_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1E)
10218
+#define PR_CAR_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1E)
10219
+#define PR_OTHER_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A1F)
10220
+#define PR_OTHER_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A1F)
10221
+#define PR_OTHER_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A1F)
10222
+#define PR_TRANSMITABLE_DISPLAY_NAME PROP_TAG( PT_TSTRING, 0x3A20)
10223
+#define PR_TRANSMITABLE_DISPLAY_NAME_W PROP_TAG( PT_UNICODE, 0x3A20)
10224
+#define PR_TRANSMITABLE_DISPLAY_NAME_A PROP_TAG( PT_STRING8, 0x3A20)
10225
+#define PR_PAGER_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A21)
10226
+#define PR_PAGER_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A21)
10227
+#define PR_PAGER_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A21)
10228
+#define PR_BEEPER_TELEPHONE_NUMBER PR_PAGER_TELEPHONE_NUMBER
10229
+#define PR_BEEPER_TELEPHONE_NUMBER_W PR_PAGER_TELEPHONE_NUMBER_W
10230
+#define PR_BEEPER_TELEPHONE_NUMBER_A PR_PAGER_TELEPHONE_NUMBER_A
10231
+#define PR_USER_CERTIFICATE PROP_TAG( PT_BINARY, 0x3A22)
10232
+#define PR_PRIMARY_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A23)
10233
+#define PR_PRIMARY_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A23)
10234
+#define PR_PRIMARY_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A23)
10235
+#define PR_BUSINESS_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A24)
10236
+#define PR_BUSINESS_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A24)
10237
+#define PR_BUSINESS_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A24)
10238
+#define PR_HOME_FAX_NUMBER PROP_TAG( PT_TSTRING, 0x3A25)
10239
+#define PR_HOME_FAX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A25)
10240
+#define PR_HOME_FAX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A25)
10241
+#define PR_COUNTRY PROP_TAG( PT_TSTRING, 0x3A26)
10242
+#define PR_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A26)
10243
+#define PR_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A26)
10244
+#define PR_BUSINESS_ADDRESS_COUNTRY PR_COUNTRY
10245
+#define PR_BUSINESS_ADDRESS_COUNTRY_W PR_COUNTRY_W
10246
+#define PR_BUSINESS_ADDRESS_COUNTRY_A PR_COUNTRY_A
10248
+#define PR_LOCALITY PROP_TAG( PT_TSTRING, 0x3A27)
10249
+#define PR_LOCALITY_W PROP_TAG( PT_UNICODE, 0x3A27)
10250
+#define PR_LOCALITY_A PROP_TAG( PT_STRING8, 0x3A27)
10251
+#define PR_BUSINESS_ADDRESS_CITY PR_LOCALITY
10252
+#define PR_BUSINESS_ADDRESS_CITY_W PR_LOCALITY_W
10253
+#define PR_BUSINESS_ADDRESS_CITY_A PR_LOCALITY_A
10255
+#define PR_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A28)
10256
+#define PR_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A28)
10257
+#define PR_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A28)
10258
+#define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE PR_STATE_OR_PROVINCE
10259
+#define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_W PR_STATE_OR_PROVINCE_W
10260
+#define PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_A PR_STATE_OR_PROVINCE_A
10262
+#define PR_STREET_ADDRESS PROP_TAG( PT_TSTRING, 0x3A29)
10263
+#define PR_STREET_ADDRESS_W PROP_TAG( PT_UNICODE, 0x3A29)
10264
+#define PR_STREET_ADDRESS_A PROP_TAG( PT_STRING8, 0x3A29)
10265
+#define PR_BUSINESS_ADDRESS_STREET PR_STREET_ADDRESS
10266
+#define PR_BUSINESS_ADDRESS_STREET_W PR_STREET_ADDRESS_W
10267
+#define PR_BUSINESS_ADDRESS_STREET_A PR_STREET_ADDRESS_A
10269
+#define PR_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A2A)
10270
+#define PR_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A2A)
10271
+#define PR_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A2A)
10272
+#define PR_BUSINESS_ADDRESS_POSTAL_CODE PR_POSTAL_CODE
10273
+#define PR_BUSINESS_ADDRESS_POSTAL_CODE_W PR_POSTAL_CODE_W
10274
+#define PR_BUSINESS_ADDRESS_POSTAL_CODE_A PR_POSTAL_CODE_A
10277
+#define PR_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A2B)
10278
+#define PR_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A2B)
10279
+#define PR_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A2B)
10280
+#define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX PR_POST_OFFICE_BOX
10281
+#define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX_W PR_POST_OFFICE_BOX_W
10282
+#define PR_BUSINESS_ADDRESS_POST_OFFICE_BOX_A PR_POST_OFFICE_BOX_A
10285
+#define PR_TELEX_NUMBER PROP_TAG( PT_TSTRING, 0x3A2C)
10286
+#define PR_TELEX_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2C)
10287
+#define PR_TELEX_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2C)
10288
+#define PR_ISDN_NUMBER PROP_TAG( PT_TSTRING, 0x3A2D)
10289
+#define PR_ISDN_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2D)
10290
+#define PR_ISDN_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2D)
10291
+#define PR_ASSISTANT_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A2E)
10292
+#define PR_ASSISTANT_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2E)
10293
+#define PR_ASSISTANT_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2E)
10294
+#define PR_HOME2_TELEPHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A2F)
10295
+#define PR_HOME2_TELEPHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A2F)
10296
+#define PR_HOME2_TELEPHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A2F)
10297
+#define PR_ASSISTANT PROP_TAG( PT_TSTRING, 0x3A30)
10298
+#define PR_ASSISTANT_W PROP_TAG( PT_UNICODE, 0x3A30)
10299
+#define PR_ASSISTANT_A PROP_TAG( PT_STRING8, 0x3A30)
10300
+#define PR_SEND_RICH_INFO PROP_TAG( PT_BOOLEAN, 0x3A40)
10302
+#define PR_WEDDING_ANNIVERSARY PROP_TAG( PT_SYSTIME, 0x3A41)
10303
+#define PR_BIRTHDAY PROP_TAG( PT_SYSTIME, 0x3A42)
10306
+#define PR_HOBBIES PROP_TAG( PT_TSTRING, 0x3A43)
10307
+#define PR_HOBBIES_W PROP_TAG( PT_UNICODE, 0x3A43)
10308
+#define PR_HOBBIES_A PROP_TAG( PT_STRING8, 0x3A43)
10310
+#define PR_MIDDLE_NAME PROP_TAG( PT_TSTRING, 0x3A44)
10311
+#define PR_MIDDLE_NAME_W PROP_TAG( PT_UNICODE, 0x3A44)
10312
+#define PR_MIDDLE_NAME_A PROP_TAG( PT_STRING8, 0x3A44)
10314
+#define PR_DISPLAY_NAME_PREFIX PROP_TAG( PT_TSTRING, 0x3A45)
10315
+#define PR_DISPLAY_NAME_PREFIX_W PROP_TAG( PT_UNICODE, 0x3A45)
10316
+#define PR_DISPLAY_NAME_PREFIX_A PROP_TAG( PT_STRING8, 0x3A45)
10318
+#define PR_PROFESSION PROP_TAG( PT_TSTRING, 0x3A46)
10319
+#define PR_PROFESSION_W PROP_TAG( PT_UNICODE, 0x3A46)
10320
+#define PR_PROFESSION_A PROP_TAG( PT_STRING8, 0x3A46)
10322
+#define PR_PREFERRED_BY_NAME PROP_TAG( PT_TSTRING, 0x3A47)
10323
+#define PR_PREFERRED_BY_NAME_W PROP_TAG( PT_UNICODE, 0x3A47)
10324
+#define PR_PREFERRED_BY_NAME_A PROP_TAG( PT_STRING8, 0x3A47)
10326
+#define PR_SPOUSE_NAME PROP_TAG( PT_TSTRING, 0x3A48)
10327
+#define PR_SPOUSE_NAME_W PROP_TAG( PT_UNICODE, 0x3A48)
10328
+#define PR_SPOUSE_NAME_A PROP_TAG( PT_STRING8, 0x3A48)
10330
+#define PR_COMPUTER_NETWORK_NAME PROP_TAG( PT_TSTRING, 0x3A49)
10331
+#define PR_COMPUTER_NETWORK_NAME_W PROP_TAG( PT_UNICODE, 0x3A49)
10332
+#define PR_COMPUTER_NETWORK_NAME_A PROP_TAG( PT_STRING8, 0x3A49)
10334
+#define PR_CUSTOMER_ID PROP_TAG( PT_TSTRING, 0x3A4A)
10335
+#define PR_CUSTOMER_ID_W PROP_TAG( PT_UNICODE, 0x3A4A)
10336
+#define PR_CUSTOMER_ID_A PROP_TAG( PT_STRING8, 0x3A4A)
10338
+#define PR_TTYTDD_PHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A4B)
10339
+#define PR_TTYTDD_PHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A4B)
10340
+#define PR_TTYTDD_PHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A4B)
10342
+#define PR_FTP_SITE PROP_TAG( PT_TSTRING, 0x3A4C)
10343
+#define PR_FTP_SITE_W PROP_TAG( PT_UNICODE, 0x3A4C)
10344
+#define PR_FTP_SITE_A PROP_TAG( PT_STRING8, 0x3A4C)
10346
+#define PR_GENDER PROP_TAG( PT_SHORT, 0x3A4D)
10348
+#define PR_MANAGER_NAME PROP_TAG( PT_TSTRING, 0x3A4E)
10349
+#define PR_MANAGER_NAME_W PROP_TAG( PT_UNICODE, 0x3A4E)
10350
+#define PR_MANAGER_NAME_A PROP_TAG( PT_STRING8, 0x3A4E)
10352
+#define PR_NICKNAME PROP_TAG( PT_TSTRING, 0x3A4F)
10353
+#define PR_NICKNAME_W PROP_TAG( PT_UNICODE, 0x3A4F)
10354
+#define PR_NICKNAME_A PROP_TAG( PT_STRING8, 0x3A4F)
10356
+#define PR_PERSONAL_HOME_PAGE PROP_TAG( PT_TSTRING, 0x3A50)
10357
+#define PR_PERSONAL_HOME_PAGE_W PROP_TAG( PT_UNICODE, 0x3A50)
10358
+#define PR_PERSONAL_HOME_PAGE_A PROP_TAG( PT_STRING8, 0x3A50)
10361
+#define PR_BUSINESS_HOME_PAGE PROP_TAG( PT_TSTRING, 0x3A51)
10362
+#define PR_BUSINESS_HOME_PAGE_W PROP_TAG( PT_UNICODE, 0x3A51)
10363
+#define PR_BUSINESS_HOME_PAGE_A PROP_TAG( PT_STRING8, 0x3A51)
10365
+#define PR_CONTACT_VERSION PROP_TAG( PT_CLSID, 0x3A52)
10366
+#define PR_CONTACT_ENTRYIDS PROP_TAG( PT_MV_BINARY, 0x3A53)
10368
+#define PR_CONTACT_ADDRTYPES PROP_TAG( PT_MV_TSTRING, 0x3A54)
10369
+#define PR_CONTACT_ADDRTYPES_W PROP_TAG( PT_MV_UNICODE, 0x3A54)
10370
+#define PR_CONTACT_ADDRTYPES_A PROP_TAG( PT_MV_STRING8, 0x3A54)
10372
+#define PR_CONTACT_DEFAULT_ADDRESS_INDEX PROP_TAG( PT_LONG, 0x3A55)
10374
+#define PR_CONTACT_EMAIL_ADDRESSES PROP_TAG( PT_MV_TSTRING, 0x3A56)
10375
+#define PR_CONTACT_EMAIL_ADDRESSES_W PROP_TAG( PT_MV_UNICODE, 0x3A56)
10376
+#define PR_CONTACT_EMAIL_ADDRESSES_A PROP_TAG( PT_MV_STRING8, 0x3A56)
10379
+#define PR_COMPANY_MAIN_PHONE_NUMBER PROP_TAG( PT_TSTRING, 0x3A57)
10380
+#define PR_COMPANY_MAIN_PHONE_NUMBER_W PROP_TAG( PT_UNICODE, 0x3A57)
10381
+#define PR_COMPANY_MAIN_PHONE_NUMBER_A PROP_TAG( PT_STRING8, 0x3A57)
10383
+#define PR_CHILDRENS_NAMES PROP_TAG( PT_MV_TSTRING, 0x3A58)
10384
+#define PR_CHILDRENS_NAMES_W PROP_TAG( PT_MV_UNICODE, 0x3A58)
10385
+#define PR_CHILDRENS_NAMES_A PROP_TAG( PT_MV_STRING8, 0x3A58)
10389
+#define PR_HOME_ADDRESS_CITY PROP_TAG( PT_TSTRING, 0x3A59)
10390
+#define PR_HOME_ADDRESS_CITY_W PROP_TAG( PT_UNICODE, 0x3A59)
10391
+#define PR_HOME_ADDRESS_CITY_A PROP_TAG( PT_STRING8, 0x3A59)
10393
+#define PR_HOME_ADDRESS_COUNTRY PROP_TAG( PT_TSTRING, 0x3A5A)
10394
+#define PR_HOME_ADDRESS_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A5A)
10395
+#define PR_HOME_ADDRESS_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A5A)
10397
+#define PR_HOME_ADDRESS_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A5B)
10398
+#define PR_HOME_ADDRESS_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A5B)
10399
+#define PR_HOME_ADDRESS_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A5B)
10401
+#define PR_HOME_ADDRESS_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A5C)
10402
+#define PR_HOME_ADDRESS_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A5C)
10403
+#define PR_HOME_ADDRESS_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A5C)
10405
+#define PR_HOME_ADDRESS_STREET PROP_TAG( PT_TSTRING, 0x3A5D)
10406
+#define PR_HOME_ADDRESS_STREET_W PROP_TAG( PT_UNICODE, 0x3A5D)
10407
+#define PR_HOME_ADDRESS_STREET_A PROP_TAG( PT_STRING8, 0x3A5D)
10409
+#define PR_HOME_ADDRESS_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A5E)
10410
+#define PR_HOME_ADDRESS_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A5E)
10411
+#define PR_HOME_ADDRESS_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A5E)
10413
+#define PR_OTHER_ADDRESS_CITY PROP_TAG( PT_TSTRING, 0x3A5F)
10414
+#define PR_OTHER_ADDRESS_CITY_W PROP_TAG( PT_UNICODE, 0x3A5F)
10415
+#define PR_OTHER_ADDRESS_CITY_A PROP_TAG( PT_STRING8, 0x3A5F)
10417
+#define PR_OTHER_ADDRESS_COUNTRY PROP_TAG( PT_TSTRING, 0x3A60)
10418
+#define PR_OTHER_ADDRESS_COUNTRY_W PROP_TAG( PT_UNICODE, 0x3A60)
10419
+#define PR_OTHER_ADDRESS_COUNTRY_A PROP_TAG( PT_STRING8, 0x3A60)
10421
+#define PR_OTHER_ADDRESS_POSTAL_CODE PROP_TAG( PT_TSTRING, 0x3A61)
10422
+#define PR_OTHER_ADDRESS_POSTAL_CODE_W PROP_TAG( PT_UNICODE, 0x3A61)
10423
+#define PR_OTHER_ADDRESS_POSTAL_CODE_A PROP_TAG( PT_STRING8, 0x3A61)
10425
+#define PR_OTHER_ADDRESS_STATE_OR_PROVINCE PROP_TAG( PT_TSTRING, 0x3A62)
10426
+#define PR_OTHER_ADDRESS_STATE_OR_PROVINCE_W PROP_TAG( PT_UNICODE, 0x3A62)
10427
+#define PR_OTHER_ADDRESS_STATE_OR_PROVINCE_A PROP_TAG( PT_STRING8, 0x3A62)
10429
+#define PR_OTHER_ADDRESS_STREET PROP_TAG( PT_TSTRING, 0x3A63)
10430
+#define PR_OTHER_ADDRESS_STREET_W PROP_TAG( PT_UNICODE, 0x3A63)
10431
+#define PR_OTHER_ADDRESS_STREET_A PROP_TAG( PT_STRING8, 0x3A63)
10433
+#define PR_OTHER_ADDRESS_POST_OFFICE_BOX PROP_TAG( PT_TSTRING, 0x3A64)
10434
+#define PR_OTHER_ADDRESS_POST_OFFICE_BOX_W PROP_TAG( PT_UNICODE, 0x3A64)
10435
+#define PR_OTHER_ADDRESS_POST_OFFICE_BOX_A PROP_TAG( PT_STRING8, 0x3A64)
10439
+ * Profile section properties
10442
+#define PR_STORE_PROVIDERS PROP_TAG( PT_BINARY, 0x3D00)
10443
+#define PR_AB_PROVIDERS PROP_TAG( PT_BINARY, 0x3D01)
10444
+#define PR_TRANSPORT_PROVIDERS PROP_TAG( PT_BINARY, 0x3D02)
10446
+#define PR_DEFAULT_PROFILE PROP_TAG( PT_BOOLEAN, 0x3D04)
10447
+#define PR_AB_SEARCH_PATH PROP_TAG( PT_MV_BINARY, 0x3D05)
10448
+#define PR_AB_DEFAULT_DIR PROP_TAG( PT_BINARY, 0x3D06)
10449
+#define PR_AB_DEFAULT_PAB PROP_TAG( PT_BINARY, 0x3D07)
10451
+#define PR_FILTERING_HOOKS PROP_TAG( PT_BINARY, 0x3D08)
10452
+#define PR_SERVICE_NAME PROP_TAG( PT_TSTRING, 0x3D09)
10453
+#define PR_SERVICE_NAME_W PROP_TAG( PT_UNICODE, 0x3D09)
10454
+#define PR_SERVICE_NAME_A PROP_TAG( PT_STRING8, 0x3D09)
10455
+#define PR_SERVICE_DLL_NAME PROP_TAG( PT_TSTRING, 0x3D0A)
10456
+#define PR_SERVICE_DLL_NAME_W PROP_TAG( PT_UNICODE, 0x3D0A)
10457
+#define PR_SERVICE_DLL_NAME_A PROP_TAG( PT_STRING8, 0x3D0A)
10458
+#define PR_SERVICE_ENTRY_NAME PROP_TAG( PT_STRING8, 0x3D0B)
10459
+#define PR_SERVICE_UID PROP_TAG( PT_BINARY, 0x3D0C)
10460
+#define PR_SERVICE_EXTRA_UIDS PROP_TAG( PT_BINARY, 0x3D0D)
10461
+#define PR_SERVICES PROP_TAG( PT_BINARY, 0x3D0E)
10462
+#define PR_SERVICE_SUPPORT_FILES PROP_TAG( PT_MV_TSTRING, 0x3D0F)
10463
+#define PR_SERVICE_SUPPORT_FILES_W PROP_TAG( PT_MV_UNICODE, 0x3D0F)
10464
+#define PR_SERVICE_SUPPORT_FILES_A PROP_TAG( PT_MV_STRING8, 0x3D0F)
10465
+#define PR_SERVICE_DELETE_FILES PROP_TAG( PT_MV_TSTRING, 0x3D10)
10466
+#define PR_SERVICE_DELETE_FILES_W PROP_TAG( PT_MV_UNICODE, 0x3D10)
10467
+#define PR_SERVICE_DELETE_FILES_A PROP_TAG( PT_MV_STRING8, 0x3D10)
10468
+#define PR_AB_SEARCH_PATH_UPDATE PROP_TAG( PT_BINARY, 0x3D11)
10469
+#define PR_PROFILE_NAME PROP_TAG( PT_TSTRING, 0x3D12)
10470
+#define PR_PROFILE_NAME_A PROP_TAG( PT_STRING8, 0x3D12)
10471
+#define PR_PROFILE_NAME_W PROP_TAG( PT_UNICODE, 0x3D12)
10474
+ * Status object properties
10477
+#define PR_IDENTITY_DISPLAY PROP_TAG( PT_TSTRING, 0x3E00)
10478
+#define PR_IDENTITY_DISPLAY_W PROP_TAG( PT_UNICODE, 0x3E00)
10479
+#define PR_IDENTITY_DISPLAY_A PROP_TAG( PT_STRING8, 0x3E00)
10480
+#define PR_IDENTITY_ENTRYID PROP_TAG( PT_BINARY, 0x3E01)
10481
+#define PR_RESOURCE_METHODS PROP_TAG( PT_LONG, 0x3E02)
10482
+#define PR_RESOURCE_TYPE PROP_TAG( PT_LONG, 0x3E03)
10483
+#define PR_STATUS_CODE PROP_TAG( PT_LONG, 0x3E04)
10484
+#define PR_IDENTITY_SEARCH_KEY PROP_TAG( PT_BINARY, 0x3E05)
10485
+#define PR_OWN_STORE_ENTRYID PROP_TAG( PT_BINARY, 0x3E06)
10486
+#define PR_RESOURCE_PATH PROP_TAG( PT_TSTRING, 0x3E07)
10487
+#define PR_RESOURCE_PATH_W PROP_TAG( PT_UNICODE, 0x3E07)
10488
+#define PR_RESOURCE_PATH_A PROP_TAG( PT_STRING8, 0x3E07)
10489
+#define PR_STATUS_STRING PROP_TAG( PT_TSTRING, 0x3E08)
10490
+#define PR_STATUS_STRING_W PROP_TAG( PT_UNICODE, 0x3E08)
10491
+#define PR_STATUS_STRING_A PROP_TAG( PT_STRING8, 0x3E08)
10492
+#define PR_X400_DEFERRED_DELIVERY_CANCEL PROP_TAG( PT_BOOLEAN, 0x3E09)
10493
+#define PR_HEADER_FOLDER_ENTRYID PROP_TAG( PT_BINARY, 0x3E0A)
10494
+#define PR_REMOTE_PROGRESS PROP_TAG( PT_LONG, 0x3E0B)
10495
+#define PR_REMOTE_PROGRESS_TEXT PROP_TAG( PT_TSTRING, 0x3E0C)
10496
+#define PR_REMOTE_PROGRESS_TEXT_W PROP_TAG( PT_UNICODE, 0x3E0C)
10497
+#define PR_REMOTE_PROGRESS_TEXT_A PROP_TAG( PT_STRING8, 0x3E0C)
10498
+#define PR_REMOTE_VALIDATE_OK PROP_TAG( PT_BOOLEAN, 0x3E0D)
10501
+ * Display table properties
10504
+#define PR_CONTROL_FLAGS PROP_TAG( PT_LONG, 0x3F00)
10505
+#define PR_CONTROL_STRUCTURE PROP_TAG( PT_BINARY, 0x3F01)
10506
+#define PR_CONTROL_TYPE PROP_TAG( PT_LONG, 0x3F02)
10507
+#define PR_DELTAX PROP_TAG( PT_LONG, 0x3F03)
10508
+#define PR_DELTAY PROP_TAG( PT_LONG, 0x3F04)
10509
+#define PR_XPOS PROP_TAG( PT_LONG, 0x3F05)
10510
+#define PR_YPOS PROP_TAG( PT_LONG, 0x3F06)
10511
+#define PR_CONTROL_ID PROP_TAG( PT_BINARY, 0x3F07)
10512
+#define PR_INITIAL_DETAILS_PANE PROP_TAG( PT_LONG, 0x3F08)
10515
+ * Secure property id range
10518
+#define PROP_ID_SECURE_MIN 0x67F0
10519
+#define PROP_ID_SECURE_MAX 0x67FF
10522
+#endif /* MAPITAGS_H */
10523
diff -urN exim-4.34-orig/src/version.c exim-4.34/src/version.c
10524
--- exim-4.34-orig/src/version.c Mon May 10 14:31:20 2004
10525
+++ exim-4.34/src/version.c Mon May 10 16:15:55 2004
10531
#define THIS_VERSION "4.34"
10533
+#define EXISCAN_VERSION "21"
10535
/* The header file cnumber.h contains a single line containing the
10536
compilation number, making it easy to have it updated automatically.
10538
version_cnumber_format = US"%d\0<<eximcnumber>>";
10539
sprintf(CS version_cnumber, CS version_cnumber_format, cnumber);
10540
version_string = US THIS_VERSION "\0<<eximversion>>";
10541
+exiscan_version_string = US EXISCAN_VERSION;
10543
Ustrcpy(today, __DATE__);
10544
if (today[4] == ' ') today[4] = '0';