~ubuntu-branches/ubuntu/hardy/exim4/hardy-proposed

« back to all changes in this revision

Viewing changes to debian/patches/exiscan.patch

  • Committer: Bazaar Package Importer
  • Author(s): Marc Haber
  • Date: 2005-07-02 06:08:34 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050702060834-qk17pd52kb9nt3bj
Tags: 4.52-1
* new upstream version 4.51. (mh)
  * adapt 70_remove_exim-users_references
  * remove 37_gnutlsparams
  * adapt 36_pcre
  * adapt 31_eximmanpage
* fix package priorities to have them in sync with override again. (mh)
* Fix error in nb (Norwegian) translation.
  Thanks to Helge Hafting. (mh). Closes: #315775
* Standards-Version: 3.6.2, no changes needed. (mh)

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
4
 
@@ -285,14 +285,14 @@
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.
7
 
 
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)
22
 
 
23
 
 exim:   pcre/libpcre.a lookups/lookups.a auths/auths.a \
24
 
@@ -498,12 +498,14 @@
25
 
 # Dependencies for the "ordinary" exim modules
26
 
 
27
 
 acl.o:           $(HDRS) acl.c
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
37
 
 dns.o:           $(HDRS) dns.c
38
 
 enq.o:           $(HDRS) enq.c
39
 
@@ -517,7 +519,9 @@
40
 
 ip.o:            $(HDRS) ip.c
41
 
 log.o:           $(HDRS) log.c
42
 
 lss.o:           $(HDRS) lss.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
47
 
 os.o:            $(HDRS) os.c
48
 
 parse.o:         $(HDRS) parse.c
49
 
@@ -525,6 +529,7 @@
50
 
 rda.o:           $(HDRS) rda.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
57
 
@@ -533,11 +538,14 @@
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
69
 
 tod.o:           $(HDRS) tod.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
75
 
@@ -0,0 +1 @@
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
80
 
@@ -0,0 +1,440 @@
81
 
+--------------------------------------------------------------
82
 
+exiscan-acl example configurations / FAQ
83
 
+--------------------------------------------------------------
84
 
+
85
 
+Author: Tom Kistner <tom@duncanthrax.net>
86
 
+
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.
90
 
+
91
 
+This document shows some example configuration snippets:
92
 
+
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
99
 
+   tag in the subject.
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
105
 
+   preferences.
106
 
+
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
112
 
+not get it "right".
113
 
+
114
 
+I recommend  to read  the exiscan  documentation on  the above
115
 
+mentioned website before trying to make sense of the following
116
 
+examples.
117
 
+
118
 
+Each  example  shows part  of  a DATA  ACL  definition, unless
119
 
+otherwise noted. 
120
 
+
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.
128
 
+
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
134
 
+# host field.
135
 
+accept  hosts = 127.0.0.1:+relay_from_hosts
136
 
+
137
 
+# Unpack MIME containers and reject file extensions
138
 
+# used by worms. Note that the extension list may be
139
 
+# incomplete.
140
 
+deny  message = $found_extension files are not accepted here
141
 
+      demime = com:vbs:bat:pif:scr
142
 
+
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)
147
 
+      demime = *
148
 
+      condition = ${if >{$demime_errorlevel}{2}{1}{0}}
149
 
+
150
 
+# Reject messages containing malware.
151
 
+deny message = This message contains malware ($malware_name)
152
 
+     malware = *
153
 
+     
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}}
159
 
+     spam = nobody
160
 
+     
161
 
+# Finally accept all other messages that have
162
 
+# made it to this point
163
 
+accept
164
 
+------------------ */
165
 
+
166
 
+
167
 
+
168
 
+--------------------------------------------------------------
169
 
+2. Adding a cryptographic "scanning done" header
170
 
+--------------------------------------------------------------
171
 
+
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
176
 
+how to do it:
177
 
+
178
 
+At the very beginning of your DATA ACL, put this:
179
 
+
180
 
+/* -----------------
181
 
+# Check our crytographic header. If it matches, accept
182
 
+# the message.
183
 
+accept condition = ${if eq {${hmac{md5}\
184
 
+                                  {mysecret}\
185
 
+                                  {$body_linecount}}}\
186
 
+                           {$h_X-Scan-Signature:} {1}{0}}
187
 
+------------------ */
188
 
+
189
 
+At the end, just before the final "accept" verb, put this:
190
 
+
191
 
+/* -----------------
192
 
+# Add the cryptographic header.
193
 
+warn message = X-Scan-Signature: ${hmac{md5}{mysecret}\
194
 
+                                       {$body_linecount}}
195
 
+------------------ */
196
 
+
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".
201
 
+
202
 
+
203
 
+--------------------------------------------------------------
204
 
+3. Marking Spam messages with extra headers and subject tag
205
 
+--------------------------------------------------------------
206
 
+
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.
217
 
+
218
 
+The  following  example  will  unconditionally  put  two  spam
219
 
+information headers  in each  message, if  it is  smaller than
220
 
+eighty kilobytes:
221
 
+
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}}
232
 
+     spam = nobody:true
233
 
+     
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}}
240
 
+     spam = nobody:true
241
 
+------------------ */
242
 
+
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
245
 
+filter.
246
 
+
247
 
+In the DATA ACL, put this:
248
 
+/* -----------------
249
 
+warn message = X-New-Subject: *SPAM* $h_subject:
250
 
+     spam = nobody
251
 
+------------------ */
252
 
+
253
 
+In the system filter, put this:
254
 
+/* -----------------
255
 
+if "${if def:header_X-New-Subject: {there}}" is there
256
 
+then
257
 
+   headers remove Subject
258
 
+   headers add "Subject: $h_X-New-Subject:"
259
 
+   headers remove X-New-Subject
260
 
+endif
261
 
+------------------ */
262
 
+
263
 
+
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:
270
 
+
271
 
+/* -----------------
272
 
+deny message = Spam score too high ($spam_score)
273
 
+     condition = ${if <{$message_size}{80k}{1}{0}}
274
 
+     spam = nobody:true
275
 
+     condition = ${if >{$spam_score_int}{100}{1}{0}}
276
 
+------------------ */
277
 
+
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).
281
 
+
282
 
+
283
 
+
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
289
 
+or pass them.
290
 
+
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:
295
 
+
296
 
+/* -----------------
297
 
+warn log_message = frozen by spam scanner, score $spam_score
298
 
+     spam = nobody
299
 
+     control = freeze
300
 
+------------------ */
301
 
+
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.
306
 
+
307
 
+This is the DATA ACL entry:
308
 
+
309
 
+/* -----------------
310
 
+warn message = X-Redirect-To: spambox@mycompany.com
311
 
+     spam = nobody
312
 
+------------------ */
313
 
+
314
 
+This puts the target address in a special header, which can in
315
 
+turn be read with this router:
316
 
+
317
 
+/* -----------------
318
 
+scan_redirect:
319
 
+     driver = redirect
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
 
+------------------ */
326
 
+
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.
333
 
+
334
 
+
335
 
+--------------------------------------------------------------
336
 
+6. Having multiple content scanning profiles for several
337
 
+   users or domains.
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
348
 
+individual ones.
349
 
+
350
 
+I will first sum up the possible solutions to this dilemma:
351
 
+
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
357
 
+     hosts.
358
 
+  
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
363
 
+     a.) a bit.
364
 
+  
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.
371
 
+  
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.
374
 
+
375
 
+a.) Making sure  each incoming  message that  will be  scanned
376
 
+    only has one recipient.
377
 
+    
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
381
 
+    thing.
382
 
+    
383
 
+    Here is a RCPT ACL that implements the behaviour
384
 
+    (shortened, do not copy 1:1!):
385
 
+    
386
 
+    /* ------------
387
 
+    acl_check_rcpt:
388
 
+
389
 
+      # accept local, relay-allowed
390
 
+      # and authenticated sources
391
 
+      
392
 
+      accept  hosts         = :
393
 
+      deny    local_parts   = ^.*[@%!/|]
394
 
+      accept  hosts         = 127.0.0.1:+relay_from_hosts
395
 
+      accept  authenticated = *
396
 
+    
397
 
+      # the following treat non-local,
398
 
+      # non-authenticated sources
399
 
+      
400
 
+      defer   message       = only one recipient at a time
401
 
+              condition     = ${if def:acl_m0 {1}{0}}
402
 
+    
403
 
+      # [ .. ]
404
 
+      # put RBLs etc. here
405
 
+      # [ .. ]
406
 
+      
407
 
+      accept  domains       = +local_domains
408
 
+              endpass
409
 
+              message       = unknown user
410
 
+              verify        = recipient
411
 
+              set acl_m0    = $local_part@$domain
412
 
+    
413
 
+      accept  domains       = +relay_to_domains
414
 
+              endpass
415
 
+              message       = unrouteable address
416
 
+              verify        = recipient
417
 
+              set acl_m0    = $domain
418
 
+    
419
 
+      deny    message       = relay not permitted
420
 
+    ------------ */
421
 
+    
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. 
428
 
+    
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.
433
 
+    
434
 
+
435
 
+b.) Having  several  scanning  profiles  that  "customers" can
436
 
+    choose from.
437
 
+    
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:
442
 
+    
443
 
+    domain-a.com:   reject-aggressive
444
 
+    domain-b.org:   warn-only
445
 
+    domain-c.net:   reject-aggressive
446
 
+    domain-d.com:   reject-conservative
447
 
+    [ .. ]
448
 
+    
449
 
+    Suppose you put that in a file called /etc/exim/scanprefs
450
 
+    
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.
454
 
+    
455
 
+    Here is a RCPT ACL that implements the behaviour
456
 
+    (shortened, do not copy 1:1!):
457
 
+    
458
 
+    /* ------------
459
 
+    acl_check_rcpt:
460
 
+
461
 
+      # accept local, relay-allowed and authenticated sources
462
 
+      
463
 
+      accept  hosts         = :
464
 
+      deny    local_parts   = ^.*[@%!/|]
465
 
+      accept  hosts         = 127.0.0.1:+relay_from_hosts
466
 
+      accept  authenticated = *
467
 
+    
468
 
+      # the following treat non-local, non-authenticated sources
469
 
+      
470
 
+      defer   message       = try this address in the next batch
471
 
+              condition     = ${if eq {${acl_m0}}\
472
 
+                              {${lookup{$domain}\
473
 
+                              lsearch{/etc/exim/scanprefs}}}\
474
 
+                              {0}{1}}
475
 
+    
476
 
+      # [ .. ]
477
 
+      # put RBLs etc. here
478
 
+      # [ .. ]
479
 
+      
480
 
+      accept  domains       = +local_domains
481
 
+              endpass
482
 
+              message       = unknown user
483
 
+              verify        = recipient
484
 
+              set acl_m0    = $local_part@$domain
485
 
+    
486
 
+      accept  domains       = +relay_to_domains
487
 
+              endpass
488
 
+              message       = unrouteable address
489
 
+              verify        = recipient
490
 
+              set acl_m0    = ${lookup{$domain}\
491
 
+                              lsearch{/etc/exim/scanprefs}}
492
 
+    
493
 
+      deny    message       = relay not permitted
494
 
+    ------------ */
495
 
+    
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.
500
 
+    
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.
504
 
+    
505
 
+    
506
 
+c.) Classic  content  scanning  without  the  possibility   of
507
 
+    rejects after DATA.
508
 
+    
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.
514
 
+    
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.
520
 
+    
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
524
 
@@ -0,0 +1,1072 @@
525
 
+--------------------------------------------------------------
526
 
+The exiscan-acl patch for exim4 - Documentation
527
 
+--------------------------------------------------------------
528
 
+(c) Tom Kistner <tom@duncanthrax.net> 2003-????
529
 
+License: GPL
530
 
+
531
 
+The exiscan-acl patch adds  content scanning to the  exim4 ACL
532
 
+system. It supports the following scanning features:
533
 
+
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.
541
 
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.
549
 
+
550
 
+Support for Brightmail AntiSpam requires special  compile-time
551
 
+flags. Please refer to chapter 7 for details.
552
 
+
553
 
+The   default   exim   configure   file   contains   commented
554
 
+configuration examples for some features of exiscan-acl.
555
 
+
556
 
+
557
 
+0. Overall concept / Overview
558
 
+--------------------------------------------------------------
559
 
+
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
563
 
+
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).
578
 
+
579
 
+All  facilites work  on a  MBOX copy  of the  message that  is
580
 
+temporarily spooled up in a file called:
581
 
+
582
 
+  <spool_directory>/scan/<message_id>/<message_id>.eml
583
 
+
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
591
 
+default.
592
 
+
593
 
+
594
 
+1. The acl_smtp_mime MIME ACL
595
 
+--------------------------------------------------------------
596
 
+
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.
600
 
+
601
 
+Here are the facts on acl_smtp_mime:
602
 
+
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.
606
 
+  
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.
613
 
+    
614
 
+  - It is ONLY called if the message has a MIME-Version header.
615
 
+
616
 
+  - MIME parts will NOT be dumped to disk by default, you have
617
 
+    to call  the "decode"  condition to  do that  (see further
618
 
+    below).
619
 
+
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.
627
 
+    
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:
631
 
+
632
 
+  /* ---------------
633
 
+  
634
 
+  # -- section 1 ----
635
 
+  [ ... ]
636
 
+  acl_smtp_mime = my_mime_acl
637
 
+  [ ... ]
638
 
+  
639
 
+  # -- acl section ----
640
 
+  begin acl
641
 
+  
642
 
+  [ ... ]
643
 
+  
644
 
+  my_mime_acl:
645
 
+  
646
 
+    < ACL logic >
647
 
+    
648
 
+  [ ... ]
649
 
+  
650
 
+  ---------------- */
651
 
+
652
 
+The following list describes all expansion variables that are
653
 
+available in the MIME ACL:
654
 
+
655
 
+  $mime_content_type
656
 
+  ------------------
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:
662
 
+  
663
 
+  text/plain
664
 
+  text/html
665
 
+  application/octet-stream
666
 
+  image/jpeg
667
 
+  audio/midi
668
 
+
669
 
+  If  the  MIME  part  has  no  "Content-Type:"  header,  this
670
 
+  variable is the empty string.
671
 
+
672
 
+
673
 
+  $mime_filename
674
 
+  --------------
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.
682
 
+  
683
 
+  
684
 
+  $mime_charset
685
 
+  -------------
686
 
+  Contains the  charset identifier,  if one  was found  in the
687
 
+  "Content-Type:" header. Examples for charset identifiers are
688
 
+  
689
 
+  us-ascii
690
 
+  gb2312 (Chinese)
691
 
+  iso-8859-1
692
 
+  
693
 
+  Please note that this value  will NOT be normalized, so  you
694
 
+  should do matches case-insensitively.
695
 
+  
696
 
+  
697
 
+  $mime_boundary
698
 
+  --------------
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
703
 
+  empty string. 
704
 
+  
705
 
+  
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.
711
 
+  
712
 
+  
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
718
 
+  -printable".
719
 
+
720
 
+
721
 
+  $mime_content_id
722
 
+  ----------------
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.
726
 
+  
727
 
+  
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.
735
 
+  
736
 
+  
737
 
+  $mime_part_count
738
 
+  ----------------
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.
747
 
+  
748
 
+  
749
 
+  $mime_is_multipart
750
 
+  ------------------
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.
756
 
757
 
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.
764
 
+
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:
768
 
+
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
772
 
+     multipart.
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
776
 
+     attachments.
777
 
+
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:
781
 
+  
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
 
+    ----------------------- */
787
 
+  
788
 
+  
789
 
+  $mime_is_rfc822
790
 
+  ---------------
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.
794
 
+
795
 
+
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.
801
 
+  
802
 
+  
803
 
+  $mime_content_size
804
 
+  ------------------
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.
810
 
+
811
 
+
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
815
 
+
816
 
+decode = [/<PATH>/]<FILENAME>
817
 
+
818
 
+The right hand side is expanded before use. After expansion,
819
 
+the value can
820
 
+
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.
835
 
+    
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.
841
 
+
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.
846
 
+
847
 
+
848
 
+
849
 
+2. Match message or MIME parts against regular expressions
850
 
+--------------------------------------------------------------
851
 
+
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.
858
 
+
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
866
 
+matched.
867
 
+
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.
872
 
+
873
 
+Here is a simple example:
874
 
+
875
 
+/* ----------------------
876
 
+deny message = contains blacklisted regex ($regex_match_string)
877
 
+     regex = [Mm]ortgage : URGENT BUSINESS PROPOSAL
878
 
+----------------------- */
879
 
+
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
883
 
+expression.
884
 
+
885
 
+Warning: With large messages,  these conditions can be  fairly
886
 
+CPU-intensive.
887
 
+
888
 
+
889
 
+
890
 
+3. Antispam measures with SpamAssassin
891
 
+--------------------------------------------------------------
892
 
+
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
898
 
+
899
 
+perl -MCPAN -e 'install Mail::SpamAssassin'
900
 
+
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.
904
 
+
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):
910
 
+
911
 
+spamd_address = 127.0.0.1 783
912
 
+
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:
916
 
+
917
 
+spamd_address = /var/run/spamd_socket
918
 
+
919
 
+If you use the above mentioned default, you do NOT need to set
920
 
+this option.
921
 
+
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:
927
 
+
928
 
+spamd_address = 192.168.2.10 783 : 192.168.2.11 783 : 192.168.2.12 783
929
 
+
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.
937
 
+
938
 
+To use the  antispam facility, put  the "spam" condition  in a
939
 
+DATA ACL block. Here is a very simple example:
940
 
+
941
 
+/* ---------------
942
 
+deny message = This message was classified as SPAM
943
 
+        spam = joe
944
 
+---------------- */
945
 
+
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
952
 
+immediately.
953
 
+
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".
957
 
+
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. 
963
 
+
964
 
+When the condition is run, it sets up the following  expansion
965
 
+variables:
966
 
+
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.
970
 
+                  
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
980
 
+                    or transports.
981
 
+                    
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.
988
 
+  
989
 
+  $spam_report      A  multiline  text  table,  containing the
990
 
+                    full SpamAssassin report for the  message.
991
 
+                    Useful for inclusion in headers or  reject
992
 
+                    messages.
993
 
+            
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.
997
 
+
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:
1003
 
+
1004
 
+/* ---------------
1005
 
+deny message = This message was classified as SPAM
1006
 
+        spam = joe/defer_ok
1007
 
+---------------- */
1008
 
+
1009
 
+This will  cause messages  to be  accepted even  if there is a
1010
 
+problem with spamd.
1011
 
+
1012
 
+Finally, here is  a commented example  on how to  use the spam
1013
 
+condition:
1014
 
+
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
1021
 
+      
1022
 
+# add second subject line with *SPAM* marker when message
1023
 
+# is over threshold
1024
 
+warn  message = Subject: *SPAM* $h_Subject
1025
 
+      spam = nobody
1026
 
+
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
 
+----------------- */
1032
 
+
1033
 
+
1034
 
+
1035
 
+4. The "malware" facility
1036
 
+   Scan messages for viruses using an external virus scanner
1037
 
+--------------------------------------------------------------
1038
 
+
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.
1043
 
+
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:
1048
 
+
1049
 
+  av_scanner = <scanner-type>:<option1>:<option2>:[...]
1050
 
+  
1051
 
+The following scanner-types are supported in this release:
1052
 
+
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:
1061
 
+              
1062
 
+              av_scanner = sophie:/tmp/sophie
1063
 
+
1064
 
+
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".
1070
 
+              Example:
1071
 
+              
1072
 
+              av_scanner = kavdaemon:/opt/AVP/AvpCtl
1073
 
+              
1074
 
+              
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:
1083
 
+              
1084
 
+              av_scanner = clamd:192.168.2.100 1234
1085
 
+              or
1086
 
+              av_scanner = clamd:/opt/clamd/socket
1087
 
+              
1088
 
+              
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
1094
 
+              
1095
 
+              /usr/local/drweb/run/drwebd.sock
1096
 
+              
1097
 
+              is used. Example:
1098
 
+              
1099
 
+              av_scanner = drweb:192.168.2.20 31337
1100
 
+              or
1101
 
+              av_scanner = drweb:/var/run/drwebd.sock
1102
 
+              
1103
 
+              Thanks  to  Alex  Miller  <asm@abbyy.com.ua> for
1104
 
+              contributing the code for this scanner.              
1105
 
+              
1106
 
+              
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:
1118
 
+              
1119
 
+              av_scanner = mksd:2
1120
 
+
1121
 
+
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:
1126
 
+              
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.
1130
 
+                
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.
1137
 
+                
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.
1142
 
+                
1143
 
+              Example:
1144
 
+              
1145
 
+              Sophos  Sweep reports  a virus  on a  line  like
1146
 
+              this:
1147
 
+
1148
 
+              Virus 'W32/Magistr-B' found in file ./those.bat
1149
 
+
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!)
1155
 
+
1156
 
+              Altogether,   this   makes   the   configuration
1157
 
+              setting:
1158
 
+              
1159
 
+              av_scanner = cmdline:\
1160
 
+              /path/to/sweep -all -rec -archive %s:\
1161
 
+              found:'(.+)'
1162
 
+              
1163
 
+
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
1167
 
+
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.
1171
 
+    
1172
 
+  - "false" or "0", in which case no scanning is done and  the
1173
 
+    condition will fail immediately.
1174
 
+    
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
1179
 
+    viruses.
1180
 
+    
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.
1185
 
+
1186
 
+The malware condition caches its  results, so when you use  it
1187
 
+multiple times,  the actual  scanning process  is only carried
1188
 
+out once.
1189
 
+
1190
 
+If your virus scanner  cannot unpack MIME and  TNEF containers
1191
 
+itself,  you  should use  the  demime condition  prior  to the
1192
 
+malware condition.
1193
 
+
1194
 
+Here is a simple example:
1195
 
+
1196
 
+/* ----------------------
1197
 
+deny message = This message contains malware ($malware_name)
1198
 
+     demime = *
1199
 
+     malware = *
1200
 
+---------------------- */
1201
 
+
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:
1205
 
+
1206
 
+/* ----------------------
1207
 
+deny message = This message contains malware ($malware_name)
1208
 
+     demime = *
1209
 
+     malware = */defer_ok
1210
 
+---------------------- */
1211
 
+
1212
 
+
1213
 
+
1214
 
+5. The "demime" facility
1215
 
+   MIME unpacking, sanity checking and file extension blocking
1216
 
+--------------------------------------------------------------
1217
 
+
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.
1221
 
+
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.
1229
 
+
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.
1238
 
+
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.
1243
 
+
1244
 
+A short example:
1245
 
+
1246
 
+/* ------------
1247
 
+deny message = Found blacklisted file attachment
1248
 
+     demime = vbs:com:bat:pif:prf:lnk
1249
 
+--------------- */
1250
 
+
1251
 
+When the condition is run, it sets up the following  expansion
1252
 
+variables:
1253
 
+
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
1260
 
+                      occured.
1261
 
+
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.
1266
 
+                          
1267
 
+ $found_extension     When  the  "demime"  condition   returns
1268
 
+                      "true", this variable contains the  file
1269
 
+                      extension it has found.
1270
 
+                          
1271
 
+Both $demime_errorlevel  and $demime_reason  are set  with the
1272
 
+first call of the "demime"  condition, and are not changed  on
1273
 
+subsequent calls.
1274
 
+
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.
1278
 
+
1279
 
+Here is a more elaborate example on how to use this facility:
1280
 
+
1281
 
+/* -----------------
1282
 
+# Reject messages with serious MIME container errors
1283
 
+deny  message = Found MIME error ($demime_reason).
1284
 
+      demime = *
1285
 
+      condition = ${if >{$demime_errorlevel}{2}{1}{0}}
1286
 
+
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
1291
 
+
1292
 
+# Freeze .exe and .doc files. Postmaster can
1293
 
+# examine them and eventually thaw them up.
1294
 
+deny  log_message = Another $found_extension file.
1295
 
+      demime = exe:doc
1296
 
+      control = freeze
1297
 
+--------------------- */
1298
 
+
1299
 
+
1300
 
+
1301
 
+6. The "fakereject" control statement
1302
 
+   Reject a message while really accepting it.
1303
 
+--------------------------------------------------------------
1304
 
+
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
1308
 
+message of:
1309
 
+
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).
1313
 
+
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.
1317
 
+
1318
 
+
1319
 
+
1320
 
+7. Brighmail AntiSpam (BMI) suppport
1321
 
+--------------------------------------------------------------
1322
 
+
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
1326
 
+"BMI" from now on.
1327
 
+
1328
 
+
1329
 
+0) BMI concept and implementation overview
1330
 
+
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
1341
 
+following steps:
1342
 
+
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
1346
 
+     file)
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.
1350
 
+
1351
 
+These four steps are explained in more details below. 
1352
 
+
1353
 
+1) Adding support for BMI at compile time
1354
 
+
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:
1361
 
+  
1362
 
+  CFLAGS=-DBRIGHTMAIL -I/path/to/the/dir/with/the/includefile
1363
 
+  EXTRALIBS_EXIM=-L/path/to/the/dir/with/the/library -lbmiclient_single
1364
 
+  
1365
 
+  If  you use  other CFLAGS  or EXTRALIBS_EXIM  settings then
1366
 
+  merge the content of these lines with them.
1367
 
+  
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.
1373
 
+
1374
 
+
1375
 
+2) Setting up BMI support in the exim main configuration
1376
 
+
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:
1380
 
+  
1381
 
+  bmi_config_file = /opt/brightmail/etc/brightmail.cfg
1382
 
+  
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.
1386
 
+
1387
 
+
1388
 
+3) Set up ACL control statement
1389
 
+
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:
1399
 
+  
1400
 
+
1401
 
+  accept  domains       = +local_domains
1402
 
+          endpass
1403
 
+          verify        = recipient
1404
 
+          control       = bmi_run
1405
 
+
1406
 
+  accept  domains       = +relay_to_domains
1407
 
+          endpass
1408
 
+          verify        = recipient
1409
 
+          control       = bmi_run
1410
 
+  
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.
1413
 
+
1414
 
+
1415
 
+4) Setting up routers to use BMI verdicts
1416
 
+
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:
1423
 
+  
1424
 
+  o deliver the message normally
1425
 
+  o deliver the message to an alternate location
1426
 
+  o do not deliver the message
1427
 
+  
1428
 
+  To query  the verdict  for a  recipient, the  implementation
1429
 
+  offers the following tools:
1430
 
+  
1431
 
+  
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
1435
 
+    available:
1436
 
+    
1437
 
+    o bmi_deliver_default
1438
 
+    
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.
1443
 
+      
1444
 
+    o bmi_deliver_alternate
1445
 
+    
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.
1452
 
+      
1453
 
+    o bmi_dont_deliver
1454
 
+    
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:
1459
 
+      
1460
 
+        # don't deliver messages handled by the BMI server
1461
 
+        bmi_blackhole:
1462
 
+          driver = redirect
1463
 
+          bmi_dont_deliver
1464
 
+          data = :blackhole:
1465
 
+      
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.
1470
 
+      
1471
 
+      
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:
1477
 
+    
1478
 
+      # special router for BMI rule #5, #8 and #11
1479
 
+      bmi_rule_redirect:
1480
 
+        driver = redirect
1481
 
+        bmi_rule = 5:8:11
1482
 
+        data = postmaster@mydomain.com
1483
 
+      
1484
 
+  
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
1488
 
+    available:
1489
 
+    
1490
 
+    o $bmi_base64_verdict
1491
 
+    
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:
1495
 
+      
1496
 
+      localuser:
1497
 
+        driver = accept
1498
 
+        check_local_user
1499
 
+        headers_add = X-Brightmail-Verdict: $bmi_base64_verdict
1500
 
+        transport = local_delivery
1501
 
+      
1502
 
+      If there is no verdict available for the recipient being
1503
 
+      routed, this variable contains the empty string.
1504
 
+    
1505
 
+    o $bmi_base64_tracker_verdict
1506
 
+    
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:
1511
 
+      
1512
 
+      localuser:
1513
 
+        driver = accept
1514
 
+        check_local_user
1515
 
+        headers_add = X-Brightmail-Tracker: $bmi_base64_tracker_verdict
1516
 
+        transport = local_delivery
1517
 
+        
1518
 
+      If there is no verdict available for the recipient being
1519
 
+      routed, this variable contains the empty string.
1520
 
+      
1521
 
+    o $bmi_alt_location
1522
 
+    
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.
1531
 
+      
1532
 
+    o $bmi_deliver
1533
 
+    
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.
1537
 
+      
1538
 
+      $bmi_deliver is '0': the message should NOT be delivered.
1539
 
+      $bmi_deliver is '1': the message should be delivered.
1540
 
+      
1541
 
+   
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.
1550
 
+  
1551
 
+  
1552
 
+5) Using per-recipient opt-in information (Optional)
1553
 
+
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'.
1571
 
+  
1572
 
+  The file format:
1573
 
+  
1574
 
+    user1@mydomain.com: <OPTIN STRING1>:<OPTIN STRING2>
1575
 
+    user2@thatdomain.com: <OPTIN STRING3>
1576
 
+    
1577
 
+    
1578
 
+  The example:
1579
 
+  
1580
 
+    accept  domains       = +relay_to_domains
1581
 
+            endpass
1582
 
+            verify        = recipient
1583
 
+            bmi_optin     = ${lookup{$local_part@$domain}lsearch{/etc/exim/bmi_optin_data}}
1584
 
+            control       = bmi_run  
1585
 
+  
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
1589
 
+  strings.
1590
 
+  
1591
 
+  For a list of available opt-in strings, please contact  your
1592
 
+  Brightmail representative.
1593
 
+  
1594
 
+--------------------------------------------------------------
1595
 
+End of file
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
1600
 
@@ -42,6 +42,10 @@
1601
 
 uschar *action_required;
1602
 
 uschar *alternate_config = NULL;
1603
 
 
1604
 
+#ifdef BRIGHTMAIL
1605
 
+int     bmi_run                = 0;
1606
 
+uschar *bmi_verdicts           = NULL;
1607
 
+#endif
1608
 
 int     body_max = 20000;
1609
 
 
1610
 
 uschar *exim_path              = US BIN_DIRECTORY "/exim"
1611
 
@@ -127,6 +131,8 @@
1612
 
 BOOL    deliver_manual_thaw    = FALSE;
1613
 
 BOOL    dont_deliver           = FALSE;
1614
 
 
1615
 
+BOOL   fake_reject            = FALSE;
1616
 
+
1617
 
 header_line *header_last       = NULL;
1618
 
 header_line *header_list       = NULL;
1619
 
 
1620
 
@@ -136,6 +142,7 @@
1621
 
 
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;
1627
 
 uschar *message_id;
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.
1634
 
 
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
1651
 
 
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
1657
 
@@ -190,6 +196,7 @@
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
1665
 
@@ -208,7 +215,9 @@
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
1675
 
@@ -216,6 +225,7 @@
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
1703
 
@@ -7,8 +7,13 @@
1704
 
 
1705
 
 /* Code for handling Access Control Lists (ACLs) */
1706
 
 
1707
 
+/* This file has been modified by the exiscan-acl patch. */
1708
 
+
1709
 
 #include "exim.h"
1710
 
 
1711
 
+#ifdef BRIGHTMAIL
1712
 
+#include "bmi_spam.h"
1713
 
+#endif
1714
 
 
1715
 
 /* Default callout timeout */
1716
 
 
1717
 
@@ -32,19 +37,26 @@
1718
 
 /* ACL condition and modifier codes - keep in step with the table that
1719
 
 follows. */
1720
 
 
1721
 
-enum { ACLC_ACL, ACLC_AUTHENTICATED, ACLC_CONDITION, ACLC_CONTROL, ACLC_DELAY,
1722
 
+enum { ACLC_ACL, ACLC_AUTHENTICATED,
1723
 
+#ifdef BRIGHTMAIL
1724
 
+  ACLC_BMI_OPTIN,
1725
 
+#endif
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 };
1732
 
 
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. */
1736
 
 
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", 
1742
 
+#ifdef BRIGHTMAIL
1743
 
+  US"bmi_optin",
1744
 
+#endif
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", 
1748
 
   US"verify" };
1749
 
 
1750
 
 /* Flags to indicate for which conditions /modifiers a string expansion is done
1751
 
@@ -54,9 +66,14 @@
1752
 
 static uschar cond_expand_at_top[] = {
1753
 
   TRUE,    /* acl */
1754
 
   FALSE,   /* authenticated */
1755
 
+#ifdef BRIGHTMAIL
1756
 
+  TRUE,    /* bmi_optin */
1757
 
+#endif
1758
 
   TRUE,    /* condition */
1759
 
   TRUE,    /* control */
1760
 
+  TRUE,    /* decode */
1761
 
   TRUE,    /* delay */
1762
 
+  TRUE,    /* demime */
1763
 
   TRUE,    /* dnslists */
1764
 
   FALSE,   /* domains */
1765
 
   FALSE,   /* encrypted */
1766
 
@@ -65,11 +82,15 @@
1767
 
   FALSE,   /* local_parts */
1768
 
   TRUE,    /* log_message */
1769
 
   TRUE,    /* logwrite */
1770
 
+  TRUE,    /* malware */
1771
 
   TRUE,    /* message */
1772
 
+  TRUE,    /* mime_regex */
1773
 
   FALSE,   /* recipients */
1774
 
+  TRUE,    /* regex */
1775
 
   FALSE,   /* sender_domains */
1776
 
   FALSE,   /* senders */
1777
 
   TRUE,    /* set */
1778
 
+  TRUE,    /* spam */
1779
 
   TRUE     /* verify */
1780
 
 };
1781
 
 
1782
 
@@ -78,9 +99,14 @@
1783
 
 static uschar cond_modifiers[] = {
1784
 
   FALSE,   /* acl */
1785
 
   FALSE,   /* authenticated */
1786
 
+#ifdef BRIGHTMAIL
1787
 
+  TRUE,    /* bmi_optin */
1788
 
+#endif
1789
 
   FALSE,   /* condition */
1790
 
   TRUE,    /* control */
1791
 
+  FALSE,   /* decode */
1792
 
   TRUE,    /* delay */
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 */
1802
 
   TRUE,    /* message */
1803
 
+  FALSE,   /* mime_regex */
1804
 
   FALSE,   /* recipients */
1805
 
+  FALSE,   /* regex */
1806
 
   FALSE,   /* sender_domains */
1807
 
   FALSE,   /* senders */
1808
 
   TRUE,    /* set */
1809
 
+  FALSE,   /* spam */
1810
 
   FALSE    /* verify */
1811
 
 };
1812
 
 
1813
 
@@ -102,8 +132,20 @@
1814
 
 
1815
 
 static unsigned int cond_forbids[] = {
1816
 
   0,                                               /* acl */
1817
 
+  
1818
 
   (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_CONNECT)|   /* authenticated */
1819
 
     (1<<ACL_WHERE_HELO),
1820
 
+    
1821
 
+#ifdef BRIGHTMAIL
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),                                                 
1829
 
+#endif
1830
 
+    
1831
 
   0,                                               /* condition */
1832
 
 
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),
1837
 
 
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),
1845
 
+
1846
 
   0,                                               /* delay */
1847
 
+
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),
1855
 
+
1856
 
   (1<<ACL_WHERE_NOTSMTP),                          /* dnslists */
1857
 
 
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 @@
1866
 
 
1867
 
   (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_CONNECT)|   /* encrypted */
1868
 
     (1<<ACL_WHERE_HELO),
1869
 
+    
1870
 
   0,                                               /* endpass */
1871
 
+  
1872
 
   (1<<ACL_WHERE_NOTSMTP),                          /* hosts */
1873
 
 
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),
1882
 
 
1883
 
   0,                                               /* log_message */
1884
 
+  
1885
 
   0,                                               /* logwrite */
1886
 
+
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),
1894
 
+  
1895
 
   0,                                               /* message */
1896
 
 
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),
1904
 
+
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),
1913
 
 
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),
1920
 
+
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 @@
1925
 
 
1926
 
   0,                                               /* set */
1927
 
 
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),
1935
 
+
1936
 
   /* Certain types of verify are always allowed, so we let it through
1937
 
   always and check in the verify function itself */
1938
 
 
1939
 
@@ -447,7 +541,7 @@
1940
 
 /* If this isn't a message ACL, we can't do anything with a user message.
1941
 
 Log an error. */
1942
 
 
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)
1946
 
   {
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;
1951
 
 int rc = OK;
1952
 
+int sep = '/';
1953
 
 
1954
 
 for (; cb != NULL; cb = cb->next)
1955
 
   {
1956
 
@@ -1136,6 +1231,20 @@
1957
 
       deliver_freeze = TRUE;
1958
 
       deliver_frozen_at = time(NULL);
1959
 
       }
1960
 
+    else if (Ustrcmp(arg, "fakereject") == 0)
1961
 
+      {
1962
 
+      fake_reject = TRUE;
1963
 
+      }
1964
 
+#ifdef BRIGHTMAIL
1965
 
+    else if (Ustrcmp(arg, "bmi_run") == 0)
1966
 
+      {
1967
 
+      bmi_run = 1;
1968
 
+      }
1969
 
+#endif
1970
 
+    else if (Ustrcmp(arg, "no_mbox_unspool") == 0)
1971
 
+      {
1972
 
+      no_mbox_unspool = TRUE;
1973
 
+      }
1974
 
     else if (Ustrcmp(arg, "queue_only") == 0)
1975
 
       {
1976
 
       queue_only_policy = TRUE;
1977
 
@@ -1167,7 +1276,70 @@
1978
 
     break;
1979
 
 
1980
 
     case ACLC_DNSLISTS:
1981
 
-    rc = verify_check_dnsbl(&arg);
1982
 
+      rc = verify_check_dnsbl(&arg);
1983
 
+    break;
1984
 
+
1985
 
+#ifdef BRIGHTMAIL
1986
 
+    case ACLC_BMI_OPTIN:
1987
 
+      {
1988
 
+      int old_pool = store_pool;
1989
 
+      store_pool = POOL_PERM;
1990
 
+      bmi_current_optin = string_copy(arg);
1991
 
+      store_pool = old_pool;
1992
 
+      }
1993
 
+    break;
1994
 
+#endif
1995
 
+
1996
 
+    case ACLC_DECODE:
1997
 
+      rc = mime_decode(&arg);
1998
 
+    break;
1999
 
+
2000
 
+    case ACLC_MIME_REGEX:
2001
 
+      rc = mime_regex(&arg);
2002
 
+    break;
2003
 
+
2004
 
+    case ACLC_DEMIME:
2005
 
+      rc = demime(&arg);
2006
 
+    break;
2007
 
+
2008
 
+    case ACLC_MALWARE:
2009
 
+      {
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))
2016
 
+            != NULL) {
2017
 
+        if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
2018
 
+          {
2019
 
+          /* FAIL so that the message is passed to the next ACL */
2020
 
+          rc = FAIL;
2021
 
+          }
2022
 
+        }
2023
 
+      }
2024
 
+    break;
2025
 
+
2026
 
+    case ACLC_SPAM:
2027
 
+      {
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. */
2031
 
+      rc = spam(&ss);
2032
 
+      /* Modify return code based upon the existance of options. */
2033
 
+      while ((ss = string_nextinlist(&arg, &sep, big_buffer, big_buffer_size))
2034
 
+            != NULL) {
2035
 
+        if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
2036
 
+          {
2037
 
+          /* FAIL so that the message is passed to the next ACL */
2038
 
+          rc = FAIL;
2039
 
+          }
2040
 
+        }
2041
 
+      }
2042
 
+    break;
2043
 
+
2044
 
+    case ACLC_REGEX:
2045
 
+      rc = regex(&arg);
2046
 
     break;
2047
 
 
2048
 
     case ACLC_DOMAINS:
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)
2055
 
     {
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
2060
 
@@ -0,0 +1,474 @@
2061
 
+/*************************************************
2062
 
+*     Exim - an Internet mail transport agent    *
2063
 
+*************************************************/
2064
 
+
2065
 
+/* This file is part of the exiscan-acl content scanner
2066
 
+   patch. It is NOT part of the standard exim distribution. */
2067
 
+
2068
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
2069
 
+/* License: GPL */
2070
 
+
2071
 
+/* Code for calling Brightmail AntiSpam. */
2072
 
+
2073
 
+#include "exim.h"
2074
 
+#include "bmi_spam.h"
2075
 
+
2076
 
+#ifdef BRIGHTMAIL
2077
 
+
2078
 
+uschar *bmi_current_optin = NULL;
2079
 
+
2080
 
+uschar *bmi_process_message(header_line *header_list, int data_fd) {
2081
 
+  BmiSystem *system = NULL;
2082
 
+  BmiMessage *message = NULL;
2083
 
+  BmiError err;
2084
 
+  BmiErrorLocation err_loc;
2085
 
+  BmiErrorType err_type;
2086
 
+  const BmiVerdict *verdict = NULL;
2087
 
+  FILE *data_file;
2088
 
+  uschar data_buffer[4096];
2089
 
+  uschar localhost[] = "127.0.0.1";
2090
 
+  uschar *host_address;
2091
 
+  uschar *verdicts = NULL;
2092
 
+  int i,j;
2093
 
+  
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);
2100
 
+    return NULL;
2101
 
+  }
2102
 
+
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);
2110
 
+    return NULL;
2111
 
+  }
2112
 
+
2113
 
+  /* Send IP address of sending host */
2114
 
+  if (sender_host_address == NULL)
2115
 
+    host_address = localhost;
2116
 
+  else
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);
2126
 
+    return NULL;
2127
 
+  };
2128
 
+
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);
2138
 
+    return NULL;
2139
 
+  };
2140
 
+
2141
 
+  /* Send envelope recipients */
2142
 
+  for(i=0;i<recipients_count;i++) {
2143
 
+    recipient_item *r = recipients_list + i;
2144
 
+    BmiOptin *optin = NULL;
2145
 
+    
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);
2156
 
+        optin = NULL;
2157
 
+      };
2158
 
+    };
2159
 
+    
2160
 
+    err = bmiAccumulateTO((char *)r->address, optin, message);
2161
 
+    
2162
 
+    if (optin != NULL)
2163
 
+      bmiOptinFree(optin);
2164
 
+    
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);
2172
 
+      return NULL;
2173
 
+    };
2174
 
+  };
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);
2183
 
+    return NULL;
2184
 
+  };
2185
 
+  
2186
 
+  /* Send message headers */
2187
 
+  while (header_list != NULL) {
2188
 
+    /* skip deleted headers */
2189
 
+    if (header_list->type == '*') {
2190
 
+      header_list = header_list->next;
2191
 
+      continue;
2192
 
+    };
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);
2201
 
+      return NULL;
2202
 
+    };
2203
 
+    header_list = header_list->next;
2204
 
+  };
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);
2213
 
+    return NULL;
2214
 
+  };
2215
 
+  
2216
 
+  /* Send body */
2217
 
+  data_file = fdopen(data_fd,"r");
2218
 
+  do {
2219
 
+    j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
2220
 
+    if (j > 0) {
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);
2229
 
+        return NULL;
2230
 
+      };
2231
 
+    };
2232
 
+  } while (j > 0);
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);
2241
 
+    return NULL;
2242
 
+  };
2243
 
+  
2244
 
+  
2245
 
+  /* End message */
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);
2254
 
+    return NULL;
2255
 
+  };
2256
 
+  
2257
 
+  /* get store for the verdict string */
2258
 
+  verdicts = store_get(1);
2259
 
+  *verdicts = '\0';
2260
 
+  
2261
 
+  for ( err = bmiAccessFirstVerdict(message, &verdict);
2262
 
+        verdict != NULL;
2263
 
+        err = bmiAccessNextVerdict(message, verdict, &verdict) ) {
2264
 
+    char *verdict_str;
2265
 
+
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 */
2269
 
+      return NULL;
2270
 
+    };
2271
 
+    if (*verdicts != '\0')
2272
 
+      Ustrcat(verdicts, US ":");
2273
 
+    Ustrcat(verdicts, US verdict_str);
2274
 
+    bmiFreeStr(verdict_str);
2275
 
+  };
2276
 
+
2277
 
+  DEBUG(D_receive) debug_printf("bmi verdicts: %s\n", verdicts);
2278
 
+
2279
 
+  if (Ustrlen(verdicts) == 0)
2280
 
+    return NULL;
2281
 
+  else
2282
 
+    return verdicts;
2283
 
+}
2284
 
+
2285
 
+
2286
 
+int bmi_get_delivery_status(uschar *base64_verdict) {
2287
 
+  BmiError err;
2288
 
+  BmiErrorLocation err_loc;
2289
 
+  BmiErrorType err_type;
2290
 
+  BmiVerdict *verdict = NULL;
2291
 
+  int rc = 1;   /* deliver by default */
2292
 
+  
2293
 
+  /* always deliver when there is no verdict */
2294
 
+  if (base64_verdict == NULL)
2295
 
+    return 1;
2296
 
+
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);
2304
 
+    return 1;
2305
 
+  };
2306
 
+
2307
 
+  err = bmiVerdictError(verdict);
2308
 
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
2309
 
+    /* deliver normally due to error */
2310
 
+    rc = 1;
2311
 
+  }
2312
 
+  else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
2313
 
+    /* deliver normally */
2314
 
+    rc = 1;    
2315
 
+  }
2316
 
+  else if (bmiVerdictAccessDestination(verdict) == NULL) {
2317
 
+    /* do not deliver */
2318
 
+    rc = 0;
2319
 
+  }
2320
 
+  else {
2321
 
+    /* deliver to alternate location */
2322
 
+    rc = 1;
2323
 
+  };
2324
 
+  
2325
 
+  bmiFreeVerdict(verdict);
2326
 
+  return rc;
2327
 
+}
2328
 
+
2329
 
+
2330
 
+uschar *bmi_get_alt_location(uschar *base64_verdict) {
2331
 
+  BmiError err;
2332
 
+  BmiErrorLocation err_loc;
2333
 
+  BmiErrorType err_type;
2334
 
+  BmiVerdict *verdict = NULL;
2335
 
+  uschar *rc = NULL;
2336
 
+  
2337
 
+  /* always deliver when there is no verdict */
2338
 
+  if (base64_verdict == NULL)
2339
 
+    return NULL;
2340
 
+
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);
2348
 
+    return NULL;
2349
 
+  };
2350
 
+  
2351
 
+  err = bmiVerdictError(verdict);
2352
 
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
2353
 
+    /* deliver normally due to error */
2354
 
+    rc = NULL;
2355
 
+  }
2356
 
+  else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) {
2357
 
+    /* deliver normally */
2358
 
+    rc = NULL; 
2359
 
+  }
2360
 
+  else if (bmiVerdictAccessDestination(verdict) == NULL) {
2361
 
+    /* do not deliver */
2362
 
+    rc = NULL;
2363
 
+  }
2364
 
+  else {
2365
 
+    /* deliver to alternate location */
2366
 
+    rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1);
2367
 
+    Ustrcpy(rc, bmiVerdictAccessDestination(verdict));
2368
 
+    rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0';
2369
 
+  };
2370
 
+  
2371
 
+  bmiFreeVerdict(verdict);
2372
 
+  return rc;
2373
 
+}
2374
 
+
2375
 
+uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
2376
 
+  BmiError err;
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;
2384
 
+  int sep = 0;
2385
 
+  
2386
 
+  /* return nothing if there are no verdicts available */
2387
 
+  if (bmi_verdicts == NULL)
2388
 
+    return NULL;
2389
 
+  
2390
 
+  /* allocate room for the b64 verdict string */
2391
 
+  verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1);
2392
 
+  
2393
 
+  /* loop through verdicts */
2394
 
+  verdict_ptr = bmi_verdicts;
2395
 
+  while ((verdict_str = (const char *)string_nextinlist(&verdict_ptr, &sep,
2396
 
+                                          verdict_buffer,
2397
 
+                                          Ustrlen(bmi_verdicts)+1)) != NULL) {
2398
 
+    
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);
2406
 
+      return NULL;
2407
 
+    };
2408
 
+    
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;
2415
 
+      
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"";
2421
 
+      }
2422
 
+      else {
2423
 
+        *rcpt_domain = '\0';
2424
 
+        rcpt_domain++;
2425
 
+      };
2426
 
+
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;
2432
 
+      };   
2433
 
+    };
2434
 
+  
2435
 
+    bmiFreeVerdict(verdict);
2436
 
+  };
2437
 
+  
2438
 
+  return NULL;
2439
 
+}
2440
 
+
2441
 
+
2442
 
+uschar *bmi_get_base64_tracker_verdict(uschar *base64_verdict) {
2443
 
+  BmiError err;
2444
 
+  BmiErrorLocation err_loc;
2445
 
+  BmiErrorType err_type;
2446
 
+  BmiVerdict *verdict = NULL;
2447
 
+  uschar *rc = NULL;
2448
 
+  
2449
 
+  /* always deliver when there is no verdict */
2450
 
+  if (base64_verdict == NULL)
2451
 
+    return NULL;
2452
 
+
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);
2460
 
+    return NULL;
2461
 
+  };
2462
 
+  
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);
2470
 
+    return NULL;
2471
 
+  };
2472
 
+  
2473
 
+  bmiFreeVerdict(verdict);
2474
 
+  return rc;
2475
 
+}
2476
 
+
2477
 
+
2478
 
+int bmi_check_rule(uschar *base64_verdict, uschar *option_list) {
2479
 
+  BmiError err;
2480
 
+  BmiErrorLocation err_loc;
2481
 
+  BmiErrorType err_type;
2482
 
+  BmiVerdict *verdict = NULL;
2483
 
+  int rc = 0;
2484
 
+  uschar *rule_num;
2485
 
+  uschar *rule_ptr;
2486
 
+  uschar rule_buffer[32];
2487
 
+  int sep = 0;
2488
 
+  
2489
 
+  
2490
 
+  /* no verdict -> no rule fired */
2491
 
+  if (base64_verdict == NULL)
2492
 
+    return 0;
2493
 
+  
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);
2501
 
+    return 0;
2502
 
+  };
2503
 
+  
2504
 
+  err = bmiVerdictError(verdict);
2505
 
+  if (bmiErrorIsFatal(err) == BMI_TRUE) {
2506
 
+    /* error -> no rule fired */
2507
 
+    bmiFreeVerdict(verdict);
2508
 
+    return 0;
2509
 
+  }
2510
 
+  
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;
2516
 
+    
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);
2524
 
+        rc = 1;
2525
 
+        break;
2526
 
+      };
2527
 
+    };
2528
 
+  };
2529
 
+
2530
 
+  bmiFreeVerdict(verdict);
2531
 
+  return rc;
2532
 
+};
2533
 
+
2534
 
+#endif
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
2538
 
@@ -0,0 +1,26 @@
2539
 
+/*************************************************
2540
 
+*     Exim - an Internet mail transport agent    *
2541
 
+*************************************************/
2542
 
+
2543
 
+/* This file is part of the exiscan-acl content scanner
2544
 
+   patch. It is NOT part of the standard exim distribution. */
2545
 
+
2546
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
2547
 
+/* License: GPL */
2548
 
+
2549
 
+/* Code for calling Brightmail AntiSpam. */
2550
 
+
2551
 
+#ifdef BRIGHTMAIL
2552
 
+
2553
 
+#include <bmi_api.h>
2554
 
+
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 *);
2561
 
+
2562
 
+extern uschar *bmi_current_optin;
2563
 
+
2564
 
+#endif
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
2568
 
@@ -101,7 +101,7 @@
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)
2574
 
 
2575
 
 #define SUPPORT_A6
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 @@
2581
 
 
2582
 
 # You should not change that setting until you understand how ACLs work.
2583
 
 
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.
2587
 
+
2588
 
+# acl_smtp_mime = acl_check_mime
2589
 
+# acl_smtp_data = acl_check_content
2590
 
+
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.
2595
 
+
2596
 
+# av_scanner = sophie:/var/run/sophie
2597
 
+
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.
2602
 
+
2603
 
+# spamd_address = 127.0.0.1 783
2604
 
 
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
2609
 
 
2610
 
 
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 ...
2616
 
+
2617
 
+acl_check_mime:
2618
 
+
2619
 
+  # Decode MIME parts to disk. This will support virus scanners later.
2620
 
+  warn decode = default
2621
 
+
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} \
2627
 
+                     {1}{0}}
2628
 
+  
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}}
2633
 
+
2634
 
+  accept
2635
 
+
2636
 
+acl_check_content:
2637
 
+
2638
 
+  # Reject virus infested messages.
2639
 
+  deny  message = This message contains malware ($malware_name)
2640
 
+        malware = *
2641
 
+
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
2648
 
+
2649
 
+  # Add X-Spam-Flag if spam is over system-wide threshold
2650
 
+  warn message = X-Spam-Flag: YES
2651
 
+       spam = nobody
2652
 
+
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}}
2657
 
+
2658
 
+  # finally accept all the rest
2659
 
+  accept
2660
 
+  
2661
 
 
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
2667
 
@@ -10,6 +10,9 @@
2668
 
 
2669
 
 #include "exim.h"
2670
 
 
2671
 
+#ifdef BRIGHTMAIL
2672
 
+#include "bmi_spam.h"
2673
 
+#endif
2674
 
 
2675
 
 /* Data block for keeping track of subprocesses for parallel remote
2676
 
 delivery. */
2677
 
@@ -152,6 +155,13 @@
2678
 
 deliver_domain = addr->domain;
2679
 
 self_hostname = addr->self_hostname;
2680
 
 
2681
 
+#ifdef BRIGHTMAIL
2682
 
+bmi_deliver = 1;    /* deliver by default */
2683
 
+bmi_alt_location = NULL;
2684
 
+bmi_base64_verdict = NULL;
2685
 
+bmi_base64_tracker_verdict = NULL;
2686
 
+#endif
2687
 
+
2688
 
 /* If there's only one address we can set everything. */
2689
 
 
2690
 
 if (addr->next == NULL)
2691
 
@@ -201,6 +211,19 @@
2692
 
       deliver_localpart_suffix = addr->parent->suffix;
2693
 
       }
2694
 
     }
2695
 
+  
2696
 
+#ifdef BRIGHTMAIL
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);
2705
 
+    };
2706
 
+#endif
2707
 
+  
2708
 
   }
2709
 
 
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
2714
 
@@ -0,0 +1,1276 @@
2715
 
+/*************************************************
2716
 
+*     Exim - an Internet mail transport agent    *
2717
 
+*************************************************/
2718
 
+
2719
 
+/* This file is part of the exiscan-acl content scanner
2720
 
+patch. It is NOT part of the standard exim distribution. */
2721
 
+
2722
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
2723
 
+/* License: GPL */
2724
 
+
2725
 
+/* Code for unpacking MIME containers. Called from acl.c. */
2726
 
+
2727
 
+#include "exim.h"
2728
 
+#include "demime.h"
2729
 
+
2730
 
+uschar demime_reason_buffer[1024];
2731
 
+struct file_extension *file_extensions = NULL;
2732
 
+
2733
 
+int demime(uschar **listptr) {
2734
 
+  int sep = 0;
2735
 
+  uschar *list = *listptr;
2736
 
+  uschar *option;
2737
 
+  uschar option_buffer[64];
2738
 
+  unsigned long long mbox_size;
2739
 
+  FILE *mbox_file;
2740
 
+  uschar defer_error_buffer[1024];
2741
 
+  int demime_rc = 0;
2742
 
+  
2743
 
+  /* reset found_extension variable */
2744
 
+  found_extension = NULL;
2745
 
+  
2746
 
+  /* try to find 1st option */
2747
 
+  if ((option = string_nextinlist(&list, &sep,
2748
 
+                                  option_buffer,
2749
 
+                                  sizeof(option_buffer))) != NULL) {
2750
 
+    
2751
 
+    /* parse 1st option */
2752
 
+    if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) {
2753
 
+      /* explicitly no demimeing */
2754
 
+      return FAIL;
2755
 
+    };
2756
 
+  }
2757
 
+  else {
2758
 
+    /* no options -> no demimeing */
2759
 
+    return FAIL;
2760
 
+  };
2761
 
+  
2762
 
+  /* make sure the eml mbox file is spooled up */
2763
 
+  mbox_file = spool_mbox(&mbox_size);
2764
 
+  
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");
2769
 
+    return DEFER;  
2770
 
+  };
2771
 
+  
2772
 
+  /* call demimer if not already done earlier */
2773
 
+  if (!demime_ok)
2774
 
+    demime_rc = mime_demux(mbox_file, defer_error_buffer);
2775
 
+  
2776
 
+  fclose(mbox_file);
2777
 
+  
2778
 
+  if (demime_rc == DEFER) {
2779
 
+    /* temporary failure (DEFER => DEFER) */
2780
 
+    log_write(0, LOG_MAIN,
2781
 
+        "demime acl condition: %s", defer_error_buffer);
2782
 
+    return DEFER;
2783
 
+  };
2784
 
+  
2785
 
+  /* set demime_ok to avoid unpacking again */
2786
 
+  demime_ok = 1;
2787
 
+  
2788
 
+  /* check for file extensions, if there */
2789
 
+  while (option != NULL) {
2790
 
+    struct file_extension *this_extension = file_extensions;
2791
 
+    
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;
2796
 
+      return OK;
2797
 
+    };
2798
 
+
2799
 
+    /* loop thru extension list */
2800
 
+    while (this_extension != NULL) {   
2801
 
+      if (strcmpic(option, this_extension->file_extension_string) == 0) {
2802
 
+        /* found one */
2803
 
+        found_extension = this_extension->file_extension_string;
2804
 
+        return OK;
2805
 
+      };
2806
 
+      this_extension = this_extension->next;
2807
 
+    };
2808
 
+    
2809
 
+    /* grab next extension from option list */
2810
 
+    option = string_nextinlist(&list, &sep,
2811
 
+                               option_buffer,
2812
 
+                               sizeof(option_buffer));
2813
 
+  };
2814
 
+  
2815
 
+  /* nothing found */
2816
 
+  return FAIL;
2817
 
+}
2818
 
+
2819
 
+
2820
 
+/*************************************************
2821
 
+*   unpack TNEF in given directory               *
2822
 
+*************************************************/
2823
 
+
2824
 
+int mime_unpack_tnef(uschar *directory) {
2825
 
+  uschar filepath[1024];
2826
 
+  int n;
2827
 
+  struct dirent *entry;
2828
 
+  DIR *tempdir;
2829
 
+  
2830
 
+       /* open the dir */
2831
 
+       tempdir = opendir(CS directory);
2832
 
+       if (tempdir == NULL) {
2833
 
+         return -2;
2834
 
+       };
2835
 
+       
2836
 
+       /* loop thru dir */
2837
 
+       n = 0;
2838
 
+       do {
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);
2846
 
+    };
2847
 
+       } while (1);
2848
 
+       
2849
 
+       closedir(tempdir);
2850
 
+  return 0;
2851
 
+}
2852
 
+
2853
 
+
2854
 
+/*************************************************
2855
 
+* small hex_str -> integer conversion function   *
2856
 
+*************************************************/
2857
 
+
2858
 
+/* needed for quoted-printable
2859
 
+*/
2860
 
+
2861
 
+unsigned int mime_hstr_i(uschar *cptr) {
2862
 
+  unsigned int i, j = 0;
2863
 
+  
2864
 
+  while (cptr && *cptr && isxdigit(*cptr)) {
2865
 
+    i = *cptr++ - '0';
2866
 
+    if (9 < i) i -= 7;
2867
 
+    j <<= 4;
2868
 
+    j |= (i & 0x0f);
2869
 
+  }
2870
 
+  
2871
 
+  return(j);
2872
 
+}
2873
 
+
2874
 
+
2875
 
+/*************************************************
2876
 
+* decode quoted-printable chars                  *
2877
 
+*************************************************/
2878
 
+
2879
 
+/* gets called when we hit a =
2880
 
+   returns: new pointer position
2881
 
+   result code in c:
2882
 
+          -2 - decode error
2883
 
+          -1 - soft line break, no char
2884
 
+           0-255 - char to write
2885
 
+*/
2886
 
+
2887
 
+uschar *mime_decode_qp(uschar *qp_p,int *c) {
2888
 
+  uschar hex[] = {0,0,0};
2889
 
+  int nan = 0;
2890
 
+  uschar *initial_pos = qp_p;
2891
 
+  
2892
 
+  /* advance one char */
2893
 
+  qp_p++;
2894
 
+  
2895
 
+  REPEAT_FIRST:
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 */
2901
 
+    nan = 1;
2902
 
+    qp_p++;
2903
 
+    goto REPEAT_FIRST;
2904
 
+  }
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 */
2907
 
+    if (nan) {
2908
 
+      /* this is illegal */
2909
 
+      *c = -2;
2910
 
+      return initial_pos;
2911
 
+    }
2912
 
+    else {
2913
 
+      hex[0] = *qp_p;
2914
 
+      qp_p++;
2915
 
+    };
2916
 
+  }
2917
 
+  else if (*qp_p == '\n') {    
2918
 
+    /* hit soft line break already, continue */
2919
 
+    *c = -1;
2920
 
+    return qp_p;
2921
 
+  }
2922
 
+  else {
2923
 
+    /* illegal char here */
2924
 
+    *c = -2;
2925
 
+    return initial_pos;
2926
 
+  };
2927
 
+  
2928
 
+  if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
2929
 
+    if (hex[0] > 0) {
2930
 
+      hex[1] = *qp_p;
2931
 
+      /* do hex conversion */
2932
 
+      *c = mime_hstr_i(hex);
2933
 
+      qp_p++;
2934
 
+      return qp_p;
2935
 
+    }
2936
 
+    else {
2937
 
+      /* huh ? */
2938
 
+      *c = -2;
2939
 
+      return initial_pos;  
2940
 
+    };
2941
 
+  }
2942
 
+  else {
2943
 
+    /* illegal char */
2944
 
+    *c = -2;
2945
 
+    return initial_pos;  
2946
 
+  };
2947
 
+  
2948
 
+}
2949
 
+
2950
 
+
2951
 
+/*************************************************
2952
 
+* open new dump file                             *
2953
 
+*************************************************/
2954
 
+
2955
 
+/* open new dump file
2956
 
+   returns: -2 soft error
2957
 
+            or file #, FILE * in f
2958
 
+*/
2959
 
+
2960
 
+int mime_get_dump_file(uschar *extension, FILE **f, uschar *info) {
2961
 
+  uschar file_name[1024];
2962
 
+  int result;
2963
 
+  unsigned int file_nr;
2964
 
+  uschar default_extension[] = ".com";
2965
 
+  uschar *p;
2966
 
+  
2967
 
+  if (extension == NULL)
2968
 
+    extension = default_extension;
2969
 
+  
2970
 
+  /* scan the proposed extension.
2971
 
+     if it is longer than 4 chars, or
2972
 
+     contains exotic chars, use the default extension */
2973
 
+  
2974
 
+/*  if (Ustrlen(extension) > 4) {
2975
 
+    extension = default_extension;
2976
 
+  };
2977
 
+*/  
2978
 
+  
2979
 
+  p = extension+1;
2980
 
+  
2981
 
+  while (*p != 0) {
2982
 
+    *p = (uschar)tolower((uschar)*p);
2983
 
+    if ( (*p < 97) || (*p > 122) ) {
2984
 
+      extension = default_extension;
2985
 
+      break;  
2986
 
+    };
2987
 
+    p++;
2988
 
+  };
2989
 
+  
2990
 
+  /* find a new file to write to */
2991
 
+  file_nr = 0;
2992
 
+  do {
2993
 
+    struct stat mystat;
2994
 
+    
2995
 
+    snprintf(CS file_name,1024,"%s/scan/%s/%s-%05u%s",spool_directory,message_id,message_id,file_nr,extension);
2996
 
+    file_nr++;
2997
 
+    if (file_nr >= MIME_SANITY_MAX_DUMP_FILES) {
2998
 
+      /* max parts reached */
2999
 
+      mime_trigger_error(MIME_ERRORLEVEL_TOO_MANY_PARTS);
3000
 
+      break;
3001
 
+    };
3002
 
+    result = stat(CS file_name,&mystat);
3003
 
+  }
3004
 
+  while(result != -1);
3005
 
+  
3006
 
+  *f = fopen(CS file_name,"w+");
3007
 
+  if (*f == NULL) {
3008
 
+    /* cannot open new dump file, disk full ? -> soft error */
3009
 
+    snprintf(CS info, 1024,"unable to open dump file");
3010
 
+    return -2;
3011
 
+  };
3012
 
3013
 
+  return file_nr;
3014
 
+}
3015
 
+
3016
 
+
3017
 
+/*************************************************
3018
 
+* Find a string in a mime header                 *
3019
 
+*************************************************/
3020
 
+
3021
 
+/* Find a string in a mime header, and optionally fill in
3022
 
+   the value associated with it into *value
3023
 
3024
 
+   returns: 0 - nothing found
3025
 
+            1 - found param
3026
 
+            2 - found param + value
3027
 
+*/
3028
 
+
3029
 
+int mime_header_find(uschar *header, uschar *param, uschar **value) {
3030
 
+  uschar *needle;
3031
 
+  
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;
3039
 
+        
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)
3046
 
+            return 0;
3047
 
+          
3048
 
+          Ustrncpy(*value,value_start,(value_end - value_start));
3049
 
+          (*value)[(value_end - value_start)] = '\0';
3050
 
+          return 2;
3051
 
+        };
3052
 
+      };
3053
 
+    };
3054
 
+    return 1;
3055
 
+  };
3056
 
+  return 0;
3057
 
+}
3058
 
+
3059
 
+
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
3067
 
+
3068
 
+   In header mode, the line will be "cooked".
3069
 
+*/
3070
 
+
3071
 
+int mime_read_line(FILE *f, int mime_demux_mode, uschar *buffer, long *num_copied) {
3072
 
+  int c = EOF;
3073
 
+  int done = 0;
3074
 
+  int header_value_mode = 0;
3075
 
+  int header_open_brackets = 0;
3076
 
+  
3077
 
+  *num_copied = 0;
3078
 
+  
3079
 
+  while(!done) {
3080
 
+    
3081
 
+    c = fgetc(f);
3082
 
+    if (c == EOF) break;
3083
 
+   
3084
 
+    /* --------- header mode -------------- */
3085
 
+    if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) {
3086
 
+      
3087
 
+      /* always skip CRs */
3088
 
+      if (c == '\r') continue;
3089
 
+      
3090
 
+      if (c == '\n') {
3091
 
+        if ((*num_copied) > 0) {
3092
 
+          /* look if next char is '\t' or ' ' */
3093
 
+          c = fgetc(f);
3094
 
+          if (c == EOF) break;
3095
 
+          if ( (c == '\t') || (c == ' ') ) continue;
3096
 
+          ungetc(c,f);
3097
 
+        };
3098
 
+        /* end of the header, terminate with ';' */
3099
 
+        c = ';';
3100
 
+        done = 1;
3101
 
+      };
3102
 
+    
3103
 
+      /* skip control characters */
3104
 
+      if (c < 32) continue;
3105
 
+    
3106
 
+      /* skip whitespace + tabs */
3107
 
+      if ( (c == ' ') || (c == '\t') )
3108
 
+        continue;
3109
 
+
3110
 
+      if (header_value_mode) {
3111
 
+        /* --------- value mode ----------- */
3112
 
+        /* skip quotes */
3113
 
+        if (c == '"') continue;
3114
 
+        
3115
 
+        /* leave value mode on ';' */
3116
 
+        if (c == ';') {
3117
 
+          header_value_mode = 0;
3118
 
+        };
3119
 
+        /* -------------------------------- */
3120
 
+      }
3121
 
+      else {
3122
 
+        /* -------- non-value mode -------- */
3123
 
+        if (c == '\\') {
3124
 
+          /* quote next char. can be used
3125
 
+          to escape brackets. */
3126
 
+          c = fgetc(f);
3127
 
+          if (c == EOF) break;
3128
 
+        }
3129
 
+        else if (c == '(') {
3130
 
+          header_open_brackets++;
3131
 
+          continue;
3132
 
+        }
3133
 
+        else if ((c == ')') && header_open_brackets) {
3134
 
+          header_open_brackets--;
3135
 
+          continue;
3136
 
+        }
3137
 
+        else if ( (c == '=') && !header_open_brackets ) {
3138
 
+          /* enter value mode */
3139
 
+          header_value_mode = 1;          
3140
 
+        };
3141
 
+        
3142
 
+        /* skip chars while we are in a comment */
3143
 
+        if (header_open_brackets > 0)
3144
 
+          continue;
3145
 
+        /* -------------------------------- */
3146
 
+      };
3147
 
+    }
3148
 
+    /* ------------------------------------ */
3149
 
+    else {
3150
 
+    /* ----------- non-header mode -------- */
3151
 
+      /* break on '\n' */
3152
 
+      if (c == '\n')
3153
 
+        done = 1;
3154
 
+    /* ------------------------------------ */
3155
 
+    };
3156
 
+    
3157
 
+    /* copy the char to the buffer */
3158
 
+    buffer[*num_copied] = (uschar)c;
3159
 
+    /* raise counter */
3160
 
+    (*num_copied)++;
3161
 
+    
3162
 
+    /* break if buffer is full */
3163
 
+    if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1) {
3164
 
+      done = 1;
3165
 
+    };
3166
 
+  }
3167
 
+  
3168
 
+  /* 0-terminate */
3169
 
+  buffer[*num_copied] = '\0';
3170
 
+  
3171
 
+  if (*num_copied > MIME_SANITY_MAX_LINE_LENGTH-1)
3172
 
+    return MIME_READ_LINE_OVERFLOW;
3173
 
+  else
3174
 
+    if (c == EOF)
3175
 
+      return MIME_READ_LINE_EOF;
3176
 
+    else
3177
 
+      return MIME_READ_LINE_OK;
3178
 
+}
3179
 
+
3180
 
+
3181
 
+/*************************************************
3182
 
+* Check for a MIME boundary                      *
3183
 
+*************************************************/
3184
 
+
3185
 
+/* returns: 0 - no boundary found
3186
 
+            1 - start boundary found
3187
 
+            2 - end boundary found
3188
 
+*/
3189
 
+
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;
3194
 
+  
3195
 
+  /* check for '--' first */
3196
 
+  if (Ustrncmp(line,"--",2) == 0) {
3197
 
+    
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];
3202
 
+             j++;
3203
 
+      };
3204
 
+    };
3205
 
+    workbuf[j+1]='\0';
3206
 
+
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 */
3211
 
+          return 2;
3212
 
+        };      
3213
 
+        return 1;
3214
 
+      };
3215
 
+      thisboundary = thisboundary->next;
3216
 
+    };
3217
 
+  };
3218
 
+  
3219
 
+  return 0;  
3220
 
+}
3221
 
+
3222
 
+
3223
 
+/*************************************************
3224
 
+* Check for start of a UUENCODE block            *
3225
 
+*************************************************/
3226
 
+
3227
 
+/* returns 0 for no hit,
3228
 
+           >0 for hit
3229
 
+*/
3230
 
+
3231
 
+int mime_check_uu_start(uschar *line, uschar *uu_file_extension, int *has_tnef) {
3232
 
+  
3233
 
+  if ( (strncmpic(line,US"begin ",6) == 0)) {
3234
 
+    uschar *uu_filename = &line[6];
3235
 
+    
3236
 
+    /* skip perms, if present */
3237
 
+    Ustrtoul(&line[6],&uu_filename,10);
3238
 
+      
3239
 
+    /* advance one char */
3240
 
+    uu_filename++;
3241
 
+    
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) {
3246
 
+      *has_tnef = 1;  
3247
 
+    };
3248
 
+    
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,'.');
3253
 
3254
 
+    return sscanf(CS uu_filename, "%4[.0-9A-Za-z]",CS uu_file_extension);
3255
 
+  }
3256
 
+  else {
3257
 
+    /* nothing found */
3258
 
+    return 0;
3259
 
+  };
3260
 
+}
3261
 
+
3262
 
+
3263
 
+/*************************************************
3264
 
+* Decode a uu line                               *
3265
 
+*************************************************/
3266
 
+
3267
 
+/* returns number of decoded bytes
3268
 
+         -2 for soft errors
3269
 
+*/
3270
 
+
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) {
3274
 
+  uschar *p;
3275
 
+  long num_decoded = 0;
3276
 
+  uschar tmp_c;
3277
 
+  uschar *work;
3278
 
+  int uu_decoded_line_len, uu_encoded_line_len;
3279
 
+  
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);
3284
 
+    return -2;
3285
 
+  };
3286
 
+
3287
 
+  work = (uschar *)malloc(line_len);
3288
 
+  if (work == NULL) {
3289
 
+    snprintf(CS info, 1024,"unable to allocate %lu bytes",line_len);
3290
 
+    return -2;
3291
 
+  };
3292
 
+  
3293
 
+  memcpy(work,line,line_len);
3294
 
+  
3295
 
+  /* First char is line length
3296
 
+  This is microsofts way of getting it. Scary. */
3297
 
+  if (work[0] < 32) {
3298
 
+    /* ignore this line */
3299
 
+    return 0;
3300
 
+  }
3301
 
+  else {
3302
 
+    uu_decoded_line_len = uudec[work[0]];
3303
 
+  };
3304
 
+  
3305
 
+  p = &work[1];
3306
 
+
3307
 
+  while (*p > 32) {
3308
 
+    *p = uudec[*p];
3309
 
+    p++;
3310
 
+  };
3311
 
+
3312
 
+  uu_encoded_line_len = (p - &work[1]);
3313
 
+  p = &work[1];
3314
 
+          
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;
3320
 
+    };
3321
 
+    return -1;
3322
 
+  };
3323
 
+
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;
3329
 
+    };
3330
 
+    return -1;
3331
 
+  };
3332
 
+
3333
 
+  while ( ((p - &work[1]) < uu_encoded_line_len) && (num_decoded < uu_decoded_line_len)) {
3334
 
+           
3335
 
+    /* byte 0 ---------------------- */
3336
 
+    if ((p - &work[1] + 1) >= uu_encoded_line_len) {
3337
 
+      return 0;
3338
 
+    }
3339
 
+    
3340
 
+    (*data)[num_decoded] = *p;
3341
 
+    (*data)[num_decoded] <<= 2;
3342
 
+    
3343
 
+    tmp_c = *(p+1);
3344
 
+    tmp_c >>= 4;
3345
 
+    (*data)[num_decoded] |= tmp_c;
3346
 
+    
3347
 
+    num_decoded++;
3348
 
+    p++;
3349
 
+     
3350
 
+    /* byte 1 ---------------------- */
3351
 
+    if ((p - &work[1] + 1) >= uu_encoded_line_len) {
3352
 
+      return 0;
3353
 
+    }
3354
 
+    
3355
 
+    (*data)[num_decoded] = *p;
3356
 
+    (*data)[num_decoded] <<= 4;
3357
 
+    
3358
 
+    tmp_c = *(p+1);
3359
 
+    tmp_c >>= 2;
3360
 
+    (*data)[num_decoded] |= tmp_c;
3361
 
+    
3362
 
+    num_decoded++;
3363
 
+    p++;
3364
 
+   
3365
 
+    /* byte 2 ---------------------- */
3366
 
+    if ((p - &work[1] + 1) >= uu_encoded_line_len) {
3367
 
+      return 0;
3368
 
+    }
3369
 
+    
3370
 
+    (*data)[num_decoded] = *p;
3371
 
+    (*data)[num_decoded] <<= 6;
3372
 
+    
3373
 
+    (*data)[num_decoded] |= *(p+1);
3374
 
+    
3375
 
+    num_decoded++;
3376
 
+    p+=2;
3377
 
+   
3378
 
+  };
3379
 
+  
3380
 
+  return uu_decoded_line_len;
3381
 
+}
3382
 
+
3383
 
+
3384
 
+/*************************************************
3385
 
+* Decode a b64 or qp line                        *
3386
 
+*************************************************/
3387
 
+
3388
 
+/* returns number of decoded bytes
3389
 
+         -1 for hard errors
3390
 
+         -2 for soft errors
3391
 
+*/
3392
 
+
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) {
3398
 
+  uschar *p;
3399
 
+  long num_decoded = 0;
3400
 
+  int offset = 0;
3401
 
+  uschar tmp_c;
3402
 
+  
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);
3407
 
+    return -2;
3408
 
+  };
3409
 
+  
3410
 
+  if (mime_demux_mode == MIME_DEMUX_MODE_BASE64) {
3411
 
+    /* ---------------------------------------------- */
3412
 
+    
3413
 
+    /* NULL out trailing '\r' and '\n' chars */
3414
 
+    while (Ustrrchr(line,'\r') != NULL) {
3415
 
+      *(Ustrrchr(line,'\r')) = '\0';
3416
 
+    };
3417
 
+    while (Ustrrchr(line,'\n') != NULL) {
3418
 
+      *(Ustrrchr(line,'\n')) = '\0';
3419
 
+    };
3420
 
+    
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;
3426
 
+      };
3427
 
+    };
3428
 
+
3429
 
+    p = line;
3430
 
+    offset = 0;
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;
3437
 
+        };
3438
 
+        offset++;
3439
 
+      }
3440
 
+      else {
3441
 
+        *p = b64[*(p+offset)];
3442
 
+        p++;
3443
 
+      };
3444
 
+    };
3445
 
+    *p = 255;
3446
 
+   
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;
3452
 
+      };
3453
 
+    };
3454
 
+          
3455
 
+    /* line is translated, start bit shifting */
3456
 
+    p = line;
3457
 
+    num_decoded = 0;
3458
 
+          
3459
 
+    while(*p != 255) {
3460
 
+    
3461
 
+      /* byte 0 ---------------------- */
3462
 
+      if (*(p+1) == 255) {
3463
 
+        break;
3464
 
+      }
3465
 
+      
3466
 
+      (*data)[num_decoded] = *p;
3467
 
+      (*data)[num_decoded] <<= 2;
3468
 
+      
3469
 
+      tmp_c = *(p+1);
3470
 
+      tmp_c >>= 4;
3471
 
+      (*data)[num_decoded] |= tmp_c;
3472
 
+      
3473
 
+      num_decoded++;
3474
 
+      p++;
3475
 
+       
3476
 
+      /* byte 1 ---------------------- */
3477
 
+      if (*(p+1) == 255) {
3478
 
+        break;
3479
 
+      }
3480
 
+      
3481
 
+      (*data)[num_decoded] = *p;
3482
 
+      (*data)[num_decoded] <<= 4;
3483
 
+      
3484
 
+      tmp_c = *(p+1);
3485
 
+      tmp_c >>= 2;
3486
 
+      (*data)[num_decoded] |= tmp_c;
3487
 
+      
3488
 
+      num_decoded++;
3489
 
+      p++;
3490
 
+      
3491
 
+      /* byte 2 ---------------------- */
3492
 
+      if (*(p+1) == 255) {
3493
 
+        break;
3494
 
+      }
3495
 
+      
3496
 
+      (*data)[num_decoded] = *p;
3497
 
+      (*data)[num_decoded] <<= 6;
3498
 
+      
3499
 
+      (*data)[num_decoded] |= *(p+1);
3500
 
+      
3501
 
+      num_decoded++;
3502
 
+      p+=2;
3503
 
+      
3504
 
+    };
3505
 
+    return num_decoded;   
3506
 
+    /* ---------------------------------------------- */
3507
 
+  }
3508
 
+  else if (mime_demux_mode == MIME_DEMUX_MODE_QP) {
3509
 
+    /* ---------------------------------------------- */
3510
 
+    p = line;
3511
 
+         
3512
 
+    while (*p != 0) {
3513
 
+      if (*p == '=') {
3514
 
+        int decode_qp_result;
3515
 
+        
3516
 
+        p = mime_decode_qp(p,&decode_qp_result);
3517
 
+              
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;
3523
 
+          };
3524
 
+          (*data)[num_decoded] = '=';
3525
 
+          num_decoded++;
3526
 
+          p++;
3527
 
+        }
3528
 
+        else if (decode_qp_result == -1) {
3529
 
+          /* End of the line with soft line break. 
3530
 
+          Bail out. */
3531
 
+          goto QP_RETURN;
3532
 
+        }
3533
 
+        else if (decode_qp_result >= 0) {
3534
 
+          (*data)[num_decoded] = decode_qp_result;
3535
 
+          num_decoded++;
3536
 
+        };
3537
 
+      }
3538
 
+      else {
3539
 
+        (*data)[num_decoded] = *p;
3540
 
+        num_decoded++;
3541
 
+        p++;
3542
 
+      };
3543
 
+    };
3544
 
+    QP_RETURN:
3545
 
+    return num_decoded;
3546
 
+    /* ---------------------------------------------- */
3547
 
+  };
3548
 
+  
3549
 
+  return 0;
3550
 
+}
3551
 
+
3552
 
+
3553
 
+
3554
 
+/*************************************************
3555
 
+* Log demime errors and set mime error level     *
3556
 
+*************************************************/
3557
 
+
3558
 
+/* This sets the global demime_reason expansion
3559
 
+variable and the demime_errorlevel gauge. */
3560
 
+
3561
 
+void mime_trigger_error(int level, uschar *format, ...) {
3562
 
+  char *f;
3563
 
+  va_list ap;
3564
 
+
3565
 
+  if( (f = malloc(16384+23)) != NULL ) {
3566
 
+    /* first log the incident */
3567
 
+    sprintf(f,"demime acl condition: ");
3568
 
+    f+=22;
3569
 
+    va_start(ap, format);
3570
 
+    vsnprintf(f, 16383,(char *)format, ap);
3571
 
+    va_end(ap);
3572
 
+    f-=22;
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;
3580
 
+    };
3581
 
+    free(f);
3582
 
+  };
3583
 
+}
3584
 
+
3585
 
+/*************************************************
3586
 
+* Demultiplex MIME stream.                       *
3587
 
+*************************************************/
3588
 
+
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"
3592
 
+
3593
 
+ This function will report human parsable errors in
3594
 
+ *info.
3595
 
+
3596
 
+ returns DEFER -> soft error (see *info)
3597
 
+         OK    -> EOF hit, all ok
3598
 
+*/
3599
 
+
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;
3605
 
+  uschar *line;
3606
 
+  int mime_read_line_status = MIME_READ_LINE_OK;
3607
 
+  long line_len;
3608
 
+  struct boundary *boundaries = NULL;
3609
 
+  struct mime_part mime_part_p;
3610
 
+  int has_tnef = 0;
3611
 
+  int has_rfc822 = 0;
3612
 
+  
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);
3617
 
+    return DEFER;
3618
 
+  };
3619
 
+  
3620
 
+  /* clear MIME header structure */
3621
 
+  memset(&mime_part_p,0,sizeof(mime_part));
3622
 
+  
3623
 
+  /* ----------------------- start demux loop --------------------- */
3624
 
+  while (mime_read_line_status == MIME_READ_LINE_OK) {
3625
 
+  
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);
3629
 
+    
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;
3634
 
+      continue;
3635
 
+    }
3636
 
+    else if (mime_read_line_status == MIME_READ_LINE_EOF) {
3637
 
+      break;
3638
 
+    };
3639
 
+
3640
 
+    if (mime_demux_mode == MIME_DEMUX_MODE_MIME_HEADERS) {
3641
 
+      /* -------------- header mode --------------------- */
3642
 
+      
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) {
3647
 
+        int tmp;
3648
 
+        
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;
3653
 
+        }
3654
 
+        else {
3655
 
+          /* default to plain mode if no specific encoding type found */
3656
 
+          mime_demux_mode = MIME_DEMUX_MODE_PLAIN;
3657
 
+        };
3658
 
+        
3659
 
+        /* open new dump file */
3660
 
+        tmp = mime_get_dump_file(mime_part_p.extension, &mime_dump_file, info);
3661
 
+        if (tmp < 0) {
3662
 
+          return DEFER;
3663
 
+        };
3664
 
+
3665
 
+        /* clear out mime_part */
3666
 
+        memset(&mime_part_p,0,sizeof(mime_part));
3667
 
+      }
3668
 
+      else {
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;
3674
 
+          
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);
3678
 
+
3679
 
+          /* check for TNEF content type, remember to unpack TNEF later. */
3680
 
+          if (mime_header_find(line,US"application/ms-tnef",NULL) > 0)
3681
 
+            has_tnef = 1;
3682
 
+          
3683
 
+          /* check for message/rfcxxx attachments */
3684
 
+          if (mime_header_find(line,US"message/rfc822",NULL) > 0)
3685
 
+            has_rfc822 = 1;
3686
 
+          
3687
 
+          /* find the file extension, but do not fill it in
3688
 
+          it is already set, since content-disposition has
3689
 
+          precedence. */
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;
3700
 
+              }
3701
 
+              else {
3702
 
+                struct file_extension *this_extension =
3703
 
+                  (struct file_extension *)malloc(sizeof(file_extension));
3704
 
+                
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;
3711
 
+              };
3712
 
+            };
3713
 
+          };
3714
 
+        
3715
 
+          /* find a boundary and add it to the list, if present */
3716
 
+          value = line;
3717
 
+          if (mime_header_find(line,US"boundary",&value) == 2) {
3718
 
+            struct boundary *thisboundary;
3719
 
+
3720
 
+            if (Ustrlen(value) > MIME_SANITY_MAX_BOUNDARY_LENGTH) {
3721
 
+              mime_trigger_error(MIME_ERRORLEVEL_BOUNDARY_LENGTH); 
3722
 
+            }
3723
 
+            else {
3724
 
+              thisboundary = (struct boundary*)malloc(sizeof(boundary));
3725
 
+              thisboundary->next = boundaries;
3726
 
+              thisboundary->boundary_string = value;
3727
 
+              boundaries = thisboundary;
3728
 
+            };
3729
 
+          };
3730
 
+        
3731
 
+          if (mime_part_p.seen_content_type == 0) {
3732
 
+            mime_part_p.seen_content_type = 1;
3733
 
+          }
3734
 
+          else {
3735
 
+            mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
3736
 
+          };
3737
 
+          /* ---------------------------------------------------------------------------- */
3738
 
+        }
3739
 
+        else if (strncmpic(US"content-transfer-encoding:",line,Ustrlen("content-transfer-encoding:")) == 0) {
3740
 
+          /* ---------------------------- Content-Transfer-Encoding header -------------- */
3741
 
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;
3745
 
+            }
3746
 
+            else if (mime_header_find(line,US"quoted-printable",NULL) > 0) {
3747
 
+              mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_QP;
3748
 
+            }
3749
 
+            else {
3750
 
+              mime_part_p.seen_content_transfer_encoding = MIME_DEMUX_MODE_PLAIN;
3751
 
+            };
3752
 
+          }
3753
 
+          else {
3754
 
+            mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
3755
 
+          };
3756
 
+          /* ---------------------------------------------------------------------------- */
3757
 
+        }
3758
 
+        else if (strncmpic(US"content-disposition:",line,Ustrlen("content-disposition:")) == 0) {
3759
 
+          /* ---------------------------- Content-Disposition header -------------------- */
3760
 
+          uschar *value = line;
3761
 
+          
3762
 
+          if (mime_part_p.seen_content_disposition == 0) {
3763
 
+            mime_part_p.seen_content_disposition = 1;
3764
 
+          
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;
3774
 
+              }
3775
 
+              else {
3776
 
+                struct file_extension *this_extension =
3777
 
+                  (struct file_extension *)malloc(sizeof(file_extension));
3778
 
+                
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;
3785
 
+              };
3786
 
+            };
3787
 
+          }
3788
 
+          else {
3789
 
+            mime_trigger_error(MIME_ERRORLEVEL_DOUBLE_HEADERS);
3790
 
+          };
3791
 
+          /* ---------------------------------------------------------------------------- */
3792
 
+        };
3793
 
+      };    /* End of header checks */
3794
 
+      /* ------------------------------------------------ */
3795
 
+    }
3796
 
+    else {
3797
 
+      /* -------------- non-header mode ----------------- */
3798
 
+      int tmp;
3799
 
+
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);
3810
 
+          if (tmp < 0) {
3811
 
+            free(line);
3812
 
+            return DEFER;
3813
 
+          };
3814
 
+        };
3815
 
+      }
3816
 
+      else {
3817
 
+        uschar *data;
3818
 
+        long data_len = 0;
3819
 
+
3820
 
+        if (uu_mode == MIME_UU_MODE_UNCONFIRMED) {
3821
 
+         /* We are in unconfirmed UUENCODE mode. */
3822
 
+         
3823
 
+         data_len = uu_decode_line(line,&data,line_len,info);
3824
 
+         
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;
3829
 
+           };
3830
 
+           uu_mode = MIME_UU_MODE_OFF;
3831
 
+           return DEFER;
3832
 
+         }
3833
 
+         else if (data_len == -1) {
3834
 
+           if (uu_dump_file != NULL) {
3835
 
+            fclose(uu_dump_file); uu_dump_file = NULL;
3836
 
+           };
3837
 
+           uu_mode = MIME_UU_MODE_OFF;
3838
 
+           data_len = 0;
3839
 
+         }
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;
3844
 
+         };
3845
 
+        }
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;
3852
 
+            };
3853
 
+            uu_mode = MIME_UU_MODE_OFF;
3854
 
+          }
3855
 
+          else {
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;
3861
 
+               };
3862
 
+               uu_mode = MIME_UU_MODE_OFF;
3863
 
+               return DEFER;
3864
 
+             }
3865
 
+             else if (data_len == -1) {
3866
 
+               /* skip this line */
3867
 
+               data_len = 0;
3868
 
+             };
3869
 
+          };
3870
 
+        };
3871
 
+       
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) {
3875
 
+            /* short write */
3876
 
+            snprintf(CS info, 1024,"short write on uudecode dump file");
3877
 
+            free(line);
3878
 
+            return DEFER;            
3879
 
+          };
3880
 
+        };
3881
 
+      };
3882
 
+      
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
3886
 
+        file. */
3887
 
+
3888
 
+        /* Check for a known boundary. */
3889
 
+        tmp = mime_check_boundary(line,boundaries);
3890
 
+        if (tmp == 1) {
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 */
3896
 
+            if (has_rfc822) {
3897
 
+              has_rfc822 = 0;
3898
 
+              rewind(mime_dump_file);
3899
 
+              mime_demux(mime_dump_file,info);
3900
 
+            };
3901
 
+            
3902
 
+            fclose(mime_dump_file); mime_dump_file = NULL;
3903
 
+          };
3904
 
+        }
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 */
3911
 
+            if (has_rfc822) {
3912
 
+              has_rfc822 = 0;
3913
 
+              rewind(mime_dump_file);
3914
 
+              mime_demux(mime_dump_file,info);
3915
 
+            };
3916
 
+            
3917
 
+            fclose(mime_dump_file); mime_dump_file = NULL;
3918
 
+          };
3919
 
+        }
3920
 
+        else {
3921
 
+          uschar *data;
3922
 
+          long data_len = 0;
3923
 
+          
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 */
3927
 
+            data = line;
3928
 
+            data_len = line_len;
3929
 
+          }
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. */
3934
 
+              data_len = 0;
3935
 
+            };
3936
 
+          };
3937
 
+          
3938
 
+          /* write data to dump file */
3939
 
+          if (data_len > 0) {
3940
 
+            if (fwrite(data,1,data_len,mime_dump_file) < data_len) {
3941
 
+              /* short write */
3942
 
+              snprintf(CS info, 1024,"short write on dump file");
3943
 
+              free(line);
3944
 
+              return DEFER;            
3945
 
+            };
3946
 
+          };
3947
 
+          
3948
 
+        };
3949
 
+      }
3950
 
+      else {
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;
3958
 
+        };
3959
 
+        
3960
 
+      };
3961
 
+      /* ------------------------------------------------ */
3962
 
+    };
3963
 
+  };
3964
 
+  /* ----------------------- end demux loop ----------------------- */
3965
 
+  
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);
3971
 
+  
3972
 
+  /* release line buffer */
3973
 
+  free(line);
3974
 
+  
3975
 
+  /* FIXME: release boundary buffers.
3976
 
+  Not too much of a problem since
3977
 
+  this instance of exim is not resident. */
3978
 
+  
3979
 
+  if (has_tnef) {
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 */
3983
 
+    
3984
 
+    snprintf(CS file_name,1024,"%s/scan/%s",spool_directory,message_id);
3985
 
+    mime_unpack_tnef(file_name);
3986
 
+  };
3987
 
+
3988
 
+  return 0;
3989
 
+}
3990
 
+
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
3994
 
@@ -0,0 +1,146 @@
3995
 
+/*************************************************
3996
 
+*     Exim - an Internet mail transport agent    *
3997
 
+*************************************************/
3998
 
+
3999
 
+/* This file is part of the exiscan-acl content scanner
4000
 
+patch. It is NOT part of the standard exim distribution. */
4001
 
+
4002
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
4003
 
+/* License: GPL */
4004
 
+
4005
 
+/* demime defines */
4006
 
+
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
4012
 
+
4013
 
+#define MIME_UU_MODE_OFF             0
4014
 
+#define MIME_UU_MODE_UNCONFIRMED     1
4015
 
+#define MIME_UU_MODE_CONFIRMED       2
4016
 
+
4017
 
+#define MIME_MAX_EXTENSION 128
4018
 
+
4019
 
+#define MIME_READ_LINE_EOF 0
4020
 
+#define MIME_READ_LINE_OK 1
4021
 
+#define MIME_READ_LINE_OVERFLOW 2
4022
 
+
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
4029
 
+
4030
 
+
4031
 
+
4032
 
+/* MIME errorlevel settings */
4033
 
+
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"
4046
 
+
4047
 
+
4048
 
+/* demime structures */
4049
 
+
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;
4060
 
+} mime_part;
4061
 
+
4062
 
+typedef struct boundary {
4063
 
+  struct boundary *next;
4064
 
+  uschar *boundary_string;
4065
 
+} boundary;
4066
 
+
4067
 
+typedef struct file_extension {
4068
 
+  struct file_extension *next;
4069
 
+  uschar *file_extension_string;
4070
 
+} file_extension;
4071
 
+
4072
 
+/* available functions for the TNEF library (tnef.c & tnef.h) */
4073
 
+
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 );
4080
 
+
4081
 
+
4082
 
+
4083
 
+/* demime.c prototypes */
4084
 
+
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 *);
4097
 
+
4098
 
+
4099
 
+
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 
4118
 
+};
4119
 
+
4120
 
+
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 
4139
 
+};
4140
 
+
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);
4149
 
+#ifdef BRIGHTMAIL
4150
 
+      printf("Contains Brightmail AntiSpam support via the exiscan-acl patch.\n");
4151
 
+#endif      
4152
 
       }
4153
 
 
4154
 
     else badarg = TRUE;
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 },
4162
 
+#ifdef BRIGHTMAIL
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 },
4167
 
+#endif
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 },
4171
 
@@ -301,6 +307,8 @@
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 },
4180
 
@@ -309,6 +317,7 @@
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 },
4188
 
@@ -330,6 +339,7 @@
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] },
4219
 
@@ -366,6 +392,7 @@
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,   &regex_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
4241
 
@@ -66,6 +66,7 @@
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 *);
4249
 
@@ -119,6 +120,7 @@
4250
 
 
4251
 
 extern void    log_close_all(void);
4252
 
 
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 *,
4268
 
                  BOOL, uschar *);
4269
 
@@ -175,6 +182,7 @@
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);
4277
 
@@ -234,6 +242,8 @@
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 *);
4286
 
@@ -285,6 +295,8 @@
4287
 
 extern tree_node *tree_search(tree_node *, uschar *);
4288
 
 extern void    tree_write(tree_node *, FILE *);
4289
 
 
4290
 
+extern void    unspool_mbox(void);
4291
 
+
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
4298
 
@@ -161,6 +161,7 @@
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;
4306
 
@@ -181,6 +182,7 @@
4307
 
                                    US"EHLO or HELO",
4308
 
                                    US"MAIL",
4309
 
                                    US"MAILAUTH",
4310
 
+                                   US"MIME",
4311
 
                                    US"RCPT",
4312
 
                                    US"STARTTLS",
4313
 
                                    US"VRFY",
4314
 
@@ -194,6 +196,7 @@
4315
 
                                    550,     /* HELO/EHLO */
4316
 
                                    550,     /* MAIL */
4317
 
                                    0,       /* MAILAUTH; not relevant */
4318
 
+                                   550,     /* MIME */
4319
 
                                    550,     /* RCPT */
4320
 
                                    550,     /* STARTTLS */
4321
 
                                    252,     /* VRFY */
4322
 
@@ -296,6 +299,7 @@
4323
 
 uschar *auth_defer_msg         = US"reason not recorded";
4324
 
 uschar *auth_defer_user_msg    = US"";
4325
 
 int     auto_thaw              = 0;
4326
 
+uschar *av_scanner             = US"sophie:/var/run/sophie";
4327
 
 
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;
4334
 
+#ifdef BRIGHTMAIL
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;
4340
 
+int     bmi_run                = 0;
4341
 
+uschar *bmi_verdicts           = NULL;
4342
 
+#endif
4343
 
 int     body_linecount         = 0;
4344
 
 uschar *bounce_message_file    = NULL;
4345
 
 uschar *bounce_message_text    = NULL;
4346
 
@@ -412,6 +425,9 @@
4347
 
 BOOL    deliver_selectstring_regex = FALSE;
4348
 
 uschar *deliver_selectstring_sender = NULL;
4349
 
 BOOL    deliver_selectstring_sender_regex = FALSE;
4350
 
+int     demime_errorlevel      = 0;
4351
 
+int     demime_ok              = 0;
4352
 
+uschar *demime_reason          = NULL;
4353
 
 BOOL    disable_logging        = FALSE;
4354
 
 
4355
 
 uschar *dns_again_means_nonexist = NULL;
4356
 
@@ -441,6 +457,7 @@
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;
4367
 
 
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"";
4379
 
@@ -609,6 +628,7 @@
4380
 
 
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;
4407
 
 
4408
 
 uid_t  *never_users            = NULL;
4409
 
+BOOL    no_mbox_unspool        = FALSE;
4410
 
 
4411
 
 uid_t   original_euid;
4412
 
 gid_t   originator_gid;
4413
 
@@ -729,6 +766,7 @@
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;
4421
 
@@ -753,6 +791,9 @@
4422
 
     NULL,                      /* driver name */
4423
 
 
4424
 
     NULL,                      /* address_data */
4425
 
+#ifdef BRIGHTMAIL
4426
 
+    NULL,                      /* bmi_rule */
4427
 
+#endif
4428
 
     NULL,                      /* cannot_route_message */
4429
 
     NULL,                      /* condition */
4430
 
     NULL,                      /* current_directory */
4431
 
@@ -781,6 +822,11 @@
4432
 
     NULL,                      /* transport_name */
4433
 
 
4434
 
     TRUE,                      /* address_test */
4435
 
+#ifdef BRIGHTMAIL
4436
 
+    FALSE,                     /* bmi_deliver_alternate */
4437
 
+    FALSE,                     /* bmi_deliver_default */
4438
 
+    FALSE,                     /* bmi_dont_deliver */
4439
 
+#endif
4440
 
     TRUE,                      /* expn */
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
4458
 
@@ -103,6 +103,7 @@
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 */
4471
 
 
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) */
4477
 
+#ifdef BRIGHTMAIL
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 */
4485
 
+#endif
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 */
4489
 
@@ -220,6 +231,9 @@
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 */
4497
 
 
4498
 
 extern uschar *dns_again_means_nonexist; /* Domains that are badly set up */
4499
 
@@ -249,6 +263,7 @@
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 */
4507
 
@@ -257,6 +272,7 @@
4508
 
 extern BOOL    extract_addresses_remove_arguments; /* Controls -t behaviour */
4509
 
 extern uschar *extra_local_interfaces; /* Local, non-listen interfaces */
4510
 
 
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 */
4515
 
@@ -264,6 +280,7 @@
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 */
4522
 
 
4523
 
@@ -342,6 +359,7 @@
4524
 
 
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;
4551
 
 
4552
 
 extern uid_t  *never_users;            /* List of uids never to be used */
4553
 
+extern BOOL    no_mbox_unspool;        /* don't unspool exiscan files */
4554
 
 
4555
 
 extern optionlist optionlist_auths[];      /* These option lists are made */
4556
 
 extern int     optionlist_auths_size;      /* global so that readconf can */
4557
 
@@ -446,6 +481,7 @@
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
4580
 
@@ -16,7 +16,6 @@
4581
 
 #include "mytypes.h"
4582
 
 #include "store.h"
4583
 
 
4584
 
-
4585
 
 /* The function and its return codes. */
4586
 
 
4587
 
 extern int local_scan(int, uschar **);
4588
 
@@ -107,6 +106,9 @@
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 */
4592
 
+#ifdef BRIGHTMAIL
4593
 
+  uschar *bmi_optin;
4594
 
+#endif
4595
 
 } recipient_item;
4596
 
 
4597
 
 
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
4601
 
@@ -710,7 +710,7 @@
4602
 
 
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 };
4608
 
 
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
4613
 
@@ -0,0 +1,1200 @@
4614
 
+/*************************************************
4615
 
+*     Exim - an Internet mail transport agent    *
4616
 
+*************************************************/
4617
 
+
4618
 
+/* This file is part of the exiscan-acl content scanner
4619
 
+patch. It is NOT part of the standard exim distribution. */
4620
 
+
4621
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
4622
 
+/* License: GPL */
4623
 
+
4624
 
+/* Code for calling virus (malware) scanners. Called from acl.c. */
4625
 
+
4626
 
+#include "exim.h"
4627
 
+
4628
 
+/* declaration of private routines */
4629
 
+int mksd_scan_packed(int sock);
4630
 
+int mksd_scan_unpacked(int sock, int maxproc);
4631
 
+
4632
 
+/* SHUT_WR seems to be undefined on Unixware ? */
4633
 
+#ifndef SHUT_WR
4634
 
+#define SHUT_WR 1
4635
 
+#endif
4636
 
+
4637
 
+#define DRWEBD_SCAN_CMD        0x0001
4638
 
+#define DRWEBD_RETURN_VIRUSES  0x0001
4639
 
+
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);
4650
 
+}
4651
 
+
4652
 
+uschar malware_name_buffer[256];
4653
 
+int malware_ok = 0;
4654
 
+
4655
 
+int malware(uschar **listptr) {
4656
 
+  int sep = 0;
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;
4665
 
+  FILE *mbox_file;
4666
 
+  int roffset;
4667
 
+  const pcre *re;
4668
 
+  const uschar *rerror;
4669
 
+  
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");
4676
 
+    return DEFER;  
4677
 
+  };
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);
4681
 
+  
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) {
4686
 
+    
4687
 
+    /* parse 1st option */
4688
 
+    if ( (strcmpic(malware_regex,US"false") == 0) || 
4689
 
+         (Ustrcmp(malware_regex,"0") == 0) ) {
4690
 
+      /* explicitly no matching */
4691
 
+      return FAIL;
4692
 
+    };
4693
 
+    
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;
4699
 
+    };
4700
 
+  }
4701
 
+  else {
4702
 
+    /* empty means "don't match anything" */
4703
 
+    return FAIL;
4704
 
+  };
4705
 
+
4706
 
+  /* compile the regex, see if it works */
4707
 
+  re = pcre_compile(CS malware_regex, PCRE_COPT, (const char **)&rerror, &roffset, NULL);
4708
 
+  if (re == 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);
4711
 
+    return DEFER;
4712
 
+  };
4713
 
+
4714
 
+  /* Do not scan twice. */
4715
 
+  if (malware_ok == 0) {
4716
 
+
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");
4724
 
+      return DEFER;
4725
 
+    };
4726
 
+    
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;
4746
 
+               pcre *drweb_re;
4747
 
+    
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;
4752
 
+               };
4753
 
+
4754
 
+               if (*drweb_options != '/') {
4755
 
+    
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);
4760
 
+                               return DEFER;
4761
 
+                       }
4762
 
+    
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);
4767
 
+                               return DEFER;
4768
 
+                       }
4769
 
+    
4770
 
+                       in = *(struct in_addr *) he->h_addr_list[0];
4771
 
+    
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)",
4776
 
+                                       strerror(errno));
4777
 
+                               return DEFER;
4778
 
+                       }
4779
 
+    
4780
 
+                       if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
4781
 
+                               close(sock); 
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));
4785
 
+                               return DEFER;
4786
 
+                       }
4787
 
+
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);
4793
 
+
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));
4800
 
+                               return DEFER; 
4801
 
+                       }
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));
4807
 
+                               return DEFER; 
4808
 
+                       }
4809
 
+                       drweb_slen = htonl(fsize);
4810
 
+                       lseek(drweb_fd, 0, SEEK_SET);
4811
 
+
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)) {
4817
 
+                               close(sock); 
4818
 
+                               close(drweb_fd);
4819
 
+                               log_write(0, LOG_MAIN|LOG_PANIC,
4820
 
+                                       "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options);
4821
 
+                               return DEFER;
4822
 
+                       }
4823
 
+
4824
 
+                       drweb_fbuf = (uschar *) malloc (fsize);
4825
 
+                       if (!drweb_fbuf) {
4826
 
+                               close(sock);
4827
 
+                               close(drweb_fd);
4828
 
+                               log_write(0, LOG_MAIN|LOG_PANIC,
4829
 
+                                       "malware acl condition: drweb: unable to allocate memory %u for file (%s)", 
4830
 
+                                       fsize, scanrequest);
4831
 
+                               return DEFER;
4832
 
+                       }
4833
 
+
4834
 
+                       result = read (drweb_fd, drweb_fbuf, fsize);
4835
 
+                       if (result == -1) {
4836
 
+                               close(sock);
4837
 
+                               close(drweb_fd);
4838
 
+                               log_write(0, LOG_MAIN|LOG_PANIC,
4839
 
+                                       "malware acl condition: drweb: can't read spool file %s: %s",
4840
 
+                                       scanrequest, strerror(errno));
4841
 
+                               return DEFER; 
4842
 
+                       }
4843
 
+                       
4844
 
+                       /* send file body to socket */
4845
 
+                       if (send(sock, drweb_fbuf, fsize, 0) < 0) {
4846
 
+                               close(sock);
4847
 
+                               log_write(0, LOG_MAIN|LOG_PANIC,
4848
 
+                                       "malware acl condition: drweb: unable to send file body to socket (%s)", drweb_options);
4849
 
+                               return DEFER;
4850
 
+                       }
4851
 
+                       close(drweb_fd);
4852
 
+                       free(drweb_fbuf);
4853
 
+               }
4854
 
+               else {
4855
 
+                       /* open the drwebd UNIX socket */
4856
 
+                       sock = socket(AF_UNIX, SOCK_STREAM, 0);
4857
 
+                       if (sock < 0) {
4858
 
+                               log_write(0, LOG_MAIN|LOG_PANIC,
4859
 
+                                       "malware acl condition: drweb: can't open UNIX socket");
4860
 
+                               return DEFER; 
4861
 
+                       }
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) {
4865
 
+                               close(sock);
4866
 
+                               log_write(0, LOG_MAIN|LOG_PANIC,
4867
 
+                                       "malware acl condition: drweb: unable to connect to socket (%s). errno=%d", drweb_options, errno);
4868
 
+                               return DEFER;
4869
 
+                       }
4870
 
+      
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));
4876
 
+
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)) {
4883
 
+                               close(sock);
4884
 
+                               log_write(0, LOG_MAIN|LOG_PANIC,
4885
 
+                                       "malware acl condition: drweb: unable to send commands to socket (%s)", drweb_options);
4886
 
+                               return DEFER;
4887
 
+                       }
4888
 
+               }
4889
 
+
4890
 
+               /* wait for result */
4891
 
+               if ((bread = recv(sock, &drweb_rc, sizeof(drweb_rc), 0) != sizeof(drweb_rc))) {
4892
 
+                       close(sock);
4893
 
+                       log_write(0, LOG_MAIN|LOG_PANIC,
4894
 
+                               "malware acl condition: drweb: unable to read return code");
4895
 
+                       return DEFER;
4896
 
+               }
4897
 
+               drweb_rc = ntohl(drweb_rc);
4898
 
+    
4899
 
+               if ((bread = recv(sock, &drweb_vnum, sizeof(drweb_vnum), 0) != sizeof(drweb_vnum))) {
4900
 
+                       close(sock);
4901
 
+                       log_write(0, LOG_MAIN|LOG_PANIC,
4902
 
+                               "malware acl condition: drweb: unable to read the number of viruses");
4903
 
+                       return DEFER;
4904
 
+               }
4905
 
+               drweb_vnum = ntohl(drweb_vnum);
4906
 
+               
4907
 
+               /* "virus(es) found" if virus number is > 0 */
4908
 
+               if (drweb_vnum)
4909
 
+               {
4910
 
+                       int i;
4911
 
+                       uschar pre_malware_nb[256];
4912
 
+                       
4913
 
+                       malware_name = malware_name_buffer;
4914
 
+                       
4915
 
+                       /* setup default virus name */
4916
 
+                       Ustrcpy(malware_name_buffer,"unknown");
4917
 
+                       
4918
 
+                       /* read and concatenate virus names into one string */
4919
 
+                       for (i=0;i<drweb_vnum;i++)
4920
 
+                       {
4921
 
+                               /* read the size of report */
4922
 
+                               if ((bread = recv(sock, &drweb_slen, sizeof(drweb_slen), 0) != sizeof(drweb_slen))) {
4923
 
+                                       close(sock);
4924
 
+                                       log_write(0, LOG_MAIN|LOG_PANIC,
4925
 
+                                               "malware acl condition: drweb: cannot read report size");
4926
 
+                                       return DEFER;
4927
 
+                               };
4928
 
+                               drweb_slen = ntohl(drweb_slen);
4929
 
+                       
4930
 
+                               /* read report body */
4931
 
+                               if ((bread = recv(sock, tmpbuf, drweb_slen, 0)) != drweb_slen) {
4932
 
+                                       close(sock);
4933
 
+                                       log_write(0, LOG_MAIN|LOG_PANIC,
4934
 
+                                               "malware acl condition: drweb: cannot read report string");
4935
 
+                                       return DEFER;
4936
 
+                               };
4937
 
+                               tmpbuf[drweb_slen] = '\0';
4938
 
+
4939
 
+                               /* set up match regex, depends on retcode */
4940
 
+                               Ustrcpy(drweb_match_string, "infected\\swith\\s*(.+?)$");
4941
 
+
4942
 
+                               drweb_re = pcre_compile( CS drweb_match_string,
4943
 
+                                       PCRE_COPT,
4944
 
+                                       (const char **)&rerror,
4945
 
+                                       &roffset,
4946
 
+                                       NULL );
4947
 
+            
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);
4952
 
+                               }
4953
 
+                               /* the first name we just copy to malware_name */
4954
 
+                               if (i==0)
4955
 
+                                       Ustrcpy(CS malware_name_buffer, CS pre_malware_nb);
4956
 
+                               else {
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);
4962
 
+                                       }
4963
 
+                               }
4964
 
+                       }
4965
 
+               }
4966
 
+               else {
4967
 
+                       /* no virus found */
4968
 
+                       malware_name = NULL;
4969
 
+               };
4970
 
+               close(sock);
4971
 
+       }
4972
 
+       /* ----------------------------------------------------------------------- */
4973
 
+    
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;
4980
 
+      int sock;
4981
 
+      time_t t;
4982
 
+      uschar tmpbuf[1024];
4983
 
+      uschar scanrequest[1024];
4984
 
+      uschar kav_match_string[128];
4985
 
+      int kav_rc;
4986
 
+      unsigned long kav_reportlen, bread;
4987
 
+      pcre *kav_re;
4988
 
+    
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;
4994
 
+      };
4995
 
+    
4996
 
+      /* open the kavdaemon socket */
4997
 
+      sock = socket(AF_UNIX, SOCK_STREAM, 0);
4998
 
+      if (sock < 0) {
4999
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5000
 
+             "malware acl condition: can't open UNIX socket.");
5001
 
+        return DEFER; 
5002
 
+      }
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) {
5006
 
+        close(sock);
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);
5009
 
+        return DEFER;
5010
 
+      }
5011
 
+      
5012
 
+      /* get current date and time, build scan request */
5013
 
+      time(&t);
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);
5016
 
+      
5017
 
+      /* send scan request */
5018
 
+      if (send(sock, scanrequest, Ustrlen(scanrequest)+1, 0) < 0) {
5019
 
+        close(sock);
5020
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5021
 
+             "malware acl condition: unable to write to kavdaemon UNIX socket (%s)", kav_options);
5022
 
+        return DEFER;
5023
 
+      }
5024
 
+      
5025
 
+      /* wait for result */
5026
 
+      if ((bread = recv(sock, tmpbuf, 2, 0) != 2)) {
5027
 
+        close(sock);
5028
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5029
 
+             "malware acl condition: unable to read 2 bytes from kavdaemon socket.");
5030
 
+        return DEFER;
5031
 
+      }
5032
 
+    
5033
 
+      /* get errorcode from one nibble */
5034
 
+      if (test_byte_order() == LITTLE_MY_ENDIAN) {
5035
 
+        kav_rc = tmpbuf[0] & 0x0F;
5036
 
+      }
5037
 
+      else {
5038
 
+        kav_rc = tmpbuf[1] & 0x0F;
5039
 
+      };
5040
 
+    
5041
 
+      /* improper kavdaemon configuration */
5042
 
+      if ( (kav_rc == 5) || (kav_rc == 6) ) {
5043
 
+        close(sock);
5044
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5045
 
+             "malware acl condition: please reconfigure kavdaemon to NOT disinfect or remove infected files.");
5046
 
+        return DEFER;
5047
 
+      };
5048
 
+      
5049
 
+      if (kav_rc == 1) {
5050
 
+        close(sock);
5051
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5052
 
+             "malware acl condition: kavdaemon reported 'scanning not completed' (code 1).");
5053
 
+        return DEFER;
5054
 
+      };
5055
 
+    
5056
 
+      if (kav_rc == 7) {
5057
 
+        close(sock);
5058
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5059
 
+             "malware acl condition: kavdaemon reported 'kavdaemon damaged' (code 7).");
5060
 
+        return DEFER;
5061
 
+      };
5062
 
+    
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 */
5065
 
+    
5066
 
+      /* "virus found" return codes (2-4) */
5067
 
+      if ((kav_rc > 1) && (kav_rc < 5)) {
5068
 
+        int report_flag = 0;
5069
 
+        
5070
 
+        /* setup default virus name */
5071
 
+        Ustrcpy(malware_name_buffer,"unknown");
5072
 
+        malware_name = malware_name_buffer;
5073
 
+      
5074
 
+        if (test_byte_order() == LITTLE_MY_ENDIAN) {
5075
 
+          report_flag = tmpbuf[1];
5076
 
+        }
5077
 
+        else {
5078
 
+          report_flag = tmpbuf[0];
5079
 
+        };
5080
 
+      
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) {
5085
 
+            close(sock);
5086
 
+            log_write(0, LOG_MAIN|LOG_PANIC,
5087
 
+                  "malware acl condition: cannot read report size from kavdaemon");
5088
 
+            return DEFER;
5089
 
+          };
5090
 
+  
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 */
5095
 
+            if( kav_rc == 3 )
5096
 
+              Ustrcpy(kav_match_string, "suspicion:\\s*(.+?)\\s*$");
5097
 
+            else
5098
 
+              Ustrcpy(kav_match_string, "infected:\\s*(.+?)\\s*$");
5099
 
+  
5100
 
+            kav_re = pcre_compile( CS kav_match_string,
5101
 
+                                   PCRE_COPT,
5102
 
+                                   (const char **)&rerror,
5103
 
+                                   &roffset,
5104
 
+                                   NULL );
5105
 
+            
5106
 
+            /* read report, linewise */  
5107
 
+            while (kav_reportlen > 0) {
5108
 
+              int result = 0;
5109
 
+              int ovector[30];
5110
 
+              
5111
 
+              bread = 0;
5112
 
+              while ( recv(sock, &tmpbuf[bread], 1, 0) == 1 ) {
5113
 
+                kav_reportlen--;
5114
 
+                if ( (tmpbuf[bread] == '\n') || (bread > 1021) ) break;
5115
 
+                bread++;
5116
 
+              };
5117
 
+              bread++;
5118
 
+              tmpbuf[bread] = '\0';
5119
 
+              
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);
5124
 
+                break;
5125
 
+              };
5126
 
+            };
5127
 
+          };
5128
 
+        };
5129
 
+      }
5130
 
+      else {
5131
 
+        /* no virus found */
5132
 
+        malware_name = NULL;
5133
 
+      };
5134
 
+    
5135
 
+      close(sock);
5136
 
+    }
5137
 
+    /* ----------------------------------------------------------------------- */
5138
 
+    
5139
 
+    
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];
5157
 
+      int trigger = 0;
5158
 
+      int result;
5159
 
+      int ovector[30];
5160
 
+      
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.");
5168
 
+        return DEFER; 
5169
 
+      };
5170
 
+    
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.");
5178
 
+        return DEFER; 
5179
 
+      };
5180
 
+    
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);
5186
 
+        return DEFER;
5187
 
+      };
5188
 
+    
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.");
5196
 
+        return DEFER; 
5197
 
+      };
5198
 
+    
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);
5204
 
+        return DEFER;
5205
 
+      };
5206
 
+    
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");
5212
 
+      
5213
 
+      /* store exims signal handlers */
5214
 
+      eximsigchld = signal(SIGCHLD,SIG_DFL);
5215
 
+      eximsigpipe = signal(SIGPIPE,SIG_DFL);
5216
 
+      
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);
5223
 
+        return DEFER;
5224
 
+      };
5225
 
+      
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");
5228
 
+      
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);
5235
 
+        return DEFER;
5236
 
+      };
5237
 
+      
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) ) {
5241
 
+          /* short write */
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);
5247
 
+          return DEFER;
5248
 
+        };
5249
 
+        /* try trigger match */
5250
 
+        if (!trigger && regex_match_and_setup(cmdline_trigger_re, linebuffer, 0, -1))
5251
 
+          trigger = 1;
5252
 
+      };
5253
 
+      
5254
 
+      fclose(scanner_record);
5255
 
+      pclose(scanner_out);
5256
 
+      signal(SIGCHLD,eximsigchld);
5257
 
+      signal(SIGPIPE,eximsigpipe);
5258
 
+      
5259
 
+      if (trigger) {
5260
 
+        /* setup default virus name */
5261
 
+        Ustrcpy(malware_name_buffer,"unknown");
5262
 
+        malware_name = malware_name_buffer;
5263
 
+        
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) {
5267
 
+          /* try match */
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);
5271
 
+          };
5272
 
+        };
5273
 
+        fclose(scanner_record);
5274
 
+      }
5275
 
+      else {
5276
 
+        /* no virus found */
5277
 
+        malware_name = NULL;
5278
 
+      };
5279
 
+    }
5280
 
+    /* ----------------------------------------------------------------------- */
5281
 
+    
5282
 
+    
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";
5288
 
+      int bread = 0;
5289
 
+      struct sockaddr_un server;
5290
 
+      int sock;
5291
 
+      uschar file_name[1024];
5292
 
+      uschar av_buffer[1024];
5293
 
+      
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;
5299
 
+      };
5300
 
+    
5301
 
+      /* open the sophie socket */
5302
 
+      sock = socket(AF_UNIX, SOCK_STREAM, 0);
5303
 
+      if (sock < 0) {
5304
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5305
 
+             "malware acl condition: can't open UNIX socket.");
5306
 
+        return DEFER; 
5307
 
+      }
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) {
5311
 
+        close(sock);
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);
5314
 
+        return DEFER;
5315
 
+      }
5316
 
+      
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) {
5320
 
+        close(sock);
5321
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5322
 
+             "malware acl condition: unable to write to sophie UNIX socket (%s)", sophie_options);
5323
 
+        return DEFER; 
5324
 
+      };
5325
 
+      
5326
 
+      write(sock, "\n", 1);
5327
 
+      
5328
 
+      /* wait for result */
5329
 
+      memset(av_buffer, 0, sizeof(av_buffer));
5330
 
+      if ((!(bread = read(sock, av_buffer, sizeof(av_buffer))) > 0)) {
5331
 
+        close(sock);
5332
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5333
 
+             "malware acl condition: unable to read from sophie UNIX socket (%s)", sophie_options);
5334
 
+        return DEFER;
5335
 
+      };
5336
 
+    
5337
 
+      close(sock);
5338
 
+    
5339
 
+      /* infected ? */
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;
5344
 
+      }
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");
5348
 
+        return DEFER;
5349
 
+      }
5350
 
+      else {
5351
 
+        /* all ok, no virus */
5352
 
+        malware_name = NULL;
5353
 
+      };
5354
 
+    }
5355
 
+    /* ----------------------------------------------------------------------- */
5356
 
+    
5357
 
+
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";
5364
 
+      uschar *p,*vname;
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;
5372
 
+
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;
5378
 
+      }
5379
 
+    
5380
 
+      /* socket does not start with '/' -> network socket */
5381
 
+      if (*clamd_options != '/') {
5382
 
+    
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);
5387
 
+          return DEFER;
5388
 
+        };
5389
 
+    
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);
5394
 
+          return DEFER;
5395
 
+        }
5396
 
+    
5397
 
+        in = *(struct in_addr *) he->h_addr_list[0];
5398
 
+    
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)",
5403
 
+                    strerror(errno));
5404
 
+          return DEFER;
5405
 
+        }
5406
 
+    
5407
 
+        if (ip_connect(sock, AF_INET, (uschar*)inet_ntoa(in), port, 5) < 0) {
5408
 
+          close(sock); 
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));
5412
 
+          return DEFER;
5413
 
+        }
5414
 
+      }
5415
 
+      else {
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)",
5420
 
+                    strerror(errno));
5421
 
+          return DEFER;
5422
 
+        }
5423
 
+    
5424
 
+        server.sun_family = AF_UNIX;
5425
 
+        Ustrcpy(server.sun_path, clamd_options);
5426
 
+    
5427
 
+        if (connect(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un)) < 0) {
5428
 
+          close(sock);
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) );
5432
 
+          return DEFER;
5433
 
+        }
5434
 
+      }
5435
 
+    
5436
 
+      /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
5437
 
+    
5438
 
+      snprintf(CS file_name,1024,"SCAN %s/scan/%s\n", spool_directory, message_id);
5439
 
+    
5440
 
+      if (send(sock, file_name, Ustrlen(file_name), 0) < 0) {
5441
 
+        close(sock);
5442
 
+        log_write(0, LOG_MAIN|LOG_PANIC,"malware acl condition: clamd: unable to write to socket (%s)",
5443
 
+                  strerror(errno));
5444
 
+        return DEFER;
5445
 
+      }
5446
 
+    
5447
 
+      /* 
5448
 
+        We're done sending, close socket for writing.
5449
 
+        
5450
 
+        One user reported that clamd 0.70 does not like this any more ...
5451
 
+        
5452
 
+      */
5453
 
+      
5454
 
+      /* shutdown(sock, SHUT_WR); */
5455
 
+    
5456
 
+      /* Read the result */
5457
 
+      memset(av_buffer, 0, sizeof(av_buffer));
5458
 
+      bread = read(sock, av_buffer, sizeof(av_buffer));
5459
 
+      close(sock);
5460
 
+
5461
 
+      if (!(bread  > 0)) {
5462
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5463
 
+                  "malware acl condition: clamd: unable to read from socket (%s)",
5464
 
+                  strerror(errno));
5465
 
+        return DEFER;
5466
 
+      }
5467
 
+    
5468
 
+      if (bread == sizeof(av_buffer)) {
5469
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5470
 
+                  "malware acl condition: clamd: buffer too small");
5471
 
+        return DEFER;
5472
 
+      }
5473
 
+    
5474
 
+      /* Check the result. ClamAV Returns
5475
 
+         infected: -> "<filename>: <virusname> FOUND"
5476
 
+         not-infected: -> "<filename>: OK"
5477
 
+               error: -> "<filename>: <errcode> ERROR */
5478
 
+         
5479
 
+      if (!(*av_buffer)) {
5480
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5481
 
+                  "malware acl condition: clamd: ClamAV returned null");
5482
 
+        return DEFER;
5483
 
+      }
5484
 
+    
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",
5489
 
+                  av_buffer);  
5490
 
+        return DEFER;
5491
 
+      }
5492
 
+    
5493
 
+      /* strip filename strip CR at the end */
5494
 
+      ++p;
5495
 
+      while (*p == ' ') ++p;
5496
 
+      vname = p;
5497
 
+      p = vname + Ustrlen(vname) - 1;
5498
 
+      if( *p == '\n' ) *p = '\0';
5499
 
+
5500
 
+      if ((p = Ustrstr(vname, "FOUND"))!=NULL) {
5501
 
+           *p=0;
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;
5506
 
+      }
5507
 
+      else {
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++;
5513
 
+
5514
 
+              log_write(0, LOG_MAIN|LOG_PANIC,
5515
 
+                     "malware acl condition: clamd: ClamAV returned %s",vname);
5516
 
+              return DEFER;
5517
 
+           }
5518
 
+           else {
5519
 
+              /* Everything should be OK */
5520
 
+              malware_name = NULL;
5521
 
+           }
5522
 
+      }
5523
 
+    }
5524
 
+    /* ----------------------------------------------------------------------- */
5525
 
+    
5526
 
+    
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;
5534
 
+      int sock;
5535
 
+      int retval;
5536
 
+      
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);
5545
 
+          return DEFER;
5546
 
+        }
5547
 
+      }
5548
 
+      
5549
 
+      /* open the mksd socket */
5550
 
+      sock = socket(AF_UNIX, SOCK_STREAM, 0);
5551
 
+      if (sock < 0) {
5552
 
+        log_write(0, LOG_MAIN|LOG_PANIC,
5553
 
+             "malware acl condition: can't open UNIX socket.");
5554
 
+        return DEFER; 
5555
 
+      }
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) {
5559
 
+        close(sock);
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);
5562
 
+        return DEFER;
5563
 
+      }
5564
 
+      
5565
 
+      malware_name = NULL;
5566
 
+      
5567
 
+      /* choose the appropriate scan routine */
5568
 
+      retval = demime_ok ?
5569
 
+               mksd_scan_unpacked(sock, mksd_maxproc) :
5570
 
+               mksd_scan_packed(sock);
5571
 
+      
5572
 
+      if (retval != OK)
5573
 
+        return retval;
5574
 
+    }
5575
 
+    /* ----------------------------------------------------------------------- */
5576
 
+
5577
 
+
5578
 
+
5579
 
+    /* "unknown" scanner type ------------------------------------------------- */
5580
 
+    else {
5581
 
+      log_write(0, LOG_MAIN|LOG_PANIC,
5582
 
+             "malware condition: unknown scanner type '%s'", scanner_name);
5583
 
+      return DEFER;
5584
 
+    };
5585
 
+    /* ----------------------------------------------------------------------- */
5586
 
+  
5587
 
+    /* set "been here, done that" marker */
5588
 
+    malware_ok = 1;
5589
 
+  };
5590
 
+
5591
 
+  /* match virus name against pattern (caseless ------->----------v) */
5592
 
+  if ( (malware_name != NULL) &&
5593
 
+       (regex_match_and_setup(re, malware_name, 0, -1)) ) {
5594
 
+    return OK;
5595
 
+  }
5596
 
+  else {
5597
 
+    return FAIL;
5598
 
+  };
5599
 
+}
5600
 
+
5601
 
+/* ============= private routines for the "mksd" scanner type ============== */
5602
 
+
5603
 
+#include <sys/uio.h>
5604
 
+
5605
 
+int mksd_writev (int sock, struct iovec *iov, int iovcnt)
5606
 
+{
5607
 
+  int i;
5608
 
+  
5609
 
+  for (;;) {
5610
 
+    do
5611
 
+      i = writev (sock, iov, iovcnt);
5612
 
+    while ((i < 0) && (errno == EINTR));
5613
 
+    if (i <= 0) {
5614
 
+      close (sock);
5615
 
+      log_write(0, LOG_MAIN|LOG_PANIC,
5616
 
+                "malware acl condition: unable to write to mksd UNIX socket (/var/run/mksd/socket)");
5617
 
+      return -1;
5618
 
+    }
5619
 
+    
5620
 
+    for (;;)
5621
 
+      if (i >= iov->iov_len) {
5622
 
+        if (--iovcnt == 0)
5623
 
+          return 0;
5624
 
+        i -= iov->iov_len;
5625
 
+        iov++;
5626
 
+      } else {
5627
 
+        iov->iov_len -= i;
5628
 
+        iov->iov_base = CS iov->iov_base + i;
5629
 
+        break;
5630
 
+      }
5631
 
+  }
5632
 
+}
5633
 
+
5634
 
+int mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size)
5635
 
+{
5636
 
+  int offset = 0;
5637
 
+  int i;
5638
 
+  
5639
 
+  do {
5640
 
+    if ((i = recv (sock, av_buffer+offset, av_buffer_size-offset, 0)) <= 0) {
5641
 
+      close (sock);
5642
 
+      log_write(0, LOG_MAIN|LOG_PANIC,
5643
 
+                "malware acl condition: unable to read from mksd UNIX socket (/var/run/mksd/socket)");
5644
 
+      return -1;
5645
 
+    }
5646
 
+    
5647
 
+    offset += i;
5648
 
+    /* offset == av_buffer_size -> buffer full */
5649
 
+    if (offset == av_buffer_size) {
5650
 
+      close (sock);
5651
 
+      log_write(0, LOG_MAIN|LOG_PANIC,
5652
 
+                "malware acl condition: malformed reply received from mksd");
5653
 
+      return -1;
5654
 
+    }
5655
 
+  } while (av_buffer[offset-1] != '\n');
5656
 
+  
5657
 
+  av_buffer[offset] = '\0';
5658
 
+  return offset;
5659
 
+}
5660
 
+
5661
 
+int mksd_parse_line (char *line)
5662
 
+{
5663
 
+  char *p;
5664
 
+  
5665
 
+  switch (*line) {
5666
 
+    case 'O':
5667
 
+      /* OK */
5668
 
+      return OK;
5669
 
+    case 'E':
5670
 
+    case 'A':
5671
 
+      /* ERR */
5672
 
+      if ((p = strchr (line, '\n')) != NULL)
5673
 
+        (*p) = '\0';
5674
 
+      log_write(0, LOG_MAIN|LOG_PANIC,
5675
 
+                "malware acl condition: mksd scanner failed: %s", line);
5676
 
+      return DEFER;
5677
 
+    default:
5678
 
+      /* VIR */
5679
 
+      if ((p = strchr (line, '\n')) != NULL) {
5680
 
+        (*p) = '\0';
5681
 
+        if (((p-line) > 5) && ((p-line) < sizeof (malware_name_buffer)) && (line[3] == ' '))
5682
 
+          if (((p = strchr (line+4, ' ')) != NULL) && ((p-line) > 4)) {
5683
 
+            (*p) = '\0';
5684
 
+            Ustrcpy (malware_name_buffer, line+4);
5685
 
+           malware_name = malware_name_buffer;
5686
 
+            return OK;
5687
 
+          }
5688
 
+      }
5689
 
+      log_write(0, LOG_MAIN|LOG_PANIC,
5690
 
+                "malware acl condition: malformed reply received from mksd: %s", line);
5691
 
+      return DEFER;
5692
 
+  }
5693
 
+}
5694
 
+
5695
 
+int mksd_scan_packed (int sock)
5696
 
+{
5697
 
+  struct iovec iov[7];
5698
 
+  char *cmd = "MSQ/scan/.eml\n";
5699
 
+  uschar av_buffer[1024];
5700
 
+  
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;
5713
 
+  
5714
 
+  if (mksd_writev (sock, iov, 7) < 0)
5715
 
+    return DEFER;
5716
 
+  
5717
 
+  if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer)) < 0)
5718
 
+    return DEFER;
5719
 
+  
5720
 
+  close (sock);
5721
 
+  
5722
 
+  return mksd_parse_line (CS av_buffer);
5723
 
+}
5724
 
+
5725
 
+int mksd_scan_unpacked (int sock, int maxproc)
5726
 
+{
5727
 
+  struct iovec iov[5];
5728
 
+  char *cmd = "\nSQ/";
5729
 
+  DIR *unpdir;
5730
 
+  struct dirent *entry;
5731
 
+  int pending = 0;
5732
 
+  uschar *line;
5733
 
+  int i, offset;
5734
 
+  uschar mbox_name[1024];
5735
 
+  uschar unpackdir[1024];
5736
 
+  uschar av_buffer[16384];
5737
 
+  
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);
5740
 
+  
5741
 
+  if ((unpdir = opendir (CS unpackdir)) == NULL) {
5742
 
+    close (sock);
5743
 
+    log_write(0, LOG_MAIN|LOG_PANIC,
5744
 
+              "malware acl condition: unable to scan spool directory");
5745
 
+    return DEFER;
5746
 
+  }
5747
 
+  
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;
5756
 
+  
5757
 
+  /* main loop */
5758
 
+  while ((unpdir != NULL) || (pending > 0)) {
5759
 
+  
5760
 
+    /* write loop */
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);
5770
 
+            return DEFER;
5771
 
+          }
5772
 
+          iov[0].iov_base = cmd + 1;
5773
 
+          iov[0].iov_len = 2;
5774
 
+          pending++;
5775
 
+        }
5776
 
+      } else {
5777
 
+        closedir (unpdir);
5778
 
+        unpdir = NULL;
5779
 
+      }
5780
 
+    }
5781
 
+    
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);
5787
 
+        return DEFER;
5788
 
+      }
5789
 
+      line = av_buffer;
5790
 
+      do {
5791
 
+        if (((i = mksd_parse_line (CS line)) != OK) || (malware_name != NULL)) {
5792
 
+          close (sock);
5793
 
+          if (unpdir != NULL)
5794
 
+            closedir (unpdir);
5795
 
+          return i;
5796
 
+        }
5797
 
+        pending--;
5798
 
+        if ((line = Ustrchr (line, '\n')) == NULL) {
5799
 
+          close (sock);
5800
 
+          if (unpdir != NULL)
5801
 
+            closedir (unpdir);
5802
 
+          log_write(0, LOG_MAIN|LOG_PANIC,
5803
 
+                    "malware acl condition: unterminated line received from mksd");
5804
 
+          return DEFER;
5805
 
+        }
5806
 
+      } while (++line != (av_buffer + offset));
5807
 
+      offset = 0;
5808
 
+    }
5809
 
+  }
5810
 
+  
5811
 
+  close (sock);
5812
 
+  return OK;
5813
 
+}
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
5817
 
@@ -0,0 +1,712 @@
5818
 
+/*************************************************
5819
 
+*     Exim - an Internet mail transport agent    *
5820
 
+*************************************************/
5821
 
+
5822
 
+/* This file is part of the exiscan-acl content scanner
5823
 
+patch. It is NOT part of the standard exim distribution. */
5824
 
+
5825
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 */
5826
 
+/* License: GPL */
5827
 
+
5828
 
+#include "exim.h"
5829
 
+#include "mime.h"
5830
 
+#include <sys/stat.h>
5831
 
+
5832
 
+FILE *mime_stream = NULL;
5833
 
+uschar *mime_current_boundary = NULL;
5834
 
+
5835
 
+
5836
 
+/*************************************************
5837
 
+* decode quoted-printable chars                  *
5838
 
+*************************************************/
5839
 
+
5840
 
+/* gets called when we hit a =
5841
 
+   returns: new pointer position
5842
 
+   result code in c:
5843
 
+          -2 - decode error
5844
 
+          -1 - soft line break, no char
5845
 
+           0-255 - char to write
5846
 
+*/
5847
 
+
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;
5853
 
+    j <<= 4;
5854
 
+    j |= (i & 0x0f);
5855
 
+  }
5856
 
+  return(j);
5857
 
+}
5858
 
+
5859
 
+uschar *mime_decode_qp_char(uschar *qp_p,int *c) {
5860
 
+  uschar hex[] = {0,0,0};
5861
 
+  int nan = 0;
5862
 
+  uschar *initial_pos = qp_p;
5863
 
+  
5864
 
+  /* advance one char */
5865
 
+  qp_p++;
5866
 
+  
5867
 
+  REPEAT_FIRST:
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 */
5873
 
+    nan = 1;
5874
 
+    qp_p++;
5875
 
+    goto REPEAT_FIRST;
5876
 
+  }
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 */
5879
 
+    if (nan) {
5880
 
+      /* this is illegal */
5881
 
+      *c = -2;
5882
 
+      return initial_pos;
5883
 
+    }
5884
 
+    else {
5885
 
+      hex[0] = *qp_p;
5886
 
+      qp_p++;
5887
 
+    };
5888
 
+  }
5889
 
+  else if (*qp_p == '\n') {    
5890
 
+    /* hit soft line break already, continue */
5891
 
+    *c = -1;
5892
 
+    return qp_p;
5893
 
+  }
5894
 
+  else {
5895
 
+    /* illegal char here */
5896
 
+    *c = -2;
5897
 
+    return initial_pos;
5898
 
+  };
5899
 
+  
5900
 
+  if ( (('0' <= *qp_p) && (*qp_p <= '9')) || (('A' <= *qp_p) && (*qp_p <= 'F')) || (('a' <= *qp_p) && (*qp_p <= 'f')) ) {
5901
 
+    if (hex[0] > 0) {
5902
 
+      hex[1] = *qp_p;
5903
 
+      /* do hex conversion */
5904
 
+      *c = mime_qp_hstr_i(hex);
5905
 
+      qp_p++;
5906
 
+      return qp_p;
5907
 
+    }
5908
 
+    else {
5909
 
+      /* huh ? */
5910
 
+      *c = -2;
5911
 
+      return initial_pos;  
5912
 
+    };
5913
 
+  }
5914
 
+  else {
5915
 
+    /* illegal char */
5916
 
+    *c = -2;
5917
 
+    return initial_pos;  
5918
 
+  };
5919
 
+}
5920
 
+
5921
 
+
5922
 
+uschar *mime_parse_line(uschar *buffer, uschar *encoding, int *num_decoded) {
5923
 
+  uschar *data = NULL;
5924
 
+
5925
 
+  data = (uschar *)malloc(Ustrlen(buffer)+2);
5926
 
+
5927
 
+  if (encoding == NULL) {
5928
 
+    /* no encoding type at all */
5929
 
+    NO_DECODING:
5930
 
+    memcpy(data, buffer, Ustrlen(buffer));
5931
 
+    data[(Ustrlen(buffer))] = 0;
5932
 
+    *num_decoded = Ustrlen(data);
5933
 
+    return data;
5934
 
+  }
5935
 
+  else if (Ustrcmp(encoding,"base64") == 0) {
5936
 
+    uschar *p = buffer;
5937
 
+    int offset = 0;
5938
 
+    
5939
 
+    /* ----- BASE64 ---------------------------------------------------- */
5940
 
+    /* NULL out '\r' and '\n' chars */
5941
 
+    while (Ustrrchr(p,'\r') != NULL) {
5942
 
+      *(Ustrrchr(p,'\r')) = '\0';
5943
 
+    };
5944
 
+    while (Ustrrchr(p,'\n') != NULL) {
5945
 
+      *(Ustrrchr(p,'\n')) = '\0';
5946
 
+    };
5947
 
+
5948
 
+    while (*(p+offset) != '\0') {
5949
 
+      /* hit illegal char ? */
5950
 
+      if (mime_b64[*(p+offset)] == 128) {
5951
 
+        offset++;
5952
 
+      }
5953
 
+      else {
5954
 
+        *p = mime_b64[*(p+offset)];
5955
 
+        p++;
5956
 
+      };
5957
 
+    };
5958
 
+    *p = 255;
5959
 
+   
5960
 
+    /* line is translated, start bit shifting */
5961
 
+    p = buffer;
5962
 
+    *num_decoded = 0;  
5963
 
+    while(*p != 255) {
5964
 
+      uschar tmp_c;
5965
 
+      
5966
 
+      /* byte 0 ---------------------- */
5967
 
+      if (*(p+1) == 255) {
5968
 
+        break;
5969
 
+      }
5970
 
+      data[(*num_decoded)] = *p;
5971
 
+      data[(*num_decoded)] <<= 2;
5972
 
+      tmp_c = *(p+1);
5973
 
+      tmp_c >>= 4;
5974
 
+      data[(*num_decoded)] |= tmp_c;
5975
 
+      (*num_decoded)++;
5976
 
+      p++;
5977
 
+      /* byte 1 ---------------------- */
5978
 
+      if (*(p+1) == 255) {
5979
 
+        break;
5980
 
+      }
5981
 
+      data[(*num_decoded)] = *p;
5982
 
+      data[(*num_decoded)] <<= 4;
5983
 
+      tmp_c = *(p+1);
5984
 
+      tmp_c >>= 2;
5985
 
+      data[(*num_decoded)] |= tmp_c;
5986
 
+      (*num_decoded)++;
5987
 
+      p++;
5988
 
+      /* byte 2 ---------------------- */
5989
 
+      if (*(p+1) == 255) {
5990
 
+        break;
5991
 
+      }
5992
 
+      data[(*num_decoded)] = *p;
5993
 
+      data[(*num_decoded)] <<= 6;
5994
 
+      data[(*num_decoded)] |= *(p+1); 
5995
 
+      (*num_decoded)++;
5996
 
+      p+=2;
5997
 
+      
5998
 
+    };
5999
 
+    return data;
6000
 
+    /* ----------------------------------------------------------------- */
6001
 
+  }
6002
 
+  else if (Ustrcmp(encoding,"quoted-printable") == 0) {
6003
 
+    uschar *p = buffer;
6004
 
+
6005
 
+    /* ----- QP -------------------------------------------------------- */
6006
 
+    *num_decoded = 0;
6007
 
+    while (*p != 0) {
6008
 
+      if (*p == '=') {
6009
 
+        int decode_qp_result;
6010
 
+        
6011
 
+        p = mime_decode_qp_char(p,&decode_qp_result);
6012
 
+              
6013
 
+        if (decode_qp_result == -2) {
6014
 
+          /* Error from decoder. p is unchanged. */
6015
 
+          data[(*num_decoded)] = '=';
6016
 
+          (*num_decoded)++;
6017
 
+          p++;
6018
 
+        }
6019
 
+        else if (decode_qp_result == -1) {
6020
 
+          break;
6021
 
+        }
6022
 
+        else if (decode_qp_result >= 0) {
6023
 
+          data[(*num_decoded)] = decode_qp_result;
6024
 
+          (*num_decoded)++;
6025
 
+        };
6026
 
+      }
6027
 
+      else {
6028
 
+        data[(*num_decoded)] = *p;
6029
 
+        (*num_decoded)++;
6030
 
+        p++;
6031
 
+      };
6032
 
+    };
6033
 
+    return data;
6034
 
+    /* ----------------------------------------------------------------- */
6035
 
+  }
6036
 
+  /* unknown encoding type, just dump as-is */
6037
 
+  else goto NO_DECODING;
6038
 
+}
6039
 
+
6040
 
+
6041
 
+FILE *mime_get_decode_file(uschar *pname, uschar *fname) {
6042
 
+  FILE *f;
6043
 
+  uschar *filename;
6044
 
+  
6045
 
+  filename = (uschar *)malloc(2048);
6046
 
+  
6047
 
+  if ((pname != NULL) && (fname != NULL)) {
6048
 
+    snprintf(CS filename, 2048, "%s/%s", pname, fname);
6049
 
+    f = fopen(CS filename,"w+");
6050
 
+  }
6051
 
+  else if (pname == NULL) {
6052
 
+    f = fopen(CS fname,"w+");
6053
 
+  }
6054
 
+  else if (fname == NULL) {
6055
 
+    int file_nr = 0;
6056
 
+    int result = 0;
6057
 
+
6058
 
+    /* must find first free sequential filename */
6059
 
+    do {
6060
 
+      struct stat mystat;
6061
 
+      snprintf(CS filename,2048,"%s/%s-%05u", pname, message_id, file_nr);
6062
 
+      file_nr++;
6063
 
+      /* security break */
6064
 
+      if (file_nr >= 1024)
6065
 
+        break;
6066
 
+      result = stat(CS filename,&mystat);
6067
 
+    }
6068
 
+    while(result != -1);
6069
 
+    f = fopen(CS filename,"w+");
6070
 
+  };
6071
 
+  
6072
 
+  /* set expansion variable */
6073
 
+  mime_decoded_filename = filename;
6074
 
+  
6075
 
+  return f;
6076
 
+}
6077
 
+
6078
 
+
6079
 
+int mime_decode(uschar **listptr) {
6080
 
+  int sep = 0;
6081
 
+  uschar *list = *listptr;
6082
 
+  uschar *option;
6083
 
+  uschar option_buffer[1024];
6084
 
+  uschar decode_path[1024];
6085
 
+  FILE *decode_file = NULL;
6086
 
+  uschar *buffer = NULL;
6087
 
+  long f_pos = 0;
6088
 
+  unsigned int size_counter = 0;
6089
 
+
6090
 
+  if (mime_stream == NULL)
6091
 
+    return FAIL;
6092
 
+  
6093
 
+  f_pos = ftell(mime_stream);
6094
 
+  
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);
6097
 
+  
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);
6103
 
+    return DEFER;
6104
 
+  };
6105
 
+  
6106
 
+  /* try to find 1st option */
6107
 
+  if ((option = string_nextinlist(&list, &sep,
6108
 
+                                  option_buffer,
6109
 
+                                  sizeof(option_buffer))) != NULL) {
6110
 
+    
6111
 
+    /* parse 1st option */
6112
 
+    if ( (Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0) ) {
6113
 
+      /* explicitly no decoding */
6114
 
+      return FAIL;
6115
 
+    };
6116
 
+    
6117
 
+    if (Ustrcmp(option,"default") == 0) {
6118
 
+      /* explicit default path + file names */
6119
 
+      goto DEFAULT_PATH;
6120
 
+    };
6121
 
+    
6122
 
+    if (option[0] == '/') {
6123
 
+      struct stat statbuf;
6124
 
+
6125
 
+      memset(&statbuf,0,sizeof(statbuf));
6126
 
+      
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);
6131
 
+      else
6132
 
+        /* does not exist or is a file, use as full file name */
6133
 
+        decode_file = mime_get_decode_file(NULL, option);
6134
 
+    }
6135
 
+    else
6136
 
+      /* assume file name only, use default path */
6137
 
+      decode_file = mime_get_decode_file(decode_path, option);
6138
 
+  }
6139
 
+  else
6140
 
+    /* no option? patch default path */
6141
 
+    DEFAULT_PATH: decode_file = mime_get_decode_file(decode_path, NULL);
6142
 
+  
6143
 
+  if (decode_file == NULL)
6144
 
+    return DEFER;
6145
 
+  
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;
6151
 
+    
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)
6156
 
+          break;
6157
 
+      };
6158
 
+    };
6159
 
+  
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);
6166
 
+      return DEFER;
6167
 
+    };
6168
 
+    size_counter += decoded_line_length;
6169
 
+    
6170
 
+    if (size_counter > 1023) { 
6171
 
+      if ((mime_content_size + (size_counter / 1024)) < 65535)
6172
 
+        mime_content_size += (size_counter / 1024);
6173
 
+      else 
6174
 
+        mime_content_size = 65535;
6175
 
+      size_counter = (size_counter % 1024);
6176
 
+    };
6177
 
+    
6178
 
+    free(decoded_line);
6179
 
+  }
6180
 
+  
6181
 
+  fclose(decode_file);
6182
 
+  
6183
 
+  clearerr(mime_stream);
6184
 
+  fseek(mime_stream,f_pos,SEEK_SET);
6185
 
+  
6186
 
+  /* round up remaining size bytes to one k */
6187
 
+  if (size_counter) {
6188
 
+    mime_content_size++;
6189
 
+  };
6190
 
+  
6191
 
+  return OK;
6192
 
+}
6193
 
+
6194
 
+int mime_get_header(FILE *f, uschar *header) {
6195
 
+  int c = EOF;
6196
 
+  int done = 0;
6197
 
+  int header_value_mode = 0;
6198
 
+  int header_open_brackets = 0;
6199
 
+  int num_copied = 0;
6200
 
+  
6201
 
+  while(!done) {
6202
 
+    
6203
 
+    c = fgetc(f);
6204
 
+    if (c == EOF) break;
6205
 
+   
6206
 
+    /* always skip CRs */
6207
 
+    if (c == '\r') continue;
6208
 
+    
6209
 
+    if (c == '\n') {
6210
 
+      if (num_copied > 0) {
6211
 
+        /* look if next char is '\t' or ' ' */
6212
 
+        c = fgetc(f);
6213
 
+        if (c == EOF) break;
6214
 
+        if ( (c == '\t') || (c == ' ') ) continue;
6215
 
+        ungetc(c,f);
6216
 
+      };
6217
 
+      /* end of the header, terminate with ';' */
6218
 
+      c = ';';
6219
 
+      done = 1;
6220
 
+    };
6221
 
+  
6222
 
+    /* skip control characters */
6223
 
+    if (c < 32) continue;
6224
 
+
6225
 
+    if (header_value_mode) {
6226
 
+      /* --------- value mode ----------- */
6227
 
+      /* skip leading whitespace */
6228
 
+      if ( ((c == '\t') || (c == ' ')) && (header_value_mode == 1) )
6229
 
+        continue;
6230
 
+      
6231
 
+      /* we have hit a non-whitespace char, start copying value data */
6232
 
+      header_value_mode = 2;
6233
 
+      
6234
 
+      /* skip quotes */
6235
 
+      if (c == '"') continue;
6236
 
+      
6237
 
+      /* leave value mode on ';' */
6238
 
+      if (c == ';') {
6239
 
+        header_value_mode = 0;
6240
 
+      };
6241
 
+      /* -------------------------------- */
6242
 
+    }
6243
 
+    else {
6244
 
+      /* -------- non-value mode -------- */
6245
 
+      /* skip whitespace + tabs */
6246
 
+      if ( (c == ' ') || (c == '\t') )
6247
 
+        continue;
6248
 
+      if (c == '\\') {
6249
 
+        /* quote next char. can be used
6250
 
+        to escape brackets. */
6251
 
+        c = fgetc(f);
6252
 
+        if (c == EOF) break;
6253
 
+      }
6254
 
+      else if (c == '(') {
6255
 
+        header_open_brackets++;
6256
 
+        continue;
6257
 
+      }
6258
 
+      else if ((c == ')') && header_open_brackets) {
6259
 
+        header_open_brackets--;
6260
 
+        continue;
6261
 
+      }
6262
 
+      else if ( (c == '=') && !header_open_brackets ) {
6263
 
+        /* enter value mode */
6264
 
+        header_value_mode = 1;
6265
 
+      };
6266
 
+      
6267
 
+      /* skip chars while we are in a comment */
6268
 
+      if (header_open_brackets > 0)
6269
 
+        continue;
6270
 
+      /* -------------------------------- */
6271
 
+    };
6272
 
+    
6273
 
+    /* copy the char to the buffer */
6274
 
+    header[num_copied] = (uschar)c;
6275
 
+    /* raise counter */
6276
 
+    num_copied++;
6277
 
+    
6278
 
+    /* break if header buffer is full */
6279
 
+    if (num_copied > MIME_MAX_HEADER_SIZE-1) {
6280
 
+      done = 1;
6281
 
+    };
6282
 
+  };
6283
 
+
6284
 
+  if (header[num_copied-1] != ';') {
6285
 
+    header[num_copied-1] = ';';
6286
 
+  };
6287
 
+
6288
 
+  /* 0-terminate */
6289
 
+  header[num_copied] = '\0';
6290
 
+  
6291
 
+  /* return 0 for EOF or empty line */
6292
 
+  if ((c == EOF) || (num_copied == 1))
6293
 
+    return 0;
6294
 
+  else
6295
 
+    return 1;
6296
 
+}
6297
 
+
6298
 
+
6299
 
+int mime_acl_check(FILE *f, struct mime_boundary_context *context, uschar 
6300
 
+                   **user_msgptr, uschar **log_msgptr) {
6301
 
+  int rc = OK;
6302
 
+  uschar *header = NULL;
6303
 
+  struct mime_boundary_context nested_context;
6304
 
+
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);
6310
 
+    return DEFER;
6311
 
+  };
6312
 
+
6313
 
+  /* Not actually used at the moment, but will be vital to fixing
6314
 
+   * some RFC 2046 nonconformance later... */
6315
 
+  nested_context.parent = context;
6316
 
+
6317
 
+  /* loop through parts */
6318
 
+  while(1) {
6319
 
+  
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;
6334
 
+  
6335
 
+    /*
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
6339
 
+    block.
6340
 
+    */
6341
 
+    
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.
6345
 
+     *
6346
 
+     * (I have moved partway towards adding support, however, by adding 
6347
 
+     * a "parent" field to my new boundary-context structure.)
6348
 
+     */
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);
6358
 
+              return rc;
6359
 
+            }
6360
 
+            else {
6361
 
+              debug_printf("Next part with boundary %s\n", context->boundary);
6362
 
+            };
6363
 
+            /* can't use break here */
6364
 
+            goto DECODE_HEADERS;
6365
 
+          }
6366
 
+        };
6367
 
+      }
6368
 
+      /* Hit EOF or read error. Ugh. */
6369
 
+      debug_printf("Hit EOF ...\n");
6370
 
+      return rc;
6371
 
+    };
6372
 
+  
6373
 
+    DECODE_HEADERS:
6374
 
+    /* parse headers, set up expansion variables */
6375
 
+    while(mime_get_header(f,header)) {
6376
 
+      int i;
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;
6381
 
+        
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 != ';') {
6388
 
+            *p = tolower(*p);
6389
 
+            p++;
6390
 
+          };
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;
6398
 
+          
6399
 
+          /* make p point to the next character after the closing ';' */
6400
 
+          p += (header_value_len+1);
6401
 
+          
6402
 
+          /* grab all param=value tags on the remaining line, check if they are interesting */
6403
 
+          NEXT_PARAM_SEARCH: while (*p != 0) {
6404
 
+            int j;
6405
 
+            for (j = 0; j < mime_parameter_list_size; j++) {
6406
 
+              uschar *param_value = NULL;
6407
 
+              int param_value_len = 0;
6408
 
+              
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, &param_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;
6424
 
+              };
6425
 
+            }
6426
 
+            /* There is something, but not one of our interesting parameters.
6427
 
+               Advance to the next semicolon */
6428
 
+            while(*p != ';') p++;
6429
 
+            p++;
6430
 
+          };
6431
 
+        };
6432
 
+      };
6433
 
+    };
6434
 
+    
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;
6439
 
+    
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;
6444
 
+    
6445
 
+    /* raise global counter */
6446
 
+    mime_part_count++;
6447
 
+    
6448
 
+    /* copy current file handle to global variable */
6449
 
+    mime_stream = f;
6450
 
+    mime_current_boundary = context ? context->boundary : 0;
6451
 
+
6452
 
+    /* Note the context */
6453
 
+    mime_is_coverletter = !(context && context->context == MBC_ATTACHMENT);
6454
 
+    
6455
 
+    /* call ACL handling function */
6456
 
+    rc = acl_check(ACL_WHERE_MIME, NULL, acl_smtp_mime, user_msgptr, log_msgptr);
6457
 
+    
6458
 
+    mime_stream = NULL;
6459
 
+    mime_current_boundary = NULL;
6460
 
+    
6461
 
+    if (rc != OK) break;
6462
 
+    
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);
6468
 
+
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;
6474
 
+      else
6475
 
+        nested_context.context = MBC_COVERLETTER_ONESHOT;
6476
 
+
6477
 
+      rc = mime_acl_check(f, &nested_context, user_msgptr, log_msgptr);
6478
 
+      if (rc != OK) break;
6479
 
+    }
6480
 
+    else if ( (mime_content_type != NULL) &&
6481
 
+            (Ustrncmp(mime_content_type,"message/rfc822",14) == 0) ) {
6482
 
+      uschar *rfc822name = NULL;
6483
 
+      uschar filename[2048];
6484
 
+      int file_nr = 0;
6485
 
+      int result = 0;
6486
 
+      
6487
 
+      /* must find first free sequential filename */
6488
 
+      do {
6489
 
+        struct stat mystat;
6490
 
+        snprintf(CS filename,2048,"%s/scan/%s/__rfc822_%05u", spool_directory, message_id, file_nr);
6491
 
+        file_nr++;
6492
 
+        /* security break */
6493
 
+        if (file_nr >= 128)
6494
 
+          goto NO_RFC822;
6495
 
+        result = stat(CS filename,&mystat);
6496
 
+      }
6497
 
+      while(result != -1);
6498
 
+      
6499
 
+      rfc822name = filename;
6500
 
+      
6501
 
+      /* decode RFC822 attachment */
6502
 
+      mime_decoded_filename = NULL;
6503
 
+      mime_stream = f;
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.");
6512
 
+        return DEFER;
6513
 
+      };
6514
 
+      mime_decoded_filename = NULL;
6515
 
+    };
6516
 
+    
6517
 
+    NO_RFC822:
6518
 
+    /* If the boundary of this instance is NULL, we are finished here */
6519
 
+    if (context == NULL) break;
6520
 
+
6521
 
+    if (context->context == MBC_COVERLETTER_ONESHOT)
6522
 
+      context->context = MBC_ATTACHMENT;
6523
 
+  
6524
 
+  };
6525
 
+
6526
 
+  return rc;
6527
 
+}
6528
 
+
6529
 
+
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
6533
 
@@ -0,0 +1,77 @@
6534
 
+/*************************************************
6535
 
+*     Exim - an Internet mail transport agent    *
6536
 
+*************************************************/
6537
 
+
6538
 
+/* This file is part of the exiscan-acl content scanner
6539
 
+patch. It is NOT part of the standard exim distribution. */
6540
 
+
6541
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 */
6542
 
+/* License: GPL */
6543
 
+
6544
 
+
6545
 
+#define MIME_MAX_HEADER_SIZE 8192
6546
 
+#define MIME_MAX_LINE_LENGTH 32768
6547
 
+
6548
 
+#define MBC_ATTACHMENT            0
6549
 
+#define MBC_COVERLETTER_ONESHOT   1
6550
 
+#define MBC_COVERLETTER_ALL       2
6551
 
+
6552
 
+struct mime_boundary_context
6553
 
+{
6554
 
+  struct mime_boundary_context *parent;
6555
 
+  unsigned char *boundary;
6556
 
+  int context;
6557
 
+};
6558
 
+
6559
 
+typedef struct mime_header {
6560
 
+  uschar *name;
6561
 
+  int    namelen;
6562
 
+  void   *value;
6563
 
+} mime_header;
6564
 
+
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 }
6571
 
+};
6572
 
+
6573
 
+static int mime_header_list_size = sizeof(mime_header_list)/sizeof(mime_header);
6574
 
+
6575
 
+
6576
 
+
6577
 
+typedef struct mime_parameter {
6578
 
+  uschar *name;
6579
 
+  int    namelen;
6580
 
+  void   *value;
6581
 
+} mime_parameter;
6582
 
+
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 }
6588
 
+};
6589
 
+
6590
 
+static int mime_parameter_list_size = sizeof(mime_parameter_list)/sizeof(mime_parameter);
6591
 
+
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 
6610
 
+};
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
6614
 
@@ -141,6 +141,7 @@
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 },
6620
 
 #ifdef SUPPORT_TLS
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 },
6628
 
+#ifdef BRIGHTMAIL
6629
 
+  { "bmi_config_file",          opt_stringptr,   &bmi_config_file },
6630
 
+#endif
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 },
6634
 
@@ -312,6 +317,7 @@
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
6645
 
@@ -10,7 +10,9 @@
6646
 
 
6647
 
 #include "exim.h"
6648
 
 
6649
 
-
6650
 
+#ifdef BRIGHTMAIL
6651
 
+#include "bmi_spam.h"
6652
 
+#endif
6653
 
 
6654
 
 /*************************************************
6655
 
 *                Local static variables          *
6656
 
@@ -436,6 +438,13 @@
6657
 
 
6658
 
 recipients_list[recipients_count].address = recipient;
6659
 
 recipients_list[recipients_count].pno = pno;
6660
 
+
6661
 
+#ifdef BRIGHTMAIL
6662
 
+recipients_list[recipients_count].bmi_optin = bmi_current_optin;
6663
 
+/* reset optin string pointer for next recipient */
6664
 
+bmi_current_optin = NULL;
6665
 
+#endif
6666
 
+
6667
 
 recipients_list[recipients_count++].errors_to = NULL;
6668
 
 }
6669
 
 
6670
 
@@ -2530,6 +2539,124 @@
6671
 
 
6672
 
   if (smtp_input && !smtp_batched_input)
6673
 
     {
6674
 
+    if (acl_smtp_mime != NULL && recipients_count > 0)
6675
 
+      {
6676
 
+      FILE *mbox_file;
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;
6682
 
+      
6683
 
+      memset(CS rfc822_file_path,0,2048);
6684
 
+      
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;
6691
 
+          continue;
6692
 
+        };
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");
6695
 
+          goto DO_MIME_ACL;
6696
 
+        };
6697
 
+        my_headerlist = my_headerlist->next;
6698
 
+      };
6699
 
+      
6700
 
+      DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
6701
 
+      goto NO_MIME_ACL;
6702
 
+      
6703
 
+      DO_MIME_ACL:
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);
6711
 
+        unspool_mbox(); 
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 */
6716
 
+      };
6717
 
+      
6718
 
+      mime_is_rfc822 = 0;
6719
 
+
6720
 
+      MIME_ACL_CHECK:
6721
 
+      mime_part_count = -1;
6722
 
+      rc = mime_acl_check(mbox_file, NULL, &user_msg, &log_msg);
6723
 
+      fclose(mbox_file);
6724
 
+      
6725
 
+      if (Ustrlen(rfc822_file_path) > 0) {
6726
 
+        mime_part_count = mime_part_count_buffer;
6727
 
+        
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;
6732
 
+        };
6733
 
+      };
6734
 
+      
6735
 
+      /* check if we must check any message/rfc822 attachments */
6736
 
+      if (rc == OK) {
6737
 
+        uschar temp_path[1024];
6738
 
+        int n;
6739
 
+        struct dirent *entry;
6740
 
+        DIR *tempdir;
6741
 
6742
 
+        snprintf(CS temp_path, 1024, "%s/scan/%s", spool_directory, message_id);
6743
 
+
6744
 
+       tempdir = opendir(CS temp_path);
6745
 
+       n = 0;
6746
 
+       do {
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);
6752
 
+           break;
6753
 
+          }; 
6754
 
+       } while (1);
6755
 
+       closedir(tempdir);
6756
 
+        
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;
6764
 
+          };
6765
 
+          /* set RFC822 expansion variable */
6766
 
+          mime_is_rfc822 = 1;
6767
 
+          mime_part_count_buffer = mime_part_count;
6768
 
+          goto MIME_ACL_CHECK;
6769
 
+        };
6770
 
+      };
6771
 
+      
6772
 
+      END_MIME_ACL:
6773
 
+      add_acl_headers(US"MIME");
6774
 
+      if (rc == DISCARD)
6775
 
+        {
6776
 
+        recipients_count = 0;
6777
 
+        blackholed_by = US"MIME ACL";
6778
 
+        }
6779
 
+      else if (rc != OK)
6780
 
+        {
6781
 
+        Uunlink(spool_name);
6782
 
+        unspool_mbox();
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 */
6788
 
+        }; 
6789
 
+      }
6790
 
6791
 
+    NO_MIME_ACL:
6792
 
     if (acl_smtp_data != NULL && recipients_count > 0)
6793
 
       {
6794
 
       uschar *user_msg, *log_msg;
6795
 
@@ -2543,6 +2670,7 @@
6796
 
       else if (rc != OK)
6797
 
         {
6798
 
         Uunlink(spool_name);
6799
 
+        unspool_mbox();
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 @@
6804
 
       }
6805
 
     }
6806
 
 
6807
 
+
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. */
6810
 
 
6811
 
@@ -2592,6 +2721,8 @@
6812
 
   enable_dollar_recipients = FALSE;
6813
 
   }
6814
 
 
6815
 
+unspool_mbox();
6816
 
+
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));
6823
 
 
6824
 
+
6825
 
+#ifdef BRIGHTMAIL
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);
6830
 
+};
6831
 
+#endif
6832
 
+
6833
 
+
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 @@
6838
 
 if this happens? */
6839
 
 
6840
 
 TIDYUP:
6841
 
+
6842
 
 process_info[process_info_len] = 0;          /* Remove message id */
6843
 
 if (data_file != NULL) fclose(data_file);    /* Frees the lock */
6844
 
 
6845
 
@@ -3037,12 +3179,31 @@
6846
 
     {
6847
 
     if (smtp_reply == NULL)
6848
 
       {
6849
 
-      smtp_printf("250 OK id=%s\r\n", message_id);
6850
 
+        if (fake_reject)
6851
 
+        {
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");
6855
 
+        }
6856
 
+        else  
6857
 
+          smtp_printf("250 OK id=%s\r\n", message_id);
6858
 
+      
6859
 
       if (host_checking)
6860
 
         fprintf(stdout,
6861
 
           "\n**** SMTP testing: that is not a real message id!\n\n");
6862
 
+      
6863
 
       }
6864
 
-    else if (smtp_reply[0] != 0) smtp_printf("%.1024s\r\n", smtp_reply);
6865
 
+    else if (smtp_reply[0] != 0)
6866
 
+      {
6867
 
+        if (fake_reject && (smtp_reply[0] == '2'))
6868
 
+        {
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");
6872
 
+        }
6873
 
+        else 
6874
 
+          smtp_printf("%.1024s\r\n", smtp_reply);
6875
 
+      };
6876
 
     }
6877
 
 
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
6882
 
@@ -0,0 +1,246 @@
6883
 
+/*************************************************
6884
 
+*     Exim - an Internet mail transport agent    *
6885
 
+*************************************************/
6886
 
+
6887
 
+/* This file is part of the exiscan-acl content scanner
6888
 
+patch. It is NOT part of the standard exim distribution. */
6889
 
+
6890
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
6891
 
+/* License: GPL */
6892
 
+
6893
 
+/* Code for matching regular expressions against headers and body.
6894
 
+ Called from acl.c. */
6895
 
+
6896
 
+#include "exim.h"
6897
 
+#include <unistd.h>
6898
 
+#include <sys/mman.h>
6899
 
+
6900
 
+/* Structure to hold a list of Regular expressions */
6901
 
+typedef struct pcre_list {
6902
 
+  pcre *re;
6903
 
+  uschar *pcre_text;
6904
 
+  struct pcre_list *next;
6905
 
+} pcre_list;
6906
 
+
6907
 
+uschar regex_match_string_buffer[1024];
6908
 
+
6909
 
+extern FILE *mime_stream;
6910
 
+extern uschar *mime_current_boundary;
6911
 
+
6912
 
+int regex(uschar **listptr) {
6913
 
+  int sep = 0;
6914
 
+  uschar *list = *listptr;
6915
 
+  uschar *regex_string;
6916
 
+  uschar regex_string_buffer[1024];
6917
 
+  unsigned long long mbox_size;
6918
 
+  FILE *mbox_file;
6919
 
+  pcre *re;
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;
6925
 
+  long f_pos = 0;
6926
 
+  
6927
 
+  /* reset expansion variable */
6928
 
+  regex_match_string = NULL;
6929
 
+  
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");
6937
 
+      return DEFER;
6938
 
+    };
6939
 
+  }
6940
 
+  else {
6941
 
+    f_pos = ftell(mime_stream);
6942
 
+    mbox_file = mime_stream;
6943
 
+  };
6944
 
+  
6945
 
+  /* precompile our regexes */
6946
 
+  while ((regex_string = string_nextinlist(&list, &sep,
6947
 
+                                           regex_string_buffer,
6948
 
+                                           sizeof(regex_string_buffer))) != NULL) {
6949
 
+    
6950
 
+    /* parse option */
6951
 
+    if ( (strcmpic(regex_string,US"false") == 0) || 
6952
 
+         (Ustrcmp(regex_string,"0") == 0) ) {
6953
 
+      /* explicitly no matching */
6954
 
+      continue;
6955
 
+    };
6956
 
+    
6957
 
+    /* compile our regular expression */
6958
 
+    re = pcre_compile( CS regex_string,
6959
 
+                       0,
6960
 
+                       &pcre_error,
6961
 
+                       &pcre_erroffset,
6962
 
+                       NULL );
6963
 
+
6964
 
+    if (re == NULL) {
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);
6967
 
+      continue;
6968
 
+    }
6969
 
+    else {
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;
6975
 
+    };
6976
 
+  };
6977
 
+  
6978
 
+  /* no regexes -> nothing to do */
6979
 
+  if (re_list_head == NULL) {
6980
 
+    return FAIL;
6981
 
+  };
6982
 
+  
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 */
6991
 
+          break;
6992
 
+      };
6993
 
+    };
6994
 
+    re_list_item = re_list_head;
6995
 
+    do {
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);
7003
 
+        else {
7004
 
+          clearerr(mime_stream);
7005
 
+          fseek(mime_stream,f_pos,SEEK_SET);
7006
 
+        };
7007
 
+        return OK;
7008
 
+      };
7009
 
+      re_list_item = re_list_item->next;
7010
 
+    } while (re_list_item != NULL);
7011
 
+  };
7012
 
+  
7013
 
+  if (mime_stream == NULL)
7014
 
+    fclose(mbox_file);
7015
 
+  else {
7016
 
+    clearerr(mime_stream);
7017
 
+    fseek(mime_stream,f_pos,SEEK_SET);
7018
 
+  };
7019
 
+    
7020
 
+  /* no matches ... */
7021
 
+  return FAIL;
7022
 
+}
7023
 
+
7024
 
+
7025
 
+int mime_regex(uschar **listptr) {
7026
 
+  int sep = 0;
7027
 
+  uschar *list = *listptr;
7028
 
+  uschar *regex_string;
7029
 
+  uschar regex_string_buffer[1024];
7030
 
+  pcre *re;
7031
 
+  pcre_list *re_list_head = NULL;
7032
 
+  pcre_list *re_list_item;
7033
 
+  const char *pcre_error;
7034
 
+  int pcre_erroffset;
7035
 
+  FILE *f;
7036
 
+  uschar *mime_subject = NULL;
7037
 
+  int mime_subject_len = 0;
7038
 
+
7039
 
+  /* reset expansion variable */
7040
 
+  regex_match_string = NULL;
7041
 
+
7042
 
+  /* precompile our regexes */
7043
 
+  while ((regex_string = string_nextinlist(&list, &sep,
7044
 
+                                           regex_string_buffer,
7045
 
+                                           sizeof(regex_string_buffer))) != NULL) {
7046
 
+    
7047
 
+    /* parse option */
7048
 
+    if ( (strcmpic(regex_string,US"false") == 0) || 
7049
 
+         (Ustrcmp(regex_string,"0") == 0) ) {
7050
 
+      /* explicitly no matching */
7051
 
+      continue;
7052
 
+    };
7053
 
+    
7054
 
+    /* compile our regular expression */
7055
 
+    re = pcre_compile( CS regex_string,
7056
 
+                       0,
7057
 
+                       &pcre_error,
7058
 
+                       &pcre_erroffset,
7059
 
+                       NULL );
7060
 
+
7061
 
+    if (re == NULL) {
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);
7064
 
+      continue;
7065
 
+    }
7066
 
+    else {
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;
7072
 
+    };
7073
 
+  };
7074
 
+  
7075
 
+  /* no regexes -> nothing to do */
7076
 
+  if (re_list_head == NULL) {
7077
 
+    return FAIL;
7078
 
+  };
7079
 
+  
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.");
7089
 
+      return DEFER;
7090
 
+    };
7091
 
+  };
7092
 
+
7093
 
+
7094
 
+  /* open file */
7095
 
+  f = fopen(CS mime_decoded_filename, "r");
7096
 
+  if (f == NULL) {
7097
 
+    /* open failed */
7098
 
+    log_write(0, LOG_MAIN,
7099
 
+         "mime_regex acl condition warning - can't open '%s' for reading.", mime_decoded_filename);
7100
 
+    return DEFER;
7101
 
+  };
7102
 
+  
7103
 
+  /* get 32k memory */
7104
 
+  mime_subject = (uschar *)store_get(32767);
7105
 
+  
7106
 
+  /* read max 32k chars from file */
7107
 
+  mime_subject_len = fread(mime_subject, 1, 32766, f);
7108
 
+  
7109
 
+  re_list_item = re_list_head;
7110
 
+  do {
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;
7117
 
+      fclose(f);
7118
 
+      return OK;
7119
 
+    };
7120
 
+    re_list_item = re_list_item->next;
7121
 
+  } while (re_list_item != NULL);
7122
 
+
7123
 
+  fclose(f);
7124
 
+  
7125
 
+  /* no matches ... */
7126
 
+  return FAIL;
7127
 
+}
7128
 
+
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
7132
 
@@ -10,6 +10,9 @@
7133
 
 
7134
 
 #include "exim.h"
7135
 
 
7136
 
+#ifdef BRIGHTMAIL
7137
 
+#include "bmi_spam.h"
7138
 
+#endif
7139
 
 
7140
 
 
7141
 
 /* Generic options for routers, all of which live inside router_instance
7142
 
@@ -32,6 +35,16 @@
7143
 
                  (void *)(offsetof(router_instance, address_data)) },
7144
 
   { "address_test",       opt_bool|opt_public,
7145
 
                  (void *)(offsetof(router_instance, address_test)) },
7146
 
+#ifdef BRIGHTMAIL
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)) },
7155
 
+#endif
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 @@
7160
 
     }
7161
 
   }
7162
 
 
7163
 
+#ifdef BRIGHTMAIL
7164
 
+
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 */
7170
 
+    DEBUG(D_route)
7171
 
+      debug_printf("%s router skipped: none of bmi_rule rules fired\n", r->name);
7172
 
+    return SKIP;
7173
 
+  };
7174
 
+};
7175
 
+
7176
 
+/* check if message should not be delivered */
7177
 
+if (r->bmi_dont_deliver) {
7178
 
+  if (bmi_deliver == 1) {
7179
 
+    DEBUG(D_route)
7180
 
+      debug_printf("%s router skipped: bmi_dont_deliver is FALSE\n", r->name);
7181
 
+    return SKIP;
7182
 
+  };
7183
 
+};
7184
 
+
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)) {
7188
 
+    DEBUG(D_route)
7189
 
+      debug_printf("%s router skipped: bmi_deliver_alternate is FALSE\n", r->name);
7190
 
+    return SKIP;
7191
 
+  };
7192
 
+};
7193
 
+
7194
 
+/* check if message should go to default location */
7195
 
+if (r->bmi_deliver_default) {
7196
 
+  if ((bmi_deliver == 0) || (bmi_alt_location != NULL)) {
7197
 
+    DEBUG(D_route)
7198
 
+      debug_printf("%s router skipped: bmi_deliver_default is FALSE\n", r->name);
7199
 
+    return SKIP;
7200
 
+  };
7201
 
+};
7202
 
+
7203
 
+#endif
7204
 
+
7205
 
+
7206
 
 /* All the checks passed. */
7207
 
 
7208
 
 return OK;
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
7212
 
@@ -790,6 +790,8 @@
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;
7225
 
+#ifdef BRIGHTMAIL
7226
 
+bmi_run = 0;
7227
 
+bmi_verdicts = NULL;
7228
 
+#endif
7229
 
 
7230
 
 for (i = 0; i < ACL_M_MAX; i++) acl_var[ACL_C_MAX + i] = NULL;
7231
 
 
7232
 
@@ -1747,8 +1753,10 @@
7233
 
 BOOL drop = rc == FAIL_DROP;
7234
 
 uschar *lognl;
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);
7239
 
+
7240
 
+if (where == ACL_WHERE_DATA) what = US"after DATA";
7241
 
+if (where == ACL_WHERE_MIME) what = US"during MIME ACL checks";
7242
 
 
7243
 
 if (drop) rc = FAIL;
7244
 
 
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. */
7248
 
 
7249
 
-if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA)
7250
 
+if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA || where == ACL_WHERE_MIME)
7251
 
   {
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
7257
 
@@ -0,0 +1,338 @@
7258
 
+/*************************************************
7259
 
+*     Exim - an Internet mail transport agent    *
7260
 
+*************************************************/
7261
 
+
7262
 
+/* This file is part of the exiscan-acl content scanner
7263
 
+patch. It is NOT part of the standard exim distribution. */
7264
 
+
7265
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
7266
 
+/* License: GPL */
7267
 
+
7268
 
+/* Code for calling spamassassin's spamd. Called from acl.c. */
7269
 
+
7270
 
+#include "exim.h"
7271
 
+#include "spam.h"
7272
 
+
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] = "";
7278
 
+int spam_ok = 0;
7279
 
+int spam_rc = 0;
7280
 
+
7281
 
+int spam(uschar **listptr) {
7282
 
+  int sep = 0;
7283
 
+  uschar *list = *listptr;
7284
 
+  uschar *user_name;
7285
 
+  uschar user_name_buffer[128];
7286
 
+  unsigned long long mbox_size;
7287
 
+  FILE *mbox_file;
7288
 
+  int spamd_sock;
7289
 
+  uschar spamd_buffer[32600];
7290
 
+  int i, j, offset;
7291
 
+  uschar spamd_version[8];
7292
 
+  uschar spamd_score_char;
7293
 
+  double spamd_threshold, spamd_score;
7294
 
+  int spamd_report_offset;
7295
 
+  uschar *p,*q;
7296
 
+  int override = 0;
7297
 
+  struct sockaddr_un server;
7298
 
+
7299
 
+  /* find the username from the option list */
7300
 
+  if ((user_name = string_nextinlist(&list, &sep,
7301
 
+                                     user_name_buffer,
7302
 
+                                     sizeof(user_name_buffer))) == NULL) {
7303
 
+    /* no username given, this means no scanning should be done */
7304
 
+    return FAIL;
7305
 
+  };
7306
 
+
7307
 
+  /* if username is "0" or "false", do not scan */
7308
 
+  if ( (Ustrcmp(user_name,"0") == 0) ||
7309
 
+       (strcmpic(user_name,US"false") == 0) ) {
7310
 
+    return FAIL;
7311
 
+  };
7312
 
+
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 */
7316
 
+    override = 1;
7317
 
+  };
7318
 
+
7319
 
+  /* if we scanned for this username last time, just return */ 
7320
 
+  if ( spam_ok && ( Ustrcmp(prev_user_name, user_name) == 0 ) ) {
7321
 
+    if (override)
7322
 
+      return OK;
7323
 
+    else
7324
 
+      return spam_rc;
7325
 
+  };
7326
 
+  
7327
 
+  /* make sure the eml mbox file is spooled up */
7328
 
+  mbox_file = spool_mbox(&mbox_size);
7329
 
+  
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");
7334
 
+    return DEFER;
7335
 
+  };
7336
 
+
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];
7347
 
+
7348
 
+    /* Check how many spamd servers we have
7349
 
+       and register their addresses */
7350
 
+    while ((address = string_nextinlist(&spamd_address_list_ptr, &sep,
7351
 
+                                        address_buffer,
7352
 
+                                        sizeof(address_buffer))) != NULL) {
7353
 
+      
7354
 
+      spamd_address_container *this_spamd =
7355
 
+        (spamd_address_container *)store_get(sizeof(spamd_address_container));
7356
 
+      
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);
7361
 
+        continue;
7362
 
+      };
7363
 
+      
7364
 
+      spamd_address_vector[num_servers] = this_spamd;
7365
 
+      num_servers++;
7366
 
+      if (num_servers > 31)
7367
 
+        break;
7368
 
+    };
7369
 
+    
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);
7375
 
+      return DEFER;
7376
 
+    };
7377
 
+
7378
 
+    current_server = start_server = (int)now % num_servers;
7379
 
+
7380
 
+    while (1) {
7381
 
+      
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);
7385
 
+      
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);
7391
 
+        return DEFER; 
7392
 
+      };
7393
 
+      
7394
 
+      if (ip_connect( spamd_sock,
7395
 
+                      AF_INET,
7396
 
+                      spamd_address_vector[current_server]->tcp_addr,
7397
 
+                      spamd_address_vector[current_server]->tcp_port,
7398
 
+                      5 ) > -1) {
7399
 
+        /* connection OK */
7400
 
+        break;
7401
 
+      };
7402
 
+      
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,
7407
 
+         strerror(errno));
7408
 
+      current_server++;
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);
7415
 
+        return DEFER;
7416
 
+      };
7417
 
+    };
7418
 
+
7419
 
+  }
7420
 
+  else {
7421
 
+    /* open the local socket */
7422
 
+
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)",
7426
 
+                strerror(errno));
7427
 
+      fclose(mbox_file);
7428
 
+      return DEFER;
7429
 
+    }
7430
 
+
7431
 
+    server.sun_family = AF_UNIX;
7432
 
+    Ustrcpy(server.sun_path, spamd_address);
7433
 
+
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);
7440
 
+      return DEFER;
7441
 
+    }
7442
 
+
7443
 
+  }
7444
 
+
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",
7449
 
+           user_name,
7450
 
+           mbox_size);
7451
 
+
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);
7459
 
+    return DEFER;
7460
 
+  };
7461
 
+
7462
 
+  /* now send the file */
7463
 
+  do {
7464
 
+    j = fread(spamd_buffer,1,sizeof(spamd_buffer),mbox_file);
7465
 
+    if (j > 0) {
7466
 
+      i = send(spamd_sock,spamd_buffer,j,0);
7467
 
+      if (i != j) {
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);
7472
 
+        return DEFER;
7473
 
+      };
7474
 
+    };
7475
 
+  }
7476
 
+  while (j > 0);
7477
 
+
7478
 
+  fclose(mbox_file);
7479
 
+
7480
 
+  /* we're done sending, close socket for writing */
7481
 
+  shutdown(spamd_sock,SHUT_WR);
7482
 
+  
7483
 
+  /* read spamd response */
7484
 
+  memset(spamd_buffer, 0, sizeof(spamd_buffer));
7485
 
+  offset = 0;
7486
 
+  while((i = ip_recv(spamd_sock,
7487
 
+                     spamd_buffer + offset,
7488
 
+                     sizeof(spamd_buffer) - offset - 1,
7489
 
+                     SPAMD_READ_TIMEOUT)) > 0 ) {
7490
 
+    offset += i;
7491
 
+  }
7492
 
+
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);
7498
 
+    return DEFER;
7499
 
+  }
7500
 
+
7501
 
+  /* reading done */
7502
 
+  close(spamd_sock);
7503
 
+
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 ) {
7507
 
+              
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");
7513
 
+      return DEFER;
7514
 
+    };
7515
 
+  };
7516
 
+
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') {
7522
 
+    /* skip \r */
7523
 
+    if (*p == '\r') {
7524
 
+      p++;
7525
 
+      continue;
7526
 
+    };
7527
 
+    *q = *p;
7528
 
+    q++;
7529
 
+    if (*p == '\n') {
7530
 
+      *q = '\t';
7531
 
+      q++;
7532
 
+      /* eat whitespace */
7533
 
+      while( (*p <= ' ') && (*p != '\0') ) {
7534
 
+        p++;
7535
 
+      };
7536
 
+      p--;
7537
 
+    };
7538
 
+    p++;
7539
 
+  };
7540
 
+  /* NULL-terminate */
7541
 
+  *q = '\0';
7542
 
+  q--;
7543
 
+  /* cut off trailing leftovers */
7544
 
+  while (*q <= ' ') {
7545
 
+    *q = '\0';
7546
 
+    q--;
7547
 
+  };
7548
 
+  spam_report = spam_report_buffer;
7549
 
+
7550
 
+  /* create spam bar */
7551
 
+  spamd_score_char = spamd_score > 0 ? '+' : '-';
7552
 
+  j = abs((int)(spamd_score));
7553
 
+  i = 0;
7554
 
+  if( j != 0 ) {
7555
 
+    while((i < j) && (i <= MAX_SPAM_BAR_CHARS))
7556
 
+       spam_bar_buffer[i++] = spamd_score_char;
7557
 
+  }
7558
 
+  else{
7559
 
+    spam_bar_buffer[0] = '/';
7560
 
+    i = 1;
7561
 
+  }
7562
 
+  spam_bar_buffer[i] = '\0';
7563
 
+  spam_bar = spam_bar_buffer;
7564
 
+
7565
 
+  /* create "float" spam score */
7566
 
+  snprintf(CS spam_score_buffer, sizeof(spam_score_buffer),"%.1f", spamd_score);
7567
 
+  spam_score = spam_score_buffer;
7568
 
+
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;
7573
 
+
7574
 
+  /* compare threshold against score */
7575
 
+  if (spamd_score >= spamd_threshold) {
7576
 
+    /* spam as determined by user's threshold */
7577
 
+    spam_rc = OK;
7578
 
+  }
7579
 
+  else {
7580
 
+    /* not spam */
7581
 
+    spam_rc = FAIL;
7582
 
+  };
7583
 
+  
7584
 
+  /* remember user name and "been here" for it */
7585
 
+  Ustrcpy(prev_user_name, user_name);
7586
 
+  spam_ok = 1;
7587
 
+  
7588
 
+  if (override) {
7589
 
+    /* always return OK, no matter what the score */
7590
 
+    return OK;
7591
 
+  }
7592
 
+  else {
7593
 
+    return spam_rc;
7594
 
+  };
7595
 
+}
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
7599
 
@@ -0,0 +1,30 @@
7600
 
+/*************************************************
7601
 
+*     Exim - an Internet mail transport agent    *
7602
 
+*************************************************/
7603
 
+
7604
 
+/* This file is part of the exiscan-acl content scanner
7605
 
+patch. It is NOT part of the standard exim distribution. */
7606
 
+
7607
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
7608
 
+/* License: GPL */
7609
 
+
7610
 
+/* spam defines */
7611
 
+
7612
 
+/* timeout for reading from spamd */
7613
 
+#define SPAMD_READ_TIMEOUT 3600
7614
 
+
7615
 
+/* maximum length of the spam bar */
7616
 
+#define MAX_SPAM_BAR_CHARS 50
7617
 
+
7618
 
+/* SHUT_WR seems to be undefined on Unixware ? */
7619
 
+#ifndef SHUT_WR
7620
 
+#define SHUT_WR 1
7621
 
+#endif
7622
 
+
7623
 
+typedef struct spamd_address_container {
7624
 
+  uschar tcp_addr[24];
7625
 
+  unsigned int tcp_port;
7626
 
+} spamd_address_container;
7627
 
+
7628
 
+
7629
 
+
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
7633
 
@@ -241,6 +241,7 @@
7634
 
 body_linecount = 0;
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 */
7641
 
@@ -250,6 +251,7 @@
7642
 
 interface_port = 0;
7643
 
 local_error_message = FALSE;
7644
 
 local_scan_data = NULL;
7645
 
+spam_score_int = NULL;
7646
 
 message_linecount = 0;
7647
 
 received_protocol = NULL;
7648
 
 received_count = 0;
7649
 
@@ -266,6 +268,11 @@
7650
 
 sender_set_untrusted = FALSE;
7651
 
 tree_nonrecipients = NULL;
7652
 
 
7653
 
+#ifdef BRIGHTMAIL
7654
 
+bmi_run = 0;
7655
 
+bmi_verdicts = NULL;
7656
 
+#endif
7657
 
+
7658
 
 #ifdef SUPPORT_TLS
7659
 
 tls_certificate_verified = FALSE;
7660
 
 tls_cipher = NULL;
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);
7667
 
+#ifdef BRIGHTMAIL
7668
 
+  else if (Ustrncmp(big_buffer, "-bmi_verdicts ", 14) == 0)
7669
 
+    bmi_verdicts = string_copy(big_buffer + 14);
7670
 
+#endif
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
7677
 
@@ -0,0 +1,196 @@
7678
 
+/*************************************************
7679
 
+*     Exim - an Internet mail transport agent    *
7680
 
+*************************************************/
7681
 
+
7682
 
+/* This file is part of the exiscan-acl content scanner
7683
 
+patch. It is NOT part of the standard exim distribution. */
7684
 
+
7685
 
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-???? */
7686
 
+/* License: GPL */
7687
 
+
7688
 
+/* Code for setting up a MBOX style spool file inside a /scan/<msgid>
7689
 
+sub directory of exim's spool directory. */
7690
 
+
7691
 
+#include "exim.h"
7692
 
+
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;
7698
 
+
7699
 
+int spool_mbox_ok = 0;
7700
 
+uschar spooled_message_id[17];
7701
 
+
7702
 
+/* returns a pointer to the FILE, and puts the size in bytes into mbox_file_size */
7703
 
+
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];
7708
 
+  FILE *mbox_file;
7709
 
+  FILE *data_file = NULL;
7710
 
+  header_line *my_headerlist;
7711
 
+  struct stat statbuf;
7712
 
+  int i,j;
7713
 
+  
7714
 
+  /*
7715
 
+  uschar *received;
7716
 
+  uschar *timestamp;
7717
 
+  */
7718
 
+  
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);
7723
 
+      return NULL;
7724
 
+    };
7725
 
+    
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);
7730
 
+      return NULL;
7731
 
+    };
7732
 
+    
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");
7736
 
+    
7737
 
+    if (mbox_file == NULL) {
7738
 
+      debug_printf("unable to open file for writing: %s\n", mbox_path);
7739
 
+      return NULL;
7740
 
+    };
7741
 
+    
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 */
7744
 
+       
7745
 
+    /* removed for 4.34
7746
 
+    
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);
7753
 
+      }
7754
 
+      else {
7755
 
+        my_received = string_sprintf("%s; %s\n", received, timestamp);
7756
 
+      }
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);
7761
 
+        return NULL;
7762
 
+      };
7763
 
+    };
7764
 
+    
7765
 
+    */
7766
 
+    
7767
 
+    /* write all header lines to mbox file */
7768
 
+    my_headerlist = header_list;
7769
 
+    while (my_headerlist != NULL) {
7770
 
+      
7771
 
+      /* skip deleted headers */
7772
 
+      if (my_headerlist->type == '*') {
7773
 
+        my_headerlist = my_headerlist->next;
7774
 
+        continue;
7775
 
+      };
7776
 
+  
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);
7781
 
+        return NULL;
7782
 
+      };
7783
 
+      
7784
 
+      my_headerlist = my_headerlist->next;
7785
 
+    };
7786
 
+  
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)
7794
 
+        break;
7795
 
+    };
7796
 
+
7797
 
+    fread(data_buffer, 1, 18, data_file);
7798
 
+    
7799
 
+    do {
7800
 
+      j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
7801
 
+      if (j > 0) {
7802
 
+        i = fwrite(data_buffer, 1, j, mbox_file);
7803
 
+        if (i != j) {
7804
 
+          debug_printf("error/short write on writing in: %s", mbox_path);
7805
 
+          fclose(mbox_file);
7806
 
+          fclose(data_file);
7807
 
+          return NULL;
7808
 
+        };
7809
 
+      };
7810
 
+    } while (j > 0);
7811
 
+    
7812
 
+    fclose(data_file);
7813
 
+    fclose(mbox_file);
7814
 
+    Ustrcpy(spooled_message_id, message_id);
7815
 
+    spool_mbox_ok = 1;
7816
 
+  };
7817
 
+
7818
 
+  snprintf(CS mbox_path, 1024, "%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
7819
 
+
7820
 
+  /* get the size of the mbox message */
7821
 
+  stat(CS mbox_path, &statbuf);
7822
 
+  *mbox_file_size = statbuf.st_size;
7823
 
+
7824
 
+  /* open [message_id].eml file for reading */
7825
 
+  mbox_file = Ufopen(mbox_path,"r");
7826
 
+  
7827
 
+  return mbox_file;
7828
 
+}
7829
 
+
7830
 
+/* remove mbox spool file, demimed files and temp directory */
7831
 
+void unspool_mbox(void) {
7832
 
+
7833
 
+  /* reset all exiscan state variables */
7834
 
+  demime_ok = 0;
7835
 
+  demime_errorlevel = 0;
7836
 
+  demime_reason = NULL;
7837
 
+  file_extensions = NULL;
7838
 
+  spam_ok = 0;
7839
 
+  malware_ok = 0;
7840
 
+  
7841
 
+  if (spool_mbox_ok) {
7842
 
+
7843
 
+    spool_mbox_ok = 0;
7844
 
+    
7845
 
+    if (!no_mbox_unspool) {
7846
 
+      uschar mbox_path[1024];
7847
 
+      uschar file_path[1024];
7848
 
+      int n;
7849
 
+      struct dirent *entry;
7850
 
+      DIR *tempdir;
7851
 
+      
7852
 
+      snprintf(CS mbox_path, 1024, "%s/scan/%s", spool_directory, spooled_message_id);
7853
 
+       
7854
 
+       tempdir = opendir(CS mbox_path);
7855
 
+       /* loop thru dir & delete entries */
7856
 
+       n = 0;
7857
 
+       do {
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);
7864
 
+            }; 
7865
 
+       } while (n > -1);
7866
 
+       
7867
 
+       closedir(tempdir);
7868
 
+       
7869
 
+       /* remove directory */
7870
 
+       n = rmdir(CS mbox_path);
7871
 
+    };
7872
 
+  };
7873
 
+}
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");
7884
 
 
7885
 
+#ifdef BRIGHTMAIL
7886
 
+if (bmi_verdicts != NULL) fprintf(f, "-bmi_verdicts %s\n", bmi_verdicts);
7887
 
+#endif
7888
 
+
7889
 
 #ifdef SUPPORT_TLS
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
7895
 
@@ -219,6 +219,9 @@
7896
 
   uschar *driver_name;            /* Must be first */
7897
 
 
7898
 
   uschar *address_data;           /* Arbitrary data */
7899
 
+#ifdef BRIGHTMAIL
7900
 
+  uschar *bmi_rule;               /* Brightmail AntiSpam rule checking */
7901
 
+#endif
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 */
7907
 
 
7908
 
   BOOL    address_test;           /* Use this router when testing addresses */
7909
 
+#ifdef BRIGHTMAIL
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 */
7913
 
+#endif
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
7920
 
@@ -0,0 +1,757 @@
7921
 
+/*************************************************
7922
 
+*     Exim - an Internet mail transport agent    *
7923
 
+*************************************************/
7924
 
+
7925
 
+/* This file is part of the exiscan-acl content scanner
7926
 
+patch. It is NOT part of the standard exim distribution. */
7927
 
+
7928
 
+/* Code for unpacking TNEF containers. Called from demime.c. */
7929
 
+
7930
 
+/***************************************************************************
7931
 
+ * tnef2txt
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.
7935
 
+*
7936
 
+ * 18/10/2001
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.
7940
 
+*
7941
 
+ * Brandon Long (blong@uiuc.edu), April 1997
7942
 
+* 1.0 Version
7943
 
+*   Supports most types, but doesn't decode properties.  Maybe some other
7944
 
+*   time.
7945
 
+*
7946
 
+ * 1.1 Version (7/1/97)
7947
 
+*   Supports saving of attAttachData to a file given by attAttachTitle
7948
 
+*   start of property decoding support
7949
 
+*
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.
7957
 
+*
7958
 
+ * 1.3 Version (7/22/97)
7959
 
+*   Ok, take out the DTR over the stream, now uses read_16.
7960
 
+*
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
 
+***************************************************************************/
7965
 
+
7966
 
+#include <stdio.h>
7967
 
+#include <sys/stat.h>
7968
 
+#include <stdlib.h>
7969
 
+#include <errno.h>
7970
 
+#include <string.h>
7971
 
+#include <netinet/in.h>
7972
 
+#include "tnef.h"
7973
 
+
7974
 
+
7975
 
+#define VERSION "pldtnef/0.0.1"
7976
 
+
7977
 
+int _TNEF_syslogging = 0;
7978
 
+int _TNEF_stderrlogging = 0;
7979
 
+int _TNEF_verbose = 0;
7980
 
+int _TNEF_debug = 0;
7981
 
+
7982
 
+int Verbose = FALSE;
7983
 
+int SaveData = FALSE;
7984
 
+
7985
 
+char _TNEF_path[1024]="";
7986
 
+
7987
 
+uint8 *tnef_home;
7988
 
+uint8 *tnef_limit;
7989
 
+
7990
 
+/*------------------------------------------------------------------------
7991
 
+Procedure:     TNEF_set_path ID:1
7992
 
+Purpose:
7993
 
+Input:
7994
 
+Output:
7995
 
+Errors:
7996
 
+------------------------------------------------------------------------*/
7997
 
+int TNEF_set_path( char *path )
7998
 
+{
7999
 
+       snprintf(_TNEF_path,1023,"%s",path);
8000
 
+
8001
 
+       return 0;
8002
 
+}
8003
 
+
8004
 
+
8005
 
+/*------------------------------------------------------------------------
8006
 
+Procedure:     TNEF_set_verbosity ID:1
8007
 
+Purpose:
8008
 
+Input:
8009
 
+Output:
8010
 
+Errors:
8011
 
+------------------------------------------------------------------------*/
8012
 
+int TNEF_set_verbosity( int level )
8013
 
+{
8014
 
+       _TNEF_verbose = level;
8015
 
+       return _TNEF_verbose;
8016
 
+}
8017
 
+
8018
 
+
8019
 
+
8020
 
+
8021
 
+/*------------------------------------------------------------------------
8022
 
+Procedure:     TNEF_set_debug ID:1
8023
 
+Purpose:
8024
 
+Input:
8025
 
+Output:
8026
 
+Errors:
8027
 
+------------------------------------------------------------------------*/
8028
 
+int TNEF_set_debug( int level )
8029
 
+{
8030
 
+       _TNEF_debug = level;
8031
 
+       TNEF_set_verbosity( level );
8032
 
+       return _TNEF_debug;
8033
 
+}
8034
 
+
8035
 
+
8036
 
+
8037
 
+/*------------------------------------------------------------------------
8038
 
+Procedure:     TNEF_set_syslogging ID:1
8039
 
+Purpose:       Turns on/off the syslog feature for TNEF error messages
8040
 
+Input:
8041
 
+Output:
8042
 
+Errors:
8043
 
+------------------------------------------------------------------------*/
8044
 
+int TNEF_set_syslogging( int level )
8045
 
+{
8046
 
+       _TNEF_syslogging = level;
8047
 
+       return _TNEF_syslogging;
8048
 
+}
8049
 
+
8050
 
+
8051
 
+
8052
 
+
8053
 
+/*------------------------------------------------------------------------
8054
 
+Procedure:     TNEF_set_stderrlogging ID:1
8055
 
+Purpose:       Turns on/off the stderr feature for TNEF error messages
8056
 
+Input:
8057
 
+Output:
8058
 
+Errors:
8059
 
+------------------------------------------------------------------------*/
8060
 
+int TNEF_set_stderrlogging( int level )
8061
 
+{
8062
 
+       _TNEF_stderrlogging = level;
8063
 
+       return _TNEF_stderrlogging;
8064
 
+}
8065
 
+
8066
 
+
8067
 
+/* Some systems don't like to read unaligned data */
8068
 
+/*------------------------------------------------------------------------
8069
 
+Procedure:     read_32 ID:1
8070
 
+Purpose:
8071
 
+Input:
8072
 
+Output:
8073
 
+Errors:
8074
 
+------------------------------------------------------------------------*/
8075
 
+uint32 read_32(uint8 *tsp)
8076
 
+{
8077
 
+       uint8 a,b,c,d;
8078
 
+       uint32 ret;
8079
 
+
8080
 
+       if (tsp+4 > tnef_limit)
8081
 
+       {
8082
 
+               if ((_TNEF_verbose)||(_TNEF_stderrlogging)||(_TNEF_debug)) fprintf(stderr,"TNEF read_32() Attempting to read past end\n");
8083
 
+               return -1;
8084
 
+       }
8085
 
+
8086
 
+       a = *tsp;
8087
 
+       b = *(tsp+1);
8088
 
+       c = *(tsp+2);
8089
 
+       d = *(tsp+3);
8090
 
+
8091
 
+       ret =  long_little_endian(a<<24 | b<<16 | c<<8 | d);
8092
 
+
8093
 
+       return ret;
8094
 
+}
8095
 
+
8096
 
+/*------------------------------------------------------------------------
8097
 
+Procedure:     read_16 ID:1
8098
 
+Purpose:
8099
 
+Input:
8100
 
+Output:
8101
 
+Errors:
8102
 
+------------------------------------------------------------------------*/
8103
 
+uint16 read_16(uint8 *tsp)
8104
 
+{
8105
 
+       uint8 a,b;
8106
 
+       uint16 ret;
8107
 
+
8108
 
+       if (tsp+2 > tnef_limit)
8109
 
+       {
8110
 
+               if ((_TNEF_verbose)||(_TNEF_stderrlogging)||(_TNEF_debug)) fprintf(stderr,"TNEF read_16() Attempting to read past end\n");
8111
 
+               return -1;
8112
 
+       }
8113
 
+
8114
 
+
8115
 
+       a = *tsp;
8116
 
+       b = *(tsp + 1);
8117
 
+
8118
 
+       ret = little_endian(a<<8 | b);
8119
 
+
8120
 
+       return ret;
8121
 
+}
8122
 
+
8123
 
+
8124
 
+
8125
 
+/*------------------------------------------------------------------------
8126
 
+Procedure:     make_string ID:1
8127
 
+Purpose:
8128
 
+Input:
8129
 
+Output:
8130
 
+Errors:
8131
 
+------------------------------------------------------------------------*/
8132
 
+char *make_string(uint8 *tsp, int size)
8133
 
+{
8134
 
+       static char s[256] = "";
8135
 
+       int len = (size>sizeof(s)-1) ? sizeof(s)-1 : size;
8136
 
+
8137
 
+       strncpy(s,(char *)tsp, len);
8138
 
+       s[len] = '\0';
8139
 
+       return s;
8140
 
+}
8141
 
+
8142
 
+
8143
 
+/*------------------------------------------------------------------------
8144
 
+Procedure:     handle_props ID:1
8145
 
+Purpose:
8146
 
+Input:
8147
 
+Output:
8148
 
+Errors:
8149
 
+------------------------------------------------------------------------*/
8150
 
+
8151
 
+int save_attach_data(char *, uint8 *, uint32);
8152
 
+
8153
 
+int handle_props(uint8 *tsp)
8154
 
+{
8155
 
+       int bytes = 0;
8156
 
+       uint32 num_props = 0;
8157
 
+       uint32 x = 0;
8158
 
+
8159
 
+
8160
 
+       num_props = read_32(tsp);
8161
 
+       bytes += sizeof(num_props);
8162
 
+
8163
 
+       while (x < num_props)
8164
 
+       {
8165
 
+               uint32 prop_tag;
8166
 
+               uint32 num;
8167
 
+               char filename[256];
8168
 
+               static int file_num = 0;
8169
 
+
8170
 
+               prop_tag = read_32(tsp+bytes);
8171
 
+               bytes += sizeof(prop_tag);
8172
 
+
8173
 
+               switch (prop_tag & PROP_TYPE_MASK)
8174
 
+               {
8175
 
+               case PT_BINARY:
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)
8181
 
+                       {
8182
 
+                               sprintf (filename, "XAM_%d.rtf", file_num);
8183
 
+                               file_num++;
8184
 
+                               save_attach_data(filename, tsp+bytes, num);
8185
 
+                       }
8186
 
+                       /* num + PAD */
8187
 
+                       bytes += num + ((num % 4) ? (4 - num%4) : 0);
8188
 
+                       break;
8189
 
+               case PT_STRING8:
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);
8196
 
+                       break;
8197
 
+               case PT_UNICODE:
8198
 
+               case PT_OBJECT:
8199
 
+                       break;
8200
 
+               case PT_I2:
8201
 
+                       bytes += 2;
8202
 
+                       break;
8203
 
+               case PT_LONG:
8204
 
+                       bytes += 4;
8205
 
+                       break;
8206
 
+               case PT_R4:
8207
 
+                       bytes += 4;
8208
 
+                       break;
8209
 
+               case PT_DOUBLE:
8210
 
+                       bytes += 8;
8211
 
+                       break;
8212
 
+               case PT_CURRENCY:
8213
 
+               case PT_APPTIME:
8214
 
+               case PT_ERROR:
8215
 
+                       bytes += 4;
8216
 
+                       break;
8217
 
+               case PT_BOOLEAN:
8218
 
+                       bytes += 4;
8219
 
+                       break;
8220
 
+               case PT_I8:
8221
 
+                       bytes += 8;
8222
 
+               case PT_SYSTIME:
8223
 
+                       bytes += 8;
8224
 
+                       break;
8225
 
+               }
8226
 
+               x++;
8227
 
+       }
8228
 
+
8229
 
+       return 0;
8230
 
+}
8231
 
+
8232
 
+
8233
 
+
8234
 
+
8235
 
+/*------------------------------------------------------------------------
8236
 
+Procedure:     save_attach_data ID:1
8237
 
+Purpose:
8238
 
+Input:
8239
 
+Output:
8240
 
+Errors:
8241
 
+------------------------------------------------------------------------*/
8242
 
+int save_attach_data(char *title, uint8 *tsp, uint32 size)
8243
 
+{
8244
 
+       FILE *out;
8245
 
+       char filename[1024];
8246
 
+
8247
 
+       /*
8248
 
+       if ((*tsp +size) > _TNEF_size)
8249
 
+       {
8250
 
+       return -1;
8251
 
+       }
8252
 
+       */
8253
 
+       snprintf(filename,1023,"%s/%s",_TNEF_path,title);
8254
 
+
8255
 
+       out = fopen(filename, "w");
8256
 
+       if (!out)
8257
 
+       {
8258
 
+               if (_TNEF_stderrlogging > 0) fprintf(stderr, "Error openning file %s for writing\n", filename);
8259
 
+               return -1;
8260
 
+       }
8261
 
+
8262
 
+       fwrite(tsp, sizeof(uint8), size, out);
8263
 
+       fclose(out);
8264
 
+       return 0;
8265
 
+}
8266
 
+
8267
 
+
8268
 
+
8269
 
+
8270
 
+/*------------------------------------------------------------------------
8271
 
+Procedure:     default_handler ID:1
8272
 
+Purpose:
8273
 
+Input:
8274
 
+Output:
8275
 
+Errors:
8276
 
+------------------------------------------------------------------------*/
8277
 
+int default_handler(uint32 attribute, uint8 *tsp, uint32 size)
8278
 
+{
8279
 
+       uint16 type = ATT_TYPE(attribute);
8280
 
+
8281
 
+       switch (type) {
8282
 
+       case atpTriples:
8283
 
+               break;
8284
 
+       case atpString:
8285
 
+       case atpText:
8286
 
+               break;
8287
 
+       case atpDate:
8288
 
+               break;
8289
 
+       case atpShort:
8290
 
+               break;
8291
 
+       case atpLong:
8292
 
+               break;
8293
 
+       case atpByte:
8294
 
+               break;
8295
 
+       case atpWord:
8296
 
+               break;
8297
 
+       case atpDword:
8298
 
+               break;
8299
 
+       default:
8300
 
+               break;
8301
 
+       }
8302
 
+       return 0;
8303
 
+
8304
 
+}
8305
 
+
8306
 
+
8307
 
+
8308
 
+
8309
 
+/*------------------------------------------------------------------------
8310
 
+Procedure:     read_attribute ID:1
8311
 
+Purpose:
8312
 
+Input:
8313
 
+Output:
8314
 
+Errors:
8315
 
+------------------------------------------------------------------------*/
8316
 
+int read_attribute(uint8 *tsp)
8317
 
+{
8318
 
+
8319
 
+       int bytes = 0, header = 0;
8320
 
+       uint32 attribute;
8321
 
+       uint8 component = 0;
8322
 
+       uint32 size = 0;
8323
 
+       uint16 checksum = 0;
8324
 
+       static char attach_title[256] = {
8325
 
+               0                               };
8326
 
+       static uint32 attach_size = 0;
8327
 
+       static uint32 attach_loc  = 0;
8328
 
+
8329
 
+       /* What component are we look at? */
8330
 
+ component = *tsp;
8331
 
+
8332
 
+       bytes += sizeof(uint8);
8333
 
+
8334
 
+       /* Read the attributes of this component */
8335
 
+
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);
8340
 
+
8341
 
+       /* Read the size of the information we have to read */
8342
 
+
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);
8347
 
+
8348
 
+       /* The header size equals the sum of all the things we've read
8349
 
+         so far. */
8350
 
+
8351
 
+       header = bytes;
8352
 
+
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.
8358
 
+       */
8359
 
+
8360
 
+       bytes += size;
8361
 
+
8362
 
+       /* Read in the checksum for this component
8363
 
+       
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
8367
 
+  */
8368
 
+
8369
 
+       if ( bytes < 0 ) return -1;
8370
 
+
8371
 
+       /* --END of ammendment. */
8372
 
+
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);
8376
 
+
8377
 
+       if (_TNEF_debug) fprintf(stderr,"Decoding attribute %d\n",attribute);
8378
 
+
8379
 
+       switch (attribute) {
8380
 
+       case attNull:
8381
 
+               default_handler(attribute, tsp+header, size);
8382
 
+               break;
8383
 
+       case attFrom:
8384
 
+               default_handler(attribute, tsp+header, size);
8385
 
+               break;
8386
 
+       case attSubject:
8387
 
+               break;
8388
 
+       case attDateSent:
8389
 
+               break;
8390
 
+       case attDateRecd:
8391
 
+               break;
8392
 
+       case attMessageStatus:
8393
 
+               break;
8394
 
+       case attMessageClass:
8395
 
+               break;
8396
 
+       case attMessageID:
8397
 
+               break;
8398
 
+       case attParentID:
8399
 
+               break;
8400
 
+       case attConversationID:
8401
 
+               break;
8402
 
+       case attBody:
8403
 
+               default_handler(attribute, tsp+header, size);
8404
 
+               break;
8405
 
+       case attPriority:
8406
 
+               break;
8407
 
+       case attAttachData:
8408
 
+               attach_size=size;
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))
8412
 
+                       {
8413
 
+                               if (_TNEF_verbose) fprintf(stdout,"Decoding %s\n", attach_title);
8414
 
+                       }
8415
 
+                       else
8416
 
+                           {
8417
 
+                               if (_TNEF_syslogging > 0) syslog(1,"TNEF: Error saving attachment %s\n",attach_title);
8418
 
+                       }
8419
 
+               }
8420
 
+               break;
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))
8425
 
+                       {
8426
 
+                               if (_TNEF_verbose) fprintf(stdout,"Decoding %s\n", attach_title);
8427
 
+                       }
8428
 
+                       else
8429
 
+                           {
8430
 
+                               if (_TNEF_syslogging > 0) syslog(1,"TNEF: Error saving attachment %s\n",attach_title);
8431
 
+                       }
8432
 
+               }
8433
 
+               break;
8434
 
+       case attAttachMetaFile:
8435
 
+               default_handler(attribute, tsp+header, size);
8436
 
+               break;
8437
 
+       case attAttachCreateDate:
8438
 
+               break;
8439
 
+       case attAttachModifyDate:
8440
 
+               break;
8441
 
+       case attDateModified:
8442
 
+               break;
8443
 
+       case attAttachTransportFilename:
8444
 
+               default_handler(attribute, tsp+header, size);
8445
 
+               break;
8446
 
+       case attAttachRenddata:
8447
 
+               attach_title[0]=0;
8448
 
+               attach_size=0;
8449
 
+               attach_loc=0;
8450
 
+               default_handler(attribute, tsp+header, size);
8451
 
+               break;
8452
 
+       case attMAPIProps:
8453
 
+               handle_props(tsp+header);
8454
 
+               break;
8455
 
+       case attRecipTable:
8456
 
+               default_handler(attribute, tsp+header, size);
8457
 
+               break;
8458
 
+       case attAttachment:
8459
 
+               default_handler(attribute, tsp+header, size);
8460
 
+               break;
8461
 
+       case attTnefVersion:
8462
 
+               {
8463
 
+                       uint32 version;
8464
 
+                       version = read_32(tsp+header);
8465
 
+                       if (version == -1) return -1;
8466
 
+               }
8467
 
+               break;
8468
 
+       case attOemCodepage:
8469
 
+               default_handler(attribute, tsp+header, size);
8470
 
+               break;
8471
 
+       case attOriginalMessageClass:
8472
 
+               break;
8473
 
+       case attOwner:
8474
 
+               default_handler(attribute, tsp+header, size);
8475
 
+               break;
8476
 
+       case attSentFor:
8477
 
+               default_handler(attribute, tsp+header, size);
8478
 
+               break;
8479
 
+       case attDelegate:
8480
 
+               default_handler(attribute, tsp+header, size);
8481
 
+               break;
8482
 
+       case attDateStart:
8483
 
+               break;
8484
 
+       case attDateEnd:
8485
 
+               break;
8486
 
+       case attAidOwner:
8487
 
+               default_handler(attribute, tsp+header, size);
8488
 
+               break;
8489
 
+       case attRequestRes:
8490
 
+               default_handler(attribute, tsp+header, size);
8491
 
+               break;
8492
 
+       default:
8493
 
+               default_handler(attribute, tsp+header, size);
8494
 
+               break;
8495
 
+       }
8496
 
+       return bytes;
8497
 
+
8498
 
+}
8499
 
+
8500
 
+
8501
 
+
8502
 
+
8503
 
+/*------------------------------------------------------------------------
8504
 
+Procedure:     decode_tnef ID:1
8505
 
+Purpose:
8506
 
+Input:
8507
 
+Output:
8508
 
+Errors:
8509
 
+------------------------------------------------------------------------*/
8510
 
+int TNEF_decode_tnef(uint8 *tnef_stream, int size)
8511
 
+{
8512
 
+
8513
 
+       int ra_response;
8514
 
+       uint8 *tsp;
8515
 
+
8516
 
+       if (_TNEF_debug) fprintf(stderr,"TNEF_decode_tnef: Start. Size = %d\n",size);
8517
 
+
8518
 
+       if (size < 4)
8519
 
+       {
8520
 
+               if (_TNEF_debug) fprintf(stderr,"TNEF_decode_tnef: Skipping short file\n");
8521
 
+               return 0;
8522
 
+       }
8523
 
+
8524
 
+       /* TSP == TNEF Stream Pointer (well memory block actually!)
8525
 
+       */
8526
 
+       tsp = tnef_stream;
8527
 
+
8528
 
+       /* Read in the signature of this TNEF
8529
 
+       */
8530
 
+       if (TNEF_SIGNATURE == read_32(tsp))
8531
 
+       {
8532
 
+               if (_TNEF_debug) fprintf(stderr,"TNEF signature is good\n");
8533
 
+       }
8534
 
+       else
8535
 
+           {
8536
 
+               if (_TNEF_stderrlogging > 0) fprintf(stderr,"TNEF_decode_tnef: Bad TNEF signature, expecting %x got %lx\n",TNEF_SIGNATURE,read_32(tsp));
8537
 
+       }
8538
 
+
8539
 
+       /* Move tsp pointer along
8540
 
+       */
8541
 
+       tsp += sizeof(TNEF_SIGNATURE);
8542
 
+
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.
8546
 
+       */
8547
 
+       if (tsp + sizeof(uint16) - tnef_stream > size)
8548
 
+       {
8549
 
+               if (_TNEF_debug) fprintf(stderr,"TNEF_decode_tnef: Skipping short file\n");
8550
 
+               return 0;
8551
 
+       }
8552
 
+
8553
 
+       if (_TNEF_debug)  fprintf(stderr,"TNEF Attach Key: %x\n",read_16(tsp));
8554
 
+       /* Move tsp pointer along
8555
 
+       */
8556
 
+       tsp += sizeof(uint16);
8557
 
+
8558
 
+       /* While we still have more bytes to process,
8559
 
+                       go through entire memory block and extract
8560
 
+                       all the required attributes and files
8561
 
+       */
8562
 
+       if (_TNEF_debug) fprintf(stderr,"TNEF - Commence reading attributes\n");
8563
 
+       while ((tsp - tnef_stream) < size)
8564
 
+       {
8565
 
+               if (_TNEF_debug) fprintf(stderr,"Offset = %d\n",tsp -tnef_home);
8566
 
+               ra_response = read_attribute(tsp);
8567
 
+               if ( ra_response > 0 )
8568
 
+               {
8569
 
+                       tsp += ra_response;
8570
 
+               } else {
8571
 
+
8572
 
+                       /* Must find out /WHY/ this happens, and, how to rectify the issue. */
8573
 
+
8574
 
+                       tsp++;
8575
 
+                       if (_TNEF_debug) fprintf(stderr,"TNEF - Attempting to read attribute resulted in a sub-zero response, ending decoding to be safe\n");
8576
 
+                       break;
8577
 
+               }
8578
 
+       }
8579
 
+
8580
 
+       if (_TNEF_debug) fprintf(stderr,"TNEF - DONE.\n");
8581
 
+
8582
 
+       return 0;
8583
 
+}
8584
 
+
8585
 
+
8586
 
+
8587
 
+
8588
 
+
8589
 
+
8590
 
+/*------------------------------------------------------------------------
8591
 
+Procedure:     TNEF_main ID:1
8592
 
+Purpose:       Decodes a given TNEF encoded file
8593
 
+Input:
8594
 
+Output:
8595
 
+Errors:
8596
 
+------------------------------------------------------------------------*/
8597
 
+int TNEF_main( char *filename )
8598
 
+{
8599
 
+       FILE *fp;
8600
 
+       struct stat sb;
8601
 
+       uint8 *tnef_stream;
8602
 
+       int size, nread;
8603
 
+
8604
 
+       if (_TNEF_debug) fprintf(stderr,"TNEF_main: Start, decoding %s\n",filename);
8605
 
+
8606
 
+       SaveData = TRUE;
8607
 
+
8608
 
+       /* Test to see if the file actually exists
8609
 
+       */
8610
 
+       if (stat(filename,&sb) == -1)
8611
 
+       {
8612
 
+               if (_TNEF_stderrlogging > 0) fprintf(stderr,"Error stating file %s (%s)\n", filename,strerror(errno));
8613
 
+               return -1;
8614
 
+       }
8615
 
+
8616
 
+       /* Get the filesize */
8617
 
+       
8618
 
+       size = sb.st_size;
8619
 
+
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
8623
 
+       */
8624
 
+       
8625
 
+       tnef_home = tnef_stream = (uint8 *)malloc(size);
8626
 
+       tnef_limit = tnef_home +size;
8627
 
+
8628
 
+       /* If we were unable to allocate enough memory, then we
8629
 
+          should report this */
8630
 
+          
8631
 
+       if (tnef_stream == NULL)
8632
 
+       {
8633
 
+               if (_TNEF_stderrlogging > 0)  fprintf(stderr,"Error allocating %d bytes for loading file (%s)\n", size,strerror(errno));
8634
 
+               return -1;
8635
 
+       }
8636
 
+
8637
 
+       /* Attempt to open up the TNEF encoded file... if it fails
8638
 
+               then report the failed condition to syslog */
8639
 
+       
8640
 
+       if ((fp = fopen(filename,"r")) == NULL)
8641
 
+       {
8642
 
+               if (_TNEF_stderrlogging > 0)  fprintf(stderr,"Error opening file %s for reading (%s)\n", filename,strerror(errno));
8643
 
+               return -1;
8644
 
+       }
8645
 
+
8646
 
+       /* Attempt to read in the entire file */
8647
 
+       
8648
 
+       nread = fread(tnef_stream, sizeof(uint8), size, fp);
8649
 
+
8650
 
+       if (_TNEF_debug) fprintf(stderr,"TNEF: Read %d bytes\n",nread);
8651
 
+
8652
 
+       /* If we did not read in all the bytes, then let syslogs know! */
8653
 
+       
8654
 
+       if (nread < size)
8655
 
+       {
8656
 
+               return -1;
8657
 
+       }
8658
 
+
8659
 
+       /* Close the file */
8660
 
+       
8661
 
+       fclose(fp);
8662
 
+
8663
 
+       /* Proceed to decode the file */
8664
 
+       
8665
 
+       TNEF_decode_tnef(tnef_stream,size);
8666
 
+
8667
 
+
8668
 
+       if (_TNEF_debug) fprintf(stderr,"TNEF - finished decoding.\n");
8669
 
+
8670
 
+       return 0;
8671
 
+}
8672
 
+
8673
 
+
8674
 
+/* --------------------------END. */
8675
 
+
8676
 
+
8677
 
+
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
8681
 
@@ -0,0 +1,1841 @@
8682
 
+/*************************************************
8683
 
+*     Exim - an Internet mail transport agent    *
8684
 
+*************************************************/
8685
 
+
8686
 
+/* This file is part of the exiscan-acl content scanner
8687
 
+patch. It is NOT part of the standard exim distribution. */
8688
 
+
8689
 
+/***************************************************************************
8690
 
+ *
8691
 
+ * config.h for tnef decoder by Brandon Long
8692
 
+ * Based on config.h from S3MOD by Dan Marks and David Jeske
8693
 
+ *
8694
 
+ * (C) 1994,1995 By Daniel Marks and David Jeske
8695
 
+ *
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.
8699
 
+ *
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.
8704
 
+ *                                                 
8705
 
+ ***************************************************************************
8706
 
+ *
8707
 
+ * config.h - compile time configuration options and system specific defines
8708
 
+ *
8709
 
+ */
8710
 
+
8711
 
+/* 2003-02-03 Merged all TNEF and MAPI related headers in this file to reduce
8712
 
+   clutter
8713
 
+   - Tom Kistner
8714
 
+*/
8715
 
+
8716
 
+#include <exim.h>
8717
 
+
8718
 
+#ifndef _CONFIG_H
8719
 
+#define _CONFIG_H 1
8720
 
+
8721
 
+/***************************************************************************/
8722
 
+/* The following are system specific settings */
8723
 
+/***************************************************************************/
8724
 
+
8725
 
+#if defined(SUN)
8726
 
+#define BIT_32
8727
 
+#define ___TNEF_BYTE_ORDER 4321
8728
 
+#undef NEAR_FAR_PTR
8729
 
+
8730
 
+#elif defined (HPUX)
8731
 
+#define BIT_32
8732
 
+#define ___TNEF_BYTE_ORDER 4321
8733
 
+#undef NEAR_FAR_PTR
8734
 
+
8735
 
+#elif defined(DEC)
8736
 
+#undef NEAR_FAR_PTR
8737
 
+
8738
 
+#elif defined(__sgi)
8739
 
+#define BIT_32
8740
 
+#define ___TNEF_BYTE_ORDER 4321
8741
 
+#undef NEAR_FAR_PTR
8742
 
+
8743
 
+#elif defined(AIX)
8744
 
+#undef NEAR_FAR_PTR
8745
 
+#define ___TNEF_BYTE_ORDER 4321
8746
 
+#define BIT_32
8747
 
+
8748
 
+#elif defined(LINUX)
8749
 
+#define BIT_32
8750
 
+#undef NEAR_FAR_PTR
8751
 
+
8752
 
+#elif defined(MSDOS)
8753
 
+#define NEAR_FAR_PTR
8754
 
+#undef BIT_32
8755
 
+
8756
 
+#else
8757
 
+#undef NEAR_FAR_PTR
8758
 
+#define BIT_32
8759
 
+
8760
 
+
8761
 
+#endif /* OS/MACH TYPE */
8762
 
+
8763
 
+/***************************************************************************/
8764
 
+/* 16/32 Bit and Byte Order hacks */
8765
 
+/***************************************************************************/
8766
 
+
8767
 
+#ifdef BIT_32
8768
 
+typedef short int int16;
8769
 
+typedef unsigned short int uint16;
8770
 
+typedef int int32;
8771
 
+typedef unsigned int uint32;
8772
 
+/* typedef char int8; */
8773
 
+typedef unsigned char uint8;
8774
 
+#else
8775
 
+typedef int int16;
8776
 
+typedef unsigned int uint16;
8777
 
+typedef long int int32;
8778
 
+typedef unsigned long int uint32;
8779
 
+typedef char int8;
8780
 
+typedef unsigned char uint8;
8781
 
+#endif /* BIT_32 */
8782
 
+
8783
 
+#ifndef WIN32_TYPES
8784
 
+#define ULONG uint32
8785
 
+#define SCODE uint32
8786
 
+#define FAR
8787
 
+#define LPVOID void *
8788
 
+#define WORD uint16
8789
 
+#define DWORD uint32
8790
 
+#define LONG int32
8791
 
+#define BYTE uint8
8792
 
+#endif /* !WIN32_TYPES */
8793
 
+
8794
 
+#define endian_switch(x) (((((uint16)(x)) & 0xFF00) >> 8) | \
8795
 
+                         ((((uint16)(x)) & 0xFF) << 8))
8796
 
+
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))
8801
 
+
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))
8807
 
+#else
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 */
8813
 
+
8814
 
+#ifndef TRUE
8815
 
+#define TRUE 1
8816
 
+#endif
8817
 
+#ifndef FALSE
8818
 
+#define FALSE 0
8819
 
+#endif
8820
 
+
8821
 
+
8822
 
+#endif /* _CONFIG_H */
8823
 
+/*
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.
8829
 
+ *
8830
 
+ *  T N E F . H
8831
 
+ *
8832
 
+ *
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.
8838
 
+ *
8839
 
+ *  Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
8840
 
+ */
8841
 
+
8842
 
+#ifndef TNEF_H
8843
 
+#define TNEF_H
8844
 
+
8845
 
+#ifdef __cplusplus
8846
 
+extern "C" {
8847
 
+#endif
8848
 
+
8849
 
+
8850
 
+#ifndef BEGIN_INTERFACE
8851
 
+#define BEGIN_INTERFACE
8852
 
+#endif
8853
 
+
8854
 
+#ifndef MAPI_DIM
8855
 
+#define MAPI_DIM 1
8856
 
+#endif
8857
 
+
8858
 
+#define TNTNoffsetof(s,m) (unsigned long)&(((s *)0)->m)
8859
 
+
8860
 
+/* ------------------------------------ */
8861
 
+/* TNEF Problem and TNEF Problem Arrays */
8862
 
+/* ------------------------------------ */
8863
 
+
8864
 
+typedef struct _STnefProblem
8865
 
+{
8866
 
+    ULONG   ulComponent;
8867
 
+    ULONG   ulAttribute;
8868
 
+    ULONG   ulPropTag;
8869
 
+    SCODE   scode;
8870
 
+} STnefProblem;
8871
 
+
8872
 
+typedef struct _STnefProblemArray
8873
 
+{
8874
 
+    ULONG           cProblem;
8875
 
+    STnefProblem    aProblem[MAPI_DIM];
8876
 
+} STnefProblemArray, FAR * LPSTnefProblemArray;
8877
 
+
8878
 
+#if 0
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)))
8884
 
+#endif
8885
 
+
8886
 
+/* Pointers to TNEF Interface ---------------------------------------- */
8887
 
+
8888
 
+#if 0
8889
 
+DECLARE_MAPI_INTERFACE_PTR(ITnef, LPITNEF);
8890
 
+#endif
8891
 
+
8892
 
+/*  OpenTNEFStream */
8893
 
+
8894
 
+#define TNEF_DECODE                 ((ULONG) 0)
8895
 
+#define TNEF_ENCODE                 ((ULONG) 2)
8896
 
+
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)
8901
 
+
8902
 
+/*  AddProps, ExtractProps */
8903
 
+
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)
8910
 
+
8911
 
+/*  FinishComponent */
8912
 
+
8913
 
+#define TNEF_COMPONENT_MESSAGE      ((ULONG) 0x00001000)
8914
 
+#define TNEF_COMPONENT_ATTACHMENT   ((ULONG) 0x00002000)
8915
 
+
8916
 
+#if 0
8917
 
+#define MAPI_ITNEF_METHODS(IPURE)                                       \
8918
 
+    MAPIMETHOD(AddProps)                                                \
8919
 
+        (THIS_  ULONG                       ulFlags,                    \
8920
 
+                ULONG                       ulElemID,                   \
8921
 
+                LPVOID                      lpvData,                    \
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,                  \
8933
 
+                ULONG                       ulFlags,                    \
8934
 
+                LPSTREAM FAR *              lppStream) IPURE;           \
8935
 
+    MAPIMETHOD(SetProps)                                                \
8936
 
+        (THIS_  ULONG                       ulFlags,                    \
8937
 
+                ULONG                       ulElemID,                   \
8938
 
+                ULONG                       cValues,                    \
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;          \
8950
 
+
8951
 
+#undef       INTERFACE
8952
 
+#define      INTERFACE  ITnef
8953
 
+DECLARE_MAPI_INTERFACE_(ITnef, IUnknown)
8954
 
+{
8955
 
+    BEGIN_INTERFACE
8956
 
+    MAPI_IUNKNOWN_METHODS(PURE)
8957
 
+    MAPI_ITNEF_METHODS(PURE)
8958
 
+};
8959
 
+
8960
 
+STDMETHODIMP OpenTnefStream(
8961
 
+    LPVOID              lpvSupport,
8962
 
+    LPSTREAM            lpStream,
8963
 
+    LPTSTR              lpszStreamName,
8964
 
+    ULONG               ulFlags,
8965
 
+    LPMESSAGE           lpMessage,
8966
 
+    WORD                wKeyVal,
8967
 
+    LPITNEF FAR *       lppTNEF);
8968
 
+
8969
 
+typedef HRESULT (STDMETHODCALLTYPE FAR * LPOPENTNEFSTREAM) (
8970
 
+    LPVOID              lpvSupport,
8971
 
+    LPSTREAM            lpStream,
8972
 
+    LPTSTR              lpszStreamName,
8973
 
+    ULONG               ulFlags,
8974
 
+    LPMESSAGE           lpMessage,
8975
 
+    WORD                wKeyVal,
8976
 
+    LPITNEF FAR *       lppTNEF);
8977
 
+
8978
 
+STDMETHODIMP OpenTnefStreamEx(
8979
 
+    LPVOID              lpvSupport,
8980
 
+    LPSTREAM            lpStream,
8981
 
+    LPTSTR              lpszStreamName,
8982
 
+    ULONG               ulFlags,
8983
 
+    LPMESSAGE           lpMessage,
8984
 
+    WORD                wKeyVal,
8985
 
+    LPADRBOOK           lpAdressBook,
8986
 
+    LPITNEF FAR *       lppTNEF);
8987
 
+
8988
 
+typedef HRESULT (STDMETHODCALLTYPE FAR * LPOPENTNEFSTREAMEX) (
8989
 
+    LPVOID              lpvSupport,
8990
 
+    LPSTREAM            lpStream,
8991
 
+    LPTSTR              lpszStreamName,
8992
 
+    ULONG               ulFlags,
8993
 
+    LPMESSAGE           lpMessage,
8994
 
+    WORD                wKeyVal,
8995
 
+    LPADRBOOK           lpAdressBook,
8996
 
+    LPITNEF FAR *       lppTNEF);
8997
 
+
8998
 
+STDMETHODIMP GetTnefStreamCodepage (
8999
 
+    LPSTREAM            lpStream,
9000
 
+    ULONG FAR *         lpulCodepage,
9001
 
+    ULONG FAR *         lpulSubCodepage);
9002
 
+
9003
 
+typedef HRESULT (STDMETHODCALLTYPE FAR * LPGETTNEFSTREAMCODEPAGE) (
9004
 
+    LPSTREAM            lpStream,
9005
 
+    ULONG FAR *         lpulCodepage,
9006
 
+    ULONG FAR *         lpulSubCodepage);
9007
 
+
9008
 
+#define OPENTNEFSTREAM "OpenTnefStream"
9009
 
+#define OPENTNEFSTREAMEX "OpenTnefStreamEx"
9010
 
+#define GETTNEFSTREAMCODEPAGE "GetTnefStreamCodePage"
9011
 
+#endif
9012
 
+
9013
 
+/* -------------------------- */
9014
 
+/* TNEF Signature and Version */
9015
 
+/* -------------------------- */
9016
 
+
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))
9020
 
+
9021
 
+
9022
 
+/* ------------------------------------------- */
9023
 
+/* TNEF Down-level Attachment Types/Structures */
9024
 
+/* ------------------------------------------- */
9025
 
+
9026
 
+typedef WORD ATYP;
9027
 
+enum { atypNull, atypFile, atypOle, atypPicture, atypMax };
9028
 
+
9029
 
+#define MAC_BINARY  ((DWORD) 0x00000001)
9030
 
+
9031
 
+typedef struct _renddata
9032
 
+{
9033
 
+    ATYP    atyp;
9034
 
+    ULONG   ulPosition;
9035
 
+    WORD    dxWidth;
9036
 
+    WORD    dyHeight;
9037
 
+    DWORD   dwFlags;
9038
 
+
9039
 
+} RENDDATA, *PRENDDATA;
9040
 
+
9041
 
+/* ----------------------------------- */
9042
 
+/* TNEF Down-level Date/Time Structure */
9043
 
+/* ----------------------------------- */
9044
 
+
9045
 
+typedef struct _dtr
9046
 
+{
9047
 
+    WORD    wYear;
9048
 
+    WORD    wMonth;
9049
 
+    WORD    wDay;
9050
 
+    WORD    wHour;
9051
 
+    WORD    wMinute;
9052
 
+    WORD    wSecond;
9053
 
+    WORD    wDayOfWeek;
9054
 
+
9055
 
+} DTR;
9056
 
+
9057
 
+
9058
 
+/* ----------------------------- */
9059
 
+/* TNEF Down-level Message Flags */
9060
 
+/* ----------------------------- */
9061
 
+
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)
9068
 
+
9069
 
+
9070
 
+/* ----------------------------------------- */
9071
 
+/* TNEF Down-level Triple Address Structures */
9072
 
+/* ----------------------------------------- */
9073
 
+
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
9085
 
+{
9086
 
+    WORD    trpid;
9087
 
+    WORD    cbgrtrp;
9088
 
+    WORD    cch;
9089
 
+    WORD    cbRgb;
9090
 
+
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)))
9096
 
+
9097
 
+typedef DWORD XTYPE;
9098
 
+#define xtypeUnknown    ((XTYPE) 0)
9099
 
+#define xtypeInternet   ((XTYPE) 6)
9100
 
+
9101
 
+#define cbDisplayName   41
9102
 
+#define cbEmailName     11
9103
 
+#define cbSeverName     12
9104
 
+typedef struct _ADDR_ALIAS
9105
 
+{
9106
 
+    char    rgchName[cbDisplayName];
9107
 
+    char    rgchEName[cbEmailName];
9108
 
+    char    rgchSrvr[cbSeverName];
9109
 
+    ULONG   dibDetail;
9110
 
+    WORD    type;
9111
 
+
9112
 
+} ADDRALIAS, FAR * LPADDRALIAS;
9113
 
+#define cbALIAS sizeof(ALIAS)
9114
 
+
9115
 
+#define cbTYPE              16
9116
 
+#define cbMaxIdData         200
9117
 
+typedef struct _NSID
9118
 
+{
9119
 
+    DWORD   dwSize;
9120
 
+    unsigned char   uchType[cbTYPE];
9121
 
+    XTYPE   xtype;
9122
 
+    LONG    lTime;
9123
 
+
9124
 
+    union
9125
 
+    {
9126
 
+        ADDRALIAS   alias;
9127
 
+        char        rgchInterNet[1];
9128
 
+
9129
 
+    } address;
9130
 
+
9131
 
+} NSID, * LPNSID;
9132
 
+#define cbNSID sizeof(NSID)
9133
 
+
9134
 
+
9135
 
+/* -------------------------- */
9136
 
+/* TNEF Down-level Priorities */
9137
 
+/* -------------------------- */
9138
 
+
9139
 
+#define prioLow     3
9140
 
+#define prioNorm    2
9141
 
+#define prioHigh    1
9142
 
+
9143
 
+
9144
 
+/* ------------------------------------- */
9145
 
+/* TNEF Down-level Attributes/Properties */
9146
 
+/* ------------------------------------- */
9147
 
+
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)
9158
 
+
9159
 
+#define LVL_MESSAGE     ((BYTE) 0x01)
9160
 
+#define LVL_ATTACHMENT  ((BYTE) 0x02)
9161
 
+
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)))
9165
 
+
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 */
9192
 
+
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 */
9201
 
+
9202
 
+#ifdef __cplusplus
9203
 
+}
9204
 
+#endif
9205
 
+
9206
 
+#endif  /*  defined TNEF_H */
9207
 
+/*
9208
 
+ *  M A P I D E F S . H
9209
 
+ *
9210
 
+ *  Definitions used by MAPI clients and service providers.
9211
 
+ *
9212
 
+ *  Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
9213
 
+ */
9214
 
+
9215
 
+#ifndef MAPIDEFS_H
9216
 
+#define MAPIDEFS_H
9217
 
+
9218
 
+
9219
 
+/* Array dimension for structures with variable-sized arrays at the end. */
9220
 
+
9221
 
+/* Simple data types */
9222
 
+
9223
 
+
9224
 
+typedef WORD                WCHAR;
9225
 
+
9226
 
+#ifdef UNICODE
9227
 
+typedef WCHAR               TCHAR;
9228
 
+#else
9229
 
+typedef char                TCHAR;
9230
 
+#endif
9231
 
+
9232
 
+typedef WCHAR *         LPWSTR;
9233
 
+typedef const WCHAR *   LPCWSTR;
9234
 
+typedef TCHAR *         LPTSTR;
9235
 
+typedef const TCHAR *   LPCTSTR;
9236
 
+typedef BYTE *          LPBYTE;
9237
 
+
9238
 
+typedef ULONG *         LPULONG;
9239
 
+
9240
 
+#ifndef __LHANDLE
9241
 
+#define __LHANDLE
9242
 
+typedef unsigned long   LHANDLE, * LPLHANDLE;
9243
 
+#endif
9244
 
+
9245
 
+#if !defined(_WINBASE_) && !defined(_FILETIME_)
9246
 
+#define _FILETIME_
9247
 
+typedef struct _FILETIME
9248
 
+{
9249
 
+    DWORD dwLowDateTime;
9250
 
+    DWORD dwHighDateTime;
9251
 
+} FILETIME, * LPFILETIME;
9252
 
+#endif
9253
 
+
9254
 
+/*
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.
9261
 
+ */
9262
 
+
9263
 
+#define MAPI_MODIFY             ((ULONG) 0x00000001)
9264
 
+
9265
 
+/*
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
9269
 
+ *  contents tables
9270
 
+ */
9271
 
+
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)
9278
 
+
9279
 
+/*
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.
9283
 
+ *
9284
 
+ *  The value fMapiUnicode can be used as the 'normal' value for
9285
 
+ *  that bit, given the application's default character set.
9286
 
+ */
9287
 
+
9288
 
+#define MAPI_UNICODE            ((ULONG) 0x80000000)
9289
 
+
9290
 
+#ifdef UNICODE
9291
 
+#define fMapiUnicode            MAPI_UNICODE
9292
 
+#else
9293
 
+#define fMapiUnicode            0
9294
 
+#endif
9295
 
+
9296
 
+/* successful HRESULT */
9297
 
+#define hrSuccess               0
9298
 
+
9299
 
+
9300
 
+
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       */
9311
 
+#endif
9312
 
+
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
9319
 
+
9320
 
+/* Bit definitions for abFlags[1] of ENTRYID */
9321
 
+#define MAPI_COMPOUND           0x80
9322
 
+
9323
 
+/* ENTRYID */
9324
 
+typedef struct
9325
 
+{
9326
 
+    BYTE    abFlags[4];
9327
 
+    BYTE    ab[MAPI_DIM];
9328
 
+} ENTRYID, *LPENTRYID;
9329
 
+
9330
 
+#define CbNewENTRYID(_cb)       (offsetof(ENTRYID,ab) + (_cb))
9331
 
+#define CbENTRYID(_cb)          (offsetof(ENTRYID,ab) + (_cb))
9332
 
+
9333
 
+/* Byte-order-independent version of GUID (world-unique identifier) */
9334
 
+typedef struct _MAPIUID
9335
 
+{
9336
 
+    BYTE ab[16];
9337
 
+} MAPIUID, * LPMAPIUID;
9338
 
+
9339
 
+/* Note:  need to include C run-times (memory.h) to use this macro */
9340
 
+
9341
 
+#define IsEqualMAPIUID(lpuid1, lpuid2)  (!memcmp(lpuid1, lpuid2, sizeof(MAPIUID)))
9342
 
+
9343
 
+/*
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.
9348
 
+ */
9349
 
+
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
9353
 
+
9354
 
+/* Object type */
9355
 
+
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 */
9368
 
+
9369
 
+
9370
 
+/*
9371
 
+ *  Maximum length of profile names and passwords, not including
9372
 
+ *  the null termination character.
9373
 
+ */
9374
 
+#ifndef cchProfileNameMax
9375
 
+#define cchProfileNameMax   64
9376
 
+#define cchProfilePassMax   64
9377
 
+#endif
9378
 
+
9379
 
+
9380
 
+/* Property Types */
9381
 
+
9382
 
+#define MV_FLAG         0x1000          /* Multi-value flag */
9383
 
+
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. */
9402
 
+
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
9409
 
+
9410
 
+/*
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.
9414
 
+ *
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.
9418
 
+ */
9419
 
+
9420
 
+#ifdef  UNICODE
9421
 
+#define PT_TSTRING          PT_UNICODE
9422
 
+#define PT_MV_TSTRING       (MV_FLAG|PT_UNICODE)
9423
 
+#define LPSZ                lpszW
9424
 
+#define LPPSZ               lppszW
9425
 
+#define MVSZ                MVszW
9426
 
+#else
9427
 
+#define PT_TSTRING          PT_STRING8
9428
 
+#define PT_MV_TSTRING       (MV_FLAG|PT_STRING8)
9429
 
+#define LPSZ                lpszA
9430
 
+#define LPPSZ               lppszA
9431
 
+#define MVSZ                MVszA
9432
 
+#endif
9433
 
+
9434
 
+
9435
 
+/* Property Tags
9436
 
+ *
9437
 
+ * By convention, MAPI never uses 0 or FFFF as a property ID.
9438
 
+ * Use as null values, initializers, sentinels, or what have you.
9439
 
+ */
9440
 
+
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)
9448
 
+#if 0
9449
 
+#define CHANGE_PROP_TYPE(ulPropTag, ulPropType) \
9450
 
+                        (((ULONG)0xFFFF0000 & ulPropTag) | ulPropType)
9451
 
+#endif
9452
 
+
9453
 
+
9454
 
+/* Multi-valued Property Types */
9455
 
+
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)
9468
 
+
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
9475
 
+
9476
 
+/*
9477
 
+ *  Property type reserved bits
9478
 
+ *
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.
9482
 
+ */
9483
 
+
9484
 
+#define MV_INSTANCE     0x2000
9485
 
+#define MVI_FLAG        (MV_FLAG | MV_INSTANCE)
9486
 
+#define MVI_PROP(tag)   ((tag) | MVI_FLAG)
9487
 
+
9488
 
+
9489
 
+
9490
 
+#endif /* MAPIDEFS_H */
9491
 
+/*
9492
 
+ *  M A P I T A G S . H
9493
 
+ *
9494
 
+ *  Property tag definitions for standard properties of MAPI
9495
 
+ *  objects.
9496
 
+ *
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:
9500
 
+ *
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
9507
 
+ *
9508
 
+ *  3000    3FFF    MAPI_defined property (usually not message or recipient)
9509
 
+ *
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
9516
 
+ *                  property
9517
 
+ *
9518
 
+ *  8000    FFFE    User-defined Name-to-id mapped property
9519
 
+ *
9520
 
+ *  The 3000-3FFF range is further subdivided as follows:
9521
 
+ *
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
9533
 
+ *
9534
 
+ *  Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
9535
 
+ */
9536
 
+
9537
 
+#ifndef MAPITAGS_H
9538
 
+#define MAPITAGS_H
9539
 
+
9540
 
+/* Determine if a property is transmittable. */
9541
 
+
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)))
9547
 
+
9548
 
+/*
9549
 
+ *  Message envelope properties
9550
 
+ */
9551
 
+
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)
9566
 
+
9567
 
+
9568
 
+
9569
 
+#define PR_CONVERSATION_KEY                         PROP_TAG( PT_BINARY,    0x000B)
9570
 
+
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)
9589
 
+
9590
 
+
9591
 
+
9592
 
+
9593
 
+
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)
9601
 
+
9602
 
+
9603
 
+
9604
 
+#define PR_PARENT_KEY                               PROP_TAG( PT_BINARY,    0x0025)
9605
 
+#define PR_PRIORITY                                 PROP_TAG( PT_LONG,      0x0026)
9606
 
+
9607
 
+
9608
 
+
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)
9673
 
+
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)
9680
 
+
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)
9684
 
+
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)
9695
 
+
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)
9700
 
+
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)
9707
 
+
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)
9714
 
+
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)
9721
 
+
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)
9726
 
+
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)
9736
 
+
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)
9743
 
+
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)
9750
 
+
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)
9757
 
+
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)
9764
 
+
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)
9768
 
+
9769
 
+#define PR_DELEGATION                               PROP_TAG(PT_BINARY,     0x007E)
9770
 
+
9771
 
+#define PR_TNEF_CORRELATION_KEY                     PROP_TAG(PT_BINARY,     0x007F)
9772
 
+
9773
 
+
9774
 
+
9775
 
+/*
9776
 
+ *  Message content properties
9777
 
+ */
9778
 
+
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)
9788
 
+
9789
 
+/*  Removed PR_REPORT_ORIGIN_AUTHENTICATION_CHECK with DCR 3865, use PR_ORIGIN_CHECK */
9790
 
+
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)
9800
 
+
9801
 
+/*
9802
 
+ *  Reserved 0x1100-0x1200
9803
 
+ */
9804
 
+
9805
 
+
9806
 
+/*
9807
 
+ *  Message recipient properties
9808
 
+ */
9809
 
+
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)
9818
 
+
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)
9853
 
+
9854
 
+/*
9855
 
+ *  Message non-transmittable properties
9856
 
+ */
9857
 
+
9858
 
+/*
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
9864
 
+ */
9865
 
+
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)
9909
 
+
9910
 
+/* PR_ORIGINAL_DISPLAY_TO, _CC, and _BCC moved to transmittible range 03/09/95 */
9911
 
+
9912
 
+#define PR_ORIGINATING_MTA_CERTIFICATE              PROP_TAG( PT_BINARY,    0x0E25)
9913
 
+#define PR_PROOF_OF_SUBMISSION                      PROP_TAG( PT_BINARY,    0x0E26)
9914
 
+
9915
 
+
9916
 
+/*
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.
9919
 
+ *
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
9933
 
+ */
9934
 
+
9935
 
+/*
9936
 
+ *  Properties common to numerous MAPI objects.
9937
 
+ *
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.
9941
 
+ *
9942
 
+ *  Properties that never appear on messages are defined in the common
9943
 
+ *  property range (see above).
9944
 
+ */
9945
 
+
9946
 
+/*
9947
 
+ * properties that are common to multiple objects (including message objects)
9948
 
+ * -- these ids are in the non-transmittable range
9949
 
+ */
9950
 
+
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)
9963
 
+
9964
 
+/*
9965
 
+ * properties that are common to multiple objects (usually not including message objects)
9966
 
+ * -- these ids are in the transmittable range
9967
 
+ */
9968
 
+
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)
9995
 
+
9996
 
+/*
9997
 
+ *  MAPI Form properties
9998
 
+ */
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)
10019
 
+
10020
 
+/*
10021
 
+ *  Message store properties
10022
 
+ */
10023
 
+
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)
10027
 
+
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)
10034
 
+
10035
 
+#define PR_VALID_FOLDER_MASK                        PROP_TAG( PT_LONG,      0x35DF)
10036
 
+#define PR_IPM_SUBTREE_ENTRYID                      PROP_TAG( PT_BINARY,    0x35E0)
10037
 
+
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)
10044
 
+
10045
 
+/* Proptags 0x35E8-0x35FF reserved for folders "guaranteed" by PR_VALID_FOLDER_MASK */
10046
 
+
10047
 
+
10048
 
+/*
10049
 
+ *  Folder and AB Container properties
10050
 
+ */
10051
 
+
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)
10078
 
+
10079
 
+/* Reserved 0x36C0-0x36FF */
10080
 
+
10081
 
+/*
10082
 
+ *  Attachment properties
10083
 
+ */
10084
 
+
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)
10115
 
+
10116
 
+/*
10117
 
+ *  AB Object properties
10118
 
+ */
10119
 
+
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)
10123
 
+
10124
 
+
10125
 
+/*
10126
 
+ *  Mail user properties
10127
 
+ */
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
10247
 
+
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
10254
 
+
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
10261
 
+
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
10268
 
+
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
10275
 
+
10276
 
+
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
10283
 
+
10284
 
+
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)
10301
 
+
10302
 
+#define PR_WEDDING_ANNIVERSARY                      PROP_TAG( PT_SYSTIME, 0x3A41)
10303
 
+#define PR_BIRTHDAY                                 PROP_TAG( PT_SYSTIME, 0x3A42)
10304
 
+
10305
 
+
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)
10309
 
+
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)
10313
 
+
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)
10317
 
+
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)
10321
 
+
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)
10325
 
+
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)
10329
 
+
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)
10333
 
+
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)
10337
 
+
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)
10341
 
+
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)
10345
 
+
10346
 
+#define PR_GENDER                                   PROP_TAG( PT_SHORT, 0x3A4D)
10347
 
+
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)
10351
 
+
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)
10355
 
+
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)
10359
 
+
10360
 
+
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)
10364
 
+
10365
 
+#define PR_CONTACT_VERSION                          PROP_TAG( PT_CLSID, 0x3A52)
10366
 
+#define PR_CONTACT_ENTRYIDS                         PROP_TAG( PT_MV_BINARY, 0x3A53)
10367
 
+
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)
10371
 
+
10372
 
+#define PR_CONTACT_DEFAULT_ADDRESS_INDEX            PROP_TAG( PT_LONG, 0x3A55)
10373
 
+
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)
10377
 
+
10378
 
+
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)
10382
 
+
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)
10386
 
+
10387
 
+
10388
 
+
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)
10392
 
+
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)
10396
 
+
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)
10400
 
+
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)
10404
 
+
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)
10408
 
+
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)
10412
 
+
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)
10416
 
+
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)
10420
 
+
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)
10424
 
+
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)
10428
 
+
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)
10432
 
+
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)
10436
 
+
10437
 
+
10438
 
+/*
10439
 
+ *  Profile section properties
10440
 
+ */
10441
 
+
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)
10445
 
+
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)
10450
 
+
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)
10472
 
+
10473
 
+/*
10474
 
+ *  Status object properties
10475
 
+ */
10476
 
+
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)
10499
 
+
10500
 
+/*
10501
 
+ * Display table properties
10502
 
+ */
10503
 
+
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)
10513
 
+
10514
 
+/*
10515
 
+ * Secure property id range
10516
 
+ */
10517
 
+
10518
 
+#define PROP_ID_SECURE_MIN                          0x67F0
10519
 
+#define PROP_ID_SECURE_MAX                          0x67FF
10520
 
+
10521
 
+
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
10526
 
@@ -9,9 +9,8 @@
10527
 
 
10528
 
 #include "exim.h"
10529
 
 
10530
 
-
10531
 
 #define THIS_VERSION  "4.34"
10532
 
-
10533
 
+#define EXISCAN_VERSION "21"
10534
 
 
10535
 
 /* The header file cnumber.h contains a single line containing the
10536
 
 compilation number, making it easy to have it updated automatically.
10537
 
@@ -40,6 +39,7 @@
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;
10542
 
 
10543
 
 Ustrcpy(today, __DATE__);
10544
 
 if (today[4] == ' ') today[4] = '0';