Browse code

Restructured scan options flags from a single bitflag field to a structure containing multiple bitflag fields. This also required adding a new function to the bytecode API to get scan options a la carte, and modifying the existing function to hand back scan options in the old/deprecated uint32_t bitflag format. Re-generated bytecode iface header files.

Updated libclamav documentation detailing new scan options structure.
Renamed references to 'algorithmic' detection to 'heuristic' detection. Renaming references to 'properties' to 'collect metadata'.
Renamed references to 'scan all' to 'scan all match'.
Renamed a couple of 'Hueristic.*' signature names as 'Heuristics.*' signatures (plural) to match majority of other heuristics.

Micah Snyder authored on 2018/07/21 11:28:48
Showing 70 changed files
... ...
@@ -86,7 +86,7 @@ ClamAV 0.100, including but not limited to:
86 86
 - Raw scanning of PostScript files.
87 87
 - Fix clamsubmit to use the new virus and false positive submission web
88 88
   interface.
89
-- Optionally, flag files with the virus "Heuristic.Limits.Exceeded" when
89
+- Optionally, flag files with the virus "Heuristics.Limits.Exceeded" when
90 90
   size limitations are exceeded.
91 91
 - Improved decoders for PDF files.
92 92
 - Reduced number of compile time warnings.
... ...
@@ -1147,7 +1147,7 @@ Detailed list of changes:
1147 1147
   - Support for Sensory Networks' NodalCore hardware acceleration technology
1148 1148
   - Advanced phishing detection module (experimental)
1149 1149
   - Signatures are stored in separate trees depending on their target type
1150
-  - Algorithmic detection can be controlled with CL_SCAN_ALGORITHMIC
1150
+  - Algorithmic detection can be controlled with CL_SCAN_GENERAL_HEURISTICS
1151 1151
   - Support for new obfuscators: SUE, Y0da Cryptor, CryptFF
1152 1152
   - Support for new packers: NsPack, wwpack32, MEW, Upack
1153 1153
   - Support for SIS files (SymbianOS packages)
... ...
@@ -1598,11 +1598,11 @@ the new version of ClamAV have detected and blocked 100% of Mydoom attacks!
1598 1598
 New features in this release include:
1599 1599
 
1600 1600
 - libclamav
1601
-  - Portable Executable analyser (CL_SCAN_PE) featuring:
1601
+  - Portable Executable analyser (CL_SCAN_PARSE_PE) featuring:
1602 1602
   - UPX decompression (all versions)
1603 1603
   - Petite decompression (2.x)
1604 1604
   - FSG decompression (1.3, 1.31, 1.33)
1605
-  - detection of broken executables (CL_SCAN_BLOCKBROKEN)
1605
+  - detection of broken executables (CL_SCAN_HEURISTIC_BROKEN)
1606 1606
   - new, memory efficient, pattern matching algorithm (multipattern variant
1607 1607
     of Boyer-Moore) - it's now primary matcher and Aho-Corasick is only used
1608 1608
     for regular expression extended signatures
... ...
@@ -1618,7 +1618,7 @@ New features in this release include:
1618 1618
   - new method of mail files detection
1619 1619
   - all e-mail attachments are now scanned (previously only the first ten
1620 1620
     attachments were scanned)
1621
-  - added support for scanning URLs in e-mails (CL_SCAN_MAILURL)
1621
+  - added support for scanning URLs in e-mails (CL_SCAN_PARSE_MAILURL)
1622 1622
   - detection of Worm.Mydoom.M.log
1623 1623
   - updated API (still backward compatible but please consult clamdoc.pdf
1624 1624
     (Section 6) and adapt your software)
... ...
@@ -39,6 +39,7 @@
39 39
 #include "shared/optparser.h"
40 40
 #include "shared/misc.h"
41 41
 
42
+#include "clamav-config.h"
42 43
 #include "libclamav/str.h"
43 44
 #include "libclamav/clamav.h"
44 45
 #include "libclamav/others.h"
... ...
@@ -68,7 +68,7 @@ static void onas_ddd_handle_in_moved_to(struct ddd_thrarg *tharg, const char *pa
68 68
 static void onas_ddd_handle_in_create(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask);
69 69
 static void onas_ddd_handle_in_moved_from(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd);
70 70
 static void onas_ddd_handle_in_delete(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd);
71
-static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int options);
71
+static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int extra_options);
72 72
 
73 73
 static void onas_ddd_exit(int sig);
74 74
 
... ...
@@ -527,8 +527,9 @@ static void onas_ddd_handle_in_moved_to(struct ddd_thrarg *tharg,
527 527
 	return;
528 528
 }
529 529
 
530
-static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int options) {
530
+static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int extra_options) {
531 531
 
532
+	int thread_started = 1;
532 533
 	struct scth_thrarg *scth_tharg = NULL;
533 534
 	pthread_attr_t scth_attr;
534 535
 	pthread_t scth_pid = 0;
... ...
@@ -537,20 +538,37 @@ static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char
537 537
 		if (pthread_attr_init(&scth_attr)) break;
538 538
 		pthread_attr_setdetachstate(&scth_attr, PTHREAD_CREATE_JOINABLE);
539 539
 
540
-		if (!(scth_tharg = (struct scth_thrarg *) malloc(sizeof(struct scth_thrarg)))) break;
540
+		/* Allocate memory for arguments. Thread is responsible for freeing it. */
541
+		if (!(scth_tharg = (struct scth_thrarg *) calloc(sizeof(struct scth_thrarg), 1))) break;
542
+		if (!(scth_tharg->options = (struct cl_scan_options *) calloc(sizeof(struct cl_scan_options), 1))) break;
541 543
 
542
-		scth_tharg->options = options;
544
+		(void) memcpy(scth_tharg->options, tharg->options, sizeof(struct cl_scan_options));
545
+
546
+		scth_tharg->extra_options = extra_options;
543 547
 		scth_tharg->opts = tharg->opts;
544 548
 		scth_tharg->pathname = strdup(pathname);
545 549
 		scth_tharg->engine = tharg->engine;
546 550
 
547
-		if (!pthread_create(&scth_pid, &scth_attr, onas_scan_th, scth_tharg)) break;
548
-
549
-		free(scth_tharg);
550
-		scth_tharg = NULL;
551
+		thread_started = pthread_create(&scth_pid, &scth_attr, onas_scan_th, scth_tharg);
551 552
 	} while(0);
552
-	if (!scth_tharg) logg("!ScanOnAccess: Unable to kick off extra scanning.\n");
553 553
 
554
+	if (0 != thread_started) {
555
+		/* Failed to create thread. Free anything we may have allocated. */
556
+		logg("!ScanOnAccess: Unable to kick off extra scanning.\n");
557
+		if (NULL != scth_tharg) {
558
+			if (NULL != scth_tharg->pathname){
559
+				free(scth_tharg->pathname);
560
+				scth_tharg->pathname = NULL;
561
+			}
562
+			if (NULL != scth_tharg->options) {
563
+				free(scth_tharg->options);
564
+				scth_tharg->options = NULL;
565
+			}
566
+			free(scth_tharg);
567
+			scth_tharg = NULL;
568
+		}
569
+	}
570
+	
554 571
 	return;
555 572
 }
556 573
 
... ...
@@ -22,19 +22,24 @@
22 22
 #ifndef __ONAS_IN_H
23 23
 #define __ONAS_IN_H
24 24
 
25
-#define ONAS_IN 0x01
26
-#define ONAS_FAN 0x02
25
+#include "shared/optparser.h"
26
+#include "libclamav/clamav.h"
27
+
28
+/*
29
+ * Extra options for onas_scan_th(). 
30
+ */
31
+#define ONAS_IN 	0x01
32
+#define ONAS_FAN 	0x02
27 33
 
28 34
 #define MAX_WATCH_LEN 7
29 35
 
30 36
 struct ddd_thrarg {
31 37
 	int sid;
32
-	int options;
38
+	struct cl_scan_options *options;
33 39
 	int fan_fd;
34 40
 	uint64_t fan_mask;
35 41
 	const struct optstruct *opts;
36 42
 	const struct cl_engine *engine;
37
-	const struct cl_limits *limits;
38 43
 };
39 44
 
40 45
 
... ...
@@ -171,24 +171,36 @@ void *onas_fan_th(void *arg)
171 171
 	    }
172 172
 
173 173
     } else if (!optget(tharg->opts, "OnAccessDisableDDD")->enabled) {
174
+		int thread_started = 1;
174 175
 	    do {
175 176
 		    if(pthread_attr_init(&ddd_attr)) break;
176 177
 		    pthread_attr_setdetachstate(&ddd_attr, PTHREAD_CREATE_JOINABLE);
177 178
 
178
-		    if(!(ddd_tharg = (struct ddd_thrarg *) malloc(sizeof(struct ddd_thrarg)))) break;
179
+			/* Allocate memory for arguments. Thread is responsible for freeing it. */
180
+		    if (!(ddd_tharg = (struct ddd_thrarg *) calloc(sizeof(struct ddd_thrarg), 1))) break;
181
+			if (!(ddd_tharg->options = (struct cl_scan_options *) calloc(sizeof(struct cl_scan_options), 1))) break;
179 182
 
183
+			(void) memcpy(ddd_tharg->options, tharg->options, sizeof(struct cl_scan_options));
180 184
 		    ddd_tharg->fan_fd = onas_fan_fd;
181 185
 		    ddd_tharg->fan_mask = fan_mask;
182 186
 		    ddd_tharg->opts = tharg->opts;
183 187
 		    ddd_tharg->engine = tharg->engine;
184
-		    ddd_tharg->options = tharg->options;
185 188
 
186
-		    if(!pthread_create(&ddd_pid, &ddd_attr, onas_ddd_th, ddd_tharg)) break;
187
-
188
-		    free(ddd_tharg);
189
-		    ddd_tharg=NULL;
189
+		    thread_started = pthread_create(&ddd_pid, &ddd_attr, onas_ddd_th, ddd_tharg);
190 190
 	    } while(0);
191
-	    if (!ddd_tharg) logg("!Unable to start dynamic directory determination.\n");
191
+
192
+		if (0 != thread_started) {
193
+			/* Failed to create thread. Free anything we may have allocated. */
194
+			logg("!Unable to start dynamic directory determination.\n");
195
+			if (NULL != ddd_tharg) {
196
+				if (NULL != ddd_tharg->options) {
197
+					free(ddd_tharg->options);
198
+					ddd_tharg->options = NULL;
199
+				}
200
+				free(ddd_tharg);
201
+				ddd_tharg = NULL;
202
+			}
203
+		}
192 204
 
193 205
     } else {
194 206
 	    if((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) {
... ...
@@ -94,7 +94,7 @@ int onas_fan_checkowner(int pid, const struct optstruct *opts)
94 94
     return CHK_CLEAN;
95 95
 }
96 96
 
97
-int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, int options, int extinfo)
97
+int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, struct cl_scan_options *options, int extinfo)
98 98
 {
99 99
     int ret = 0;
100 100
     struct cb_context context;
... ...
@@ -22,6 +22,7 @@
22 22
 #define __CLAMD_ONAS_OTHERS_H
23 23
 
24 24
 #include "shared/optparser.h"
25
+#include "libclamav/clamav.h"
25 26
 
26 27
 typedef enum {
27 28
     CHK_CLEAN,
... ...
@@ -30,6 +31,6 @@ typedef enum {
30 30
 } cli_check_t;
31 31
 
32 32
 int onas_fan_checkowner(int pid, const struct optstruct *opts);
33
-int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, int options, int extinfo);
33
+int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, struct cl_scan_options *options, int extinfo);
34 34
 
35 35
 #endif
... ...
@@ -38,6 +38,7 @@
38 38
 #include "priv_fts.h"
39 39
 
40 40
 #include "onaccess_scth.h"
41
+#include "onaccess_others.h"
41 42
 
42 43
 #include "libclamav/clamav.h"
43 44
 
... ...
@@ -132,16 +133,31 @@ void *onas_scan_th(void *arg) {
132 132
 	sigaction(SIGUSR1, &act, NULL);
133 133
 	sigaction(SIGSEGV, &act, NULL);
134 134
 
135
-	if (tharg->options & ONAS_SCTH_ISDIR) {
135
+	if (NULL == tharg || NULL == tharg->pathname || NULL == tharg->opts || NULL == tharg->engine) {
136
+		logg("ScanOnAccess: Invalid thread arguments for extra scanning\n");
137
+		goto done;
138
+	}
139
+
140
+	if (tharg->extra_options & ONAS_SCTH_ISDIR) {
136 141
 		logg("*ScanOnAccess: Performing additional scanning on directory '%s'\n", tharg->pathname);
137 142
 		onas_scth_handle_dir(tharg->pathname, tharg);
138
-	} else if (tharg->options & ONAS_SCTH_ISFILE) {
143
+	} else if (tharg->extra_options & ONAS_SCTH_ISFILE) {
139 144
 		logg("*ScanOnAccess: Performing additional scanning on file '%s'\n", tharg->pathname);
140 145
 		onas_scth_handle_file(tharg->pathname, tharg);
141 146
 	}
142 147
 
143
-	free(tharg->pathname);
144
-	tharg->pathname = NULL;
148
+done:
149
+	if (NULL != tharg->pathname){
150
+		free(tharg->pathname);
151
+		tharg->pathname = NULL;
152
+	}
153
+	if (NULL != tharg->options) {
154
+		free(tharg->options);
155
+		tharg->options = NULL;
156
+	}
157
+	if (NULL != tharg) {
158
+		free(tharg);
159
+	}
145 160
 
146 161
 	return NULL;
147 162
 }
... ...
@@ -21,13 +21,17 @@
21 21
 #ifndef __ONAS_SCTH_H
22 22
 #define __ONAS_SCTH_H
23 23
 
24
+#include "shared/optparser.h"
25
+#include "libclamav/clamav.h"
26
+
24 27
 #define ONAS_SCTH_ISDIR  0x01
25 28
 #define ONAS_SCTH_ISFILE 0x02
26 29
 
27 30
 struct scth_thrarg {
28
-	int options;
31
+	uint32_t extra_options;
32
+	struct cl_scan_options *options;
29 33
 	const struct optstruct *opts;
30
-        const struct cl_engine *engine;
34
+	const struct cl_engine *engine;
31 35
 	char *pathname;
32 36
 };
33 37
 
... ...
@@ -117,7 +117,7 @@ void clamd_virus_found_cb(int fd, const char *virname, void *ctx)
117 117
     
118 118
     if (d == NULL)
119 119
         return;
120
-    if (!(d->options & CL_SCAN_ALLMATCHES) && !(d->options & CL_SCAN_HEURISTIC_PRECEDENCE))
120
+    if (!(d->options->general & CL_SCAN_GENERAL_ALLMATCHES) && !(d->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE))
121 121
         return;
122 122
     if (virname == NULL)
123 123
         return;
... ...
@@ -277,7 +277,7 @@ int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_rea
277 277
 
278 278
     if (ret == CL_VIRUS) {
279 279
 
280
-         if (scandata->options & CL_SCAN_ALLMATCHES || (scandata->infected && scandata->options & CL_SCAN_HEURISTIC_PRECEDENCE)) {
280
+         if (scandata->options->general & CL_SCAN_GENERAL_ALLMATCHES || (scandata->infected && scandata->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)) {
281 281
             if(optget(scandata->opts, "PreludeEnable")->enabled){
282 282
                 prelude_logging(filename, virname, context.virhash, context.virsize);
283 283
             }
... ...
@@ -353,9 +353,14 @@ int scan_pathchk(const char *path, struct cli_ftw_cbdata *data)
353 353
     return 0;
354 354
 }
355 355
 
356
-int scanfd(const client_conn_t *conn, unsigned long int *scanned,
357
-	   const struct cl_engine *engine,
358
-	   unsigned int options, const struct optstruct *opts, int odesc, int stream)
356
+int scanfd(
357
+	const client_conn_t *conn,
358
+	unsigned long int *scanned,
359
+	const struct cl_engine *engine,
360
+	struct cl_scan_options *options,
361
+	const struct optstruct *opts,
362
+	int odesc,
363
+	int stream)
359 364
 {
360 365
     int ret, fd = conn->scanfd;
361 366
 	const char *virname = NULL;
... ...
@@ -418,7 +423,13 @@ int scanfd(const client_conn_t *conn, unsigned long int *scanned,
418 418
 	return ret;
419 419
 }
420 420
 
421
-int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, char term)
421
+int scanstream(
422
+	int odesc,
423
+	unsigned long int *scanned,
424
+	const struct cl_engine *engine,
425
+	struct cl_scan_options *options,
426
+	const struct optstruct *opts,
427
+	char term)
422 428
 {
423 429
 	int ret, sockfd, acceptd;
424 430
 	int tmpd, bread, retval, firsttimeout, timeout, btread;
... ...
@@ -24,6 +24,7 @@
24 24
 
25 25
 #include <sys/types.h>
26 26
 
27
+#include "libclamav/others.h"
27 28
 #include "libclamav/clamav.h"
28 29
 #include "shared/optparser.h"
29 30
 #include "thrmgr.h"
... ...
@@ -42,7 +43,7 @@ struct scan_cb_data {
42 42
     const client_conn_t *conn;
43 43
     const char *toplevel_path;
44 44
     unsigned long scanned;
45
-    unsigned int options;
45
+    struct cl_scan_options *options;
46 46
     struct cl_engine *engine;
47 47
     const struct optstruct *opts;
48 48
     threadpool_t *thr_pool;
... ...
@@ -57,8 +58,8 @@ struct cb_context {
57 57
     struct scan_cb_data *scandata;
58 58
 };
59 59
 
60
-int scanfd(const client_conn_t *conn, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, int odesc, int stream);
61
-int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, unsigned int options, const struct optstruct *opts, char term);
60
+int scanfd(const client_conn_t *conn, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, int odesc, int stream);
61
+int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, char term);
62 62
 int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data);
63 63
 int scan_pathchk(const char *path, struct cli_ftw_cbdata *data);
64 64
 void hash_callback(int fd, unsigned long long size, const unsigned char *md5, const char *virname, void *ctx);
... ...
@@ -718,7 +718,7 @@ static int handle_stream(client_conn_t *conn, struct fd_buf *buf, const struct o
718 718
 int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts)
719 719
 {
720 720
 	int max_threads, max_queue, readtimeout, ret = 0;
721
-	unsigned int options = 0;
721
+	struct cl_scan_options options;
722 722
 	char timestr[32];
723 723
 #ifndef	_WIN32
724 724
 	struct sigaction sigact;
... ...
@@ -742,7 +742,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
742 742
 	threadpool_t *thr_pool;
743 743
 
744 744
 #if defined(FANOTIFY) || defined(CLAMAUTH)
745
-	pthread_t fan_pid;
745
+	pthread_t fan_pid = 0;
746 746
 	pthread_attr_t fan_attr;
747 747
 	struct thrarg *tharg = NULL; /* shut up gcc */
748 748
 #endif
... ...
@@ -751,6 +751,9 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
751 751
 	memset(&sigact, 0, sizeof(struct sigaction));
752 752
 #endif
753 753
 
754
+	/* Initalize scan options struct */
755
+	memset(&options, 0, sizeof(struct cl_scan_options));
756
+
754 757
     /* set up limits */
755 758
     if((opt = optget(opts, "MaxScanSize"))->active) {
756 759
 	if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, opt->numarg))) {
... ...
@@ -922,11 +925,11 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
922 922
 
923 923
     if(optget(opts, "ScanArchive")->enabled) {
924 924
 	logg("Archive support enabled.\n");
925
-	options |= CL_SCAN_ARCHIVE;
925
+	options.parse |= CL_SCAN_PARSE_ARCHIVE;
926 926
 
927 927
 	if(optget(opts, "ArchiveBlockEncrypted")->enabled) {
928 928
 	    logg("Archive: Blocking encrypted archives.\n");
929
-	    options |= CL_SCAN_BLOCKENCRYPTED;
929
+	    options.heuristic |= CL_SCAN_HEURISTIC_ENCRYPTED;
930 930
 	}
931 931
 
932 932
     } else {
... ...
@@ -935,28 +938,28 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
935 935
 
936 936
     if (optget(opts, "BlockMax")->enabled) {
937 937
         logg("BlockMax heuristic detection enabled.\n");
938
-        options |= CL_SCAN_BLOCKMAX;
938
+        options.heuristic |= CL_SCAN_HEURISTIC_EXCEEDS_MAX;
939 939
     } else {
940 940
         logg("BlockMax heuristic detection disabled.\n");
941 941
     }
942 942
 
943 943
     if(optget(opts, "AlgorithmicDetection")->enabled) {
944 944
 	logg("Algorithmic detection enabled.\n");
945
-	options |= CL_SCAN_ALGORITHMIC;
945
+	options.general |= CL_SCAN_GENERAL_HEURISTICS;
946 946
     } else {
947 947
 	logg("Algorithmic detection disabled.\n");
948 948
     }
949 949
 
950 950
     if(optget(opts, "ScanPE")->enabled) {
951 951
 	logg("Portable Executable support enabled.\n");
952
-	options |= CL_SCAN_PE;
952
+	options.parse |= CL_SCAN_PARSE_PE;
953 953
     } else {
954 954
 	logg("Portable Executable support disabled.\n");
955 955
     }
956 956
 
957 957
     if(optget(opts, "ScanELF")->enabled) {
958 958
 	logg("ELF support enabled.\n");
959
-	options |= CL_SCAN_ELF;
959
+	options.parse |= CL_SCAN_PARSE_ELF;
960 960
     } else {
961 961
 	logg("ELF support disabled.\n");
962 962
     }
... ...
@@ -964,17 +967,17 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
964 964
     if(optget(opts, "ScanPE")->enabled || optget(opts, "ScanELF")->enabled) {
965 965
 	if(optget(opts, "DetectBrokenExecutables")->enabled) {
966 966
 	    logg("Detection of broken executables enabled.\n");
967
-	    options |= CL_SCAN_BLOCKBROKEN;
967
+	    options.heuristic |= CL_SCAN_HEURISTIC_BROKEN;
968 968
 	}
969 969
     }
970 970
 
971 971
     if(optget(opts, "ScanMail")->enabled) {
972 972
 	logg("Mail files support enabled.\n");
973
-	options |= CL_SCAN_MAIL;
973
+	options.parse |= CL_SCAN_PARSE_MAIL;
974 974
 
975 975
 	if(optget(opts, "ScanPartialMessages")->enabled) {
976 976
 	    logg("Mail: RFC1341 handling enabled.\n");
977
-	    options |= CL_SCAN_PARTIAL_MESSAGE;
977
+	    options.mail |= CL_SCAN_MAIL_PARTIAL_MESSAGE;
978 978
 	}
979 979
 
980 980
     } else {
... ...
@@ -983,10 +986,10 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
983 983
 
984 984
     if(optget(opts, "ScanOLE2")->enabled) {
985 985
 	logg("OLE2 support enabled.\n");
986
-	options |= CL_SCAN_OLE2;
986
+	options.parse |= CL_SCAN_PARSE_OLE2;
987 987
 	if(optget(opts, "OLE2BlockMacros")->enabled) {
988 988
 	    logg("OLE2: Blocking all VBA macros.\n");
989
-	    options |= CL_SCAN_BLOCKMACROS;
989
+	    options.heuristic |= CL_SCAN_HEURISTIC_MACROS;
990 990
 	}
991 991
     } else {
992 992
 	logg("OLE2 support disabled.\n");
... ...
@@ -994,35 +997,35 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
994 994
 
995 995
     if(optget(opts, "ScanPDF")->enabled) {
996 996
 	logg("PDF support enabled.\n");
997
-	options |= CL_SCAN_PDF;
997
+	options.parse |= CL_SCAN_PARSE_PDF;
998 998
     } else {
999 999
 	logg("PDF support disabled.\n");
1000 1000
     }
1001 1001
 
1002 1002
     if(optget(opts, "ScanSWF")->enabled) {
1003 1003
 	logg("SWF support enabled.\n");
1004
-	options |= CL_SCAN_SWF;
1004
+	options.parse |= CL_SCAN_PARSE_SWF;
1005 1005
     } else {
1006 1006
 	logg("SWF support disabled.\n");
1007 1007
     }
1008 1008
 
1009 1009
     if(optget(opts, "ScanHTML")->enabled) {
1010 1010
 	logg("HTML support enabled.\n");
1011
-	options |= CL_SCAN_HTML;
1011
+	options.parse |= CL_SCAN_PARSE_HTML;
1012 1012
     } else {
1013 1013
 	logg("HTML support disabled.\n");
1014 1014
     }
1015 1015
 
1016 1016
     if(optget(opts, "ScanXMLDOCS")->enabled) {
1017 1017
 	logg("XMLDOCS support enabled.\n");
1018
-	options |= CL_SCAN_XMLDOCS;
1018
+	options.parse |= CL_SCAN_PARSE_XMLDOCS;
1019 1019
     } else {
1020 1020
 	logg("XMLDOCS support disabled.\n");
1021 1021
     }
1022 1022
 
1023 1023
     if(optget(opts, "ScanHWP3")->enabled) {
1024 1024
 	logg("HWP3 support enabled.\n");
1025
-	options |= CL_SCAN_HWP3;
1025
+	options.parse |= CL_SCAN_PARSE_HWP3;
1026 1026
     } else {
1027 1027
 	logg("HWP3 support disabled.\n");
1028 1028
     }
... ...
@@ -1030,28 +1033,28 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
1030 1030
     if(optget(opts,"PhishingScanURLs")->enabled) {
1031 1031
 
1032 1032
 	if(optget(opts,"PhishingAlwaysBlockCloak")->enabled) {
1033
-	    options |= CL_SCAN_PHISHING_BLOCKCLOAK; 
1033
+	    options.heuristic |= CL_SCAN_HEURISTIC_PHISHING_CLOAK; 
1034 1034
 	    logg("Phishing: Always checking for cloaked urls\n");
1035 1035
 	}
1036 1036
 
1037 1037
 	if(optget(opts,"PhishingAlwaysBlockSSLMismatch")->enabled) {
1038
-	    options |= CL_SCAN_PHISHING_BLOCKSSL;
1038
+	    options.heuristic |= CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH;
1039 1039
 	    logg("Phishing: Always checking for ssl mismatches\n");
1040 1040
 	}
1041 1041
     }
1042 1042
 
1043 1043
     if(optget(opts,"PartitionIntersection")->enabled) {
1044
-        options |= CL_SCAN_PARTITION_INTXN;
1044
+        options.heuristic |= CL_SCAN_HEURISTIC_PARTITION_INTXN;
1045 1045
         logg("Raw DMG: Always checking for partitions intersections\n");
1046 1046
     }
1047 1047
 
1048 1048
     if(optget(opts,"HeuristicScanPrecedence")->enabled) {
1049
-	    options |= CL_SCAN_HEURISTIC_PRECEDENCE;
1049
+	    options.general |= CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE;
1050 1050
 	    logg("Heuristic: precedence enabled\n");
1051 1051
     }
1052 1052
 
1053 1053
     if(optget(opts, "StructuredDataDetection")->enabled) {
1054
-        options |= CL_SCAN_STRUCTURED;
1054
+        options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED;
1055 1055
 
1056 1056
 	if((opt = optget(opts, "StructuredMinCreditCardCount"))->enabled) {
1057 1057
 	    if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_CC_COUNT, opt->numarg))) {
... ...
@@ -1074,15 +1077,15 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
1074 1074
         logg("Structured: Minimum Social Security Number Count set to %u\n", (unsigned int) val);
1075 1075
 
1076 1076
         if(optget(opts, "StructuredSSNFormatNormal")->enabled)
1077
-            options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
1077
+            options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL;
1078 1078
 
1079 1079
         if(optget(opts, "StructuredSSNFormatStripped")->enabled)
1080
-	    options |= CL_SCAN_STRUCTURED_SSN_STRIPPED;
1080
+	    options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED;
1081 1081
     }
1082 1082
 
1083 1083
 #ifdef HAVE__INTERNAL__SHA_COLLECT
1084 1084
     if(optget(opts, "DevCollectHashes")->enabled)
1085
-	options |= CL_SCAN_INTERNAL_COLLECT_SHA;
1085
+	options.dev |= CL_SCAN_DEV_COLLECT_SHA;
1086 1086
 #endif
1087 1087
 
1088 1088
     selfchk = optget(opts, "SelfCheck")->numarg;
... ...
@@ -1209,18 +1212,34 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
1209 1209
 
1210 1210
 #if defined(FANOTIFY) || defined(CLAMAUTH)
1211 1211
     {
1212
+		int thread_started = 1;
1212 1213
         do {
1213
-	    if(pthread_attr_init(&fan_attr)) break;
1214
-	    pthread_attr_setdetachstate(&fan_attr, PTHREAD_CREATE_JOINABLE);
1215
-	    if(!(tharg = (struct thrarg *) malloc(sizeof(struct thrarg)))) break;
1216
-	    tharg->opts = opts;
1217
-	    tharg->engine = engine;
1218
-	    tharg->options = options;
1219
-	    if(!pthread_create(&fan_pid, &fan_attr, onas_fan_th, tharg)) break;
1220
-	    free(tharg);
1221
-	    tharg=NULL;
1222
-	} while(0);
1223
-	if (!tharg) logg("!Unable to start on-access scan\n");
1214
+			if(pthread_attr_init(&fan_attr)) break;
1215
+			pthread_attr_setdetachstate(&fan_attr, PTHREAD_CREATE_JOINABLE);
1216
+
1217
+			/* Allocate memory for arguments. Thread is responsible for freeing it. */
1218
+			if (!(tharg = (struct thrarg *) calloc(sizeof(struct thrarg), 1))) break;
1219
+			if (!(tharg->options = (struct cl_scan_options *) calloc(sizeof(struct cl_scan_options), 1))) break;
1220
+
1221
+			(void) memcpy(tharg->options, &options, sizeof(struct cl_scan_options));
1222
+			tharg->opts = opts;
1223
+			tharg->engine = engine;
1224
+
1225
+			thread_started = pthread_create(&fan_pid, &fan_attr, onas_fan_th, tharg);
1226
+		} while(0);
1227
+
1228
+		if (0 != thread_started) {
1229
+			/* Failed to create thread. Free anything we may have allocated. */
1230
+			logg("!Unable to start on-access scan.\n");
1231
+			if (NULL != tharg) {
1232
+				if (NULL != tharg->options) {
1233
+					free(tharg->options);
1234
+					tharg->options = NULL;
1235
+				}
1236
+				free(tharg);
1237
+				tharg = NULL;
1238
+			}
1239
+		}
1224 1240
     }
1225 1241
 #else
1226 1242
 	logg("!On-access scan is not available\n");
... ...
@@ -1384,7 +1403,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
1384 1384
 		conn.scanfd = buf->recvfd;
1385 1385
 		buf->recvfd = -1;
1386 1386
 		conn.sd = buf->fd;
1387
-		conn.options = options;
1387
+		conn.options = &options;
1388 1388
 		conn.opts = opts;
1389 1389
 		conn.thrpool = thr_pool;
1390 1390
 		conn.engine = engine;
... ...
@@ -32,19 +32,9 @@
32 32
 #include "session.h"
33 33
 struct thrarg {
34 34
     int sid;
35
-    int options;
35
+    struct cl_scan_options *options;
36 36
     const struct optstruct *opts;
37 37
     const struct cl_engine *engine;
38
-    const struct cl_limits *limits;
39
-};
40
-
41
-/* thread watcher arguments */
42
-struct thrwarg {
43
-    int socketd;
44
-    struct cl_engine **engine;
45
-    const struct optstruct *opts;
46
-    const struct cl_limits *limits;
47
-    unsigned int options;
48 38
 };
49 39
 
50 40
 int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigned int dboptions, const struct optstruct *opts);
... ...
@@ -191,7 +191,7 @@ int command(client_conn_t *conn, int *virus)
191 191
 {
192 192
     int desc = conn->sd;
193 193
     struct cl_engine *engine = conn->engine;
194
-    unsigned int options = conn->options;
194
+    struct cl_scan_options *options = conn->options;
195 195
     const struct optstruct *opts = conn->opts;
196 196
     enum scan_type type = TYPE_INIT;
197 197
     int maxdirrec;
... ...
@@ -369,7 +369,7 @@ int command(client_conn_t *conn, int *virus)
369 369
 		return 1;
370 370
 	    }
371 371
 	    thrmgr_setactivetask(NULL, "ALLMATCHSCAN");
372
-	    scandata.options |= CL_SCAN_ALLMATCHES;
372
+	    scandata.options->general |= CL_SCAN_GENERAL_ALLMATCHES;
373 373
 	    type = TYPE_SCAN;
374 374
 	    break;
375 375
 	 default:
... ...
@@ -82,7 +82,7 @@ typedef struct client_conn_tag {
82 82
     char *filename;
83 83
     int scanfd;
84 84
     int sd;
85
-    unsigned int options;
85
+    struct cl_scan_options *options;
86 86
     const struct optstruct *opts;
87 87
     struct cl_engine *engine;
88 88
     time_t engine_timestamp;
... ...
@@ -289,7 +289,7 @@ static void clamscan_virus_found_cb(int fd, const char *virname, void *context)
289 289
     return;
290 290
 }
291 291
 
292
-static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, unsigned int options)
292
+static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options)
293 293
 {
294 294
     int ret = 0, fd, included;
295 295
     unsigned i;
... ...
@@ -427,7 +427,7 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
427 427
         action(filename);
428 428
 }
429 429
 
430
-static void scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, unsigned int options, unsigned int depth, dev_t dev)
430
+static void scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options, unsigned int depth, dev_t dev)
431 431
 {
432 432
     DIR *dd;
433 433
     struct dirent *dent;
... ...
@@ -540,7 +540,7 @@ static void scandirs(const char *dirname, struct cl_engine *engine, const struct
540 540
     }
541 541
 }
542 542
 
543
-static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, int options)
543
+static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options)
544 544
 {
545 545
     int ret;
546 546
     unsigned int fsize = 0;
... ...
@@ -615,7 +615,8 @@ static int scanstdin(const struct cl_engine *engine, const struct optstruct *opt
615 615
 int scanmanager(const struct optstruct *opts)
616 616
 {
617 617
     int ret = 0, i;
618
-    unsigned int options = 0, dboptions = 0, dirlnk = 1, filelnk = 1;
618
+    struct cl_scan_options options;
619
+    unsigned int dboptions = 0, dirlnk = 1, filelnk = 1;
619 620
     struct cl_engine *engine;
620 621
     STATBUF sb;
621 622
     char *file, cwd[1024], *pua_cats = NULL;
... ...
@@ -625,6 +626,9 @@ int scanmanager(const struct optstruct *opts)
625 625
     struct rlimit rlim;
626 626
 #endif
627 627
 
628
+    /* Initalize scan options struct */
629
+    memset(&options, 0, sizeof(struct cl_scan_options));
630
+
628 631
     dirlnk = optget(opts, "follow-dir-symlinks")->numarg;
629 632
     if(dirlnk > 2) {
630 633
         logg("!--follow-dir-symlinks: Invalid argument\n");
... ...
@@ -794,7 +798,7 @@ int scanmanager(const struct optstruct *opts)
794 794
     /* JSON check to prevent engine loading if specified without libjson-c  */
795 795
 #if HAVE_JSON
796 796
     if (optget(opts, "gen-json")->enabled)
797
-        options |= CL_SCAN_FILE_PROPERTIES;
797
+        options.general |= CL_SCAN_GENERAL_COLLECT_METADATA;
798 798
 #else
799 799
     if (optget(opts, "gen-json")->enabled) {
800 800
         logg("!Can't generate json (gen-json). libjson-c dev library was missing or misconfigured when ClamAV was built.\n");
... ...
@@ -1010,95 +1014,95 @@ int scanmanager(const struct optstruct *opts)
1010 1010
 
1011 1011
     /* set scan options */
1012 1012
     if(optget(opts, "allmatch")->enabled) {
1013
-        options |= CL_SCAN_ALLMATCHES;
1013
+        options.general |= CL_SCAN_GENERAL_ALLMATCHES;
1014 1014
     }
1015 1015
 
1016 1016
     if(optget(opts,"phishing-ssl")->enabled)
1017
-        options |= CL_SCAN_PHISHING_BLOCKSSL;
1017
+        options.heuristic |= CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH;
1018 1018
 
1019 1019
     if(optget(opts,"phishing-cloak")->enabled)
1020
-        options |= CL_SCAN_PHISHING_BLOCKCLOAK;
1020
+        options.heuristic |= CL_SCAN_HEURISTIC_PHISHING_CLOAK;
1021 1021
 
1022 1022
     if(optget(opts,"partition-intersection")->enabled)
1023
-        options |= CL_SCAN_PARTITION_INTXN;
1023
+        options.heuristic |= CL_SCAN_HEURISTIC_PARTITION_INTXN;
1024 1024
 
1025 1025
     if(optget(opts,"heuristic-scan-precedence")->enabled)
1026
-        options |= CL_SCAN_HEURISTIC_PRECEDENCE;
1026
+        options.general |= CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE;
1027 1027
 
1028 1028
     if(optget(opts, "scan-archive")->enabled)
1029
-        options |= CL_SCAN_ARCHIVE;
1029
+        options.parse |= CL_SCAN_PARSE_ARCHIVE;
1030 1030
 
1031 1031
     if(optget(opts, "detect-broken")->enabled)
1032
-        options |= CL_SCAN_BLOCKBROKEN;
1032
+        options.heuristic |= CL_SCAN_HEURISTIC_BROKEN;
1033 1033
 
1034 1034
     if(optget(opts, "block-encrypted")->enabled)
1035
-        options |= CL_SCAN_BLOCKENCRYPTED;
1035
+        options.heuristic |= CL_SCAN_HEURISTIC_ENCRYPTED;
1036 1036
 
1037 1037
     if(optget(opts, "block-macros")->enabled)
1038
-        options |= CL_SCAN_BLOCKMACROS;
1038
+        options.heuristic |= CL_SCAN_HEURISTIC_MACROS;
1039 1039
 
1040 1040
     if(optget(opts, "scan-pe")->enabled)
1041
-        options |= CL_SCAN_PE;
1041
+        options.parse |= CL_SCAN_PARSE_PE;
1042 1042
 
1043 1043
     if(optget(opts, "scan-elf")->enabled)
1044
-        options |= CL_SCAN_ELF;
1044
+        options.parse |= CL_SCAN_PARSE_ELF;
1045 1045
 
1046 1046
     if(optget(opts, "scan-ole2")->enabled)
1047
-        options |= CL_SCAN_OLE2;
1047
+        options.parse |= CL_SCAN_PARSE_OLE2;
1048 1048
 
1049 1049
     if(optget(opts, "scan-pdf")->enabled)
1050
-        options |= CL_SCAN_PDF;
1050
+        options.parse |= CL_SCAN_PARSE_PDF;
1051 1051
 
1052 1052
     if(optget(opts, "scan-swf")->enabled)
1053
-        options |= CL_SCAN_SWF;
1053
+        options.parse |= CL_SCAN_PARSE_SWF;
1054 1054
 
1055 1055
     if(optget(opts, "scan-html")->enabled && optget(opts, "normalize")->enabled)
1056
-        options |= CL_SCAN_HTML;
1056
+        options.parse |= CL_SCAN_PARSE_HTML;
1057 1057
 
1058 1058
     if(optget(opts, "scan-mail")->enabled)
1059
-        options |= CL_SCAN_MAIL;
1059
+        options.parse |= CL_SCAN_PARSE_MAIL;
1060 1060
 
1061 1061
     if(optget(opts, "scan-xmldocs")->enabled)
1062
-        options |= CL_SCAN_XMLDOCS;
1062
+        options.parse |= CL_SCAN_PARSE_XMLDOCS;
1063 1063
 
1064 1064
     if(optget(opts, "scan-hwp3")->enabled)
1065
-        options |= CL_SCAN_HWP3;
1065
+        options.parse |= CL_SCAN_PARSE_HWP3;
1066 1066
 
1067 1067
     if(optget(opts, "algorithmic-detection")->enabled)
1068
-        options |= CL_SCAN_ALGORITHMIC;
1068
+        options.general |= CL_SCAN_GENERAL_HEURISTICS;
1069 1069
 
1070 1070
     if(optget(opts, "block-max")->enabled) {
1071
-        options |= CL_SCAN_BLOCKMAX;
1071
+        options.heuristic |= CL_SCAN_HEURISTIC_EXCEEDS_MAX;
1072 1072
     }
1073 1073
 
1074 1074
 #ifdef HAVE__INTERNAL__SHA_COLLECT
1075 1075
     if(optget(opts, "dev-collect-hashes")->enabled)
1076
-        options |= CL_SCAN_INTERNAL_COLLECT_SHA;
1076
+        options.dev |= CL_SCAN_DEV_COLLECT_SHA;
1077 1077
 #endif
1078 1078
 
1079 1079
     if(optget(opts, "dev-performance")->enabled)
1080
-        options |= CL_SCAN_PERFORMANCE_INFO;
1080
+        options.general |= CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO;
1081 1081
 
1082 1082
     if(optget(opts, "detect-structured")->enabled) {
1083
-        options |= CL_SCAN_STRUCTURED;
1083
+        options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED;
1084 1084
 
1085 1085
         if((opt = optget(opts, "structured-ssn-format"))->enabled) {
1086 1086
             switch(opt->numarg) {
1087 1087
             case 0:
1088
-                options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
1088
+                options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL;
1089 1089
                 break;
1090 1090
             case 1:
1091
-                options |= CL_SCAN_STRUCTURED_SSN_STRIPPED;
1091
+                options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED;
1092 1092
                 break;
1093 1093
             case 2:
1094
-                options |= (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED);
1094
+                options.heuristic |= (CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL | CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED);
1095 1095
                 break;
1096 1096
             default:
1097 1097
                 logg("!Invalid argument for --structured-ssn-format\n");
1098 1098
                 return 2;
1099 1099
             }
1100 1100
         } else {
1101
-            options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
1101
+            options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL;
1102 1102
         }
1103 1103
 
1104 1104
         if((opt = optget(opts, "structured-ssn-count"))->active) {
... ...
@@ -1118,7 +1122,7 @@ int scanmanager(const struct optstruct *opts)
1118 1118
             }
1119 1119
         }
1120 1120
     } else {
1121
-        options &= ~CL_SCAN_STRUCTURED;
1121
+        options.heuristic &= ~CL_SCAN_HEURISTIC_STRUCTURED;
1122 1122
     }
1123 1123
 
1124 1124
 #ifdef C_LINUX
... ...
@@ -1135,11 +1139,11 @@ int scanmanager(const struct optstruct *opts)
1135 1135
             ret = 2;
1136 1136
         } else {
1137 1137
             CLAMSTAT(cwd, &sb);
1138
-            scandirs(cwd, engine, opts, options, 1, sb.st_dev);
1138
+            scandirs(cwd, engine, opts, &options, 1, sb.st_dev);
1139 1139
         }
1140 1140
 
1141 1141
     } else if(opts->filename && !optget(opts, "file-list")->enabled && !strcmp(opts->filename[0], "-")) { /* read data from stdin */
1142
-        ret = scanstdin(engine, opts, options);
1142
+        ret = scanstdin(engine, opts, &options);
1143 1143
     } else {
1144 1144
         if(opts->filename && optget(opts, "file-list")->enabled)
1145 1145
             logg("^Only scanning files from --file-list (files passed at cmdline are ignored)\n");
... ...
@@ -1163,18 +1167,18 @@ int scanmanager(const struct optstruct *opts)
1163 1163
                             logg("%s: Symbolic link\n", file);
1164 1164
                     } else if(CLAMSTAT(file, &sb) != -1) {
1165 1165
                         if(S_ISREG(sb.st_mode) && filelnk) {
1166
-                            scanfile(file, engine, opts, options);
1166
+                            scanfile(file, engine, opts, &options);
1167 1167
                         } else if(S_ISDIR(sb.st_mode) && dirlnk) {
1168
-                            scandirs(file, engine, opts, options, 1, sb.st_dev);
1168
+                            scandirs(file, engine, opts, &options, 1, sb.st_dev);
1169 1169
                         } else {
1170 1170
                             if(!printinfected)
1171 1171
                                 logg("%s: Symbolic link\n", file);
1172 1172
                         }
1173 1173
                     }
1174 1174
                 } else if(S_ISREG(sb.st_mode)) {
1175
-                    scanfile(file, engine, opts, options);
1175
+                    scanfile(file, engine, opts, &options);
1176 1176
                 } else if(S_ISDIR(sb.st_mode)) {
1177
-                    scandirs(file, engine, opts, options, 1, sb.st_dev);
1177
+                    scandirs(file, engine, opts, &options, 1, sb.st_dev);
1178 1178
                 } else {
1179 1179
                     logg("^%s: Not supported file type\n", file);
1180 1180
                     ret = 2;
... ...
@@ -382,7 +382,10 @@ uint32_t maxreclevel;
382 382
 uint32_t maxfiles;
383 383
 
384 384
 static	struct	cl_stat	dbstat;
385
-static	int	options = CL_SCAN_STDOPT;
385
+static	struct cl_scan_options	options;
386
+
387
+memset(&options, 0, sizeof(struct cl_scan_options));
388
+options.parse |= ~0; /* enable all parsers */
386 389
 
387 390
 #ifdef	BOUNCE
388 391
 static	int	bflag = 0;	/*
... ...
@@ -250,59 +250,104 @@ The first argument points to the database directory, the second one specifies wh
250 250
 It’s possible to scan a file or descriptor using:
251 251
 
252 252
 ```c
253
-    int cl_scanfile(const char *filename, const char **virname,
254
-    unsigned long int *scanned, const struct cl_engine *engine,
255
-    unsigned int options);
253
+    int cl_scanfile(
254
+        const char *filename,
255
+        const char **virname,
256
+        unsigned long int *scanned,
257
+        const struct cl_engine *engine,
258
+        struct cl_scan_options *options);
259
+
260
+    int cl_scandesc(
261
+        int desc,
262
+        const char **virname,
263
+        unsigned long int *scanned,
264
+        const struct cl_engine *engine,
265
+        struct cl_scan_options *options);
266
+```
267
+
268
+Both functions will store a virus name under the pointer `virname`, the virus name is part of the engine structure and must not be released directly. If the third argument (`scanned`) is not NULL, the functions will increase its value with the size of scanned data (in `CL_COUNT_PRECISION` units). The last argument (`options`) requires a pointer to a data structure that specifies the scan options.  The data structure should be `memset()` Each variable in the structure is a bit-flag field.  The structure definition is:
256 269
 
257
-    int cl_scandesc(int desc, const char **virname, unsigned
258
-    long int *scanned, const struct cl_engine *engine,
259
-    unsigned int options);
270
+```c
271
+    struct cl_scan_options {
272
+        uint32_t general;
273
+        uint32_t parse;
274
+        uint32_t alert;
275
+        uint32_t heuristic_alert;
276
+        uint32_t mail;
277
+        uint32_t dev;
278
+    };
260 279
 ```
261 280
 
262
-Both functions will store a virus name under the pointer `virname`, the virus name is part of the engine structure and must not be released directly. If the third argument (`scanned`) is not NULL, the functions will increase its value with the size of scanned data (in `CL_COUNT_PRECISION` units). The last argument (`options`) specified the scan options and supports the following flags (which can be combined using bit operators):
281
+Supported flags for each of the fields are as follows:
282
+
283
+`general` - General scanning options.
284
+
285
+- **CL_SCAN_GENERAL_ALLMATCHES**
286
+    Scan in all-match mode
287
+- **CL_SCAN_GENERAL_COLLECT_METADATA**
288
+    Collect metadata (--gen-json)
289
+- **CL_SCAN_GENERAL_HEURISTICS**
290
+    Option to enable heuristic alerts.  Required for any of the heuristic alerting options to work.
291
+
292
+`parse` - Options to enable/disable specific parsing capabilities.  Generally you will want to enable all parsers.  The easiest way to do this is to set the parse flags to ~0.
263 293
 
264
-- **CL_SCAN_STDOPT**
265
-    This is an alias for a recommended set of scan options. You should use it to make your software ready for new features in the future versions of libclamav.
266
-- **CL_SCAN_RAW**
267
-    Use it alone if you want to disable support for special files.
268
-- **CL_SCAN_ARCHIVE**
294
+- **CL_SCAN_PARSE_ARCHIVE**
269 295
     This flag enables transparent scanning of various archive formats.
270
-- **CL_SCAN_BLOCKENCRYPTED**
271
-    With this flag the library will mark encrypted archives as viruses (Encrypted.Zip, Encrypted.RAR).
272
-- **CL_SCAN_MAIL**
273
-    Enable support for mail files.
274
-- **CL_SCAN_OLE2**
275
-    Enables support for OLE2 containers (used by MS Office and .msi files).
276
-- **CL_SCAN_PDF**
296
+- **CL_SCAN_PARSE_ELF**
297
+    Enable support for ELF files.
298
+- **CL_SCAN_PARSE_PDF**
277 299
     Enables scanning within PDF files.
278
-- **CL_SCAN_SWF**
300
+- **CL_SCAN_PARSE_SWF**
279 301
     Enables scanning within SWF files, notably compressed SWF.
280
-- **CL_SCAN_PE**
302
+- **CL_SCAN_PARSE_HWP**
303
+    Enables scanning of Hangul Word Processor (HWP) files.
304
+- **CL_SCAN_PARSE_XMLDOCS**
305
+    Enables scanning of XML-formatted documents (e.g. Word, Excel, Powerpoint, HWP).
306
+- **CL_SCAN_PARSE_MAIL**
307
+    Enable support for mail files.
308
+- **CL_SCAN_PARSE_OLE2**
309
+    Enables support for OLE2 containers (used by MS Office and .msi files).
310
+- **CL_SCAN_PARSE_HTML**
311
+    This flag enables HTML normalisation (including ScrEnc decryption).
312
+- **CL_SCAN_PARSE_PE**
281 313
     This flag enables deep scanning of Portable Executable files and allows libclamav to unpack executables compressed with run-time unpackers.
282
-- **CL_SCAN_ELF**
283
-    Enable support for ELF files.
284
-- **CL_SCAN_BLOCKBROKEN**
314
+
315
+`heuristic` - Options to enable specific heuristic alerts
316
+
317
+- **CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE**
318
+    Allow heuristic match to take precedence. When enabled, if a heuristic scan (such as phishingScan) detects a possible virus/phish it will stop scan immediately. Recommended, saves CPU scan-time. When *disabled*, virus/phish detected by heuristic scans will be reported only at the end of a scan. If an archive contains both a heuristically detected virus/phishing, and a real malware, the real malware will be reported.
319
+- **CL_SCAN_HEURISTIC_ENCRYPTED**
320
+    With this flag the library will mark encrypted archives as viruses (Encrypted.Zip, Encrypted.RAR).
321
+- **CL_SCAN_HEURISTIC_BROKEN**
285 322
     libclamav will try to detect broken executables and mark them as Broken.Executable.
286
-- **CL_SCAN_HTML**
287
-    This flag enables HTML normalisation (including ScrEnc decryption).
288
-- **CL_SCAN_ALGORITHMIC**
289
-    Enable algorithmic detection of viruses.
290
-- **CL_SCAN_PHISHING_BLOCKSSL**
291
-    Phishing module: always block SSL mismatches in URLs.
292
-- **CL_SCAN_PHISHING_BLOCKCLOAK**
323
+- **CL_SCAN_HEURISTIC_EXCEEDS_MAX**
324
+    Alert when the scan of any file exceeds maximums such as max filesize, max scansize, max recursion level.
325
+- **CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH**
326
+    Heuristic for Phishing module: always block SSL mismatches in URLs.
327
+- **CL_SCAN_HEURISTIC_PHISHING_CLOAK**
293 328
     Phishing module: always block cloaked URLs.
294
-- **CL_SCAN_STRUCTURED**
295
-    Enable the DLP module which scans for credit card and SSN numbers.
296
-- **CL_SCAN_STRUCTURED_SSN_NORMAL**
297
-    Search for SSNs formatted as xx-yy-zzzz.
298
-- **CL_SCAN_STRUCTURED_SSN_STRIPPED**
299
-    Search for SSNs formatted as xxyyzzzz.
300
-- **CL_SCAN_PARTIAL_MESSAGE**
301
-    Scan RFC1341 messages split over many emails. You will need to periodically clean up `$TemporaryDirectory/clamav-partial` directory.
302
-- **CL_SCAN_HEURISTIC_PRECEDENCE**
303
-    Allow heuristic match to take precedence. When enabled, if a heuristic scan (such as phishingScan) detects a possible virus/phish it will stop scan immediately. Recommended, saves CPU scan-time. When disabled, virus/phish detected by heuristic scans will be reported only at the end of a scan. If an archive contains both a heuristically detected virus/phishing, and a real malware, the real malware will be reported.
304
-- **CL_SCAN_BLOCKMACROS**
329
+- **CL_SCAN_HEURISTIC_MACROS**
305 330
     OLE2 containers, which contain VBA macros will be marked infected (Heuristics.OLE2.ContainsMacros).
331
+- **CL_SCAN_HEURISTIC_PARTITION_INTXN**
332
+    alert if partition table size doesn't make sense
333
+- **CL_SCAN_HEURISTIC_STRUCTURED**
334
+    Enable the data loss prevention (DLP) module which scans for credit card and SSN numbers. i.e. alert when detecting personal information
335
+- **CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL**
336
+    Search for [and alert when detecting] SSNs formatted as xx-yy-zzzz.
337
+- **CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED**
338
+    Search for [and alert when detecting] SSNs formatted as xxyyzzzz.
339
+
340
+`mail` - Options to enable specific mail parsing features
341
+
342
+- **CL_SCAN_MAIL_PARTIAL_MESSAGE**
343
+    Scan RFC1341 messages split over many emails. You will need to periodically clean up `$TemporaryDirectory/clamav-partial` directory.
344
+
345
+`dev` - Options designed for use by ClamAV developers
346
+
347
+- **CL_SCAN_DEV_COLLECT_SHA**
348
+    Enables hash output in sha-collect builds - for internal use only
349
+- **CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO**
350
+    Collect performance timings
306 351
 
307 352
 All functions return `CL_CLEAN` when the file seems clean, `CL_VIRUS` when a virus is detected and another value on failure.
308 353
 
... ...
@@ -311,7 +356,7 @@ All functions return `CL_CLEAN` when the file seems clean, `CL_VIRUS` when a vir
311 311
         const char *virname;
312 312
 
313 313
     if((ret = cl_scanfile("/tmp/test.exe", &virname, NULL, engine,
314
-    CL_SCAN_STDOPT)) == CL_VIRUS) {
314
+    &options)) == CL_VIRUS) {
315 315
         printf("Virus detected: %s\n", virname);
316 316
     } else {
317 317
         printf("No virus detected.\n");
... ...
@@ -591,7 +591,7 @@ Example
591 591
 
592 592
 # When BlockMax is set, files exceeding the MaxFileSize, MaxScanSize, or
593 593
 # MaxRecursion limit will be flagged with the virus
594
-# "Heuristic.Limits.Exceeded".
594
+# "Heuristics.Limits.Exceeded".
595 595
 # Default: no
596 596
 #BlockMax yes
597 597
 
... ...
@@ -45,6 +45,7 @@ int main(int argc, char **argv)
45 45
 	long double mb;
46 46
 	const char *virname;
47 47
 	struct cl_engine *engine;
48
+    struct cl_scan_options options;
48 49
 
49 50
     if(argc != 2) {
50 51
 	printf("Usage: %s file\n", argv[0]);
... ...
@@ -85,7 +86,11 @@ int main(int argc, char **argv)
85 85
     }
86 86
 
87 87
     /* scan file descriptor */
88
-    if((ret = cl_scandesc(fd, &virname, &size, engine, CL_SCAN_STDOPT)) == CL_VIRUS) {
88
+    memset(&options, 0, sizeof(struct cl_scan_options));
89
+    options.parse |= ~0; /* enable all parsers */
90
+    options.general |= CL_SCAN_GENERAL_HEURISTICS; /* enable heuristic alert options */
91
+
92
+    if((ret = cl_scandesc(fd, &virname, &size, engine, &options)) == CL_VIRUS) {
89 93
 	printf("Virus detected: %s\n", virname);
90 94
     } else {
91 95
 	if(ret == CL_CLEAN) {
... ...
@@ -106,7 +106,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
106 106
 
107 107
     SzArEx_Init(&db);
108 108
     res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
109
-    if(res == SZ_ERROR_ENCRYPTED && DETECT_ENCRYPTED) {
109
+    if(res == SZ_ERROR_ENCRYPTED && SCAN_HEURISTIC_ENCRYPTED) {
110 110
 	cli_dbgmsg("cli_7unz: Encrypted header found in archive.\n");
111 111
 	found = cli_append_virus(ctx, "Heuristics.Encrypted.7Zip");
112 112
     } else if(res == SZ_OK) {
... ...
@@ -158,12 +158,12 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
158 158
 	    res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &allocImp, &allocTempImp);
159 159
 	    if(res == SZ_ERROR_ENCRYPTED) {
160 160
 		encrypted = 1;
161
-		if(DETECT_ENCRYPTED) {
161
+		if(SCAN_HEURISTIC_ENCRYPTED) {
162 162
 		    cli_dbgmsg("cli_7unz: Encrypted files found in archive.\n");
163 163
 		    found = cli_append_virus(ctx, "Heuristics.Encrypted.7Zip");
164 164
                     if (found != CL_CLEAN) {
165 165
                         if (found == CL_VIRUS) {
166
-                            if (SCAN_ALL)
166
+                            if (SCAN_ALLMATCHES)
167 167
                                 viruses_found++;
168 168
                         } else
169 169
                             break;
... ...
@@ -173,7 +173,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
173 173
 	    if(cli_matchmeta(ctx, name, 0, f->Size, encrypted, i, f->CrcDefined ? f->Crc : 0, NULL)) {
174 174
 		found = CL_VIRUS;
175 175
 		viruses_found++;
176
-		if (!SCAN_ALL)
176
+		if (!SCAN_ALLMATCHES)
177 177
 		    break;
178 178
 	    }
179 179
 	    if (res != SZ_OK)
... ...
@@ -194,7 +194,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
194 194
 
195 195
 		free(name);
196 196
 		if(found != CL_CLEAN)
197
-		    if (!(SCAN_ALL && found == CL_VIRUS))
197
+		    if (!(SCAN_ALLMATCHES && found == CL_VIRUS))
198 198
 			break;
199 199
 	    }
200 200
 	}
... ...
@@ -217,7 +217,7 @@ int cli_7unz (cli_ctx *ctx, size_t offset) {
217 217
     else
218 218
 	cli_dbgmsg("cli_7unz: error %d\n", res);
219 219
 
220
-    if (SCAN_ALL && viruses_found)
220
+    if (SCAN_ALLMATCHES && viruses_found)
221 221
 	return CL_VIRUS;
222 222
     return found;
223 223
 }
... ...
@@ -133,10 +133,10 @@ int cli_scanapm(cli_ctx *ctx)
133 133
     }
134 134
 
135 135
     /* check that the partition table fits in the space specified - HEURISTICS */
136
-    if ((ctx->options & CL_SCAN_PARTITION_INTXN) && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
136
+    if (SCAN_HEURISTIC_PARTITION_INTXN && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
137 137
         ret = apm_prtn_intxn(ctx, &aptable, sectorsize, old_school);
138 138
         if (ret != CL_CLEAN) {
139
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
139
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
140 140
                 detection = CL_VIRUS;
141 141
             else
142 142
                 return ret;
... ...
@@ -226,7 +226,7 @@ int cli_scanapm(cli_ctx *ctx)
226 226
         /* send the partition to cli_map_scan */
227 227
         ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
228 228
         if (ret != CL_CLEAN) {
229
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
229
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
230 230
                 detection = CL_VIRUS;
231 231
             else
232 232
                 return ret;
... ...
@@ -296,7 +296,7 @@ static int apm_prtn_intxn(cli_ctx *ctx, struct apm_partition_info *aptable, size
296 296
                 ret = cli_append_virus(ctx, PRTN_INTXN_DETECTION);
297 297
                 if (ret == CL_VIRUS)
298 298
                     virus_found = 1;
299
-                if (SCAN_ALL || ret == CL_CLEAN)
299
+                if (SCAN_ALLMATCHES || ret == CL_CLEAN)
300 300
                     tmp = 0;
301 301
                 else
302 302
                     goto leave;
... ...
@@ -394,7 +394,7 @@ static int ea05(cli_ctx *ctx, const uint8_t *base, char *tmpd) {
394 394
         return CL_ESEEK;
395 395
     }
396 396
     if(cli_magic_scandesc(i, ctx) == CL_VIRUS) {
397
-      if (!SCAN_ALL) {
397
+      if (!SCAN_ALLMATCHES) {
398 398
 	close(i);
399 399
 	if(!ctx->engine->keeptmp)
400 400
 	  if(cli_unlink(tempfile)) return CL_EUNLINK;
... ...
@@ -921,7 +921,7 @@ static int ea06(cli_ctx *ctx, const uint8_t *base, char *tmpd) {
921 921
         return CL_ESEEK;
922 922
     }
923 923
     if(cli_magic_scandesc(i, ctx) == CL_VIRUS) {
924
-      if (!SCAN_ALL) {
924
+      if (!SCAN_ALLMATCHES) {
925 925
 	close(i);
926 926
 	if(!ctx->engine->keeptmp)
927 927
 	  if (cli_unlink(tempfile)) return CL_EUNLINK;
... ...
@@ -618,8 +618,9 @@ int
618 618
 fileblobScan(const fileblob *fb)
619 619
 {
620 620
 	int rc;
621
+	cli_ctx *ctx = fb->ctx;
621 622
 	STATBUF sb;
622
-        int virus_found = 0;
623
+	int virus_found = 0;
623 624
 
624 625
 	if(fb->isInfected)
625 626
 		return CL_VIRUS;
... ...
@@ -638,7 +639,7 @@ fileblobScan(const fileblob *fb)
638 638
 	lseek(fb->fd, 0, SEEK_SET);
639 639
 	FSTAT(fb->fd, &sb);
640 640
 	if(cli_matchmeta(fb->ctx, fb->b.name, sb.st_size, sb.st_size, 0, 0, 0, NULL) == CL_VIRUS) {
641
-            if (!(fb->ctx->options & CL_SCAN_ALLMATCHES))
641
+            if (!SCAN_ALLMATCHES)
642 642
                 return CL_VIRUS;
643 643
             virus_found = 1;
644 644
         }
... ...
@@ -1834,7 +1834,7 @@ int cli_bytecode_run(const struct cli_all_bc *bcs, const struct cli_bc *bc, stru
1834 1834
 
1835 1835
 	/* need to be called here to catch any extracted but not yet scanned files
1836 1836
 	*/
1837
-	if (ctx->outfd && (ret != CL_VIRUS || cctx->options & CL_SCAN_ALLMATCHES))
1837
+	if (ctx->outfd && (ret != CL_VIRUS || cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES))
1838 1838
 	    cli_bcapi_extract_new(ctx, -1);
1839 1839
     }
1840 1840
     if (bc->state == bc_jit || test_mode) {
... ...
@@ -1854,7 +1854,7 @@ int cli_bytecode_run(const struct cli_all_bc *bcs, const struct cli_bc *bc, stru
1854 1854
 
1855 1855
 	/* need to be called here to catch any extracted but not yet scanned files
1856 1856
 	*/
1857
-	if (ctx->outfd && (ret != CL_VIRUS || cctx->options & CL_SCAN_ALLMATCHES))
1857
+	if (ctx->outfd && (ret != CL_VIRUS || cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES))
1858 1858
 	    cli_bcapi_extract_new(ctx, -1);
1859 1859
     }
1860 1860
     cli_event_time_stop(g_sigevents, bc->sigtime_id);
... ...
@@ -2866,7 +2866,7 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c
2866 2866
 	if (ctx->virname) {
2867 2867
 	    cli_dbgmsg("Bytecode runhook found virus: %s\n", ctx->virname);
2868 2868
 	    cli_append_virus(cctx, ctx->virname);
2869
-	    if (!(cctx->options & CL_SCAN_ALLMATCHES)) {
2869
+	    if (!(cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)) {
2870 2870
 		cli_bytecode_context_clear(ctx);
2871 2871
 		return CL_VIRUS;
2872 2872
 	    }
... ...
@@ -2906,7 +2906,7 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c
2906 2906
 		if (ret != CL_CLEAN) {
2907 2907
 		    if (ret == CL_VIRUS) {
2908 2908
 			cli_dbgmsg("Scanning unpacked file by bytecode %u found a virus\n", bc->id);
2909
-			if (cctx->options & CL_SCAN_ALLMATCHES) {
2909
+			if (cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES) {
2910 2910
 			    cli_bytecode_context_reset(ctx);
2911 2911
 			    continue;
2912 2912
 			}
... ...
@@ -1275,7 +1275,198 @@ uint32_t cli_bcapi_engine_dconf_level(struct cli_bc_ctx *ctx)
1275 1275
 uint32_t cli_bcapi_engine_scan_options(struct cli_bc_ctx *ctx)
1276 1276
 {
1277 1277
     cli_ctx *cctx = (cli_ctx*)ctx->ctx;
1278
-    return cctx->options;
1278
+    uint32_t options = CL_SCAN_RAW;
1279
+    
1280
+    if (cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)
1281
+        options |= CL_SCAN_ALLMATCHES;
1282
+    if (cctx->options->general & CL_SCAN_GENERAL_HEURISTICS)
1283
+        options |= CL_SCAN_ALGORITHMIC;
1284
+    if (cctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA)
1285
+        options |= CL_SCAN_FILE_PROPERTIES;
1286
+    if (cctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)
1287
+        options |= CL_SCAN_HEURISTIC_PRECEDENCE;
1288
+
1289
+    if (cctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
1290
+        options |= CL_SCAN_ARCHIVE;
1291
+    if (cctx->options->parse & CL_SCAN_PARSE_ELF)
1292
+        options |= CL_SCAN_ELF;
1293
+    if (cctx->options->parse & CL_SCAN_PARSE_PDF)
1294
+        options |= CL_SCAN_PDF;
1295
+    if (cctx->options->parse & CL_SCAN_PARSE_SWF)
1296
+        options |= CL_SCAN_SWF;
1297
+    if (cctx->options->parse & CL_SCAN_PARSE_HWP3)
1298
+        options |= CL_SCAN_HWP3;
1299
+    if (cctx->options->parse & CL_SCAN_PARSE_XMLDOCS)
1300
+        options |= CL_SCAN_XMLDOCS;
1301
+    if (cctx->options->parse & CL_SCAN_PARSE_MAIL)
1302
+        options |= CL_SCAN_MAIL;
1303
+    if (cctx->options->parse & CL_SCAN_PARSE_OLE2)
1304
+        options |= CL_SCAN_OLE2;
1305
+    if (cctx->options->parse & CL_SCAN_PARSE_HTML)
1306
+        options |= CL_SCAN_HTML;
1307
+    if (cctx->options->parse & CL_SCAN_PARSE_PE)
1308
+        options |= CL_SCAN_PE;
1309
+    // if (cctx->options->parse & CL_SCAN_MAIL_URL)
1310
+    //    options |= CL_SCAN_MAILURL; /* deprecated circa 2009 */
1311
+
1312
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN)
1313
+        options |= CL_SCAN_BLOCKBROKEN;
1314
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX)
1315
+        options |= CL_SCAN_BLOCKMAX;
1316
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH)
1317
+        options |= CL_SCAN_PHISHING_BLOCKSSL;
1318
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK)
1319
+        options |= CL_SCAN_PHISHING_BLOCKCLOAK;
1320
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS)
1321
+        options |= CL_SCAN_BLOCKMACROS;
1322
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED)
1323
+        options |= CL_SCAN_BLOCKENCRYPTED;
1324
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN)
1325
+        options |= CL_SCAN_PARTITION_INTXN;
1326
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED)
1327
+        options |= CL_SCAN_STRUCTURED;
1328
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL)
1329
+        options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
1330
+    if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED)
1331
+        options |= CL_SCAN_STRUCTURED_SSN_STRIPPED;
1332
+
1333
+    if (cctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE)
1334
+        options |= CL_SCAN_PARTIAL_MESSAGE;
1335
+
1336
+    if (cctx->options->dev & CL_SCAN_DEV_COLLECT_SHA)
1337
+        options |= CL_SCAN_INTERNAL_COLLECT_SHA;
1338
+    if (cctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO)
1339
+        options |= CL_SCAN_PERFORMANCE_INFO;
1340
+
1341
+    return options;
1342
+}
1343
+
1344
+uint32_t cli_bcapi_engine_scan_options_ex(struct cli_bc_ctx *ctx, const uint8_t *option_name, uint32_t name_len)
1345
+{
1346
+    uint32_t i = 0;
1347
+    char *option_name_l = NULL;
1348
+
1349
+    if (ctx == NULL || option_name == NULL || name_len == 0) {
1350
+        cli_warnmsg("engine_scan_options_ex: Invalid arguments!");
1351
+        return 0;
1352
+    }
1353
+
1354
+    cli_ctx *cctx = (cli_ctx*)ctx->ctx;
1355
+    if (cctx == NULL || cctx->options == NULL) {
1356
+        cli_warnmsg("engine_scan_options_ex: Invalid arguments!");
1357
+        return 0;
1358
+    }
1359
+
1360
+    option_name_l = malloc(name_len + 1);
1361
+    for (i = 0; i < name_len; i++) {
1362
+        option_name_l[0] = tolower(option_name[i]);
1363
+    }
1364
+    option_name_l[name_len] = '\0';
1365
+
1366
+    if (strncmp(option_name_l, "general", MIN(name_len, sizeof("general")))) {
1367
+        if (cli_memstr(option_name_l, name_len, "allmatch", sizeof("allmatch"))) {
1368
+            return (cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES) ? 1 : 0;
1369
+        }
1370
+        if (cli_memstr(option_name_l, name_len, "collect metadata", sizeof("collect metadata"))) {
1371
+            return (cctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA) ? 1 : 0;
1372
+        }
1373
+        if (cli_memstr(option_name_l, name_len, "heuristics", sizeof("heuristics"))) {
1374
+            return (cctx->options->general & CL_SCAN_GENERAL_HEURISTICS) ? 1 : 0;
1375
+        }
1376
+        if (cli_memstr(option_name_l, name_len, "precedence", sizeof("precedence"))) {
1377
+            return (cctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE) ? 1 : 0;
1378
+        }
1379
+        /* else unknown option */
1380
+        return 0;
1381
+    }
1382
+    else if (strncmp(option_name_l, "parse", MIN(name_len, sizeof("parse")))) {
1383
+        if (cli_memstr(option_name_l, name_len, "archive", sizeof("archive"))) {
1384
+            return (cctx->options->parse & CL_SCAN_PARSE_ARCHIVE) ? 1 : 0;
1385
+        }
1386
+        if (cli_memstr(option_name_l, name_len, "elf", sizeof("elf"))) {
1387
+            return (cctx->options->parse & CL_SCAN_PARSE_ELF) ? 1 : 0;
1388
+        }
1389
+        if (cli_memstr(option_name_l, name_len, "pdf", sizeof("pdf"))) {
1390
+            return (cctx->options->parse & CL_SCAN_PARSE_PDF) ? 1 : 0;
1391
+        }
1392
+        if (cli_memstr(option_name_l, name_len, "swf", sizeof("swf"))) {
1393
+            return (cctx->options->parse & CL_SCAN_PARSE_SWF) ? 1 : 0;
1394
+        }
1395
+        if (cli_memstr(option_name_l, name_len, "hwp3", sizeof("hwp3"))) {
1396
+            return (cctx->options->parse & CL_SCAN_PARSE_HWP3) ? 1 : 0;
1397
+        }
1398
+        if (cli_memstr(option_name_l, name_len, "xmldocs", sizeof("xmldocs"))) {
1399
+            return (cctx->options->parse & CL_SCAN_PARSE_XMLDOCS) ? 1 : 0;
1400
+        }
1401
+        if (cli_memstr(option_name_l, name_len, "mail", sizeof("mail"))) {
1402
+            return (cctx->options->parse & CL_SCAN_PARSE_MAIL) ? 1 : 0;
1403
+        }
1404
+        if (cli_memstr(option_name_l, name_len, "ole2", sizeof("ole2"))) {
1405
+            return (cctx->options->parse & CL_SCAN_PARSE_OLE2) ? 1 : 0;
1406
+        }
1407
+        if (cli_memstr(option_name_l, name_len, "html", sizeof("html"))) {
1408
+            return (cctx->options->parse & CL_SCAN_PARSE_HTML) ? 1 : 0;
1409
+        }
1410
+        if (cli_memstr(option_name_l, name_len, "pe", sizeof("pe"))) {
1411
+            return (cctx->options->parse & CL_SCAN_PARSE_PE) ? 1 : 0;
1412
+        }
1413
+        /* else unknown option */
1414
+        return 0;
1415
+    }
1416
+    else if (strncmp(option_name_l, "heuristic", MIN(name_len, sizeof("heuristic")))) {
1417
+        if (cli_memstr(option_name_l, name_len, "broken", sizeof("broken"))) {
1418
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN) ? 1 : 0;
1419
+        }
1420
+        if (cli_memstr(option_name_l, name_len, "exceeds max", sizeof("exceeds max"))) {
1421
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX) ? 1 : 0;
1422
+        }
1423
+        if (cli_memstr(option_name_l, name_len, "phishing ssl mismatch", sizeof("phishing ssl mismatch"))) {
1424
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH) ? 1 : 0;
1425
+        }
1426
+        if (cli_memstr(option_name_l, name_len, "phishing cloak", sizeof("phishing cloak"))) {
1427
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK) ? 1 : 0;
1428
+        }
1429
+        if (cli_memstr(option_name_l, name_len, "macros", sizeof("macros"))) {
1430
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS) ? 1 : 0;
1431
+        }
1432
+        if (cli_memstr(option_name_l, name_len, "encrypted", sizeof("encrypted"))) {
1433
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED) ? 1 : 0;
1434
+        }
1435
+        if (cli_memstr(option_name_l, name_len, "partition intxn", sizeof("partition intxn"))) {
1436
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN) ? 1 : 0;
1437
+        }
1438
+        if (cli_memstr(option_name_l, name_len, "structured", sizeof("structured"))) {
1439
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED) ? 1 : 0;
1440
+        }
1441
+        if (cli_memstr(option_name_l, name_len, "structured ssn normal", sizeof("structured ssn normal"))) {
1442
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL) ? 1 : 0;
1443
+        }
1444
+        if (cli_memstr(option_name_l, name_len, "structured ssn stripped", sizeof("structured ssn stripped"))) {
1445
+            return (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED) ? 1 : 0;
1446
+        }
1447
+        /* else unknown option */
1448
+        return 0;
1449
+    }
1450
+    else if (strncmp(option_name_l, "mail", MIN(name_len, sizeof("mail")))) {
1451
+        if (cli_memstr(option_name_l, name_len, "partial message", sizeof("partial message"))) {
1452
+            return (cctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE) ? 1 : 0;
1453
+        }
1454
+        /* else unknown option */
1455
+        return 0;
1456
+    }
1457
+    else if (strncmp(option_name_l, "dev", MIN(name_len, sizeof("dev")))) {
1458
+        if (cli_memstr(option_name_l, name_len, "collect sha", sizeof("collect sha"))) {
1459
+            return (cctx->options->dev & CL_SCAN_DEV_COLLECT_SHA) ? 1 : 0;
1460
+        }
1461
+        if (cli_memstr(option_name_l, name_len, "collect performance info", sizeof("collect performance info"))) {
1462
+            return (cctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO) ? 1 : 0;
1463
+        }
1464
+        /* else unknown option */
1465
+        return 0;
1466
+    } else {
1467
+        /* else unknown option */
1468
+        return 0;
1469
+    }
1279 1470
 }
1280 1471
 
1281 1472
 uint32_t cli_bcapi_engine_db_options(struct cli_bc_ctx *ctx)
... ...
@@ -1,5 +1,5 @@
1 1
 /*
2
- *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
2
+ *  Copyright (C) 2014-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 3
  *  Copyright (C) 2009-2013 Sourcefire, Inc.
4 4
  *  All rights reserved.
5 5
  *  Authors: Török Edvin, Kevin Lin
... ...
@@ -203,6 +203,45 @@ enum bc_json_type {
203 203
     JSON_TYPE_STRING     /* */
204 204
 };
205 205
 
206
+/**
207
+\group_engine
208
+ * Scan option flag values for engine_scan_options(). *DEPRECATED*
209
+ */
210
+#define CL_SCAN_RAW                     0x0
211
+#define CL_SCAN_ARCHIVE                 0x1
212
+#define CL_SCAN_MAIL                    0x2
213
+#define CL_SCAN_OLE2                    0x4
214
+#define CL_SCAN_BLOCKENCRYPTED          0x8
215
+#define CL_SCAN_HTML                    0x10
216
+#define CL_SCAN_PE                      0x20
217
+#define CL_SCAN_BLOCKBROKEN             0x40
218
+#define CL_SCAN_MAILURL                 0x80  /* deprecated circa 2009 */
219
+#define CL_SCAN_BLOCKMAX                0x100
220
+#define CL_SCAN_ALGORITHMIC             0x200
221
+//#define UNUSED                        0x400
222
+#define CL_SCAN_PHISHING_BLOCKSSL       0x800 /* ssl mismatches, not ssl by itself*/
223
+#define CL_SCAN_PHISHING_BLOCKCLOAK     0x1000
224
+#define CL_SCAN_ELF                     0x2000
225
+#define CL_SCAN_PDF                     0x4000
226
+#define CL_SCAN_STRUCTURED              0x8000
227
+#define CL_SCAN_STRUCTURED_SSN_NORMAL   0x10000
228
+#define CL_SCAN_STRUCTURED_SSN_STRIPPED 0x20000
229
+#define CL_SCAN_PARTIAL_MESSAGE         0x40000
230
+#define CL_SCAN_HEURISTIC_PRECEDENCE    0x80000
231
+#define CL_SCAN_BLOCKMACROS             0x100000
232
+#define CL_SCAN_ALLMATCHES              0x200000
233
+#define CL_SCAN_SWF                     0x400000
234
+#define CL_SCAN_PARTITION_INTXN         0x800000
235
+#define CL_SCAN_XMLDOCS                 0x1000000
236
+#define CL_SCAN_HWP3                    0x2000000
237
+//#define UNUSED                        0x4000000
238
+//#define UNUSED                        0x8000000
239
+#define CL_SCAN_FILE_PROPERTIES         0x10000000
240
+//#define UNUSED                        0x20000000
241
+#define CL_SCAN_PERFORMANCE_INFO        0x40000000 /* Collect performance timings */
242
+#define CL_SCAN_INTERNAL_COLLECT_SHA    0x80000000 /* Enables hash output in sha-collect builds - for internal use only */
243
+
244
+
206 245
 #ifdef __CLAMBC__
207 246
 
208 247
 /* --------------- BEGIN GLOBALS -------------------------------------------- */
... ...
@@ -885,7 +924,7 @@ uint32_t engine_dconf_level(void);
885 885
 
886 886
 /**
887 887
 \group_engine
888
-  * Returns the current engine's scan options.
888
+  * Returns the current engine's scan options. **DEPRECATED**
889 889
   * @return CL_SCAN* flags 
890 890
   */
891 891
 uint32_t engine_scan_options(void);
... ...
@@ -1222,5 +1261,49 @@ int32_t json_get_int(int32_t objid);
1222 1222
 //double json_get_double(int32_t objid);
1223 1223
 
1224 1224
 /* ----------------- END 0.98.4 APIs ---------------------------------- */
1225
+/* ----------------- BEGIN 0.100.0 APIs ------------------------------- */
1226
+/* ----------------- Scan Options APIs -------------------------------- */
1227
+/**
1228
+\group_engine
1229
+  * Check if any given scan option is enabled.
1230
+  * Returns non-zero if the following named options are set:
1231
+  * 
1232
+  * "general allmatch"                - all-match mode is enabled
1233
+  * "general collect metadata"        - --gen-json is enabled
1234
+  * "general heuristics"              - --gen-json is enabled
1235
+  * 
1236
+  * "parse archive"                   - archive parsing is enabled
1237
+  * "parse pdf"                       - pdf parsing is enabled
1238
+  * "parse swf"                       - swf parsing is enabled
1239
+  * "parse hwp3"                      - hwp3 parsing is enabled
1240
+  * "parse xmldocs"                   - xmldocs parsing is enabled
1241
+  * "parse mail"                      - mail parsing is enabled
1242
+  * "parse ole2"                      - ole2 parsing is enabled
1243
+  * "parse html"                      - html parsing is enabled
1244
+  * "parse pe"                        - pe parsing is enabled
1245
+  * 
1246
+  * "heuristic precedence"            - heuristic signatures are set to take precedence
1247
+  * "heuristic broken"                - broken pe heuristic is enabled
1248
+  * "heuristic exceeds max"           - heuristic for when max settings are exceeded is enabled
1249
+  * "heuristic phishing ssl mismatch" - phishing ssl mismatch heuristic is enabled
1250
+  * "heuristic phishing cloak"        - phishing cloak heuristic is enabled
1251
+  * "heuristic macros"                - macros heuristic is enabled
1252
+  * "heuristic encrypted"             - encrypted heuristic is enabled
1253
+  * "heuristic partition intxn"       - macpartition intxnros heuristic is enabled
1254
+  * "heuristic structured"            - structured heuristic is enabled
1255
+  * "heuristic structured ssn normal" - structured ssn normal heuristic is enabled
1256
+  * "heuristic structured ssn stripped" - structured ssn stripped heuristic is enabled
1257
+  * 
1258
+  * "mail partial message"            - parsing of partial mail messages is enabled
1259
+  * 
1260
+  * "dev collect sha"                 - --dev-collect-hashes is enabled
1261
+  * "dev collect performance info"    - --dev-performance is enabled
1262
+  * 
1263
+  * @param[in] scan_options enum value for desired scan option category.
1264
+  * @return CL_SCAN_<OPTION>_* flags 
1265
+  */
1266
+uint32_t engine_scan_options_ex(const uint8_t *option_name, uint32_t name_len);
1267
+
1268
+/* ----------------- END 0.101 APIs ---------------------------------- */
1225 1269
 #endif
1226 1270
 #endif
... ...
@@ -2,7 +2,7 @@
2 2
  *  ClamAV bytecode internal API
3 3
  *  This is an automatically generated file!
4 4
  *
5
- *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5
+ *  Copyright (C) 2014-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 6
  *  Copyright (C) 2009-2013 Sourcefire, Inc.
7 7
  *
8 8
  * Redistribution and use in source and binary forms, with or without
... ...
@@ -133,6 +133,7 @@ int32_t cli_bcapi_json_get_string_length(struct cli_bc_ctx *ctx , int32_t);
133 133
 int32_t cli_bcapi_json_get_string(struct cli_bc_ctx *ctx , int8_t*, int32_t, int32_t);
134 134
 int32_t cli_bcapi_json_get_boolean(struct cli_bc_ctx *ctx , int32_t);
135 135
 int32_t cli_bcapi_json_get_int(struct cli_bc_ctx *ctx , int32_t);
136
+uint32_t cli_bcapi_engine_scan_options_ex(struct cli_bc_ctx *ctx , const uint8_t*, uint32_t);
136 137
 
137 138
 const struct cli_apiglobal cli_globals[] = {
138 139
 /* Bytecode globals BEGIN */
... ...
@@ -157,18 +158,18 @@ static uint16_t cli_tmp4[]={16, 8, 8, 32, 32, 32, 32, 32, 32, 32, 32, 32, 16, 16
157 157
 static uint16_t cli_tmp5[]={32, 16, 16, 32, 32, 32, 16, 16};
158 158
 static uint16_t cli_tmp6[]={32};
159 159
 static uint16_t cli_tmp7[]={32};
160
-static uint16_t cli_tmp8[]={32, 32};
161
-static uint16_t cli_tmp9[]={32, 65, 32, 32};
162
-static uint16_t cli_tmp10[]={32, 32, 32};
163
-static uint16_t cli_tmp11[]={32};
164
-static uint16_t cli_tmp12[]={32, 65, 32, 65, 32};
165
-static uint16_t cli_tmp13[]={65, 32, 32};
166
-static uint16_t cli_tmp14[]={32, 32, 32, 32};
167
-static uint16_t cli_tmp15[]={32, 85, 32};
168
-static uint16_t cli_tmp16[]={86};
169
-static uint16_t cli_tmp17[]={32, 32, 32, 32, 32, 32, 32, 87, 87, 87, 87, 87, 87, 87, 8, 8, 8, 8, 8, 8, 8, 8, 8};
170
-static uint16_t cli_tmp18[]={8};
171
-static uint16_t cli_tmp19[]={32, 65, 32};
160
+static uint16_t cli_tmp8[]={32, 65, 32};
161
+static uint16_t cli_tmp9[]={32, 32};
162
+static uint16_t cli_tmp10[]={32, 65, 32, 32};
163
+static uint16_t cli_tmp11[]={32, 32, 32};
164
+static uint16_t cli_tmp12[]={32};
165
+static uint16_t cli_tmp13[]={32, 65, 32, 65, 32};
166
+static uint16_t cli_tmp14[]={65, 32, 32};
167
+static uint16_t cli_tmp15[]={32, 32, 32, 32};
168
+static uint16_t cli_tmp16[]={32, 86, 32};
169
+static uint16_t cli_tmp17[]={87};
170
+static uint16_t cli_tmp18[]={32, 32, 32, 32, 32, 32, 32, 88, 88, 88, 88, 88, 88, 88, 8, 8, 8, 8, 8, 8, 8, 8, 8};
171
+static uint16_t cli_tmp19[]={8};
172 172
 static uint16_t cli_tmp20[]={32, 65, 32, 32, 32, 32};
173 173
 static uint16_t cli_tmp21[]={32, 91, 32};
174 174
 static uint16_t cli_tmp22[]={92};
... ...
@@ -190,18 +191,18 @@ const struct cli_bc_type cli_apicall_types[]={
190 190
 	{DStructType, cli_tmp5, 8, 0, 0},
191 191
 	{DArrayType, cli_tmp6, 1, 0, 0},
192 192
 	{DArrayType, cli_tmp7, 64, 0, 0},
193
-	{DFunctionType, cli_tmp8, 2, 0, 0},
194
-	{DFunctionType, cli_tmp9, 4, 0, 0},
195
-	{DFunctionType, cli_tmp10, 3, 0, 0},
196
-	{DFunctionType, cli_tmp11, 1, 0, 0},
197
-	{DFunctionType, cli_tmp12, 5, 0, 0},
198
-	{DFunctionType, cli_tmp13, 3, 0, 0},
199
-	{DFunctionType, cli_tmp14, 4, 0, 0},
200
-	{DFunctionType, cli_tmp15, 3, 0, 0},
201
-	{DPointerType, cli_tmp16, 1, 0, 0},
202
-	{DStructType, cli_tmp17, 23, 0, 0},
203
-	{DArrayType, cli_tmp18, 65, 0, 0},
204
-	{DFunctionType, cli_tmp19, 3, 0, 0},
193
+	{DFunctionType, cli_tmp8, 3, 0, 0},
194
+	{DFunctionType, cli_tmp9, 2, 0, 0},
195
+	{DFunctionType, cli_tmp10, 4, 0, 0},
196
+	{DFunctionType, cli_tmp11, 3, 0, 0},
197
+	{DFunctionType, cli_tmp12, 1, 0, 0},
198
+	{DFunctionType, cli_tmp13, 5, 0, 0},
199
+	{DFunctionType, cli_tmp14, 3, 0, 0},
200
+	{DFunctionType, cli_tmp15, 4, 0, 0},
201
+	{DFunctionType, cli_tmp16, 3, 0, 0},
202
+	{DPointerType, cli_tmp17, 1, 0, 0},
203
+	{DStructType, cli_tmp18, 23, 0, 0},
204
+	{DArrayType, cli_tmp19, 65, 0, 0},
205 205
 	{DFunctionType, cli_tmp20, 6, 0, 0},
206 206
 	{DFunctionType, cli_tmp21, 3, 0, 0},
207 207
 	{DPointerType, cli_tmp22, 1, 0, 0},
... ...
@@ -214,110 +215,111 @@ const struct cli_bc_type cli_apicall_types[]={
214 214
 	{DArrayType, cli_tmp29, 3, 0, 0},
215 215
 	{DArrayType, cli_tmp30, 10, 0, 0}
216 216
 };
217
-const unsigned cli_apicall_maxtypes=sizeof(cli_apicall_types)/sizeof(cli_apicall_types[0]);
218 217
 
218
+const unsigned cli_apicall_maxtypes=sizeof(cli_apicall_types)/sizeof(cli_apicall_types[0]);
219 219
 const struct cli_apicall cli_apicalls[]={
220 220
 /* Bytecode APIcalls BEGIN */
221
-	{"test1", 10, 0, 0},
222
-	{"read", 19, 0, 1},
223
-	{"write", 19, 1, 1},
224
-	{"seek", 10, 1, 0},
225
-	{"setvirusname", 19, 2, 1},
226
-	{"debug_print_str", 19, 3, 1},
227
-	{"debug_print_uint", 8, 0, 2},
221
+	{"test1", 11, 0, 0},
222
+	{"read", 8, 0, 1},
223
+	{"write", 8, 1, 1},
224
+	{"seek", 11, 1, 0},
225
+	{"setvirusname", 8, 2, 1},
226
+	{"debug_print_str", 8, 3, 1},
227
+	{"debug_print_uint", 9, 0, 2},
228 228
 	{"disasm_x86", 25, 4, 1},
229
-	{"trace_directory", 19, 5, 1},
230
-	{"trace_scope", 19, 6, 1},
231
-	{"trace_source", 19, 7, 1},
232
-	{"trace_op", 19, 8, 1},
233
-	{"trace_value", 19, 9, 1},
234
-	{"trace_ptr", 19, 10, 1},
235
-	{"pe_rawaddr", 8, 1, 2},
236
-	{"file_find", 19, 11, 1},
237
-	{"file_byteat", 8, 2, 2},
229
+	{"trace_directory", 8, 5, 1},
230
+	{"trace_scope", 8, 6, 1},
231
+	{"trace_source", 8, 7, 1},
232
+	{"trace_op", 8, 8, 1},
233
+	{"trace_value", 8, 9, 1},
234
+	{"trace_ptr", 8, 10, 1},
235
+	{"pe_rawaddr", 9, 1, 2},
236
+	{"file_find", 8, 11, 1},
237
+	{"file_byteat", 9, 2, 2},
238 238
 	{"malloc", 24, 0, 3},
239
-	{"test2", 8, 3, 2},
239
+	{"test2", 9, 3, 2},
240 240
 	{"get_pe_section", 21, 12, 1},
241 241
 	{"fill_buffer", 20, 0, 4},
242
-	{"extract_new", 8, 4, 2},
243
-	{"read_number", 8, 5, 2},
244
-	{"hashset_new", 11, 0, 5},
245
-	{"hashset_add", 10, 2, 0},
246
-	{"hashset_remove", 10, 3, 0},
247
-	{"hashset_contains", 10, 4, 0},
248
-	{"hashset_done", 8, 6, 2},
249
-	{"hashset_empty", 8, 7, 2},
250
-	{"buffer_pipe_new", 8, 8, 2},
251
-	{"buffer_pipe_new_fromfile", 8, 9, 2},
252
-	{"buffer_pipe_read_avail", 8, 10, 2},
253
-	{"buffer_pipe_read_get", 13, 0, 6},
254
-	{"buffer_pipe_read_stopped", 10, 5, 0},
255
-	{"buffer_pipe_write_avail", 8, 11, 2},
256
-	{"buffer_pipe_write_get", 13, 1, 6},
257
-	{"buffer_pipe_write_stopped", 10, 6, 0},
258
-	{"buffer_pipe_done", 8, 12, 2},
259
-	{"inflate_init", 14, 0, 7},
260
-	{"inflate_process", 8, 13, 2},
261
-	{"inflate_done", 8, 14, 2},
262
-	{"bytecode_rt_error", 8, 15, 2},
263
-	{"jsnorm_init", 8, 16, 2},
264
-	{"jsnorm_process", 8, 17, 2},
265
-	{"jsnorm_done", 8, 18, 2},
266
-	{"ilog2", 10, 7, 0},
267
-	{"ipow", 14, 1, 7},
268
-	{"iexp", 14, 2, 7},
269
-	{"isin", 14, 3, 7},
270
-	{"icos", 14, 4, 7},
271
-	{"memstr", 12, 0, 8},
272
-	{"hex2ui", 10, 8, 0},
273
-	{"atoi", 19, 13, 1},
274
-	{"debug_print_str_start", 19, 14, 1},
275
-	{"debug_print_str_nonl", 19, 15, 1},
276
-	{"entropy_buffer", 19, 16, 1},
277
-	{"map_new", 10, 9, 0},
278
-	{"map_addkey", 9, 0, 9},
279
-	{"map_setvalue", 9, 1, 9},
280
-	{"map_remove", 9, 2, 9},
281
-	{"map_find", 9, 3, 9},
282
-	{"map_getvaluesize", 8, 19, 2},
283
-	{"map_getvalue", 13, 2, 6},
284
-	{"map_done", 8, 20, 2},
285
-	{"file_find_limit", 9, 4, 9},
286
-	{"engine_functionality_level", 11, 1, 5},
287
-	{"engine_dconf_level", 11, 2, 5},
288
-	{"engine_scan_options", 11, 3, 5},
289
-	{"engine_db_options", 11, 4, 5},
290
-	{"extract_set_container", 8, 21, 2},
291
-	{"input_switch", 8, 22, 2},
292
-	{"get_environment", 15, 17, 1},
293
-	{"disable_bytecode_if", 9, 5, 9},
294
-	{"disable_jit_if", 9, 6, 9},
295
-	{"version_compare", 12, 1, 8},
296
-	{"check_platform", 14, 5, 7},
297
-	{"pdf_get_obj_num", 11, 5, 5},
298
-	{"pdf_get_flags", 11, 6, 5},
299
-	{"pdf_set_flags", 8, 23, 2},
300
-	{"pdf_lookupobj", 8, 24, 2},
301
-	{"pdf_getobjsize", 8, 25, 2},
302
-	{"pdf_getobj", 13, 3, 6},
303
-	{"pdf_getobjid", 8, 26, 2},
304
-	{"pdf_getobjflags", 8, 27, 2},
305
-	{"pdf_setobjflags", 10, 10, 0},
306
-	{"pdf_get_offset", 8, 28, 2},
307
-	{"pdf_get_phase", 11, 7, 5},
308
-	{"pdf_get_dumpedobjid", 11, 8, 5},
309
-	{"matchicon", 12, 2, 8},
310
-	{"running_on_jit", 11, 9, 5},
311
-	{"get_file_reliability", 11, 10, 5},
312
-	{"json_is_active", 11, 11, 5},
313
-	{"json_get_object", 9, 7, 9},
314
-	{"json_get_type", 8, 29, 2},
315
-	{"json_get_array_length", 8, 30, 2},
316
-	{"json_get_array_idx", 10, 11, 0},
317
-	{"json_get_string_length", 8, 31, 2},
318
-	{"json_get_string", 9, 8, 9},
319
-	{"json_get_boolean", 8, 32, 2},
320
-	{"json_get_int", 8, 33, 2}
242
+	{"extract_new", 9, 4, 2},
243
+	{"read_number", 9, 5, 2},
244
+	{"hashset_new", 12, 0, 5},
245
+	{"hashset_add", 11, 2, 0},
246
+	{"hashset_remove", 11, 3, 0},
247
+	{"hashset_contains", 11, 4, 0},
248
+	{"hashset_done", 9, 6, 2},
249
+	{"hashset_empty", 9, 7, 2},
250
+	{"buffer_pipe_new", 9, 8, 2},
251
+	{"buffer_pipe_new_fromfile", 9, 9, 2},
252
+	{"buffer_pipe_read_avail", 9, 10, 2},
253
+	{"buffer_pipe_read_get", 14, 0, 6},
254
+	{"buffer_pipe_read_stopped", 11, 5, 0},
255
+	{"buffer_pipe_write_avail", 9, 11, 2},
256
+	{"buffer_pipe_write_get", 14, 1, 6},
257
+	{"buffer_pipe_write_stopped", 11, 6, 0},
258
+	{"buffer_pipe_done", 9, 12, 2},
259
+	{"inflate_init", 15, 0, 7},
260
+	{"inflate_process", 9, 13, 2},
261
+	{"inflate_done", 9, 14, 2},
262
+	{"bytecode_rt_error", 9, 15, 2},
263
+	{"jsnorm_init", 9, 16, 2},
264
+	{"jsnorm_process", 9, 17, 2},
265
+	{"jsnorm_done", 9, 18, 2},
266
+	{"ilog2", 11, 7, 0},
267
+	{"ipow", 15, 1, 7},
268
+	{"iexp", 15, 2, 7},
269
+	{"isin", 15, 3, 7},
270
+	{"icos", 15, 4, 7},
271
+	{"memstr", 13, 0, 8},
272
+	{"hex2ui", 11, 8, 0},
273
+	{"atoi", 8, 13, 1},
274
+	{"debug_print_str_start", 8, 14, 1},
275
+	{"debug_print_str_nonl", 8, 15, 1},
276
+	{"entropy_buffer", 8, 16, 1},
277
+	{"map_new", 11, 9, 0},
278
+	{"map_addkey", 10, 0, 9},
279
+	{"map_setvalue", 10, 1, 9},
280
+	{"map_remove", 10, 2, 9},
281
+	{"map_find", 10, 3, 9},
282
+	{"map_getvaluesize", 9, 19, 2},
283
+	{"map_getvalue", 14, 2, 6},
284
+	{"map_done", 9, 20, 2},
285
+	{"file_find_limit", 10, 4, 9},
286
+	{"engine_functionality_level", 12, 1, 5},
287
+	{"engine_dconf_level", 12, 2, 5},
288
+	{"engine_scan_options", 12, 3, 5},
289
+	{"engine_db_options", 12, 4, 5},
290
+	{"extract_set_container", 9, 21, 2},
291
+	{"input_switch", 9, 22, 2},
292
+	{"get_environment", 16, 17, 1},
293
+	{"disable_bytecode_if", 10, 5, 9},
294
+	{"disable_jit_if", 10, 6, 9},
295
+	{"version_compare", 13, 1, 8},
296
+	{"check_platform", 15, 5, 7},
297
+	{"pdf_get_obj_num", 12, 5, 5},
298
+	{"pdf_get_flags", 12, 6, 5},
299
+	{"pdf_set_flags", 9, 23, 2},
300
+	{"pdf_lookupobj", 9, 24, 2},
301
+	{"pdf_getobjsize", 9, 25, 2},
302
+	{"pdf_getobj", 14, 3, 6},
303
+	{"pdf_getobjid", 9, 26, 2},
304
+	{"pdf_getobjflags", 9, 27, 2},
305
+	{"pdf_setobjflags", 11, 10, 0},
306
+	{"pdf_get_offset", 9, 28, 2},
307
+	{"pdf_get_phase", 12, 7, 5},
308
+	{"pdf_get_dumpedobjid", 12, 8, 5},
309
+	{"matchicon", 13, 2, 8},
310
+	{"running_on_jit", 12, 9, 5},
311
+	{"get_file_reliability", 12, 10, 5},
312
+	{"json_is_active", 12, 11, 5},
313
+	{"json_get_object", 10, 7, 9},
314
+	{"json_get_type", 9, 29, 2},
315
+	{"json_get_array_length", 9, 30, 2},
316
+	{"json_get_array_idx", 11, 11, 0},
317
+	{"json_get_string_length", 9, 31, 2},
318
+	{"json_get_string", 10, 8, 9},
319
+	{"json_get_boolean", 9, 32, 2},
320
+	{"json_get_int", 9, 33, 2},
321
+	{"engine_scan_options_ex", 8, 18, 1}
321 322
 /* Bytecode APIcalls END */
322 323
 };
323 324
 const unsigned cli_numapicalls=sizeof(cli_apicalls)/sizeof(cli_apicalls[0]);
... ...
@@ -354,7 +356,8 @@ const cli_apicall_pointer cli_apicalls1[] = {
354 354
 	(cli_apicall_pointer)cli_bcapi_debug_print_str_start,
355 355
 	(cli_apicall_pointer)cli_bcapi_debug_print_str_nonl,
356 356
 	(cli_apicall_pointer)cli_bcapi_entropy_buffer,
357
-	(cli_apicall_pointer)cli_bcapi_get_environment
357
+	(cli_apicall_pointer)cli_bcapi_get_environment,
358
+	(cli_apicall_pointer)cli_bcapi_engine_scan_options_ex
358 359
 };
359 360
 const cli_apicall_int1 cli_apicalls2[] = {
360 361
 	(cli_apicall_int1)cli_bcapi_debug_print_uint,
... ...
@@ -2,7 +2,7 @@
2 2
  *  ClamAV bytecode internal API
3 3
  *  This is an automatically generated file!
4 4
  *
5
- *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5
+ *  Copyright (C) 2014-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 6
  *  Copyright (C) 2009-2013 Sourcefire, Inc.
7 7
  *
8 8
  * Redistribution and use in source and binary forms, with or without
... ...
@@ -131,5 +131,6 @@ int32_t cli_bcapi_json_get_string_length(struct cli_bc_ctx *ctx , int32_t);
131 131
 int32_t cli_bcapi_json_get_string(struct cli_bc_ctx *ctx , int8_t*, int32_t, int32_t);
132 132
 int32_t cli_bcapi_json_get_boolean(struct cli_bc_ctx *ctx , int32_t);
133 133
 int32_t cli_bcapi_json_get_int(struct cli_bc_ctx *ctx , int32_t);
134
+uint32_t cli_bcapi_engine_scan_options_ex(struct cli_bc_ctx *ctx , const uint8_t*, uint32_t);
134 135
 
135 136
 #endif
... ...
@@ -2,7 +2,7 @@
2 2
  *  ClamAV bytecode internal API
3 3
  *  This is an automatically generated file!
4 4
  *
5
- *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5
+ *  Copyright (C) 2014-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 6
  *  Copyright (C) 2009-2013 Sourcefire, Inc.
7 7
  *
8 8
  * Redistribution and use in source and binary forms, with or without
... ...
@@ -833,7 +833,7 @@ void cache_add(unsigned char *md5, size_t size, cli_ctx *ctx) {
833 833
     level =  (*ctx->fmap && (*ctx->fmap)->dont_cache_flag) ? ctx->recursion : 0;
834 834
     if (ctx->found_possibly_unwanted && (level || !ctx->recursion))
835 835
 	return;
836
-    if (SCAN_ALL && (ctx->num_viruses > 0)) {
836
+    if (SCAN_ALLMATCHES && (ctx->num_viruses > 0)) {
837 837
 	cli_dbgmsg("cache_add: alert found within same topfile, skipping cache\n");
838 838
 	return;
839 839
     }
... ...
@@ -65,6 +65,8 @@
65 65
 #include <sys/types.h>
66 66
 #include <sys/stat.h>
67 67
 
68
+#include "cltypes.h"
69
+
68 70
 #ifdef __cplusplus
69 71
 extern "C"
70 72
 {
... ...
@@ -121,64 +123,75 @@ typedef enum cl_error_t {
121 121
 } cl_error_t;
122 122
 
123 123
 /* db options */
124
-#define CL_DB_PHISHING	    0x2
125
-#define CL_DB_PHISHING_URLS 0x8
126
-#define CL_DB_PUA	    0x10
127
-#define CL_DB_CVDNOTMP	    0x20    /* obsolete */
128
-#define CL_DB_OFFICIAL	    0x40    /* internal */
129
-#define CL_DB_PUA_MODE	    0x80
130
-#define CL_DB_PUA_INCLUDE   0x100
131
-#define CL_DB_PUA_EXCLUDE   0x200
132
-#define CL_DB_COMPILED	    0x400   /* internal */
133
-#define CL_DB_DIRECTORY	    0x800   /* internal */
134
-#define CL_DB_OFFICIAL_ONLY 0x1000
135
-#define CL_DB_BYTECODE      0x2000
136
-#define CL_DB_SIGNED	    0x4000  /* internal */
137
-#define CL_DB_BYTECODE_UNSIGNED	0x8000
138
-#define CL_DB_UNSIGNED	    0x10000 /* internal */
139
-#define CL_DB_BYTECODE_STATS 0x20000
140
-#define CL_DB_ENHANCED      0x40000
141
-#define CL_DB_PCRE_STATS    0x80000
142
-#define CL_DB_YARA_EXCLUDE  0x100000
143
-#define CL_DB_YARA_ONLY     0x200000
124
+#define CL_DB_PHISHING          0x2
125
+#define CL_DB_PHISHING_URLS     0x8
126
+#define CL_DB_PUA               0x10
127
+#define CL_DB_CVDNOTMP          0x20    /* obsolete */
128
+#define CL_DB_OFFICIAL          0x40    /* internal */
129
+#define CL_DB_PUA_MODE          0x80
130
+#define CL_DB_PUA_INCLUDE       0x100
131
+#define CL_DB_PUA_EXCLUDE       0x200
132
+#define CL_DB_COMPILED          0x400   /* internal */
133
+#define CL_DB_DIRECTORY         0x800   /* internal */
134
+#define CL_DB_OFFICIAL_ONLY     0x1000
135
+#define CL_DB_BYTECODE          0x2000
136
+#define CL_DB_SIGNED            0x4000  /* internal */
137
+#define CL_DB_BYTECODE_UNSIGNED 0x8000
138
+#define CL_DB_UNSIGNED          0x10000 /* internal */
139
+#define CL_DB_BYTECODE_STATS    0x20000
140
+#define CL_DB_ENHANCED          0x40000
141
+#define CL_DB_PCRE_STATS        0x80000
142
+#define CL_DB_YARA_EXCLUDE      0x100000
143
+#define CL_DB_YARA_ONLY         0x200000
144 144
 
145 145
 /* recommended db settings */
146
-#define CL_DB_STDOPT	    (CL_DB_PHISHING | CL_DB_PHISHING_URLS | CL_DB_BYTECODE)
147
-
148
-/* scan options */
149
-#define CL_SCAN_RAW			0x0
150
-#define CL_SCAN_ARCHIVE			0x1
151
-#define CL_SCAN_MAIL			0x2
152
-#define CL_SCAN_OLE2			0x4
153
-#define CL_SCAN_BLOCKENCRYPTED		0x8
154
-#define CL_SCAN_HTML			0x10
155
-#define CL_SCAN_PE			0x20
156
-#define CL_SCAN_BLOCKBROKEN		0x40
157
-#define CL_SCAN_MAILURL			0x80 /* ignored */
158
-#define CL_SCAN_BLOCKMAX		0x100
159
-#define CL_SCAN_ALGORITHMIC		0x200
160
-#define CL_SCAN_PHISHING_BLOCKSSL	0x800 /* ssl mismatches, not ssl by itself*/
161
-#define CL_SCAN_PHISHING_BLOCKCLOAK	0x1000
162
-#define CL_SCAN_ELF			0x2000
163
-#define CL_SCAN_PDF			0x4000
164
-#define CL_SCAN_STRUCTURED		0x8000
165
-#define CL_SCAN_STRUCTURED_SSN_NORMAL	0x10000
166
-#define CL_SCAN_STRUCTURED_SSN_STRIPPED	0x20000
167
-#define CL_SCAN_PARTIAL_MESSAGE         0x40000
168
-#define CL_SCAN_HEURISTIC_PRECEDENCE    0x80000
169
-#define CL_SCAN_BLOCKMACROS		0x100000
170
-#define CL_SCAN_ALLMATCHES		0x200000
171
-#define CL_SCAN_SWF			0x400000
172
-#define CL_SCAN_PARTITION_INTXN         0x800000
173
-#define CL_SCAN_XMLDOCS                 0x1000000
174
-#define CL_SCAN_HWP3                    0x2000000
175
-#define CL_SCAN_FILE_PROPERTIES         0x10000000
176
-//#define UNUSED                        0x20000000
177
-#define CL_SCAN_PERFORMANCE_INFO        0x40000000 /* collect performance timings */
178
-#define CL_SCAN_INTERNAL_COLLECT_SHA    0x80000000 /* Enables hash output in sha-collect builds - for internal use only */
179
-
180
-/* recommended scan settings */
181
-#define CL_SCAN_STDOPT		(CL_SCAN_ARCHIVE | CL_SCAN_MAIL | CL_SCAN_OLE2 | CL_SCAN_PDF | CL_SCAN_HTML | CL_SCAN_PE | CL_SCAN_ALGORITHMIC | CL_SCAN_ELF | CL_SCAN_SWF | CL_SCAN_XMLDOCS | CL_SCAN_HWP3)
146
+#define CL_DB_STDOPT (CL_DB_PHISHING | CL_DB_PHISHING_URLS | CL_DB_BYTECODE)
147
+
148
+/*** scan options ***/
149
+struct cl_scan_options {
150
+    uint32_t general;
151
+    uint32_t parse;
152
+    uint32_t heuristic;
153
+    uint32_t mail;
154
+    uint32_t dev;
155
+};
156
+
157
+/* general */
158
+#define CL_SCAN_GENERAL_ALLMATCHES                  0x1 /* scan in all-match mode */
159
+#define CL_SCAN_GENERAL_COLLECT_METADATA            0x2 /* collect metadata (--gen-json) */
160
+#define CL_SCAN_GENERAL_HEURISTICS                  0x4 /* option to enable heuristic alerts */
161
+#define CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE        0x8 /* allow heuristic match to take precedence. */
162
+
163
+/* parsing capabilities options */
164
+#define CL_SCAN_PARSE_ARCHIVE                       0x1
165
+#define CL_SCAN_PARSE_ELF                           0x2
166
+#define CL_SCAN_PARSE_PDF                           0x4
167
+#define CL_SCAN_PARSE_SWF                           0x8
168
+#define CL_SCAN_PARSE_HWP3                          0x10
169
+#define CL_SCAN_PARSE_XMLDOCS                       0x20
170
+#define CL_SCAN_PARSE_MAIL                          0x40
171
+#define CL_SCAN_PARSE_OLE2                          0x80
172
+#define CL_SCAN_PARSE_HTML                          0x100
173
+#define CL_SCAN_PARSE_PE                            0x200
174
+
175
+/* heuristic alerting options */
176
+#define CL_SCAN_HEURISTIC_BROKEN                    0x2
177
+#define CL_SCAN_HEURISTIC_EXCEEDS_MAX               0x4
178
+#define CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH     0x8
179
+#define CL_SCAN_HEURISTIC_PHISHING_CLOAK            0x10
180
+#define CL_SCAN_HEURISTIC_MACROS                    0x20
181
+#define CL_SCAN_HEURISTIC_ENCRYPTED                 0x40
182
+#define CL_SCAN_HEURISTIC_PARTITION_INTXN           0x80 /* alert if partition table size doesn't make sense */
183
+#define CL_SCAN_HEURISTIC_STRUCTURED                0x100 /* data loss prevention options, i.e. alert when detecting personal information */
184
+#define CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL     0x200 /* alert when detecting social security numbers */
185
+#define CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED   0x400 /* alert when detecting stripped social security numbers */
186
+
187
+/* mail scanning options */
188
+#define CL_SCAN_MAIL_PARTIAL_MESSAGE                0x1
189
+
190
+/* dev options */
191
+#define CL_SCAN_DEV_COLLECT_SHA                     0x1 /* Enables hash output in sha-collect builds - for internal use only */
192
+#define CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO        0x2 /* collect performance timings */
182 193
 
183 194
 /* cl_countsigs options */
184 195
 #define CL_COUNTSIGS_OFFICIAL	    0x1
... ...
@@ -488,11 +501,11 @@ struct cl_cvd {		    /* field no. */
488 488
 };
489 489
 
490 490
 /* file scanning */
491
-extern int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions);
492
-extern int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context);
491
+extern int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options* scanoptions);
492
+extern int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options* scanoptions, void *context);
493 493
 
494
-extern int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions);
495
-extern int cl_scanfile_callback(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context);
494
+extern int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options* scanoptions);
495
+extern int cl_scanfile_callback(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options* scanoptions, void *context);
496 496
 
497 497
 /* database handling */
498 498
 extern int cl_load(const char *path, struct cl_engine *engine, unsigned int *signo, unsigned int dboptions);
... ...
@@ -558,7 +571,7 @@ extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len);
558 558
 extern void cl_fmap_close(cl_fmap_t*);
559 559
 
560 560
 /* Scan custom data */
561
-extern int cl_scanmap_callback(cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context);
561
+extern int cl_scanmap_callback(cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *scanoptions, void *context);
562 562
 
563 563
 /* Crypto/hashing functions */
564 564
 #define SHA1_HASH_SIZE 20
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  *  ClamAV bytecode definitions.
3 3
  *
4
- *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4
+ *  Copyright (C) 2014-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5 5
  *  Copyright (C) 2009-2010 Sourcefire, Inc.
6 6
  *
7 7
  *  Authors: Török Edvin
... ...
@@ -153,7 +153,7 @@ int cli_scancpio_old(cli_ctx *ctx)
153 153
 	    continue;
154 154
 
155 155
 	if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS) {
156
-            if (!SCAN_ALL)
156
+            if (!SCAN_ALLMATCHES)
157 157
                 return CL_VIRUS;
158 158
             virus_found = 1;
159 159
         }
... ...
@@ -168,7 +168,7 @@ int cli_scancpio_old(cli_ctx *ctx)
168 168
 	    } else if(ret == CL_SUCCESS) {
169 169
 		ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY);
170 170
 		if(ret == CL_VIRUS) {
171
-                    if (!SCAN_ALL)
171
+                    if (!SCAN_ALLMATCHES)
172 172
                         return ret;
173 173
                     virus_found = 1;
174 174
                 }
... ...
@@ -247,7 +247,7 @@ int cli_scancpio_odc(cli_ctx *ctx)
247 247
 	    continue;
248 248
 
249 249
 	if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS) {
250
-            if (!SCAN_ALL)
250
+            if (!SCAN_ALLMATCHES)
251 251
                 return CL_VIRUS;
252 252
             virus_found = 1;
253 253
         }
... ...
@@ -259,7 +259,7 @@ int cli_scancpio_odc(cli_ctx *ctx)
259 259
 	} else if(ret == CL_SUCCESS) {
260 260
 	    ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY);
261 261
 	    if(ret == CL_VIRUS) {
262
-                if (!SCAN_ALL)
262
+                if (!SCAN_ALLMATCHES)
263 263
                     return ret;
264 264
                 virus_found = 1;
265 265
             }
... ...
@@ -341,7 +341,7 @@ int cli_scancpio_newc(cli_ctx *ctx, int crc)
341 341
 	    continue;
342 342
 
343 343
 	if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS) {
344
-            if (!SCAN_ALL)
344
+            if (!SCAN_ALLMATCHES)
345 345
                 return CL_VIRUS;
346 346
             virus_found = 1;
347 347
         }
... ...
@@ -352,7 +352,7 @@ int cli_scancpio_newc(cli_ctx *ctx, int crc)
352 352
 	} else if(ret == CL_SUCCESS) {
353 353
 	    ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY);
354 354
 	    if(ret == CL_VIRUS) {
355
-                if (!SCAN_ALL)
355
+                if (!SCAN_ALLMATCHES)
356 356
                     return ret;
357 357
                 virus_found = 1;
358 358
             }
... ...
@@ -239,7 +239,7 @@ int cli_scandmg(cli_ctx *ctx)
239 239
             if (depth < 0) {
240 240
                 break;
241 241
             }
242
-            if ((depth > 50) && SCAN_ALGO) {
242
+            if ((depth > 50) && SCAN_HEURISTICS) {
243 243
                 // Possible heuristic, should limit runaway
244 244
                 cli_dbgmsg("cli_scandmg: Excessive nesting in DMG TOC.\n");
245 245
                 break;
... ...
@@ -213,7 +213,7 @@ static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
213 213
     cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
214 214
     if(phnum > 128) {
215 215
         cli_dbgmsg("ELF: Suspicious number of program headers\n");
216
-        if(ctx && DETECT_BROKEN) {
216
+        if(ctx && SCAN_HEURISTIC_BROKEN) {
217 217
             cli_append_virus(ctx, "Heuristics.Broken.Executable");
218 218
             return CL_VIRUS;
219 219
         }
... ...
@@ -226,7 +226,7 @@ static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
226 226
         /* Sanity check */
227 227
         if(phentsize != sizeof(struct elf_program_hdr32)) {
228 228
             cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr32)\n");
229
-            if(ctx && DETECT_BROKEN) {
229
+            if(ctx && SCAN_HEURISTIC_BROKEN) {
230 230
                 cli_append_virus(ctx, "Heuristics.Broken.Executable");
231 231
                 return CL_VIRUS;
232 232
             }
... ...
@@ -261,7 +261,7 @@ static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
261 261
                     cli_dbgmsg("ELF: Possibly broken ELF file\n");
262 262
                 }
263 263
                 free(program_hdr);
264
-                if(ctx && DETECT_BROKEN) {
264
+                if(ctx && SCAN_HEURISTIC_BROKEN) {
265 265
                     cli_append_virus(ctx, "Heuristics.Broken.Executable");
266 266
                     return CL_VIRUS;
267 267
                 }
... ...
@@ -283,7 +283,7 @@ static int cli_elf_ph32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
283 283
         free(program_hdr);
284 284
         if(err) {
285 285
             cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
286
-            if(ctx && DETECT_BROKEN) {
286
+            if(ctx && SCAN_HEURISTIC_BROKEN) {
287 287
                 cli_append_virus(ctx, "Heuristics.Broken.Executable");
288 288
                 return CL_VIRUS;
289 289
             }
... ...
@@ -317,7 +317,7 @@ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
317 317
     cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
318 318
     if(phnum > 128) {
319 319
         cli_dbgmsg("ELF: Suspicious number of program headers\n");
320
-        if(ctx && DETECT_BROKEN) {
320
+        if(ctx && SCAN_HEURISTIC_BROKEN) {
321 321
             cli_append_virus(ctx, "Heuristics.Broken.Executable");
322 322
             return CL_VIRUS;
323 323
         }
... ...
@@ -330,7 +330,7 @@ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
330 330
         /* Sanity check */
331 331
         if (phentsize != sizeof(struct elf_program_hdr64)) {
332 332
             cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr64)\n");
333
-            if(ctx && DETECT_BROKEN) {
333
+            if(ctx && SCAN_HEURISTIC_BROKEN) {
334 334
                 cli_append_virus(ctx, "Heuristics.Broken.Executable");
335 335
                 return CL_VIRUS;
336 336
             }
... ...
@@ -365,7 +365,7 @@ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
365 365
                     cli_dbgmsg("ELF: Possibly broken ELF file\n");
366 366
                 }
367 367
                 free(program_hdr);
368
-                if(ctx && DETECT_BROKEN) {
368
+                if(ctx && SCAN_HEURISTIC_BROKEN) {
369 369
                     cli_append_virus(ctx, "Heuristics.Broken.Executable");
370 370
                     return CL_VIRUS;
371 371
                 }
... ...
@@ -387,7 +387,7 @@ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
387 387
         free(program_hdr);
388 388
         if(err) {
389 389
             cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
390
-            if(ctx && DETECT_BROKEN) {
390
+            if(ctx && SCAN_HEURISTIC_BROKEN) {
391 391
                 cli_append_virus(ctx, "Heuristics.Broken.Executable");
392 392
                 return CL_VIRUS;
393 393
             }
... ...
@@ -432,7 +432,7 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
432 432
     /* Sanity check */
433 433
     if(shentsize != sizeof(struct elf_section_hdr32)) {
434 434
 	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr32)\n");
435
-        if(ctx && DETECT_BROKEN) {
435
+        if(ctx && SCAN_HEURISTIC_BROKEN) {
436 436
 	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
437 437
 	    return CL_VIRUS;
438 438
         }
... ...
@@ -484,7 +484,7 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
484 484
                 free(elfinfo->section);
485 485
                 elfinfo->section = NULL;
486 486
 	    }
487
-            if(ctx && DETECT_BROKEN) {
487
+            if(ctx && SCAN_HEURISTIC_BROKEN) {
488 488
                 cli_append_virus(ctx, "Heuristics.Broken.Executable");
489 489
 		return CL_VIRUS;
490 490
             }
... ...
@@ -542,7 +542,7 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
542 542
     /* Sanity check */
543 543
     if(shentsize != sizeof(struct elf_section_hdr64)) {
544 544
 	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr64)\n");
545
-        if(ctx && DETECT_BROKEN) {
545
+        if(ctx && SCAN_HEURISTIC_BROKEN) {
546 546
 	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
547 547
 	    return CL_VIRUS;
548 548
         }
... ...
@@ -594,7 +594,7 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
594 594
                 free(elfinfo->section);
595 595
                 elfinfo->section = NULL;
596 596
 	    }
597
-            if(ctx && DETECT_BROKEN) {
597
+            if(ctx && SCAN_HEURISTIC_BROKEN) {
598 598
                 cli_append_virus(ctx, "Heuristics.Broken.Executable");
599 599
 		return CL_VIRUS;
600 600
             }
... ...
@@ -137,7 +137,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
137 137
     /* check the protective mbr */
138 138
     ret = gpt_check_mbr(ctx, sectorsize);
139 139
     if (ret != CL_CLEAN) {
140
-        if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
140
+        if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
141 141
             detection = CL_VIRUS;
142 142
         else
143 143
             return ret;
... ...
@@ -198,17 +198,17 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
198 198
     }
199 199
 
200 200
     /* check that the partition table has no intersections - HEURISTICS */
201
-    if ((ctx->options & CL_SCAN_PARTITION_INTXN) && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
201
+    if (SCAN_HEURISTIC_PARTITION_INTXN && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
202 202
         ret = gpt_prtn_intxn(ctx, phdr, sectorsize);
203 203
         if (ret != CL_CLEAN) {
204
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
204
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
205 205
                 detection = CL_VIRUS;
206 206
             else
207 207
                 return ret;
208 208
         }
209 209
         ret = gpt_prtn_intxn(ctx, shdr, sectorsize);
210 210
         if (ret != CL_CLEAN) {
211
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
211
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
212 212
                 detection = CL_VIRUS;
213 213
             else
214 214
                 return ret;
... ...
@@ -221,7 +221,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
221 221
         cli_dbgmsg("cli_scangpt: Scanning primary GPT partitions only\n");
222 222
         ret = gpt_scan_partitions(ctx, phdr, sectorsize);
223 223
         if (ret != CL_CLEAN) {
224
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
224
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
225 225
                 detection = CL_VIRUS;
226 226
             else
227 227
                 return ret;
... ...
@@ -231,7 +231,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
231 231
         cli_dbgmsg("cli_scangpt: Scanning secondary GPT partitions only\n");
232 232
         ret = gpt_scan_partitions(ctx, shdr, sectorsize);
233 233
         if (ret != CL_CLEAN) {
234
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
234
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
235 235
                 detection = CL_VIRUS;
236 236
             else
237 237
                 return ret;
... ...
@@ -241,7 +241,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
241 241
         cli_dbgmsg("cli_scangpt: Scanning primary GPT partitions\n");
242 242
         ret = gpt_scan_partitions(ctx, phdr, sectorsize);
243 243
         if (ret != CL_CLEAN) {
244
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
244
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
245 245
                 detection = CL_VIRUS;
246 246
             else
247 247
                 return ret;
... ...
@@ -249,7 +249,7 @@ int cli_scangpt(cli_ctx *ctx, size_t sectorsize)
249 249
         cli_dbgmsg("cli_scangpt: Scanning secondary GPT partitions\n");
250 250
         ret = gpt_scan_partitions(ctx, shdr, sectorsize);
251 251
         if (ret != CL_CLEAN) {
252
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
252
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
253 253
                 detection = CL_VIRUS;
254 254
             else
255 255
                 return ret;
... ...
@@ -351,7 +351,7 @@ static int gpt_scan_partitions(cli_ctx *ctx, struct gpt_header hdr, size_t secto
351 351
             part_size = (gpe.lastLBA - gpe.firstLBA + 1) * sectorsize;
352 352
             ret = cli_map_scan(*ctx->fmap, part_off, part_size, ctx, CL_TYPE_PART_ANY);
353 353
             if (ret != CL_CLEAN) {
354
-                if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
354
+                if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
355 355
                     detection = CL_VIRUS;
356 356
                 else
357 357
                     return ret;
... ...
@@ -654,7 +654,7 @@ static int gpt_prtn_intxn(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize
654 654
                     ret = cli_append_virus(ctx, PRTN_INTXN_DETECTION);
655 655
                     if (ret == CL_VIRUS)
656 656
                         virus_found = 1;
657
-                    if (SCAN_ALL || ret == CL_CLEAN)
657
+                    if (SCAN_ALLMATCHES || ret == CL_CLEAN)
658 658
                         tmp = 0;
659 659
                     else
660 660
                         goto leave;
... ...
@@ -662,8 +662,8 @@ static int hfsplus_walk_catalog(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hf
662 662
                 /* Check return code */
663 663
                 if (ret == CL_VIRUS) {
664 664
                     has_alerts = 1;
665
-                    if (SCAN_ALL) {
666
-                        /* Continue scanning in SCAN_ALL mode */
665
+                    if (SCAN_ALLMATCHES) {
666
+                        /* Continue scanning in SCAN_ALLMATCHES mode */
667 667
                         cli_dbgmsg("hfsplus_walk_catalog: data fork alert, continuing");
668 668
                         ret = CL_CLEAN;
669 669
                     }
... ...
@@ -681,8 +681,8 @@ static int hfsplus_walk_catalog(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hf
681 681
                 /* Check return code */
682 682
                 if (ret == CL_VIRUS) {
683 683
                     has_alerts = 1;
684
-                    if (SCAN_ALL) {
685
-                        /* Continue scanning in SCAN_ALL mode */
684
+                    if (SCAN_ALLMATCHES) {
685
+                        /* Continue scanning in SCAN_ALLMATCHES mode */
686 686
                         cli_dbgmsg("hfsplus_walk_catalog: resource fork alert, continuing");
687 687
                         ret = CL_CLEAN;
688 688
                     }
... ...
@@ -306,7 +306,7 @@ int cli_hwp5header(cli_ctx *ctx, hwp5_header_t *hwp5)
306 306
         return CL_ENULLARG;
307 307
 
308 308
 #if HAVE_JSON
309
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
309
+    if (SCAN_COLLECT_METADATA) {
310 310
         json_object *header, *flags;
311 311
 
312 312
         header = cli_jsonobj(ctx->wrkproperty, "Hwp5Header");
... ...
@@ -426,7 +426,7 @@ int cli_scanhwp5_stream(cli_ctx *ctx, hwp5_header_t *hwp5, char *name, int fd)
426 426
 
427 427
 #if HAVE_JSON
428 428
         /* JSON Output Summary Information */
429
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->properties != NULL) {
429
+        if (SCAN_COLLECT_METADATA && ctx->properties != NULL) {
430 430
             if (name && !strncmp(name, "_5_hwpsummaryinformation", 24)) {
431 431
                 cli_dbgmsg("HWP5.x: Detected a '_5_hwpsummaryinformation' stream\n");
432 432
                 /* JSONOLE2 - what to do if something breaks? */
... ...
@@ -539,7 +539,7 @@ static inline int parsehwp3_docinfo(cli_ctx *ctx, off_t offset, struct hwp3_doci
539 539
     hwp3_debug("HWP3.x: di_infoblksize: %u\n", docinfo->di_infoblksize);
540 540
 
541 541
 #if HAVE_JSON
542
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
542
+    if (SCAN_COLLECT_METADATA) {
543 543
         json_object *header, *flags;
544 544
         char *str;
545 545
 
... ...
@@ -605,7 +605,7 @@ static inline int parsehwp3_docsummary(cli_ctx *ctx, off_t offset)
605 605
     int i, iret, ret;
606 606
     json_object *summary;
607 607
 
608
-    if (!(ctx->options & CL_SCAN_FILE_PROPERTIES))
608
+    if (!SCAN_COLLECT_METADATA)
609 609
         return CL_SUCCESS;
610 610
 
611 611
     if (!(hwp3_ptr = fmap_need_off_once(*ctx->fmap, offset, HWP3_DOCSUMMARY_SIZE))) {
... ...
@@ -1537,7 +1537,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1537 1537
     hwp3_debug("HWP3.x: Information Block @ offset %llu\n", infoloc);
1538 1538
 
1539 1539
 #if HAVE_JSON
1540
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
1540
+    if (SCAN_COLLECT_METADATA) {
1541 1541
         infoblk_1 = cli_jsonobj(ctx->wrkproperty, "InfoBlk_1");
1542 1542
         if (!infoblk_1) {
1543 1543
             cli_errmsg("HWP5.x: No memory for information block object\n");
... ...
@@ -1568,7 +1568,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1568 1568
     infoid = le32_to_host(infoid);
1569 1569
 
1570 1570
 #if HAVE_JSON
1571
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
1571
+    if (SCAN_COLLECT_METADATA) {
1572 1572
         entry = cli_jsonobj(contents, NULL);
1573 1573
         if (!entry) {
1574 1574
             cli_errmsg("HWP5.x: No memory for information block entry object\n");
... ...
@@ -1584,7 +1584,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1584 1584
     if (infoid == 5) {
1585 1585
         hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Booking Information\n", infoloc);
1586 1586
 #if HAVE_JSON
1587
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1587
+        if (SCAN_COLLECT_METADATA)
1588 1588
             cli_jsonstr(entry, "Type", "Booking Information");
1589 1589
 #endif
1590 1590
         return CL_SUCCESS;
... ...
@@ -1599,7 +1599,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1599 1599
     infolen = le32_to_host(infolen);
1600 1600
 
1601 1601
 #if HAVE_JSON
1602
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
1602
+    if (SCAN_COLLECT_METADATA) {
1603 1603
         cli_jsonint64(entry, "Offset", infoloc);
1604 1604
         cli_jsonint(entry, "Length", infolen);
1605 1605
     }
... ...
@@ -1619,7 +1619,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1619 1619
         if (infolen == 0) {
1620 1620
             hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Terminating Entry\n", infoloc);
1621 1621
 #if HAVE_JSON
1622
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1622
+        if (SCAN_COLLECT_METADATA)
1623 1623
             cli_jsonstr(entry, "Type", "Terminating Entry");
1624 1624
 #endif
1625 1625
             if (last) *last = 1;
... ...
@@ -1631,7 +1631,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1631 1631
     case 1: /* Image Data */
1632 1632
         hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Image Data\n", infoloc);
1633 1633
 #if HAVE_JSON
1634
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1634
+        if (SCAN_COLLECT_METADATA)
1635 1635
             cli_jsonstr(entry, "Type", "Image Data");
1636 1636
 #endif
1637 1637
 #if HWP3_DEBUG /* additional fields can be added */
... ...
@@ -1658,7 +1658,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1658 1658
     case 2: /* OLE2 Data */
1659 1659
         hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: OLE2 Data\n", infoloc);
1660 1660
 #if HAVE_JSON
1661
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1661
+        if (SCAN_COLLECT_METADATA)
1662 1662
             cli_jsonstr(entry, "Type", "OLE2 Data");
1663 1663
 #endif
1664 1664
         if (infolen > 0)
... ...
@@ -1674,7 +1674,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1674 1674
         count = (infolen / 617);
1675 1675
         hwp3_debug("HWP3.x: Information Block[%llu]: COUNT: %d entries\n", infoloc, count);
1676 1676
 #if HAVE_JSON
1677
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
1677
+        if (SCAN_COLLECT_METADATA) {
1678 1678
             cli_jsonstr(entry, "Type", "Hypertext/Hyperlink Information");
1679 1679
             cli_jsonint(entry, "Count", count);
1680 1680
         }
... ...
@@ -1697,7 +1697,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1697 1697
     case 4: /* Presentation Information */
1698 1698
         hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Presentation Information\n", infoloc);
1699 1699
 #if HAVE_JSON
1700
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1700
+        if (SCAN_COLLECT_METADATA)
1701 1701
             cli_jsonstr(entry, "Type", "Presentation Information");
1702 1702
 #endif
1703 1703
         /* contains nothing of interest to scan */
... ...
@@ -1706,14 +1706,14 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1706 1706
         /* should never run this as it is short-circuited above */
1707 1707
         hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Booking Information\n", infoloc);
1708 1708
 #if HAVE_JSON
1709
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1709
+        if (SCAN_COLLECT_METADATA)
1710 1710
             cli_jsonstr(entry, "Type", "Booking Information");
1711 1711
 #endif
1712 1712
         break;
1713 1713
     case 6: /* Background Image Data */
1714 1714
         hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Background Image Data\n", infoloc);
1715 1715
 #if HAVE_JSON
1716
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
1716
+        if (SCAN_COLLECT_METADATA) {
1717 1717
             cli_jsonstr(entry, "Type", "Background Image Data");
1718 1718
             cli_jsonint(entry, "ImageSize", infolen-324);
1719 1719
         }
... ...
@@ -1734,7 +1734,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1734 1734
     case 0x100: /* Table Extension */
1735 1735
         hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Table Extension\n", infoloc);
1736 1736
 #if HAVE_JSON
1737
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1737
+        if (SCAN_COLLECT_METADATA)
1738 1738
             cli_jsonstr(entry, "Type", "Table Extension");
1739 1739
 #endif
1740 1740
         /* contains nothing of interest to scan */
... ...
@@ -1742,7 +1742,7 @@ static inline int parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, off_t *offset,
1742 1742
     case 0x101: /* Press Frame Information Field Name */
1743 1743
         hwp3_debug("HWP3.x: Information Block[%llu]: TYPE: Press Frame Information Field Name\n", infoloc);
1744 1744
 #if HAVE_JSON
1745
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1745
+        if (SCAN_COLLECT_METADATA)
1746 1746
             cli_jsonstr(entry, "Type", "Press Frame Information Field Name");
1747 1747
 #endif
1748 1748
         /* contains nothing of interest to scan */
... ...
@@ -1796,7 +1796,7 @@ static int hwp3_cb(void *cbdata, int fd, cli_ctx *ctx)
1796 1796
 
1797 1797
     /* Fonts - 7 entries of 2 + (n x 40) bytes where n is the first 2 bytes of the entry */
1798 1798
 #if HAVE_JSON
1799
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1799
+    if (SCAN_COLLECT_METADATA)
1800 1800
         fonts = cli_jsonarray(ctx->wrkproperty, "FontCounts");
1801 1801
 #endif
1802 1802
     for (i = 0; i < 7; i++) {
... ...
@@ -1810,7 +1810,7 @@ static int hwp3_cb(void *cbdata, int fd, cli_ctx *ctx)
1810 1810
         nfonts = le16_to_host(nfonts);
1811 1811
 
1812 1812
 #if HAVE_JSON
1813
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1813
+        if (SCAN_COLLECT_METADATA)
1814 1814
             cli_jsonint(fonts, NULL, nfonts);
1815 1815
 #endif
1816 1816
         hwp3_debug("HWP3.x: Font Entry %d with %u entries @ offset %llu\n", i+1, nfonts, (long long unsigned)offset);
... ...
@@ -1831,7 +1831,7 @@ static int hwp3_cb(void *cbdata, int fd, cli_ctx *ctx)
1831 1831
     nstyles = le16_to_host(nstyles);
1832 1832
 
1833 1833
 #if HAVE_JSON
1834
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1834
+    if (SCAN_COLLECT_METADATA)
1835 1835
         cli_jsonint(ctx->wrkproperty, "StyleCount", nstyles);
1836 1836
 #endif
1837 1837
     hwp3_debug("HWP3.x: %u Styles @ offset %llu\n", nstyles, (long long unsigned)offset);
... ...
@@ -1853,7 +1853,7 @@ static int hwp3_cb(void *cbdata, int fd, cli_ctx *ctx)
1853 1853
         return ret;
1854 1854
     }
1855 1855
 #if HAVE_JSON
1856
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES)
1856
+    if (SCAN_COLLECT_METADATA)
1857 1857
         cli_jsonint(ctx->wrkproperty, "ParagraphCount", p);
1858 1858
 #endif
1859 1859
 
... ...
@@ -1862,7 +1862,7 @@ static int hwp3_cb(void *cbdata, int fd, cli_ctx *ctx)
1862 1862
     while (!last && ((ret = parsehwp3_infoblk_1(ctx, map, &offset, &last)) == CL_SUCCESS));
1863 1863
 
1864 1864
     /* scan the uncompressed stream - both compressed and uncompressed cases [ALLMATCH] */
1865
-    if ((ret == CL_SUCCESS) || ((SCAN_ALL) && (ret == CL_VIRUS))) {
1865
+    if ((ret == CL_SUCCESS) || ((SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
1866 1866
         int subret = ret;
1867 1867
         size_t dlen = offset - start;
1868 1868
 
... ...
@@ -380,7 +380,7 @@ int cli_scanishield(cli_ctx *ctx, off_t off, size_t sz) {
380 380
 
381 381
 	cli_dbgmsg("ishield: @%lx found file %s (%s) - version %s - size %lu\n", (unsigned long int) coff, fname, path, version, (unsigned long int) fsize);
382 382
 	if(cli_matchmeta(ctx, fname, fsize, fsize, 0, fc++, 0, NULL) == CL_VIRUS) {
383
-            if (!SCAN_ALL) {
383
+            if (!SCAN_ALLMATCHES) {
384 384
                 ret = CL_VIRUS;
385 385
                 break;
386 386
             }
... ...
@@ -187,7 +187,7 @@ static int iso_parse_dir(iso9660_t *iso, unsigned int block, unsigned int len) {
187 187
             ret = cli_matchmeta(ctx, iso->buf, filesz, filesz, 0, 0, 0, NULL);
188 188
             if (ret == CL_VIRUS) {
189 189
                 viruses_found = 1;
190
-                if (!SCAN_ALL)
190
+                if (!SCAN_ALLMATCHES)
191 191
                     break;
192 192
                 ret = CL_CLEAN;
193 193
             }
... ...
@@ -206,7 +206,7 @@ static int iso_parse_dir(iso9660_t *iso, unsigned int block, unsigned int len) {
206 206
 		}
207 207
                 if (ret == CL_VIRUS) {
208 208
                     viruses_found = 1;
209
-                    if (!SCAN_ALL)
209
+                    if (!SCAN_ALLMATCHES)
210 210
                         break;
211 211
                     ret = CL_CLEAN;
212 212
                 }
... ...
@@ -31,7 +31,7 @@
31 31
 #ifdef HAVE_JSON
32 32
 int cli_json_timeout_cycle_check(cli_ctx *ctx, int *toval)
33 33
 {
34
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
34
+    if (SCAN_COLLECT_METADATA) {
35 35
         if (*toval <= 0) {
36 36
             if (cli_checktimelimit(ctx) != CL_SUCCESS) {
37 37
                 cli_errmsg("cli_json_timeout_cycle_check: timeout!\n");
... ...
@@ -385,7 +385,7 @@ int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
385 385
 		if (ret) {
386 386
 			if (ret == CL_VIRUS) {
387 387
 				virus_num++;
388
-				if (!SCAN_ALL)
388
+				if (!SCAN_ALLMATCHES)
389 389
 					break;
390 390
 			}
391 391
 			goto out_close;
... ...
@@ -434,7 +434,7 @@ int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
434 434
 		}
435 435
 		free(tmp_fname);
436 436
 		files++;
437
-		if (ret == CL_VIRUS && SCAN_ALL)
437
+		if (ret == CL_VIRUS && SCAN_ALLMATCHES)
438 438
 			continue;
439 439
 		if (ret)
440 440
 			break;
... ...
@@ -486,7 +486,7 @@ int cli_scanmschm(cli_ctx *ctx)
486 486
 		if (ret) {
487 487
 			if (ret == CL_VIRUS) {
488 488
 				virus_num++;
489
-				if (!SCAN_ALL)
489
+				if (!SCAN_ALLMATCHES)
490 490
 					break;
491 491
 			}
492 492
 			goto out_close;
... ...
@@ -536,7 +536,7 @@ int cli_scanmschm(cli_ctx *ctx)
536 536
 		}
537 537
 		free(tmp_fname);
538 538
 		files++;
539
-		if (ret == CL_VIRUS && SCAN_ALL)
539
+		if (ret == CL_VIRUS && SCAN_ALLMATCHES)
540 540
 			continue;
541 541
 		if (ret)
542 542
 			break;
... ...
@@ -175,7 +175,7 @@ struct macho_fat_arch
175 175
 #define RETURN_BROKEN					    \
176 176
     if(matcher)						    \
177 177
 	return -1;					    \
178
-    if(DETECT_BROKEN) {					    \
178
+    if(SCAN_HEURISTIC_BROKEN) {					    \
179 179
         if (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Broken.Executable")) \
180 180
             return CL_VIRUS;				    \
181 181
     }							    \
... ...
@@ -1854,7 +1854,7 @@ int cli_ac_scanbuff(
1854 1854
                                         ptN = ptN->next_same;
1855 1855
                                         continue;
1856 1856
                                     } else {
1857
-                                        if(ctx && SCAN_ALL) {
1857
+                                        if(ctx && SCAN_ALLMATCHES) {
1858 1858
                                             cli_append_virus(ctx, (const char *)pt->virname);
1859 1859
                                             viruses_found = 1;
1860 1860
                                         }
... ...
@@ -1862,7 +1862,7 @@ int cli_ac_scanbuff(
1862 1862
                                             *virname = pt->virname;
1863 1863
                                         if(customdata)
1864 1864
                                             *customdata = pt->customdata;
1865
-                                        if (!ctx || !SCAN_ALL)
1865
+                                        if (!ctx || !SCAN_ALLMATCHES)
1866 1866
                                             return CL_VIRUS;
1867 1867
                                         ptN = ptN->next_same;
1868 1868
                                         continue;
... ...
@@ -1909,7 +1909,7 @@ int cli_ac_scanbuff(
1909 1909
                                     ptN = ptN->next_same;
1910 1910
                                     continue;
1911 1911
                                 } else {
1912
-                                    if(ctx && SCAN_ALL) {
1912
+                                    if(ctx && SCAN_ALLMATCHES) {
1913 1913
                                         cli_append_virus(ctx, (const char *)pt->virname);
1914 1914
                                         viruses_found = 1;
1915 1915
                                     }
... ...
@@ -1920,7 +1920,7 @@ int cli_ac_scanbuff(
1920 1920
                                     if(customdata)
1921 1921
                                         *customdata = pt->customdata;
1922 1922
 
1923
-                                    if (!ctx || !SCAN_ALL)
1923
+                                    if (!ctx || !SCAN_ALLMATCHES)
1924 1924
                                         return CL_VIRUS;
1925 1925
 
1926 1926
                                     ptN = ptN->next_same;
... ...
@@ -381,7 +381,7 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
381 381
 		    }
382 382
 		    if(virname) {
383 383
 			*virname = p->virname;
384
-			if(ctx != NULL && SCAN_ALL) {
384
+			if(ctx != NULL && SCAN_ALLMATCHES) {
385 385
 			    cli_append_virus(ctx, *virname);
386 386
 			    //*viroffset = offset + i + j - BM_MIN_LENGTH + BM_BLOCK_SIZE;
387 387
 			}
... ...
@@ -391,7 +391,7 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
391 391
 
392 392
 		    viruses_found = 1;
393 393
 
394
-		    if(ctx != NULL && !SCAN_ALL)
394
+		    if(ctx != NULL && !SCAN_ALLMATCHES)
395 395
 			return CL_VIRUS;
396 396
 		}
397 397
 		p = p->next;
... ...
@@ -744,7 +744,7 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **
744 744
                             ret = cli_append_virus(ctx, (const char *)pm->virname);
745 745
                         if (virname)
746 746
                             *virname = pm->virname;
747
-                        if (!ctx || !SCAN_ALL)
747
+                        if (!ctx || !SCAN_ALLMATCHES)
748 748
                             if (ret != CL_CLEAN)
749 749
                                 break;
750 750
                     }
... ...
@@ -154,7 +154,7 @@ static inline int matcher_run(const struct cli_matcher *root,
154 154
 		return ret;
155 155
 
156 156
 	    /* else (ret == CL_VIRUS) */
157
-	    if (SCAN_ALL)
157
+	    if (SCAN_ALLMATCHES)
158 158
 		viruses_found = 1;
159 159
 	    else {
160 160
 		ret = cli_append_virus(ctx, *virname);
... ...
@@ -167,7 +167,7 @@ static inline int matcher_run(const struct cli_matcher *root,
167 167
     ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, ctx);
168 168
     if (ret != CL_CLEAN) {
169 169
         if (ret == CL_VIRUS) {
170
-            if (SCAN_ALL)
170
+            if (SCAN_ALLMATCHES)
171 171
                 viruses_found = 1;
172 172
             else {
173 173
                 ret = cli_append_virus(ctx, *virname);
... ...
@@ -228,9 +228,9 @@ static inline int matcher_run(const struct cli_matcher *root,
228 228
 #endif /* HAVE_PCRE */
229 229
     /* end experimental fragment */
230 230
 
231
-    if (ctx && !SCAN_ALL && ret == CL_VIRUS)
231
+    if (ctx && !SCAN_ALLMATCHES && ret == CL_VIRUS)
232 232
         return cli_append_virus(ctx, *virname);
233
-    if (ctx && SCAN_ALL && viruses_found)
233
+    if (ctx && SCAN_ALLMATCHES && viruses_found)
234 234
         return CL_VIRUS;
235 235
 
236 236
     if (saved_ret && ret == CL_CLEAN)
... ...
@@ -280,7 +280,7 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset,
280 280
 	    return ret;
281 281
 	if(ret == CL_VIRUS) {
282 282
 	    viruses_found = 1;
283
-	    if(ctx && !SCAN_ALL) {
283
+	    if(ctx && !SCAN_ALLMATCHES) {
284 284
 		return ret;
285 285
 	    }
286 286
 	}
... ...
@@ -579,7 +579,7 @@ int cli_checkfp_virus(unsigned char *digest, size_t size, cli_ctx *ctx, const ch
579 579
     }
580 580
 
581 581
 #ifdef HAVE__INTERNAL__SHA_COLLECT
582
-    if((ctx->options & CL_SCAN_INTERNAL_COLLECT_SHA) && ctx->sha_collect>0) {
582
+    if(SCAN_DEV_COLLECT_SHA && (ctx->sha_collect > 0)) {
583 583
         if((ptr = fmap_need_off_once(map, 0, size))) {
584 584
             if(!have_sha256)
585 585
                 cl_sha256(ptr, size, shash256+SHA256_HASH_SIZE, NULL);
... ...
@@ -842,7 +842,7 @@ int cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acd
842 842
 #endif
843 843
         if (rc == CL_VIRUS) {
844 844
             viruses_found = 1;
845
-            if (SCAN_ALL)
845
+            if (SCAN_ALLMATCHES)
846 846
                 continue;
847 847
             break;
848 848
         }
... ...
@@ -1053,7 +1053,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1053 1053
                 /* virname already appended by matcher_run */
1054 1054
                 viruses_found = 1;
1055 1055
             }
1056
-            if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
1056
+            if((ret == CL_VIRUS && !SCAN_ALLMATCHES) || ret == CL_EMEM) {
1057 1057
                 if(!ftonly) {
1058 1058
                     cli_ac_freedata(&gdata);
1059 1059
                     cli_pcre_freeoff(&gpoff);
... ...
@@ -1083,7 +1083,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1083 1083
                 /* virname already appended by matcher_run */
1084 1084
                 viruses_found = 1;
1085 1085
             }
1086
-            if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
1086
+            if((ret == CL_VIRUS && !SCAN_ALLMATCHES) || ret == CL_EMEM) {
1087 1087
                 cli_ac_freedata(&gdata);
1088 1088
                 cli_pcre_freeoff(&gpoff);
1089 1089
                 if(troot) {
... ...
@@ -1158,7 +1158,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1158 1158
             if((ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) {
1159 1159
                 found += 1;
1160 1160
             }
1161
-            if(!found || SCAN_ALL) {
1161
+            if(!found || SCAN_ALLMATCHES) {
1162 1162
                 if ((ret = cli_hm_scan_wild(digest[hashtype], &virname_w, hdb, hashtype)) == CL_VIRUS)
1163 1163
                     found += 2;
1164 1164
             }
... ...
@@ -1185,7 +1185,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1185 1185
             if (found % 2) {
1186 1186
                 viruses_found = 1;
1187 1187
                 ret = cli_append_virus(ctx, virname);
1188
-                if (!SCAN_ALL || ret != CL_CLEAN)
1188
+                if (!SCAN_ALLMATCHES || ret != CL_CLEAN)
1189 1189
                     break;
1190 1190
                 virname = NULL;
1191 1191
             }
... ...
@@ -1193,7 +1193,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1193 1193
             if (found > 1) {
1194 1194
                 viruses_found = 1;
1195 1195
                 ret = cli_append_virus(ctx, virname_w);
1196
-                if (!SCAN_ALL || ret != CL_CLEAN)
1196
+                if (!SCAN_ALLMATCHES || ret != CL_CLEAN)
1197 1197
                     break;
1198 1198
              }
1199 1199
         }
... ...
@@ -1204,7 +1204,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1204 1204
     cl_hash_destroy(sha256ctx);
1205 1205
 
1206 1206
     if(troot) {
1207
-        if(ret != CL_VIRUS || SCAN_ALL)
1207
+        if(ret != CL_VIRUS || SCAN_ALLMATCHES)
1208 1208
             ret = cli_exp_eval(ctx, troot, &tdata, &info, (const char *)refhash);
1209 1209
         if (ret == CL_VIRUS)
1210 1210
             viruses_found++;
... ...
@@ -1216,7 +1216,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1216 1216
     }
1217 1217
 
1218 1218
     if(groot) {
1219
-        if(ret != CL_VIRUS || SCAN_ALL)
1219
+        if(ret != CL_VIRUS || SCAN_ALLMATCHES)
1220 1220
             ret = cli_exp_eval(ctx, groot, &gdata, &info, (const char *)refhash);
1221 1221
         cli_ac_freedata(&gdata);
1222 1222
         cli_pcre_freeoff(&gpoff);
... ...
@@ -1227,7 +1227,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
1227 1227
 
1228 1228
     cli_hashset_destroy(&info.exeinfo.vinfo);
1229 1229
 
1230
-    if (SCAN_ALL && viruses_found)
1230
+    if (SCAN_ALLMATCHES && viruses_found)
1231 1231
         return CL_VIRUS;
1232 1232
     if(ret == CL_VIRUS)
1233 1233
         return CL_VIRUS;
... ...
@@ -1251,7 +1251,7 @@ int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer,
1251 1251
 
1252 1252
 	    ret = cli_append_virus(ctx, "Detected.By.Callback");
1253 1253
 	    viruses_found++;
1254
-	    if(!SCAN_ALL || ret != CL_CLEAN)
1254
+	    if(!SCAN_ALLMATCHES || ret != CL_CLEAN)
1255 1255
 		return ret;
1256 1256
 	}
1257 1257
 
... ...
@@ -1288,12 +1288,12 @@ int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer,
1288 1288
 
1289 1289
 	ret = cli_append_virus(ctx, cdb->virname);
1290 1290
 	viruses_found++;
1291
-	if(!SCAN_ALL || ret != CL_CLEAN)
1291
+	if(!SCAN_ALLMATCHES || ret != CL_CLEAN)
1292 1292
 	    return ret;
1293 1293
 
1294 1294
     } while((cdb = cdb->next));
1295 1295
 
1296
-    if (SCAN_ALL && viruses_found)
1296
+    if (SCAN_ALLMATCHES && viruses_found)
1297 1297
 	return CL_VIRUS;
1298 1298
     return CL_CLEAN;
1299 1299
 }
... ...
@@ -51,7 +51,6 @@
51 51
 #ifdef	HAVE_SYS_PARAM_H
52 52
 #include <sys/param.h>
53 53
 #endif
54
-#include "clamav.h"
55 54
 #include <dirent.h>
56 55
 #include <limits.h>
57 56
 #include <signal.h>
... ...
@@ -166,7 +165,7 @@ typedef	enum {
166 166
 #include <fcntl.h>
167 167
 
168 168
 /*
169
- * Use CL_SCAN_PARTIAL_MESSAGE to handle messages covered by section 7.3.2 of RFC1341.
169
+ * Use CL_SCAN_MAIL_PARTIAL_MESSAGE to handle messages covered by section 7.3.2 of RFC1341.
170 170
  *	This is experimental code so it is up to YOU to (1) ensure it's secure
171 171
  * (2) periodically trim the directory of old files
172 172
  *
... ...
@@ -594,7 +593,7 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx)
594 594
 	}
595 595
 	
596 596
 	if((retcode == CL_CLEAN) && ctx->found_possibly_unwanted &&
597
-	   (*ctx->virname == NULL || SCAN_ALL)) {
597
+	   (*ctx->virname == NULL || SCAN_ALLMATCHES)) {
598 598
 	    retcode = cli_append_virus(ctx, "Heuristics.Phishing.Email");
599 599
 	    ctx->found_possibly_unwanted = 0;
600 600
 	}
... ...
@@ -2131,7 +2130,7 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re
2131 2131
 				rc = OK;
2132 2132
 				break;
2133 2133
 			} else if(strcasecmp(mimeSubtype, "partial") == 0) {
2134
-				if(mctx->ctx->options&CL_SCAN_PARTIAL_MESSAGE) {
2134
+				if(mctx->ctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE) {
2135 2135
 					/* RFC1341 message split over many emails */
2136 2136
 					if(rfc1341(mainMessage, mctx->dir) >= 0)
2137 2137
 						rc = OK;
... ...
@@ -186,17 +186,17 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
186 186
     /* MBR is valid, examine bootstrap code */
187 187
     ret = cli_map_scan(*ctx->fmap, 0, sectorsize, ctx, CL_TYPE_ANY);
188 188
     if (ret != CL_CLEAN) {
189
-        if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
189
+        if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
190 190
             detection = CL_VIRUS;
191 191
         else
192 192
             return ret;
193 193
     }
194 194
 
195 195
     /* check that the partition table has no intersections - HEURISTICS */
196
-    if ((ctx->options & CL_SCAN_PARTITION_INTXN) && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
196
+    if (SCAN_HEURISTIC_PARTITION_INTXN && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
197 197
         ret = mbr_primary_prtn_intxn(ctx, mbr, sectorsize);
198 198
         if (ret != CL_CLEAN) {
199
-            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
199
+            if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
200 200
                 detection = CL_VIRUS;
201 201
             else
202 202
                 return ret;
... ...
@@ -230,7 +230,7 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
230 230
             ret = mbr_scanextprtn(ctx, &prtncount, mbr.entries[i].firstLBA, 
231 231
                                   mbr.entries[i].numLBA, sectorsize);
232 232
             if (ret != CL_CLEAN) {
233
-                if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
233
+                if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
234 234
                     detection = CL_VIRUS;
235 235
                 else
236 236
                     return ret;
... ...
@@ -244,7 +244,7 @@ int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
244 244
             mbr_parsemsg("cli_map_scan: [%u, +%u)\n", partoff, partsize);
245 245
             ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
246 246
             if (ret != CL_CLEAN) {
247
-                if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
247
+                if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
248 248
                     detection = CL_VIRUS;
249 249
                 else
250 250
                     return ret;
... ...
@@ -387,7 +387,7 @@ static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size
387 387
 
388 388
                     ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
389 389
                     if (ret != CL_CLEAN) {
390
-                        if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
390
+                        if (SCAN_ALLMATCHES && (ret == CL_VIRUS))
391 391
                             detection = CL_VIRUS;
392 392
                         else
393 393
                             return ret;
... ...
@@ -506,7 +506,7 @@ static int mbr_primary_prtn_intxn(cli_ctx *ctx, struct mbr_boot_record mbr, size
506 506
                     cli_dbgmsg("cli_scanmbr: detected intersection with partitions "
507 507
                                "[%u, %u]\n", pitxn, i);
508 508
                     ret = cli_append_virus(ctx, PRTN_INTXN_DETECTION);
509
-                    if (SCAN_ALL || ret == CL_CLEAN)
509
+                    if (SCAN_ALLMATCHES || ret == CL_CLEAN)
510 510
                         tmp = 0;
511 511
                     else
512 512
                         goto leave;
... ...
@@ -521,7 +521,7 @@ static int mbr_primary_prtn_intxn(cli_ctx *ctx, struct mbr_boot_record mbr, size
521 521
                 tmp = mbr_extended_prtn_intxn(ctx, &prtncount, 
522 522
                                   mbr.entries[i].firstLBA, sectorsize);
523 523
                 if (tmp != CL_CLEAN) {
524
-                    if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
524
+                    if (SCAN_ALLMATCHES && (tmp == CL_VIRUS)) {
525 525
                         ret = tmp;
526 526
                         tmp = 0;
527 527
                     }
... ...
@@ -587,7 +587,7 @@ static int mbr_extended_prtn_intxn(cli_ctx *ctx, unsigned *prtncount, off_t extl
587 587
                 ret = cli_append_virus(ctx, PRTN_INTXN_DETECTION);
588 588
                 if (ret == CL_VIRUS)
589 589
                     virus_found = 1;
590
-                if (SCAN_ALL || ret == CL_CLEAN)
590
+                if (SCAN_ALLMATCHES || ret == CL_CLEAN)
591 591
                     tmp = 0;
592 592
                 else
593 593
                     goto leave;
... ...
@@ -378,9 +378,9 @@ static int msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr reader,
378 378
             switch (node_type) {
379 379
             case XML_READER_TYPE_ELEMENT:
380 380
                 ret = msxml_parse_element(mxctx, reader, rlvl+1, thisjobj ? thisjobj : parent);
381
-                if (ret != CL_SUCCESS || (!SCAN_ALL && ret == CL_VIRUS)) {
381
+                if (ret != CL_SUCCESS || (!SCAN_ALLMATCHES && ret == CL_VIRUS)) {
382 382
                     return ret;
383
-                } else if (SCAN_ALL && ret == CL_VIRUS) {
383
+                } else if (SCAN_ALLMATCHES && ret == CL_VIRUS) {
384 384
                     virus = 1;
385 385
                 }
386 386
                 break;
... ...
@@ -429,9 +429,9 @@ static int msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr reader,
429 429
                     if (!(ctx->engine->keeptmp))
430 430
                         cli_unlink(tempfile);
431 431
                     free(tempfile);
432
-                    if (ret != CL_SUCCESS && (ret != CL_VIRUS || (!SCAN_ALL && ret == CL_VIRUS))) {
432
+                    if (ret != CL_SUCCESS && (ret != CL_VIRUS || (!SCAN_ALLMATCHES && ret == CL_VIRUS))) {
433 433
                         return ret;
434
-                    } else if (SCAN_ALL && ret == CL_VIRUS) {
434
+                    } else if (SCAN_ALLMATCHES && ret == CL_VIRUS) {
435 435
                         virus = 1;
436 436
                     }
437 437
                 }
... ...
@@ -476,9 +476,9 @@ static int msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr reader,
476 476
                     if (!(ctx->engine->keeptmp))
477 477
                         cli_unlink(tempfile);
478 478
                     free(tempfile);
479
-                    if (ret != CL_SUCCESS && (ret != CL_VIRUS || (!SCAN_ALL && ret == CL_VIRUS))) {
479
+                    if (ret != CL_SUCCESS && (ret != CL_VIRUS || (!SCAN_ALLMATCHES && ret == CL_VIRUS))) {
480 480
                         return ret;
481
-                    } else if (SCAN_ALL && ret == CL_VIRUS) {
481
+                    } else if (SCAN_ALLMATCHES && ret == CL_VIRUS) {
482 482
                         virus = 1;
483 483
                     }
484 484
                 }
... ...
@@ -500,9 +500,9 @@ static int msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr reader,
500 500
 #else
501 501
                     ret = mxctx->comment_cb((const char *)node_value, ctx, NULL, mxctx->comment_data);
502 502
 #endif
503
-                    if (ret != CL_SUCCESS && (ret != CL_VIRUS || (!SCAN_ALL && ret == CL_VIRUS))) {
503
+                    if (ret != CL_SUCCESS && (ret != CL_VIRUS || (!SCAN_ALLMATCHES && ret == CL_VIRUS))) {
504 504
                         return ret;
505
-                    } else if (SCAN_ALL && ret == CL_VIRUS) {
505
+                    } else if (SCAN_ALLMATCHES && ret == CL_VIRUS) {
506 506
                         virus = 1;
507 507
                     }
508 508
 
... ...
@@ -615,7 +615,7 @@ int cli_msxml_parse_document(cli_ctx *ctx, xmlTextReaderPtr reader, const struct
615 615
         ret = msxml_parse_element(mxctx, reader, 0, NULL);
616 616
 #endif
617 617
         if (ret == CL_SUCCESS);
618
-        else if (SCAN_ALL && ret == CL_VIRUS) {
618
+        else if (SCAN_ALLMATCHES && ret == CL_VIRUS) {
619 619
             /* non-allmatch simply propagates it down to return through ret */
620 620
             virus = 1;
621 621
         } else if (ret == CL_VIRUS || ret == CL_ETIMEOUT || ret == CL_BREAK) {
... ...
@@ -651,7 +651,7 @@ ole2_walk_property_tree(ole2_header_t * hdr, const char *dir, int32_t prop_index
651 651
             if ((int)(prop_block[idx].child) != -1) {
652 652
                 ret = ole2_walk_property_tree(hdr, dir, prop_block[idx].child, handler, rec_level + 1, file_count, ctx, scansize);
653 653
                 if (ret != CL_SUCCESS) {
654
-                    if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS)) {
654
+                    if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) {
655 655
                         func_ret = ret;
656 656
                     }
657 657
                     else {
... ...
@@ -686,7 +686,7 @@ ole2_walk_property_tree(ole2_header_t * hdr, const char *dir, int32_t prop_index
686 686
                 ole2_listmsg("running file handler\n");
687 687
                 ret = handler(hdr, &prop_block[idx], dir, ctx);
688 688
                 if (ret != CL_SUCCESS) {
689
-                    if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS)) {
689
+                    if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) {
690 690
                         func_ret = ret;
691 691
                     }
692 692
                     else {
... ...
@@ -701,7 +701,7 @@ ole2_walk_property_tree(ole2_header_t * hdr, const char *dir, int32_t prop_index
701 701
             if ((int)(prop_block[idx].child) != -1) {
702 702
                 ret = ole2_walk_property_tree(hdr, dir, prop_block[idx].child, handler, rec_level, file_count, ctx, scansize);
703 703
                 if (ret != CL_SUCCESS) {
704
-                    if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS)) {
704
+                    if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) {
705 705
                         func_ret = ret;
706 706
                     }
707 707
                     else {
... ...
@@ -727,7 +727,7 @@ ole2_walk_property_tree(ole2_header_t * hdr, const char *dir, int32_t prop_index
727 727
             ole2_listmsg("directory node\n");
728 728
             if (dir) {
729 729
 #if HAVE_JSON
730
-                if ((ctx->options & CL_SCAN_FILE_PROPERTIES) && (ctx->wrkproperty != NULL)) {
730
+                if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
731 731
                     if (!json_object_object_get_ex(ctx->wrkproperty, "DigitalSignatures", NULL)) {
732 732
                         name = get_property_name2(prop_block[idx].name, prop_block[idx].name_size);
733 733
                         if (name) {
... ...
@@ -758,7 +758,7 @@ ole2_walk_property_tree(ole2_header_t * hdr, const char *dir, int32_t prop_index
758 758
             if ((int)(prop_block[idx].child) != -1) {
759 759
                 ret = ole2_walk_property_tree(hdr, dirname, prop_block[idx].child, handler, rec_level + 1, file_count, ctx, scansize);
760 760
                 if (ret != CL_SUCCESS) {
761
-                    if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS)) {
761
+                    if (SCAN_ALLMATCHES && (ret == CL_VIRUS)) {
762 762
                         func_ret = ret;
763 763
                     }
764 764
                     else {
... ...
@@ -926,7 +926,7 @@ handler_enum(ole2_header_t * hdr, property_t * prop, const char *dir, cli_ctx *
926 926
 
927 927
     name = get_property_name2(prop->name, prop->name_size);
928 928
     if (name) {
929
-        if (ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL) {
929
+        if (SCAN_COLLECT_METADATA && ctx->wrkproperty != NULL) {
930 930
             arrobj = cli_jsonarray(ctx->wrkproperty, "Streams");
931 931
             if (NULL == arrobj) {
932 932
                 cli_warnmsg("ole2: no memory for streams list or streams is not an array\n");
... ...
@@ -1340,7 +1340,7 @@ handler_otf(ole2_header_t * hdr, property_t * prop, const char *dir, cli_ctx * c
1340 1340
 
1341 1341
 #if HAVE_JSON
1342 1342
     /* JSON Output Summary Information */
1343
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->properties != NULL) {
1343
+    if (SCAN_COLLECT_METADATA && (ctx->properties != NULL)) {
1344 1344
         if (!name)
1345 1345
             name = get_property_name2(prop->name, prop->name_size);
1346 1346
         if (name) {
... ...
@@ -936,8 +936,8 @@ int cl_engine_settings_free(struct cl_settings *settings)
936 936
 
937 937
 void cli_check_blockmax(cli_ctx *ctx, int rc)
938 938
 {
939
-    if (BLOCKMAX && !ctx->limit_exceeded) {
940
-        cli_append_virus (ctx, "Heuristic.Limits.Exceeded");
939
+    if (SCAN_HEURISTIC_EXCEEDS_MAX && !ctx->limit_exceeded) {
940
+        cli_append_virus (ctx, "Heuristics.Limits.Exceeded");
941 941
         ctx->limit_exceeded = 1;
942 942
         cli_dbgmsg ("Limit %s Exceeded: scanning may be incomplete and additional analysis needed for this file.\n",
943 943
             cl_strerror(rc));
... ...
@@ -1096,9 +1096,9 @@ void cli_virus_found_cb(cli_ctx * ctx)
1096 1096
 
1097 1097
 int cli_append_possibly_unwanted(cli_ctx * ctx, const char * virname)
1098 1098
 {
1099
-    if (SCAN_ALL)
1099
+    if (SCAN_ALLMATCHES)
1100 1100
         return cli_append_virus(ctx, virname);
1101
-    else if (ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE)
1101
+    else if (SCAN_HEURISTIC_PRECEDENCE)
1102 1102
         return cli_append_virus(ctx, virname);
1103 1103
     else if (ctx->num_viruses == 0 && ctx->virname != NULL && *ctx->virname == NULL) {
1104 1104
         ctx->found_possibly_unwanted = 1;
... ...
@@ -1114,16 +1114,16 @@ int cli_append_virus(cli_ctx * ctx, const char * virname)
1114 1114
         return CL_CLEAN;
1115 1115
     if (ctx->fmap != NULL && (*ctx->fmap) != NULL && CL_VIRUS != cli_checkfp_virus((*ctx->fmap)->maphash, (*ctx->fmap)->len, ctx, virname))
1116 1116
         return CL_CLEAN;
1117
-    if (!SCAN_ALL && ctx->num_viruses != 0)
1118
-        if (ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE)
1117
+    if (!SCAN_ALLMATCHES && ctx->num_viruses != 0)
1118
+        if (SCAN_HEURISTIC_PRECEDENCE)
1119 1119
             return CL_CLEAN;
1120
-    if (ctx->limit_exceeded == 0 || SCAN_ALL) { 
1120
+    if (ctx->limit_exceeded == 0 || SCAN_ALLMATCHES) { 
1121 1121
         ctx->num_viruses++;
1122 1122
         *ctx->virname = virname;
1123 1123
         cli_virus_found_cb(ctx);
1124 1124
     }
1125 1125
 #if HAVE_JSON
1126
-    if (SCAN_PROPERTIES && ctx->wrkproperty) {
1126
+    if (SCAN_COLLECT_METADATA && ctx->wrkproperty) {
1127 1127
         json_object *arrobj, *virobj;
1128 1128
         if (!json_object_object_get_ex(ctx->wrkproperty, "Viruses", &arrobj)) {
1129 1129
             arrobj = json_object_new_array();
... ...
@@ -160,7 +160,7 @@ typedef struct cli_ctx_tag {
160 160
     const struct cli_matcher *root;
161 161
     const struct cl_engine *engine;
162 162
     unsigned long scansize;
163
-    unsigned int options;
163
+    struct cl_scan_options *options;
164 164
     unsigned int recursion;
165 165
     unsigned int scannedfiles;
166 166
     unsigned int found_possibly_unwanted;
... ...
@@ -490,24 +490,37 @@ extern int (*cli_unrar_extract_next)(unrar_state_t *state, const char *dirname);
490 490
 extern void (*cli_unrar_close)(unrar_state_t *state);
491 491
 extern int have_rar;
492 492
 
493
-#define SCAN_ARCHIVE	    (ctx->options & CL_SCAN_ARCHIVE)
494
-#define SCAN_MAIL	    (ctx->options & CL_SCAN_MAIL)
495
-#define SCAN_OLE2	    (ctx->options & CL_SCAN_OLE2)
496
-#define SCAN_PDF	    (ctx->options & CL_SCAN_PDF)
497
-#define SCAN_HTML	    (ctx->options & CL_SCAN_HTML)
498
-#define SCAN_PE		    (ctx->options & CL_SCAN_PE)
499
-#define SCAN_ELF	    (ctx->options & CL_SCAN_ELF)
500
-#define SCAN_ALGO 	    (ctx->options & CL_SCAN_ALGORITHMIC)
501
-#define DETECT_ENCRYPTED    (ctx->options & CL_SCAN_BLOCKENCRYPTED)
502
-#define BLOCKMAX	    (ctx->options & CL_SCAN_BLOCKMAX)
503
-#define DETECT_BROKEN	    (ctx->options & CL_SCAN_BLOCKBROKEN)
504
-#define BLOCK_MACROS	    (ctx->options & CL_SCAN_BLOCKMACROS)
505
-#define SCAN_STRUCTURED	    (ctx->options & CL_SCAN_STRUCTURED)
506
-#define SCAN_ALL            (ctx->options & CL_SCAN_ALLMATCHES)
507
-#define SCAN_SWF            (ctx->options & CL_SCAN_SWF)
508
-#define SCAN_PROPERTIES     (ctx->options & CL_SCAN_FILE_PROPERTIES)
509
-#define SCAN_XMLDOCS        (ctx->options & CL_SCAN_XMLDOCS)
510
-#define SCAN_HWP3           (ctx->options & CL_SCAN_HWP3)
493
+#define SCAN_ALLMATCHES                         (ctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)
494
+#define SCAN_COLLECT_METADATA                   (ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA)
495
+#define SCAN_HEURISTICS                         (ctx->options->general & CL_SCAN_GENERAL_HEURISTICS)
496
+#define SCAN_HEURISTIC_PRECEDENCE               (ctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)
497
+
498
+#define SCAN_PARSE_ARCHIVE                      (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
499
+#define SCAN_PARSE_ELF                          (ctx->options->parse & CL_SCAN_PARSE_ELF)
500
+#define SCAN_PARSE_PDF                          (ctx->options->parse & CL_SCAN_PARSE_PDF)
501
+#define SCAN_PARSE_SWF                          (ctx->options->parse & CL_SCAN_PARSE_SWF)
502
+#define SCAN_PARSE_HWP3                         (ctx->options->parse & CL_SCAN_PARSE_HWP3)
503
+#define SCAN_PARSE_XMLDOCS                      (ctx->options->parse & CL_SCAN_PARSE_XMLDOCS)
504
+#define SCAN_PARSE_MAIL                         (ctx->options->parse & CL_SCAN_PARSE_MAIL)
505
+#define SCAN_PARSE_OLE2                         (ctx->options->parse & CL_SCAN_PARSE_OLE2)
506
+#define SCAN_PARSE_HTML                         (ctx->options->parse & CL_SCAN_PARSE_HTML)
507
+#define SCAN_PARSE_PE                           (ctx->options->parse & CL_SCAN_PARSE_PE)
508
+
509
+#define SCAN_HEURISTIC_BROKEN                   (ctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN)
510
+#define SCAN_HEURISTIC_EXCEEDS_MAX              (ctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX)
511
+#define SCAN_HEURISTIC_PHISHING_SSL_MISMATCH    (ctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH)
512
+#define SCAN_HEURISTIC_PHISHING_CLOAK           (ctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK)
513
+#define SCAN_HEURISTIC_MACROS                   (ctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS)
514
+#define SCAN_HEURISTIC_ENCRYPTED                (ctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED)
515
+#define SCAN_HEURISTIC_PARTITION_INTXN          (ctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN)
516
+#define SCAN_HEURISTIC_STRUCTURED               (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED)
517
+#define SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL    (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL)
518
+#define SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED  (ctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED)
519
+
520
+#define SCAN_MAIL_PARTIAL_MESSAGE               (ctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE)
521
+
522
+#define SCAN_DEV_COLLECT_SHA                    (ctx->options->dev & CL_SCAN_DEV_COLLECT_SHA)
523
+#define SCAN_DEV_COLLECT_PERF_INFO              (ctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO)
511 524
 
512 525
 /* based on macros from A. Melnikoff */
513 526
 #define cbswap16(v) (((v & 0xff) << 8) | (((v) >> 8) & 0xff))
... ...
@@ -1362,6 +1362,7 @@ static int pdf_scan_contents(int fd, struct pdf_struct *pdf)
1362 1362
 
1363 1363
 int pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t flags)
1364 1364
 {
1365
+    cli_ctx *ctx = pdf->ctx;
1365 1366
     char fullname[NAME_MAX + 1];
1366 1367
     int fout;
1367 1368
     ptrdiff_t sum = 0;
... ...
@@ -1618,7 +1619,7 @@ int pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t flags)
1618 1618
                 if (dparams)
1619 1619
                     pdf_free_dict(dparams);
1620 1620
 
1621
-                if (sum < 0 || (rc == CL_VIRUS && !(pdf->ctx->options & CL_SCAN_ALLMATCHES))) {
1621
+                if (sum < 0 || ((rc == CL_VIRUS) && !SCAN_ALLMATCHES)) {
1622 1622
                     sum = 0; /* prevents post-filter scan */
1623 1623
                     break;
1624 1624
                 }
... ...
@@ -1725,7 +1726,7 @@ int pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t flags)
1725 1725
         if (rc2 == CL_VIRUS || rc == CL_SUCCESS)
1726 1726
             rc = rc2;
1727 1727
 
1728
-        if ((rc == CL_CLEAN) || ((rc == CL_VIRUS) && (pdf->ctx->options & CL_SCAN_ALLMATCHES))) {
1728
+        if ((rc == CL_CLEAN) || ((rc == CL_VIRUS) && SCAN_ALLMATCHES)) {
1729 1729
             unsigned int dumpid = 0;
1730 1730
             for (dumpid = 0; dumpid < pdf->nobjs; dumpid++) {
1731 1731
                 if (pdf->objs[dumpid] == obj)
... ...
@@ -1736,7 +1737,7 @@ int pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t flags)
1736 1736
                 rc = rc2;
1737 1737
         }
1738 1738
 
1739
-        if (((rc == CL_CLEAN) || ((rc == CL_VIRUS) && (pdf->ctx->options & CL_SCAN_ALLMATCHES))) && (obj->flags & (1 << OBJ_CONTENTS))) {
1739
+        if (((rc == CL_CLEAN) || ((rc == CL_VIRUS) && SCAN_ALLMATCHES)) && (obj->flags & (1 << OBJ_CONTENTS))) {
1740 1740
             lseek(fout, 0, SEEK_SET);
1741 1741
             cli_dbgmsg("pdf_extract_obj: dumping contents %u %u\n", obj->id>>8, obj->id&0xff);
1742 1742
 
... ...
@@ -2480,9 +2481,10 @@ static char *pdf_readstring(const char *q0, int len, const char *key, unsigned *
2480 2480
         return s0;
2481 2481
     }
2482 2482
 
2483
-    if (*q == '<') {
2483
+    if ((*q == '<') && (len >= 3))  {
2484 2484
         start = ++q;
2485
-        q = memchr(q+1, '>', len);
2485
+        len -= 1;
2486
+        q = memchr(q+1, '>', len-1);
2486 2487
         if (!q)
2487 2488
             return NULL;
2488 2489
 
... ...
@@ -3065,6 +3067,7 @@ cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf, uint32_t *alerts)
3065 3065
     int foundobj = 0;
3066 3066
     unsigned int i = 0, j = 0;
3067 3067
     uint32_t badobjects = 0;
3068
+    cli_ctx *ctx = pdf->ctx;
3068 3069
 
3069 3070
     /* parse PDF and find obj offsets */
3070 3071
     while (CL_BREAK != (rv = pdf_findobj(pdf))) {
... ...
@@ -3096,7 +3099,7 @@ cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf, uint32_t *alerts)
3096 3096
                (pdf->flags & (1 << DECRYPTABLE_PDF)) ?
3097 3097
                "decryptable" : "not decryptable, stream will probably fail to decompress");
3098 3098
 
3099
-    if ((pdf->ctx->options & CL_SCAN_BLOCKENCRYPTED) &&
3099
+    if (SCAN_HEURISTIC_ENCRYPTED &&
3100 3100
        (pdf->flags & (1 << ENCRYPTED_PDF)) &&
3101 3101
        !(pdf->flags & (1 << DECRYPTABLE_PDF)))
3102 3102
     {
... ...
@@ -3106,7 +3109,7 @@ cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf, uint32_t *alerts)
3106 3106
         status = cli_append_virus(pdf->ctx, "Heuristics.Encrypted.PDF");
3107 3107
         if (status == CL_VIRUS) { 
3108 3108
             alerts++;
3109
-            if (pdf->ctx->options & CL_SCAN_ALLMATCHES)
3109
+            if (SCAN_ALLMATCHES)
3110 3110
                 status = CL_CLEAN;
3111 3111
         }
3112 3112
     }
... ...
@@ -3116,7 +3119,7 @@ cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf, uint32_t *alerts)
3116 3116
         cli_dbgmsg("pdf_find_and_extract_objs: (parsed hooks) returned %d\n", status);
3117 3117
         if (status == CL_VIRUS) {
3118 3118
             alerts++;
3119
-            if (pdf->ctx->options & CL_SCAN_ALLMATCHES) {
3119
+            if (SCAN_ALLMATCHES) {
3120 3120
                 status = CL_CLEAN;
3121 3121
             }
3122 3122
         }
... ...
@@ -3144,7 +3147,7 @@ cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf, uint32_t *alerts)
3144 3144
                 break;
3145 3145
             case CL_VIRUS:
3146 3146
                 alerts++;
3147
-                if (pdf->ctx->options & CL_SCAN_ALLMATCHES) {
3147
+                if (SCAN_ALLMATCHES) {
3148 3148
                     status = CL_CLEAN;
3149 3149
                 }
3150 3150
                 break;
... ...
@@ -3351,7 +3354,7 @@ int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
3351 3351
     pdf.startoff = offset;
3352 3352
 
3353 3353
     rc = run_pdf_hooks(&pdf, PDF_PHASE_PRE, -1, -1);
3354
-    if ((rc == CL_VIRUS) && SCAN_ALL) {
3354
+    if ((rc == CL_VIRUS) && SCAN_ALLMATCHES) {
3355 3355
         cli_dbgmsg("cli_pdf: (pre hooks) returned %d\n", rc);
3356 3356
         alerts++;
3357 3357
         rc = CL_CLEAN;
... ...
@@ -3383,12 +3386,12 @@ int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
3383 3383
         rc = run_pdf_hooks(&pdf, PDF_PHASE_END, -1, -1);
3384 3384
         if (rc == CL_VIRUS) {
3385 3385
             alerts++;
3386
-            if (SCAN_ALL) {
3386
+            if (SCAN_ALLMATCHES) {
3387 3387
                 rc = CL_CLEAN;
3388 3388
             }
3389 3389
         }
3390 3390
 
3391
-        if (!rc && SCAN_ALGO && (ctx->dconf->other & OTHER_CONF_PDFNAMEOBJ)) {
3391
+        if (!rc && SCAN_HEURISTICS && (ctx->dconf->other & OTHER_CONF_PDFNAMEOBJ)) {
3392 3392
             if (pdf.flags & (1 << ESCAPED_COMMON_PDFNAME)) {
3393 3393
                 /* for example /Fl#61te#44#65#63#6f#64#65 instead of /FlateDecode */
3394 3394
                 cli_append_possibly_unwanted(ctx, "Heuristics.PDF.ObfuscatedNameObject");
... ...
@@ -3657,6 +3660,7 @@ static void CCITTFaxDecode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struc
3657 3657
 #if HAVE_JSON
3658 3658
 static void JBIG2Decode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3659 3659
 {
3660
+    cli_ctx *ctx = pdf->ctx;
3660 3661
     struct json_object *pdfobj, *jbig2arr;
3661 3662
 
3662 3663
     UNUSEDPARAM(obj);
... ...
@@ -3665,7 +3669,7 @@ static void JBIG2Decode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct p
3665 3665
     if (!(pdf))
3666 3666
         return;
3667 3667
 
3668
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3668
+    if (!(SCAN_COLLECT_METADATA))
3669 3669
         return;
3670 3670
 
3671 3671
     if (!(pdf->ctx->wrkproperty))
... ...
@@ -3753,6 +3757,7 @@ static void Sig_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_a
3753 3753
 #if HAVE_JSON
3754 3754
 static void JavaScript_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3755 3755
 {
3756
+    cli_ctx *ctx = pdf->ctx;
3756 3757
     struct json_object *pdfobj, *jbig2arr;
3757 3758
 
3758 3759
     UNUSEDPARAM(act);
... ...
@@ -3760,7 +3765,7 @@ static void JavaScript_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pd
3760 3760
     if (!(pdf))
3761 3761
         return;
3762 3762
 
3763
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3763
+    if (!(SCAN_COLLECT_METADATA))
3764 3764
         return;
3765 3765
 
3766 3766
     if (!(pdf->ctx->wrkproperty))
... ...
@@ -3822,12 +3827,14 @@ static void Page_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_
3822 3822
 #if HAVE_JSON
3823 3823
 static void Author_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3824 3824
 {
3825
+    cli_ctx *ctx = pdf->ctx;
3826
+
3825 3827
     UNUSEDPARAM(act);
3826 3828
 
3827 3829
     if (!(pdf))
3828 3830
         return;
3829 3831
 
3830
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3832
+    if (!(SCAN_COLLECT_METADATA))
3831 3833
         return;
3832 3834
 
3833 3835
     if (!(pdf->stats.author)) {
... ...
@@ -3845,12 +3852,14 @@ static void Author_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfnam
3845 3845
 #if HAVE_JSON
3846 3846
 static void Creator_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3847 3847
 {
3848
+    cli_ctx *ctx = pdf->ctx;
3849
+
3848 3850
     UNUSEDPARAM(act);
3849 3851
 
3850 3852
     if (!(pdf))
3851 3853
         return;
3852 3854
 
3853
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3855
+    if (!(SCAN_COLLECT_METADATA))
3854 3856
         return;
3855 3857
 
3856 3858
     if (!(pdf->stats.creator)) {
... ...
@@ -3868,12 +3877,14 @@ static void Creator_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfna
3868 3868
 #if HAVE_JSON
3869 3869
 static void ModificationDate_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3870 3870
 {
3871
+    cli_ctx *ctx = pdf->ctx;
3872
+
3871 3873
     UNUSEDPARAM(act);
3872 3874
 
3873 3875
     if (!(pdf))
3874 3876
         return;
3875 3877
 
3876
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3878
+    if (!(SCAN_COLLECT_METADATA))
3877 3879
         return;
3878 3880
 
3879 3881
     if (!(pdf->stats.modificationdate)) {
... ...
@@ -3891,12 +3902,14 @@ static void ModificationDate_cb(struct pdf_struct *pdf, struct pdf_obj *obj, str
3891 3891
 #if HAVE_JSON
3892 3892
 static void CreationDate_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3893 3893
 {
3894
+    cli_ctx *ctx = pdf->ctx;
3895
+
3894 3896
     UNUSEDPARAM(act);
3895 3897
 
3896 3898
     if (!(pdf))
3897 3899
         return;
3898 3900
 
3899
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3901
+    if (!(SCAN_COLLECT_METADATA))
3900 3902
         return;
3901 3903
 
3902 3904
     if (!(pdf->stats.creationdate)) {
... ...
@@ -3914,12 +3927,14 @@ static void CreationDate_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct
3914 3914
 #if HAVE_JSON
3915 3915
 static void Producer_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3916 3916
 {
3917
+    cli_ctx *ctx = pdf->ctx;
3918
+
3917 3919
     UNUSEDPARAM(act);
3918 3920
 
3919 3921
     if (!(pdf))
3920 3922
         return;
3921 3923
 
3922
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3924
+    if (!(SCAN_COLLECT_METADATA))
3923 3925
         return;
3924 3926
 
3925 3927
     if (!(pdf->stats.producer)) {
... ...
@@ -3937,12 +3952,14 @@ static void Producer_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfn
3937 3937
 #if HAVE_JSON
3938 3938
 static void Title_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3939 3939
 {
3940
+    cli_ctx *ctx = pdf->ctx;
3941
+
3940 3942
     UNUSEDPARAM(act);
3941 3943
 
3942 3944
     if (!(pdf))
3943 3945
         return;
3944 3946
 
3945
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3947
+    if (!(SCAN_COLLECT_METADATA))
3946 3948
         return;
3947 3949
 
3948 3950
     if (!(pdf->stats.title)) {
... ...
@@ -3960,12 +3977,14 @@ static void Title_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname
3960 3960
 #if HAVE_JSON
3961 3961
 static void Keywords_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3962 3962
 {
3963
+    cli_ctx *ctx = pdf->ctx;
3964
+
3963 3965
     UNUSEDPARAM(act);
3964 3966
 
3965 3967
     if (!(pdf))
3966 3968
         return;
3967 3969
 
3968
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3970
+    if (!(SCAN_COLLECT_METADATA))
3969 3971
         return;
3970 3972
 
3971 3973
     if (!(pdf->stats.keywords)) {
... ...
@@ -3983,12 +4002,14 @@ static void Keywords_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfn
3983 3983
 #if HAVE_JSON
3984 3984
 static void Subject_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
3985 3985
 {
3986
+    cli_ctx *ctx = pdf->ctx;
3987
+
3986 3988
     UNUSEDPARAM(act);
3987 3989
 
3988 3990
     if (!(pdf))
3989 3991
         return;
3990 3992
 
3991
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
3993
+    if (!(SCAN_COLLECT_METADATA))
3992 3994
         return;
3993 3995
 
3994 3996
     if (!(pdf->stats.subject)) {
... ...
@@ -4045,6 +4066,7 @@ static void XFA_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_a
4045 4045
 #if HAVE_JSON
4046 4046
 static void Pages_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
4047 4047
 {
4048
+    cli_ctx *ctx = pdf->ctx;
4048 4049
     struct pdf_array *array;
4049 4050
     const char *objstart = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
4050 4051
                                          : (const char *)(obj->start + pdf->map);
... ...
@@ -4059,7 +4081,7 @@ static void Pages_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname
4059 4059
     if (!(pdf) || !(pdf->ctx->wrkproperty))
4060 4060
         return;
4061 4061
 
4062
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
4062
+    if (!(SCAN_COLLECT_METADATA))
4063 4063
         return;
4064 4064
 
4065 4065
     objsize = obj_size(pdf, obj, 1);
... ...
@@ -4112,6 +4134,7 @@ cleanup:
4112 4112
 #if HAVE_JSON
4113 4113
 static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
4114 4114
 {
4115
+    cli_ctx *ctx = pdf->ctx;
4115 4116
     json_object *colorsobj, *pdfobj;
4116 4117
     unsigned long ncolors;
4117 4118
     char *p1;
... ...
@@ -4124,7 +4147,7 @@ static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfnam
4124 4124
     if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->wrkproperty))
4125 4125
         return;
4126 4126
 
4127
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
4127
+    if (!(SCAN_COLLECT_METADATA))
4128 4128
         return;
4129 4129
 
4130 4130
     objsize = obj_size(pdf, obj, 1);
... ...
@@ -4167,6 +4190,7 @@ static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfnam
4167 4167
 #if HAVE_JSON
4168 4168
 static void pdf_export_json(struct pdf_struct *pdf)
4169 4169
 {
4170
+    cli_ctx *ctx = pdf->ctx;
4170 4171
     json_object *pdfobj;
4171 4172
     unsigned long i;
4172 4173
 
... ...
@@ -4177,7 +4201,7 @@ static void pdf_export_json(struct pdf_struct *pdf)
4177 4177
         goto cleanup;
4178 4178
     }
4179 4179
 
4180
-    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES) || !(pdf->ctx->wrkproperty)) {
4180
+    if (!(SCAN_COLLECT_METADATA) || !(pdf->ctx->wrkproperty)) {
4181 4181
         goto cleanup;
4182 4182
     }
4183 4183
 
... ...
@@ -227,6 +227,7 @@ static ptrdiff_t pdf_decodestream_internal(
227 227
     cl_error_t vir = CL_CLEAN;
228 228
     cl_error_t retval = CL_SUCCESS;
229 229
     ptrdiff_t bytes_scanned = -1;
230
+    cli_ctx *ctx = pdf->ctx;
230 231
     const char *filter = NULL;
231 232
     int i;
232 233
 
... ...
@@ -315,7 +316,7 @@ static ptrdiff_t pdf_decodestream_internal(
315 315
         }
316 316
 
317 317
         if (retval != CL_SUCCESS) {
318
-            if (retval == CL_VIRUS && pdf->ctx->options & CL_SCAN_ALLMATCHES) {
318
+            if (retval == CL_VIRUS && SCAN_ALLMATCHES) {
319 319
                 vir = CL_VIRUS;
320 320
             } else {
321 321
                 const char* reason;
... ...
@@ -223,7 +223,7 @@ FSGSTUFF; \
223 223
 #define CLI_UNPRESULTSFSG1(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,FSGCASE(NAME,free(sections)),EXPR,GOOD,FREEME)
224 224
 #define CLI_UNPRESULTSFSG2(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,FSGCASE(NAME,(void)0),EXPR,GOOD,FREEME)
225 225
 
226
-#define DETECT_BROKEN_PE (DETECT_BROKEN && !ctx->corrupted_input)
226
+#define DETECT_BROKEN_PE (SCAN_HEURISTIC_BROKEN && !ctx->corrupted_input)
227 227
 
228 228
 extern const unsigned int hashlen[];
229 229
 
... ...
@@ -598,7 +598,7 @@ static int scan_pe_mdb (cli_ctx * ctx, struct cli_exe_section *exe_section)
598 598
             if (ret != CL_CLEAN) {
599 599
                 if (ret != CL_VIRUS)
600 600
                     break;
601
-                else if (!SCAN_ALL)
601
+                else if (!SCAN_ALLMATCHES)
602 602
                     break;
603 603
             }
604 604
        }
... ...
@@ -607,7 +607,7 @@ static int scan_pe_mdb (cli_ctx * ctx, struct cli_exe_section *exe_section)
607 607
             if (ret != CL_CLEAN) {
608 608
                 if (ret != CL_VIRUS)
609 609
                     break;
610
-                else if (!SCAN_ALL)
610
+                else if (!SCAN_ALLMATCHES)
611 611
                     break;
612 612
             }
613 613
        }
... ...
@@ -2573,7 +2573,7 @@ static int scan_pe_imp(cli_ctx *ctx, struct pe_image_data_dir *dirs, struct cli_
2573 2573
             if (ret != CL_CLEAN) {
2574 2574
                 if (ret != CL_VIRUS)
2575 2575
                     break;
2576
-                else if (!SCAN_ALL)
2576
+                else if (!SCAN_ALLMATCHES)
2577 2577
                     break;
2578 2578
             }
2579 2579
         }
... ...
@@ -2582,7 +2582,7 @@ static int scan_pe_imp(cli_ctx *ctx, struct pe_image_data_dir *dirs, struct cli_
2582 2582
             if (ret != CL_CLEAN) {
2583 2583
                 if (ret != CL_VIRUS)
2584 2584
                     break;
2585
-                else if (!SCAN_ALL)
2585
+                else if (!SCAN_ALLMATCHES)
2586 2586
                     break;
2587 2587
             }
2588 2588
        }
... ...
@@ -2758,7 +2758,7 @@ int cli_scanpe(cli_ctx *ctx)
2758 2758
         return CL_ETIMEOUT;
2759 2759
     }
2760 2760
 
2761
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
2761
+    if (SCAN_COLLECT_METADATA) {
2762 2762
         pe_json = get_pe_property(ctx);
2763 2763
     }
2764 2764
 #endif
... ...
@@ -3119,7 +3119,7 @@ int cli_scanpe(cli_ctx *ctx)
3119 3119
     }
3120 3120
 
3121 3121
 #if HAVE_JSON
3122
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
3122
+    if (SCAN_COLLECT_METADATA) {
3123 3123
         snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", vep);
3124 3124
         if (pe_json != NULL)
3125 3125
             cli_jsonstr(pe_json, "EntryPoint", jsonbuf);
... ...
@@ -3349,7 +3349,7 @@ int cli_scanpe(cli_ctx *ctx)
3349 3349
         }
3350 3350
 
3351 3351
         if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */
3352
-            if(SCAN_ALGO && (DCONF & PE_CONF_POLIPOS) && !*sname && exe_sections[i].vsz > 40000 && exe_sections[i].vsz < 70000 && exe_sections[i].chr == 0xe0000060) polipos = i;
3352
+            if(SCAN_HEURISTICS && (DCONF & PE_CONF_POLIPOS) && !*sname && exe_sections[i].vsz > 40000 && exe_sections[i].vsz < 70000 && exe_sections[i].chr == 0xe0000060) polipos = i;
3353 3353
 
3354 3354
             /* check hash section sigs */
3355 3355
             if((DCONF & PE_CONF_MD5SECT) && ctx->engine->hm_mdb) {
... ...
@@ -3516,7 +3516,7 @@ int cli_scanpe(cli_ctx *ctx)
3516 3516
                 cli_warnmsg("cli_scanpe: NULL argument supplied\n");
3517 3517
                 break;
3518 3518
             case CL_VIRUS:
3519
-                if (SCAN_ALL)
3519
+                if (SCAN_ALLMATCHES)
3520 3520
                     break;
3521 3521
                 /* intentional fall-through */
3522 3522
             case CL_BREAK:
... ...
@@ -3530,7 +3530,7 @@ int cli_scanpe(cli_ctx *ctx)
3530 3530
     /* Attempt to detect some popular polymorphic viruses */
3531 3531
 
3532 3532
     /* W32.Parite.B */
3533
-    if(SCAN_ALGO && (DCONF & PE_CONF_PARITE) && !dll && epsize == 4096 && ep == exe_sections[nsections - 1].raw) {
3533
+    if(SCAN_HEURISTICS && (DCONF & PE_CONF_PARITE) && !dll && epsize == 4096 && ep == exe_sections[nsections - 1].raw) {
3534 3534
         const char *pt = cli_memstr(epbuff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15);
3535 3535
         if(pt) {
3536 3536
             pt += 15;
... ...
@@ -3538,7 +3538,7 @@ int cli_scanpe(cli_ctx *ctx)
3538 3538
                 ret = cli_append_virus(ctx,"Heuristics.W32.Parite.B");
3539 3539
                 if (ret != CL_CLEAN) {
3540 3540
                     if (ret == CL_VIRUS) {
3541
-                        if (!SCAN_ALL) {
3541
+                        if (!SCAN_ALLMATCHES) {
3542 3542
                             free(exe_sections);
3543 3543
                             return ret;
3544 3544
                         }
... ...
@@ -3554,7 +3554,7 @@ int cli_scanpe(cli_ctx *ctx)
3554 3554
     }
3555 3555
 
3556 3556
     /* Kriz */
3557
-    if(SCAN_ALGO && (DCONF & PE_CONF_KRIZ) && epsize >= 200 && CLI_ISCONTAINED(exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz, ep, 0x0fd2) && epbuff[1]=='\x9c' && epbuff[2]=='\x60') {
3557
+    if(SCAN_HEURISTICS && (DCONF & PE_CONF_KRIZ) && epsize >= 200 && CLI_ISCONTAINED(exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz, ep, 0x0fd2) && epbuff[1]=='\x9c' && epbuff[2]=='\x60') {
3558 3558
         enum {KZSTRASH,KZSCDELTA,KZSPDELTA,KZSGETSIZE,KZSXORPRFX,KZSXOR,KZSDDELTA,KZSLOOP,KZSTOP};
3559 3559
         uint8_t kzs[] = {KZSTRASH,KZSCDELTA,KZSPDELTA,KZSGETSIZE,KZSTRASH,KZSXORPRFX,KZSXOR,KZSTRASH,KZSDDELTA,KZSTRASH,KZSLOOP,KZSTOP};
3560 3560
         uint8_t *kzstate = kzs;
... ...
@@ -3663,7 +3663,7 @@ int cli_scanpe(cli_ctx *ctx)
3663 3663
                     ret = cli_append_virus(ctx,"Heuristics.W32.Kriz");
3664 3664
                     if (ret != CL_CLEAN) {
3665 3665
                         if (ret == CL_VIRUS) {
3666
-                            if (!SCAN_ALL) {
3666
+                            if (!SCAN_ALLMATCHES) {
3667 3667
                                 free(exe_sections);
3668 3668
                                 return ret;
3669 3669
                             }
... ...
@@ -3682,7 +3682,7 @@ int cli_scanpe(cli_ctx *ctx)
3682 3682
     }
3683 3683
 
3684 3684
     /* W32.Magistr.A/B */
3685
-    if(SCAN_ALGO && (DCONF & PE_CONF_MAGISTR) && !dll && (nsections>1) && (exe_sections[nsections - 1].chr & 0x80000000)) {
3685
+    if(SCAN_HEURISTICS && (DCONF & PE_CONF_MAGISTR) && !dll && (nsections>1) && (exe_sections[nsections - 1].chr & 0x80000000)) {
3686 3686
         uint32_t rsize, vsize, dam = 0;
3687 3687
 
3688 3688
         vsize = exe_sections[nsections - 1].uvsz;
... ...
@@ -3701,7 +3701,7 @@ int cli_scanpe(cli_ctx *ctx)
3701 3701
                     ret = cli_append_virus(ctx, dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A");
3702 3702
                     if (ret != CL_CLEAN) {
3703 3703
                         if (ret == CL_VIRUS) {
3704
-                            if (!SCAN_ALL) {
3704
+                            if (!SCAN_ALLMATCHES) {
3705 3705
                                 free(exe_sections);
3706 3706
                                 return ret;
3707 3707
                             }
... ...
@@ -3723,7 +3723,7 @@ int cli_scanpe(cli_ctx *ctx)
3723 3723
                     ret = cli_append_virus(ctx,dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B");
3724 3724
                     if (ret != CL_CLEAN) {
3725 3725
                         if (ret == CL_VIRUS) {
3726
-                            if (!SCAN_ALL) {
3726
+                            if (!SCAN_ALLMATCHES) {
3727 3727
                                 free(exe_sections);
3728 3728
                                 return ret;
3729 3729
                             }
... ...
@@ -3800,7 +3800,7 @@ int cli_scanpe(cli_ctx *ctx)
3800 3800
                 ret = cli_append_virus(ctx,"Heuristics.W32.Polipos.A");
3801 3801
                 if (ret != CL_CLEAN) {
3802 3802
                     if (ret == CL_VIRUS) {
3803
-                        if (!SCAN_ALL) {
3803
+                        if (!SCAN_ALLMATCHES) {
3804 3804
                             free(jumps);
3805 3805
                             free(exe_sections);
3806 3806
                             return ret;
... ...
@@ -3821,7 +3821,7 @@ int cli_scanpe(cli_ctx *ctx)
3821 3821
     }
3822 3822
 
3823 3823
     /* Trojan.Swizzor.Gen */
3824
-    if (SCAN_ALGO && (DCONF & PE_CONF_SWIZZOR) && nsections > 1 && fsize > 64*1024 && fsize < 4*1024*1024) {
3824
+    if (SCAN_HEURISTICS && (DCONF & PE_CONF_SWIZZOR) && nsections > 1 && fsize > 64*1024 && fsize < 4*1024*1024) {
3825 3825
         if(dirs[2].Size) {
3826 3826
             struct swizz_stats *stats = cli_calloc(1, sizeof(*stats));
3827 3827
             unsigned int m = 1000;
... ...
@@ -3836,7 +3836,7 @@ int cli_scanpe(cli_ctx *ctx)
3836 3836
                     ret = cli_append_virus(ctx,"Heuristics.Trojan.Swizzor.Gen");
3837 3837
                     if (ret != CL_CLEAN) {
3838 3838
                         if (ret == CL_VIRUS) {
3839
-                            if (!SCAN_ALL) {
3839
+                            if (!SCAN_ALLMATCHES) {
3840 3840
                                 free(stats);
3841 3841
                                 free(exe_sections);
3842 3842
                                 return ret;
... ...
@@ -4727,7 +4727,7 @@ out_no_petite:
4727 4727
                 CLI_UNPTEMP("yC",(spinned,exe_sections,0));
4728 4728
                 CLI_UNPRESULTS("yC",(yc_decrypt(ctx, spinned, fsize, exe_sections, nsections-1, e_lfanew, ndesc, ecx, offset)),0,(spinned,0));
4729 4729
 
4730
-                if (SCAN_ALL && yc_unp_num_viruses != ctx->num_viruses) {
4730
+                if (SCAN_ALLMATCHES && yc_unp_num_viruses != ctx->num_viruses) {
4731 4731
                     free(exe_sections);
4732 4732
                     return CL_VIRUS;
4733 4733
                 }
... ...
@@ -4991,7 +4991,7 @@ out_no_petite:
4991 4991
         return CL_ETIMEOUT;
4992 4992
 #endif
4993 4993
 
4994
-    if (SCAN_ALL && viruses_found)
4994
+    if (SCAN_ALLMATCHES && viruses_found)
4995 4995
         return CL_VIRUS;
4996 4996
 
4997 4997
     return CL_CLEAN;
... ...
@@ -739,7 +739,7 @@ int phishingScan(cli_ctx* ctx,tag_arguments_t* hrefs)
739 739
 	if(!pchk || pchk->is_disabled)
740 740
 		return CL_CLEAN;
741 741
 
742
-	if(!ctx->found_possibly_unwanted && !SCAN_ALL)
742
+	if(!ctx->found_possibly_unwanted && !SCAN_ALLMATCHES)
743 743
 		*ctx->virname=NULL;
744 744
 #if 0
745 745
 	FILE *f = fopen("/home/edwin/quarantine/urls","r");
... ...
@@ -785,10 +785,10 @@ int phishingScan(cli_ctx* ctx,tag_arguments_t* hrefs)
785 785
 				urls.link_type |= LINKTYPE_IMAGE;
786 786
 			}
787 787
 			urls.always_check_flags = 0;
788
-			if (ctx->options & CL_SCAN_PHISHING_BLOCKSSL) {
788
+			if (SCAN_HEURISTIC_PHISHING_SSL_MISMATCH) {
789 789
 				urls.always_check_flags |= CHECK_SSL;
790 790
 			}
791
-			if (ctx->options & CL_SCAN_PHISHING_BLOCKCLOAK) {
791
+			if (SCAN_HEURISTIC_PHISHING_CLOAK) {
792 792
 				urls.always_check_flags |= CHECK_CLOAKING;
793 793
 			}
794 794
 			string_init_c(&urls.realLink,(char*)hrefs->value[i]);
... ...
@@ -171,7 +171,7 @@ static int cli_scandir(const char *dirname, cli_ctx *ctx)
171 171
                             {
172 172
                                 free(fname);
173 173
 
174
-                                if (SCAN_ALL)
174
+                                if (SCAN_ALLMATCHES)
175 175
                                 {
176 176
                                     viruses_found++;
177 177
                                     continue;
... ...
@@ -189,7 +189,7 @@ static int cli_scandir(const char *dirname, cli_ctx *ctx)
189 189
                                 {
190 190
                                     free(fname);
191 191
 
192
-                                    if (SCAN_ALL)
192
+                                    if (SCAN_ALLMATCHES)
193 193
                                     {
194 194
                                         viruses_found++;
195 195
                                         continue;
... ...
@@ -213,7 +213,7 @@ static int cli_scandir(const char *dirname, cli_ctx *ctx)
213 213
     }
214 214
 
215 215
     closedir(dd);
216
-    if (SCAN_ALL && viruses_found)
216
+    if (SCAN_ALLMATCHES && viruses_found)
217 217
         return CL_VIRUS;
218 218
     return CL_CLEAN;
219 219
 }
... ...
@@ -238,12 +238,12 @@ static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx
238 238
 
239 239
     if (cli_matchmeta(ctx, metadata->filename, metadata->pack_size, metadata->unpack_size, metadata->encrypted, files, metadata->crc, NULL) == CL_VIRUS)
240 240
     {
241
-        if (!SCAN_ALL)
241
+        if (!SCAN_ALLMATCHES)
242 242
             return CL_VIRUS;
243 243
         virus_found = 1;
244 244
     }
245 245
 
246
-    if (DETECT_ENCRYPTED && metadata->encrypted)
246
+    if (SCAN_HEURISTIC_ENCRYPTED && metadata->encrypted)
247 247
     {
248 248
         cli_dbgmsg("RAR: Encrypted files found in archive.\n");
249 249
         ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
... ...
@@ -292,7 +292,7 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
292 292
         if (ret == UNRAR_PASSWD)
293 293
         {
294 294
             cli_dbgmsg("RAR: Encrypted main header\n");
295
-            if (DETECT_ENCRYPTED)
295
+            if (SCAN_HEURISTIC_ENCRYPTED)
296 296
             {
297 297
                 if (lseek(desc, 0, SEEK_SET) == -1)
298 298
                 {
... ...
@@ -373,7 +373,7 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
373 373
 
374 374
         if (ret == CL_VIRUS)
375 375
         {
376
-            if (SCAN_ALL)
376
+            if (SCAN_ALLMATCHES)
377 377
                 ret = CL_SUCCESS;
378 378
             else
379 379
                 break;
... ...
@@ -409,7 +409,7 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
409 409
     }
410 410
     cli_dbgmsg("RAR: Exit code: %d\n", ret);
411 411
 
412
-    if (SCAN_ALL && viruses_found)
412
+    if (SCAN_ALLMATCHES && viruses_found)
413 413
         return CL_VIRUS;
414 414
     return ret;
415 415
 }
... ...
@@ -460,7 +460,7 @@ static int cli_scanarj(cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
460 460
         file++;
461 461
         if (cli_matchmeta(ctx, metadata.filename, metadata.comp_size, metadata.orig_size, metadata.encrypted, file, 0, NULL) == CL_VIRUS)
462 462
         {
463
-            if (!SCAN_ALL)
463
+            if (!SCAN_ALLMATCHES)
464 464
             {
465 465
                 cli_rmdirs(dir);
466 466
                 free(dir);
... ...
@@ -493,7 +493,7 @@ static int cli_scanarj(cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
493 493
             if (rc == CL_VIRUS)
494 494
             {
495 495
                 cli_dbgmsg("ARJ: infected with %s\n", cli_get_last_virus(ctx));
496
-                if (!SCAN_ALL)
496
+                if (!SCAN_ALLMATCHES)
497 497
                 {
498 498
                     ret = CL_VIRUS;
499 499
                     if (metadata.filename)
... ...
@@ -904,7 +904,7 @@ static int cli_scanxz(cli_ctx *ctx)
904 904
         {
905 905
             if (rc == XZ_DIC_HEURISTIC)
906 906
             {
907
-                ret = cli_append_virus(ctx, "Heuristic.XZ.DicSizeLimit");
907
+                ret = cli_append_virus(ctx, "Heuristics.XZ.DicSizeLimit");
908 908
                 goto xz_exit;
909 909
             }
910 910
             cli_errmsg("cli_scanxz: decompress error: %d\n", rc);
... ...
@@ -1018,7 +1018,7 @@ static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ct
1018 1018
     if (ret == CL_VIRUS)
1019 1019
         viruses_found++;
1020 1020
 
1021
-    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
1021
+    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES))
1022 1022
     {
1023 1023
         fmap_t *map = *ctx->fmap;
1024 1024
         *ctx->fmap = cl_fmap_open_memory(data, len);
... ...
@@ -1028,7 +1028,7 @@ static int vba_scandata(const unsigned char *data, unsigned int len, cli_ctx *ct
1028 1028
         if (ret == CL_VIRUS)
1029 1029
             viruses_found++;
1030 1030
 
1031
-        if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
1031
+        if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES))
1032 1032
             ret = cli_exp_eval(ctx, groot, &gmdata, NULL, NULL);
1033 1033
         funmap(*ctx->fmap);
1034 1034
         *ctx->fmap = map;
... ...
@@ -1111,7 +1111,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1111 1111
 
1112 1112
                     if (vba_scandata(data, data_len, ctx) == CL_VIRUS)
1113 1113
                     {
1114
-                        if (SCAN_ALL)
1114
+                        if (SCAN_ALLMATCHES)
1115 1115
                             viruses_found++;
1116 1116
                         else
1117 1117
                         {
... ...
@@ -1130,11 +1130,11 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1130 1130
         free(vba_project->dir);
1131 1131
         free(vba_project->offset);
1132 1132
         free(vba_project);
1133
-        if (ret == CL_VIRUS && !SCAN_ALL)
1133
+        if (ret == CL_VIRUS && !SCAN_ALLMATCHES)
1134 1134
             break;
1135 1135
     }
1136 1136
 
1137
-    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) &&
1137
+    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) &&
1138 1138
         (hashcnt = uniq_get(U, "powerpoint document", 19, &hash)))
1139 1139
     {
1140 1140
         while (hashcnt--)
... ...
@@ -1159,7 +1159,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1159 1159
         }
1160 1160
     }
1161 1161
 
1162
-    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL)) &&
1162
+    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) &&
1163 1163
         (hashcnt = uniq_get(U, "worddocument", 12, &hash)))
1164 1164
     {
1165 1165
         while (hashcnt--)
... ...
@@ -1191,7 +1191,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1191 1191
                         *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
1192 1192
                     if (vba_scandata(data, vba_project->length[i], ctx) == CL_VIRUS)
1193 1193
                     {
1194
-                        if (SCAN_ALL)
1194
+                        if (SCAN_ALLMATCHES)
1195 1195
                             viruses_found++;
1196 1196
                         else
1197 1197
                         {
... ...
@@ -1214,7 +1214,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1214 1214
             free(vba_project);
1215 1215
             if (ret == CL_VIRUS)
1216 1216
             {
1217
-                if (SCAN_ALL)
1217
+                if (SCAN_ALLMATCHES)
1218 1218
                     viruses_found++;
1219 1219
                 else
1220 1220
                     break;
... ...
@@ -1222,12 +1222,12 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1222 1222
         }
1223 1223
     }
1224 1224
 
1225
-    if (ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
1225
+    if (ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALLMATCHES))
1226 1226
         return ret;
1227 1227
 
1228 1228
 #if HAVE_JSON
1229 1229
     /* JSON Output Summary Information */
1230
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL)
1230
+    if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL))
1231 1231
     {
1232 1232
         hashcnt = uniq_get(U, "_5_summaryinformation", 21, &hash);
1233 1233
         while (hashcnt--)
... ...
@@ -1275,7 +1275,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1275 1275
         {
1276 1276
             ret = cli_scan_ole10(fd, ctx);
1277 1277
             close(fd);
1278
-            if (ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALL))
1278
+            if (ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALLMATCHES))
1279 1279
                 return ret;
1280 1280
         }
1281 1281
     }
... ...
@@ -1316,7 +1316,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1316 1316
                         if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
1317 1317
                             if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS)
1318 1318
                             {
1319
-                                if (SCAN_ALL)
1319
+                                if (SCAN_ALLMATCHES)
1320 1320
                                     viruses_found++;
1321 1321
                                 else
1322 1322
                                 {
... ...
@@ -1339,16 +1339,16 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
1339 1339
 
1340 1340
     closedir(dd);
1341 1341
 #if HAVE_JSON
1342
-    if (hasmacros && ctx->options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL)
1342
+    if (hasmacros && SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL))
1343 1343
         cli_jsonbool(ctx->wrkproperty, "HasMacros", 1);
1344 1344
 #endif
1345
-    if (BLOCK_MACROS && hasmacros)
1345
+    if (SCAN_HEURISTIC_MACROS && hasmacros)
1346 1346
     {
1347 1347
         ret = cli_append_virus(ctx, "Heuristics.OLE2.ContainsMacros");
1348 1348
         if (ret == CL_VIRUS)
1349 1349
             viruses_found++;
1350 1350
     }
1351
-    if (SCAN_ALL && viruses_found)
1351
+    if (SCAN_ALLMATCHES && viruses_found)
1352 1352
         return CL_VIRUS;
1353 1353
     return ret;
1354 1354
 }
... ...
@@ -1392,7 +1392,7 @@ static int cli_scanhtml(cli_ctx *ctx)
1392 1392
         close(fd);
1393 1393
     }
1394 1394
 
1395
-    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
1395
+    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES))
1396 1396
     {
1397 1397
         /* CL_ENGINE_MAX_HTMLNOTAGS */
1398 1398
         curr_len = map->len;
... ...
@@ -1415,7 +1415,7 @@ static int cli_scanhtml(cli_ctx *ctx)
1415 1415
         }
1416 1416
     }
1417 1417
 
1418
-    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
1418
+    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES))
1419 1419
     {
1420 1420
         snprintf(fullname, 1024, "%s" PATHSEP "javascript", tempname);
1421 1421
         fd = open(fullname, O_RDONLY | O_BINARY);
... ...
@@ -1423,7 +1423,7 @@ static int cli_scanhtml(cli_ctx *ctx)
1423 1423
         {
1424 1424
             if ((ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1425 1425
                 viruses_found++;
1426
-            if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
1426
+            if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES))
1427 1427
             {
1428 1428
                 if ((ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL)) == CL_VIRUS)
1429 1429
                     viruses_found++;
... ...
@@ -1432,7 +1432,7 @@ static int cli_scanhtml(cli_ctx *ctx)
1432 1432
         }
1433 1433
     }
1434 1434
 
1435
-    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALL))
1435
+    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES))
1436 1436
     {
1437 1437
         snprintf(fullname, 1024, "%s" PATHSEP "rfc2397", tempname);
1438 1438
         ret = cli_scandir(fullname, ctx);
... ...
@@ -1442,7 +1442,7 @@ static int cli_scanhtml(cli_ctx *ctx)
1442 1442
         cli_rmdirs(tempname);
1443 1443
 
1444 1444
     free(tempname);
1445
-    if (SCAN_ALL && viruses_found)
1445
+    if (SCAN_ALLMATCHES && viruses_found)
1446 1446
         return CL_VIRUS;
1447 1447
     return ret;
1448 1448
 }
... ...
@@ -1590,7 +1590,7 @@ static int cli_scanscript(cli_ctx *ctx)
1590 1590
                 /* when we flush the buffer also scan */
1591 1591
                 if (cli_scanbuff(state.out, state.out_pos, offset, ctx, CL_TYPE_TEXT_ASCII, mdata) == CL_VIRUS)
1592 1592
                 {
1593
-                    if (SCAN_ALL)
1593
+                    if (SCAN_ALLMATCHES)
1594 1594
                         viruses_found++;
1595 1595
                     else
1596 1596
                     {
... ...
@@ -1616,11 +1616,11 @@ static int cli_scanscript(cli_ctx *ctx)
1616 1616
         }
1617 1617
     }
1618 1618
 
1619
-    if (ret != CL_VIRUS || SCAN_ALL)
1619
+    if (ret != CL_VIRUS || SCAN_ALLMATCHES)
1620 1620
     {
1621 1621
         if ((ret = cli_exp_eval(ctx, troot, &tmdata, NULL, NULL)) == CL_VIRUS)
1622 1622
             viruses_found++;
1623
-        if (ret != CL_VIRUS || SCAN_ALL)
1623
+        if (ret != CL_VIRUS || SCAN_ALLMATCHES)
1624 1624
             if ((ret = cli_exp_eval(ctx, groot, &gmdata, NULL, NULL)) == CL_VIRUS)
1625 1625
                 viruses_found++;
1626 1626
     }
... ...
@@ -2009,7 +2009,7 @@ static int cli_scanmail(cli_ctx *ctx)
2009 2009
      */
2010 2010
     if ((ret = cli_mbox(dir, ctx)))
2011 2011
     {
2012
-        if (ret == CL_VIRUS && SCAN_ALL)
2012
+        if (ret == CL_VIRUS && SCAN_ALLMATCHES)
2013 2013
             viruses_found++;
2014 2014
         else
2015 2015
         {
... ...
@@ -2054,24 +2054,23 @@ static int cli_scan_structured(cli_ctx *ctx)
2054 2054
     else
2055 2055
         ccfunc = dlp_get_cc_count;
2056 2056
 
2057
-    switch ((ctx->options & CL_SCAN_STRUCTURED_SSN_NORMAL) | (ctx->options & CL_SCAN_STRUCTURED_SSN_STRIPPED))
2057
+    switch (SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL | SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED)
2058 2058
     {
2059
-
2060
-    case (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED):
2059
+    case (CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL | CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED):
2061 2060
         if (ctx->engine->min_ssn_count == 1)
2062 2061
             ssnfunc = dlp_has_ssn;
2063 2062
         else
2064 2063
             ssnfunc = dlp_get_ssn_count;
2065 2064
         break;
2066 2065
 
2067
-    case CL_SCAN_STRUCTURED_SSN_NORMAL:
2066
+    case CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL:
2068 2067
         if (ctx->engine->min_ssn_count == 1)
2069 2068
             ssnfunc = dlp_has_normal_ssn;
2070 2069
         else
2071 2070
             ssnfunc = dlp_get_normal_ssn_count;
2072 2071
         break;
2073 2072
 
2074
-    case CL_SCAN_STRUCTURED_SSN_STRIPPED:
2073
+    case CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED:
2075 2074
         if (ctx->engine->min_ssn_count == 1)
2076 2075
             ssnfunc = dlp_has_stripped_ssn;
2077 2076
         else
... ...
@@ -2101,7 +2100,7 @@ static int cli_scan_structured(cli_ctx *ctx)
2101 2101
         cli_dbgmsg("cli_scan_structured: %u credit card numbers detected\n", cc_count);
2102 2102
         if (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Structured.CreditCardNumber"))
2103 2103
         {
2104
-            if (SCAN_ALL)
2104
+            if (SCAN_ALLMATCHES)
2105 2105
             {
2106 2106
                 viruses_found++;
2107 2107
             }
... ...
@@ -2117,7 +2116,7 @@ static int cli_scan_structured(cli_ctx *ctx)
2117 2117
         cli_dbgmsg("cli_scan_structured: %u social security numbers detected\n", ssn_count);
2118 2118
         if (CL_VIRUS == cli_append_virus(ctx, "Heuristics.Structured.SSN"))
2119 2119
         {
2120
-            if (SCAN_ALL)
2120
+            if (SCAN_ALLMATCHES)
2121 2121
             {
2122 2122
                 viruses_found++;
2123 2123
             }
... ...
@@ -2297,7 +2296,7 @@ static inline void perf_init(cli_ctx *ctx)
2297 2297
     uint64_t kt, ut;
2298 2298
     unsigned i;
2299 2299
 
2300
-    if (!(ctx->options & CL_SCAN_PERFORMANCE_INFO))
2300
+    if (!SCAN_DEV_COLLECT_PERF_INFO)
2301 2301
         return;
2302 2302
 
2303 2303
     ctx->perf = cli_events_new(PERFT_LAST);
... ...
@@ -2439,7 +2438,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2439 2439
                 switch (fpt->type)
2440 2440
                 {
2441 2441
                 case CL_TYPE_MHTML:
2442
-                    if (SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
2442
+                    if (SCAN_PARSE_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
2443 2443
                     {
2444 2444
                         cli_dbgmsg("MHTML signature found at %u\n", (unsigned int)fpt->offset);
2445 2445
                         nret = ret = cli_scanmail(ctx);
... ...
@@ -2447,35 +2446,35 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2447 2447
                     break;
2448 2448
 
2449 2449
                 case CL_TYPE_XDP:
2450
-                    if (SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
2450
+                    if (SCAN_PARSE_PDF && (DCONF_DOC & DOC_CONF_PDF))
2451 2451
                     {
2452 2452
                         cli_dbgmsg("XDP signature found at %u\n", (unsigned int)fpt->offset);
2453 2453
                         nret = ret = cli_scanxdp(ctx);
2454 2454
                     }
2455 2455
                     break;
2456 2456
                 case CL_TYPE_XML_WORD:
2457
-                    if (SCAN_XMLDOCS && (DCONF_DOC & DOC_CONF_MSXML))
2457
+                    if (SCAN_PARSE_XMLDOCS && (DCONF_DOC & DOC_CONF_MSXML))
2458 2458
                     {
2459 2459
                         cli_dbgmsg("XML-WORD signature found at %u\n", (unsigned int)fpt->offset);
2460 2460
                         nret = ret = cli_scanmsxml(ctx);
2461 2461
                     }
2462 2462
                     break;
2463 2463
                 case CL_TYPE_XML_XL:
2464
-                    if (SCAN_XMLDOCS && (DCONF_DOC & DOC_CONF_MSXML))
2464
+                    if (SCAN_PARSE_XMLDOCS && (DCONF_DOC & DOC_CONF_MSXML))
2465 2465
                     {
2466 2466
                         cli_dbgmsg("XML-XL signature found at %u\n", (unsigned int)fpt->offset);
2467 2467
                         nret = ret = cli_scanmsxml(ctx);
2468 2468
                     }
2469 2469
                     break;
2470 2470
                 case CL_TYPE_XML_HWP:
2471
-                    if (SCAN_XMLDOCS && (DCONF_DOC & DOC_CONF_HWP))
2471
+                    if (SCAN_PARSE_XMLDOCS && (DCONF_DOC & DOC_CONF_HWP))
2472 2472
                     {
2473 2473
                         cli_dbgmsg("XML-HWP signature found at %u\n", (unsigned int)fpt->offset);
2474 2474
                         nret = ret = cli_scanhwpml(ctx);
2475 2475
                     }
2476 2476
                     break;
2477 2477
                 case CL_TYPE_RARSFX:
2478
-                    if (type != CL_TYPE_RAR && have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
2478
+                    if (type != CL_TYPE_RAR && have_rar && SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
2479 2479
                     {
2480 2480
                         char *tmpname = NULL;
2481 2481
                         int tmpfd = fmap_fd(map);
... ...
@@ -2514,7 +2513,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2514 2514
                     break;
2515 2515
 
2516 2516
                 case CL_TYPE_ZIPSFX:
2517
-                    if (type != CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
2517
+                    if (type != CL_TYPE_ZIP && SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
2518 2518
                     {
2519 2519
                         size_t csize = map->len - fpt->offset; /* not precise */
2520 2520
                         cli_set_container(ctx, CL_TYPE_ZIP, csize);
... ...
@@ -2524,7 +2523,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2524 2524
                     break;
2525 2525
 
2526 2526
                 case CL_TYPE_CABSFX:
2527
-                    if (type != CL_TYPE_MSCAB && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
2527
+                    if (type != CL_TYPE_MSCAB && SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
2528 2528
                     {
2529 2529
                         size_t csize = map->len - fpt->offset; /* not precise */
2530 2530
                         cli_set_container(ctx, CL_TYPE_MSCAB, csize);
... ...
@@ -2534,7 +2533,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2534 2534
                     break;
2535 2535
 
2536 2536
                 case CL_TYPE_ARJSFX:
2537
-                    if (type != CL_TYPE_ARJ && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
2537
+                    if (type != CL_TYPE_ARJ && SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
2538 2538
                     {
2539 2539
                         size_t csize = map->len - fpt->offset; /* not precise */
2540 2540
                         cli_set_container(ctx, CL_TYPE_ARJ, csize);
... ...
@@ -2544,7 +2543,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2544 2544
                     break;
2545 2545
 
2546 2546
                 case CL_TYPE_7ZSFX:
2547
-                    if (type != CL_TYPE_7Z && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
2547
+                    if (type != CL_TYPE_7Z && SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
2548 2548
                     {
2549 2549
                         size_t csize = map->len - fpt->offset; /* not precise */
2550 2550
                         cli_set_container(ctx, CL_TYPE_7Z, csize);
... ...
@@ -2554,7 +2553,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2554 2554
                     break;
2555 2555
 
2556 2556
                 case CL_TYPE_ISO9660:
2557
-                    if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ISO9660))
2557
+                    if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ISO9660))
2558 2558
                     {
2559 2559
                         size_t csize = map->len - fpt->offset; /* not precise */
2560 2560
                         cli_set_container(ctx, CL_TYPE_ISO9660, csize);
... ...
@@ -2564,7 +2563,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2564 2564
                     break;
2565 2565
 
2566 2566
                 case CL_TYPE_NULSFT:
2567
-                    if (SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) &&
2567
+                    if (SCAN_PARSE_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) &&
2568 2568
                         fpt->offset > 4)
2569 2569
                     {
2570 2570
                         size_t csize = map->len - fpt->offset; /* not precise */
... ...
@@ -2575,7 +2574,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2575 2575
                     break;
2576 2576
 
2577 2577
                 case CL_TYPE_AUTOIT:
2578
-                    if (SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
2578
+                    if (SCAN_PARSE_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
2579 2579
                     {
2580 2580
                         size_t csize = map->len - fpt->offset; /* not precise */
2581 2581
                         cli_set_container(ctx, CL_TYPE_AUTOIT, csize);
... ...
@@ -2585,7 +2584,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2585 2585
                     break;
2586 2586
 
2587 2587
                 case CL_TYPE_ISHIELD_MSI:
2588
-                    if (SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ISHIELD))
2588
+                    if (SCAN_PARSE_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ISHIELD))
2589 2589
                     {
2590 2590
                         size_t csize = map->len - fpt->offset; /* not precise */
2591 2591
                         cli_set_container(ctx, CL_TYPE_AUTOIT, csize);
... ...
@@ -2595,7 +2594,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2595 2595
                     break;
2596 2596
 
2597 2597
                 case CL_TYPE_DMG:
2598
-                    if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_DMG))
2598
+                    if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_DMG))
2599 2599
                     {
2600 2600
                         cli_dbgmsg("DMG signature found at %u\n", (unsigned int)fpt->offset);
2601 2601
                         nret = cli_scandmg(ctx);
... ...
@@ -2603,7 +2602,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2603 2603
                     break;
2604 2604
 
2605 2605
                 case CL_TYPE_MBR:
2606
-                    if (SCAN_ARCHIVE)
2606
+                    if (SCAN_PARSE_ARCHIVE)
2607 2607
                     {
2608 2608
                         int iret = cli_mbr_check2(ctx, 0);
2609 2609
                         if ((iret == CL_TYPE_GPT) && (DCONF_ARCH & ARCH_CONF_GPT))
... ...
@@ -2622,7 +2621,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2622 2622
                     break;
2623 2623
 
2624 2624
                 case CL_TYPE_PDF:
2625
-                    if (type != CL_TYPE_PDF && SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
2625
+                    if (type != CL_TYPE_PDF && SCAN_PARSE_PDF && (DCONF_DOC & DOC_CONF_PDF))
2626 2626
                     {
2627 2627
                         size_t csize = map->len - fpt->offset; /* not precise */
2628 2628
                         cli_set_container(ctx, CL_TYPE_PDF, csize);
... ...
@@ -2632,7 +2631,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2632 2632
                     break;
2633 2633
 
2634 2634
                 case CL_TYPE_MSEXE:
2635
-                    if (SCAN_PE && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP || type == CL_TYPE_MSOLE2) && ctx->dconf->pe)
2635
+                    if (SCAN_PARSE_PE && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP || type == CL_TYPE_MSOLE2) && ctx->dconf->pe)
2636 2636
                     {
2637 2637
                         uint64_t curr_len = map->len;
2638 2638
                         size_t csize = map->len - fpt->offset; /* not precise */
... ...
@@ -2682,7 +2681,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2682 2682
                 {
2683 2683
                     ret = CL_TYPE_TEXT_ASCII;
2684 2684
                 }
2685
-                else if (SCAN_HTML && (type == CL_TYPE_TEXT_ASCII || type == CL_TYPE_GRAPHICS) &&
2685
+                else if (SCAN_PARSE_HTML && (type == CL_TYPE_TEXT_ASCII || type == CL_TYPE_GRAPHICS) &&
2686 2686
                          (DCONF_DOC & DOC_CONF_HTML))
2687 2687
                 {
2688 2688
                     *dettype = CL_TYPE_HTML;
... ...
@@ -2692,7 +2691,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2692 2692
 
2693 2693
             case CL_TYPE_MAIL:
2694 2694
                 cli_set_container(ctx, CL_TYPE_MAIL, map->len);
2695
-                if (SCAN_MAIL && type == CL_TYPE_TEXT_ASCII && (DCONF_MAIL & MAIL_CONF_MBOX))
2695
+                if (SCAN_PARSE_MAIL && type == CL_TYPE_TEXT_ASCII && (DCONF_MAIL & MAIL_CONF_MBOX))
2696 2696
                 {
2697 2697
                     *dettype = CL_TYPE_MAIL;
2698 2698
                     nret = cli_scanmail(ctx);
... ...
@@ -2799,11 +2798,11 @@ static int magic_scandesc_cleanup(cli_ctx *ctx, cli_file_t type, unsigned char *
2799 2799
     if (cb_retcode == CL_CLEAN && cache_clean)
2800 2800
     {
2801 2801
         perf_start(ctx, PERFT_CACHE);
2802
-        if (!(SCAN_PROPERTIES))
2802
+        if (!(SCAN_COLLECT_METADATA))
2803 2803
             cache_add(hash, hashed_size, ctx);
2804 2804
         perf_stop(ctx, PERFT_CACHE);
2805 2805
     }
2806
-    if (retcode == CL_VIRUS && SCAN_ALL)
2806
+    if (retcode == CL_VIRUS && SCAN_ALLMATCHES)
2807 2807
         return CL_CLEAN;
2808 2808
     return retcode;
2809 2809
 }
... ...
@@ -2912,7 +2911,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2912 2912
     filetype = cli_ftname(type);
2913 2913
 
2914 2914
 #if HAVE_JSON
2915
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES)
2915
+    if (SCAN_COLLECT_METADATA)
2916 2916
     {
2917 2917
         json_object *arrobj;
2918 2918
 
... ...
@@ -2953,7 +2952,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2953 2953
             }
2954 2954
             else
2955 2955
             { /* turn off property collection flag for file types we don't care about */
2956
-                ctx->options &= ~CL_SCAN_FILE_PROPERTIES;
2956
+                ctx->options->general &= ~CL_SCAN_GENERAL_COLLECT_METADATA;
2957 2957
             }
2958 2958
         }
2959 2959
         else
... ...
@@ -2979,7 +2978,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
2979 2979
         }
2980 2980
     }
2981 2981
 
2982
-    if (ctx->options & CL_SCAN_FILE_PROPERTIES)
2982
+    if (SCAN_COLLECT_METADATA)
2983 2983
     { /* separated for cases json is not tracked */
2984 2984
         ret = cli_jsonstr(ctx->wrkproperty, "FileType", filetype);
2985 2985
         if (ret != CL_SUCCESS)
... ...
@@ -3005,13 +3004,13 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3005 3005
     }
3006 3006
 
3007 3007
     perf_start(ctx, PERFT_CACHE);
3008
-    if (!(SCAN_PROPERTIES))
3008
+    if (!(SCAN_COLLECT_METADATA))
3009 3009
         res = cache_check(hash, ctx);
3010 3010
     else
3011 3011
         res = CL_VIRUS;
3012 3012
 
3013 3013
 #if HAVE_JSON
3014
-    if (SCAN_PROPERTIES /* ctx.options & CL_SCAN_FILE_PROPERTIES && ctx->wrkproperty != NULL */)
3014
+    if (SCAN_COLLECT_METADATA /* ctx.options->general & CL_SCAN_GENERAL_COLLECT_METADATA && ctx->wrkproperty != NULL */)
3015 3015
     {
3016 3016
         char hashstr[33];
3017 3017
         ret = cache_get_MD5(hash, ctx);
... ...
@@ -3047,7 +3046,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3047 3047
     memcpy((*ctx->fmap)->maphash, hash, 16);
3048 3048
     ctx->hook_lsig_matches = NULL;
3049 3049
 
3050
-    if (!(ctx->options & ~CL_SCAN_ALLMATCHES) || (ctx->recursion == ctx->engine->maxreclevel))
3050
+    if (!((ctx->options->general & ~CL_SCAN_GENERAL_ALLMATCHES) || (ctx->options->parse) || (ctx->options->heuristic) || (ctx->options->mail) || (ctx->options->dev)) || (ctx->recursion == ctx->engine->maxreclevel))
3051 3051
     { /* raw mode (stdin, etc.) or last level of recursion */
3052 3052
         if (ctx->recursion == ctx->engine->maxreclevel)
3053 3053
         {
... ...
@@ -3123,37 +3122,37 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3123 3123
         break;
3124 3124
 
3125 3125
     case CL_TYPE_HWP3:
3126
-        if (SCAN_HWP3 && (DCONF_DOC & DOC_CONF_HWP))
3126
+        if (SCAN_PARSE_HWP3 && (DCONF_DOC & DOC_CONF_HWP))
3127 3127
             ret = cli_scanhwp3(ctx);
3128 3128
         break;
3129 3129
 
3130 3130
     case CL_TYPE_HWPOLE2:
3131
-        if (SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
3131
+        if (SCAN_PARSE_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
3132 3132
             ret = cli_scanhwpole2(ctx);
3133 3133
         break;
3134 3134
 
3135 3135
     case CL_TYPE_XML_WORD:
3136
-        if (SCAN_XMLDOCS && (DCONF_DOC & DOC_CONF_MSXML))
3136
+        if (SCAN_PARSE_XMLDOCS && (DCONF_DOC & DOC_CONF_MSXML))
3137 3137
             ret = cli_scanmsxml(ctx);
3138 3138
         break;
3139 3139
 
3140 3140
     case CL_TYPE_XML_XL:
3141
-        if (SCAN_XMLDOCS && (DCONF_DOC & DOC_CONF_MSXML))
3141
+        if (SCAN_PARSE_XMLDOCS && (DCONF_DOC & DOC_CONF_MSXML))
3142 3142
             ret = cli_scanmsxml(ctx);
3143 3143
         break;
3144 3144
 
3145 3145
     case CL_TYPE_XML_HWP:
3146
-        if (SCAN_XMLDOCS && (DCONF_DOC & DOC_CONF_HWP))
3146
+        if (SCAN_PARSE_XMLDOCS && (DCONF_DOC & DOC_CONF_HWP))
3147 3147
             ret = cli_scanhwpml(ctx);
3148 3148
         break;
3149 3149
 
3150 3150
     case CL_TYPE_XDP:
3151
-        if (SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
3151
+        if (SCAN_PARSE_PDF && (DCONF_DOC & DOC_CONF_PDF))
3152 3152
             ret = cli_scanxdp(ctx);
3153 3153
         break;
3154 3154
 
3155 3155
     case CL_TYPE_RAR:
3156
-        if (have_rar && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
3156
+        if (have_rar && SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
3157 3157
         {
3158 3158
             char *tmpname = NULL;
3159 3159
             int desc = fmap_fd(*ctx->fmap);
... ...
@@ -3182,9 +3181,9 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3182 3182
     case CL_TYPE_OOXML_XL:
3183 3183
     case CL_TYPE_OOXML_HWP:
3184 3184
 #if HAVE_JSON
3185
-        if (SCAN_XMLDOCS && (DCONF_DOC & DOC_CONF_OOXML))
3185
+        if (SCAN_PARSE_XMLDOCS && (DCONF_DOC & DOC_CONF_OOXML))
3186 3186
         {
3187
-            if ((ctx->options & CL_SCAN_FILE_PROPERTIES) && (ctx->wrkproperty != NULL))
3187
+            if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL))
3188 3188
             {
3189 3189
                 ret = cli_process_ooxml(ctx, type);
3190 3190
 
... ...
@@ -3207,67 +3206,67 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3207 3207
         }
3208 3208
 #endif
3209 3209
     case CL_TYPE_ZIP:
3210
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
3210
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
3211 3211
             ret = cli_unzip(ctx);
3212 3212
         break;
3213 3213
 
3214 3214
     case CL_TYPE_GZ:
3215
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
3215
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
3216 3216
             ret = cli_scangzip(ctx);
3217 3217
         break;
3218 3218
 
3219 3219
     case CL_TYPE_BZ:
3220
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
3220
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
3221 3221
             ret = cli_scanbzip(ctx);
3222 3222
         break;
3223 3223
 
3224 3224
     case CL_TYPE_XZ:
3225
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XZ))
3225
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XZ))
3226 3226
             ret = cli_scanxz(ctx);
3227 3227
         break;
3228 3228
 
3229 3229
     case CL_TYPE_GPT:
3230
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GPT))
3230
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GPT))
3231 3231
             ret = cli_scangpt(ctx, 0);
3232 3232
         break;
3233 3233
 
3234 3234
     case CL_TYPE_APM:
3235
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_APM))
3235
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_APM))
3236 3236
             ret = cli_scanapm(ctx);
3237 3237
         break;
3238 3238
 
3239 3239
     case CL_TYPE_ARJ:
3240
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
3240
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
3241 3241
             ret = cli_scanarj(ctx, 0, NULL);
3242 3242
         break;
3243 3243
 
3244 3244
     case CL_TYPE_NULSFT:
3245
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_NSIS))
3245
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_NSIS))
3246 3246
             ret = cli_scannulsft(ctx, 0);
3247 3247
         break;
3248 3248
 
3249 3249
     case CL_TYPE_AUTOIT:
3250
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
3250
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
3251 3251
             ret = cli_scanautoit(ctx, 23);
3252 3252
         break;
3253 3253
 
3254 3254
     case CL_TYPE_MSSZDD:
3255
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))
3255
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))
3256 3256
             ret = cli_scanszdd(ctx);
3257 3257
         break;
3258 3258
 
3259 3259
     case CL_TYPE_MSCAB:
3260
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
3260
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
3261 3261
             ret = cli_scanmscab(ctx, 0);
3262 3262
         break;
3263 3263
 
3264 3264
     case CL_TYPE_HTML:
3265
-        if (SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
3265
+        if (SCAN_PARSE_HTML && (DCONF_DOC & DOC_CONF_HTML))
3266 3266
             ret = cli_scanhtml(ctx);
3267 3267
         break;
3268 3268
 
3269 3269
     case CL_TYPE_HTML_UTF16:
3270
-        if (SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
3270
+        if (SCAN_PARSE_HTML && (DCONF_DOC & DOC_CONF_HTML))
3271 3271
             ret = cli_scanhtml_utf16(ctx);
3272 3272
         break;
3273 3273
 
... ...
@@ -3277,27 +3276,27 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3277 3277
         break;
3278 3278
 
3279 3279
     case CL_TYPE_SWF:
3280
-        if (SCAN_SWF && (DCONF_DOC & DOC_CONF_SWF))
3280
+        if (SCAN_PARSE_SWF && (DCONF_DOC & DOC_CONF_SWF))
3281 3281
             ret = cli_scanswf(ctx);
3282 3282
         break;
3283 3283
 
3284 3284
     case CL_TYPE_RTF:
3285
-        if (SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
3285
+        if (SCAN_PARSE_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
3286 3286
             ret = cli_scanrtf(ctx);
3287 3287
         break;
3288 3288
 
3289 3289
     case CL_TYPE_MAIL:
3290
-        if (SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
3290
+        if (SCAN_PARSE_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
3291 3291
             ret = cli_scanmail(ctx);
3292 3292
         break;
3293 3293
 
3294 3294
     case CL_TYPE_MHTML:
3295
-        if (SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
3295
+        if (SCAN_PARSE_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
3296 3296
             ret = cli_scanmail(ctx);
3297 3297
         break;
3298 3298
 
3299 3299
     case CL_TYPE_TNEF:
3300
-        if (SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_TNEF))
3300
+        if (SCAN_PARSE_MAIL && (DCONF_MAIL & MAIL_CONF_TNEF))
3301 3301
             ret = cli_scantnef(ctx);
3302 3302
         break;
3303 3303
 
... ...
@@ -3307,52 +3306,52 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3307 3307
         break;
3308 3308
 
3309 3309
     case CL_TYPE_MSCHM:
3310
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
3310
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
3311 3311
             ret = cli_scanmschm(ctx);
3312 3312
         break;
3313 3313
 
3314 3314
     case CL_TYPE_MSOLE2:
3315
-        if (SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
3315
+        if (SCAN_PARSE_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
3316 3316
             ret = cli_scanole2(ctx);
3317 3317
         break;
3318 3318
 
3319 3319
     case CL_TYPE_7Z:
3320
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
3320
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_7Z))
3321 3321
             ret = cli_7unz(ctx, 0);
3322 3322
         break;
3323 3323
 
3324 3324
     case CL_TYPE_POSIX_TAR:
3325
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
3325
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
3326 3326
             ret = cli_scantar(ctx, 1);
3327 3327
         break;
3328 3328
 
3329 3329
     case CL_TYPE_OLD_TAR:
3330
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
3330
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
3331 3331
             ret = cli_scantar(ctx, 0);
3332 3332
         break;
3333 3333
 
3334 3334
     case CL_TYPE_CPIO_OLD:
3335
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3335
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3336 3336
             ret = cli_scancpio_old(ctx);
3337 3337
         break;
3338 3338
 
3339 3339
     case CL_TYPE_CPIO_ODC:
3340
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3340
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3341 3341
             ret = cli_scancpio_odc(ctx);
3342 3342
         break;
3343 3343
 
3344 3344
     case CL_TYPE_CPIO_NEWC:
3345
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3345
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3346 3346
             ret = cli_scancpio_newc(ctx, 0);
3347 3347
         break;
3348 3348
 
3349 3349
     case CL_TYPE_CPIO_CRC:
3350
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3350
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CPIO))
3351 3351
             ret = cli_scancpio_newc(ctx, 1);
3352 3352
         break;
3353 3353
 
3354 3354
     case CL_TYPE_BINHEX:
3355
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
3355
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
3356 3356
             ret = cli_binhex(ctx);
3357 3357
         break;
3358 3358
 
... ...
@@ -3362,30 +3361,30 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3362 3362
         break;
3363 3363
 
3364 3364
     case CL_TYPE_RIFF:
3365
-        if (SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_RIFF))
3365
+        if (SCAN_HEURISTICS && (DCONF_OTHER & OTHER_CONF_RIFF))
3366 3366
             ret = cli_scanriff(ctx);
3367 3367
         break;
3368 3368
 
3369 3369
     case CL_TYPE_GRAPHICS:
3370
-        if (SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_JPEG))
3370
+        if (SCAN_HEURISTICS && (DCONF_OTHER & OTHER_CONF_JPEG))
3371 3371
             ret = cli_scanjpeg(ctx);
3372 3372
 
3373
-        if (ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS)
3373
+        if (ctx->img_validate && SCAN_HEURISTICS && ret != CL_VIRUS)
3374 3374
             ret = cli_parsejpeg(ctx);
3375 3375
 
3376
-        if (ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
3376
+        if (ctx->img_validate && SCAN_HEURISTICS && ret != CL_VIRUS && ret != CL_EPARSE)
3377 3377
             ret = cli_parsepng(ctx);
3378 3378
 
3379
-        if (ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
3379
+        if (ctx->img_validate && SCAN_HEURISTICS && ret != CL_VIRUS && ret != CL_EPARSE)
3380 3380
             ret = cli_parsegif(ctx);
3381 3381
 
3382
-        if (ctx->img_validate && SCAN_ALGO && ret != CL_VIRUS && ret != CL_EPARSE)
3382
+        if (ctx->img_validate && SCAN_HEURISTICS && ret != CL_VIRUS && ret != CL_EPARSE)
3383 3383
             ret = cli_parsetiff(ctx);
3384 3384
 
3385 3385
         break;
3386 3386
 
3387 3387
     case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
3388
-        if (SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
3388
+        if (SCAN_PARSE_PDF && (DCONF_DOC & DOC_CONF_PDF))
3389 3389
             ret = cli_scanpdf(ctx, 0);
3390 3390
         break;
3391 3391
 
... ...
@@ -3395,7 +3394,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3395 3395
         break;
3396 3396
 
3397 3397
     case CL_TYPE_ELF:
3398
-        if (SCAN_ELF && ctx->dconf->elf)
3398
+        if (SCAN_PARSE_ELF && ctx->dconf->elf)
3399 3399
             ret = cli_scanelf(ctx);
3400 3400
         break;
3401 3401
 
... ...
@@ -3410,28 +3409,28 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3410 3410
         break;
3411 3411
 
3412 3412
     case CL_TYPE_SIS:
3413
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
3413
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
3414 3414
             ret = cli_scansis(ctx);
3415 3415
         break;
3416 3416
 
3417 3417
     case CL_TYPE_XAR:
3418
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XAR))
3418
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_XAR))
3419 3419
             ret = cli_scanxar(ctx);
3420 3420
         break;
3421 3421
 
3422 3422
     case CL_TYPE_PART_HFSPLUS:
3423
-        if (SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_HFSPLUS))
3423
+        if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_HFSPLUS))
3424 3424
             ret = cli_scanhfsplus(ctx);
3425 3425
         break;
3426 3426
 
3427 3427
     case CL_TYPE_BINARY_DATA:
3428 3428
     case CL_TYPE_TEXT_UTF16BE:
3429
-        if (SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_MYDOOMLOG))
3429
+        if (SCAN_HEURISTICS && (DCONF_OTHER & OTHER_CONF_MYDOOMLOG))
3430 3430
             ret = cli_check_mydoom_log(ctx);
3431 3431
         break;
3432 3432
 
3433 3433
     case CL_TYPE_TEXT_ASCII:
3434
-        if (SCAN_STRUCTURED && (DCONF_OTHER & OTHER_CONF_DLP))
3434
+        if (SCAN_HEURISTIC_STRUCTURED && (DCONF_OTHER & OTHER_CONF_DLP))
3435 3435
             /* TODO: consider calling this from cli_scanscript() for
3436 3436
          * a normalised text
3437 3437
          */
... ...
@@ -3445,14 +3444,14 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3445 3445
     perf_nested_stop(ctx, PERFT_CONTAINER, PERFT_SCAN);
3446 3446
     ctx->recursion--;
3447 3447
 
3448
-    if (ret == CL_VIRUS && !SCAN_ALL)
3448
+    if (ret == CL_VIRUS && !SCAN_ALLMATCHES)
3449 3449
     {
3450 3450
         cli_bitset_free(ctx->hook_lsig_matches);
3451 3451
         ctx->hook_lsig_matches = old_hook_lsig_matches;
3452 3452
         return magic_scandesc_cleanup(ctx, type, hash, hashed_size, cache_clean, ret, parent_property);
3453 3453
     }
3454 3454
 
3455
-    if (type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
3455
+    if (type == CL_TYPE_ZIP && SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
3456 3456
     {
3457 3457
         /* CL_ENGINE_MAX_ZIPTYPERCG */
3458 3458
         uint64_t curr_len = (*ctx->fmap)->len;
... ...
@@ -3464,7 +3463,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3464 3464
     }
3465 3465
 
3466 3466
     /* CL_TYPE_HTML: raw HTML files are not scanned, unless safety measure activated via DCONF */
3467
-    if (type != CL_TYPE_IGNORED && (type != CL_TYPE_HTML || !(SCAN_HTML) || !(DCONF_DOC & DOC_CONF_HTML_SKIPRAW)) && !ctx->engine->sdb)
3467
+    if (type != CL_TYPE_IGNORED && (type != CL_TYPE_HTML || !(SCAN_PARSE_HTML) || !(DCONF_DOC & DOC_CONF_HTML_SKIPRAW)) && !ctx->engine->sdb)
3468 3468
     {
3469 3469
         res = cli_scanraw(ctx, type, typercg, &dettype, (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) ? NULL : hash);
3470 3470
         if (res != CL_CLEAN)
... ...
@@ -3488,7 +3487,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3488 3488
             /* CL_VIRUS = malware found, check FP and report */
3489 3489
             case CL_VIRUS:
3490 3490
                 ret = res;
3491
-                if (SCAN_ALL)
3491
+                if (SCAN_ALLMATCHES)
3492 3492
                     break;
3493 3493
                 cli_bitset_free(ctx->hook_lsig_matches);
3494 3494
                 ctx->hook_lsig_matches = old_hook_lsig_matches;
... ...
@@ -3523,9 +3522,9 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3523 3523
     case CL_TYPE_TEXT_UTF16LE:
3524 3524
     case CL_TYPE_TEXT_UTF8:
3525 3525
         perf_nested_start(ctx, PERFT_SCRIPT, PERFT_SCAN);
3526
-        if ((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML && (ret != CL_VIRUS || SCAN_ALL) && SCAN_HTML)
3526
+        if ((DCONF_DOC & DOC_CONF_SCRIPT) && dettype != CL_TYPE_HTML && (ret != CL_VIRUS || SCAN_ALLMATCHES) && SCAN_PARSE_HTML)
3527 3527
             ret = cli_scanscript(ctx);
3528
-        if (SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (cli_get_container(ctx, -1) == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL))
3528
+        if (SCAN_PARSE_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX) && ret != CL_VIRUS && (cli_get_container(ctx, -1) == CL_TYPE_MAIL || dettype == CL_TYPE_MAIL))
3529 3529
         {
3530 3530
             ret = cli_fmap_scandesc(ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL, NULL);
3531 3531
         }
... ...
@@ -3536,7 +3535,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3536 3536
      */
3537 3537
     case CL_TYPE_MSEXE:
3538 3538
         perf_nested_start(ctx, PERFT_PE, PERFT_SCAN);
3539
-        if (SCAN_PE && ctx->dconf->pe)
3539
+        if (SCAN_PARSE_PE && ctx->dconf->pe)
3540 3540
         {
3541 3541
             unsigned int corrupted_input = ctx->corrupted_input;
3542 3542
             ret = cli_scanpe(ctx);
... ...
@@ -3636,7 +3635,7 @@ int cli_magic_scandesc_type(cli_ctx *ctx, cli_file_t type)
3636 3636
     return magic_scandesc(ctx, type);
3637 3637
 }
3638 3638
 
3639
-int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
3639
+int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options* scanoptions)
3640 3640
 {
3641 3641
     return cl_scandesc_callback(desc, virname, scanned, engine, scanoptions, NULL);
3642 3642
 }
... ...
@@ -3803,7 +3802,7 @@ int cli_mem_scandesc(const void *buffer, size_t length, cli_ctx *ctx)
3803 3803
     return ret;
3804 3804
 }
3805 3805
 
3806
-static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
3806
+static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *scanoptions, void *context)
3807 3807
 {
3808 3808
     cli_ctx ctx;
3809 3809
     int rc;
... ...
@@ -3828,7 +3827,8 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
3828 3828
     ctx.engine = engine;
3829 3829
     ctx.virname = virname;
3830 3830
     ctx.scanned = scanned;
3831
-    ctx.options = scanoptions;
3831
+    ctx.options = malloc(sizeof(struct cl_scan_options));
3832
+    memcpy(ctx.options, scanoptions, sizeof(struct cl_scan_options));
3832 3833
     ctx.found_possibly_unwanted = 0;
3833 3834
     ctx.containers = cli_calloc(sizeof(cli_ctx_container), ctx.engine->maxreclevel + 2);
3834 3835
     if (!ctx.containers)
... ...
@@ -3846,7 +3846,7 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
3846 3846
     }
3847 3847
     perf_init(&ctx);
3848 3848
 
3849
-    if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.engine->time_limit != 0)
3849
+    if (ctx.options->general & CL_SCAN_GENERAL_COLLECT_METADATA && ctx.engine->time_limit != 0)
3850 3850
     {
3851 3851
         if (gettimeofday(&ctx.time_limit, NULL) == 0)
3852 3852
         {
... ...
@@ -3868,7 +3868,7 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
3868 3868
     }
3869 3869
 
3870 3870
 #ifdef HAVE__INTERNAL__SHA_COLLECT
3871
-    if (scanoptions & CL_SCAN_INTERNAL_COLLECT_SHA)
3871
+    if (ctx.options->dev & CL_SCAN_DEV_COLLECT_SHA)
3872 3872
     {
3873 3873
         char link[32];
3874 3874
         ssize_t linksz;
... ...
@@ -3891,7 +3891,7 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
3891 3891
     rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY) : cli_magic_scandesc(desc, &ctx);
3892 3892
 
3893 3893
 #if HAVE_JSON
3894
-    if (ctx.options & CL_SCAN_FILE_PROPERTIES && ctx.properties != NULL)
3894
+    if (ctx.options->general & CL_SCAN_GENERAL_COLLECT_METADATA && (ctx.properties != NULL))
3895 3895
     {
3896 3896
         json_object *jobj;
3897 3897
         const char *jstring;
... ...
@@ -3967,7 +3967,7 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
3967 3967
                 ))
3968 3968
                 {
3969 3969
                     cli_dbgmsg("scan_common: running deprecated preclass bytecodes for target type 13\n");
3970
-                    ctx.options &= ~CL_SCAN_FILE_PROPERTIES;
3970
+                    ctx.options->general &= ~CL_SCAN_GENERAL_COLLECT_METADATA;
3971 3971
                     rc = cli_mem_scandesc(jstring, strlen(jstring), &ctx);
3972 3972
                 }
3973 3973
             }
... ...
@@ -4013,26 +4013,31 @@ static int scan_common(int desc, cl_fmap_t *map, const char **virname, unsigned
4013 4013
     }
4014 4014
 #endif
4015 4015
 
4016
-    free(ctx.containers);
4017
-    cli_bitset_free(ctx.hook_lsig_matches);
4018
-    free(ctx.fmap);
4019 4016
     if (rc == CL_CLEAN)
4020 4017
     {
4021
-        if ((ctx.num_viruses != 0 && (ctx.options & (CL_SCAN_ALLMATCHES | CL_SCAN_BLOCKMAX))) ||
4022
-            ctx.found_possibly_unwanted)
4018
+        if ((ctx.found_possibly_unwanted) ||
4019
+            ((ctx.num_viruses != 0) && 
4020
+               ((ctx.options->general & CL_SCAN_GENERAL_ALLMATCHES) || 
4021
+                (ctx.options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX))
4022
+            ))
4023 4023
             rc = CL_VIRUS;
4024 4024
     }
4025
+
4026
+    free(ctx.containers);
4027
+    cli_bitset_free(ctx.hook_lsig_matches);
4028
+    free(ctx.fmap);
4029
+    free(ctx.options);
4025 4030
     cli_logg_unsetup();
4026 4031
     perf_done(&ctx);
4027 4032
     return rc;
4028 4033
 }
4029 4034
 
4030
-int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
4035
+int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *scanoptions, void *context)
4031 4036
 {
4032 4037
     return scan_common(desc, NULL, virname, scanned, engine, scanoptions, context);
4033 4038
 }
4034 4039
 
4035
-int cl_scanmap_callback(cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
4040
+int cl_scanmap_callback(cl_fmap_t *map, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *scanoptions, void *context)
4036 4041
 {
4037 4042
     return scan_common(-1, map, virname, scanned, engine, scanoptions, context);
4038 4043
 }
... ...
@@ -4042,7 +4047,7 @@ int cli_found_possibly_unwanted(cli_ctx *ctx)
4042 4042
     if (cli_get_last_virus(ctx))
4043 4043
     {
4044 4044
         cli_dbgmsg("found Possibly Unwanted: %s\n", cli_get_last_virus(ctx));
4045
-        if (ctx->options & CL_SCAN_HEURISTIC_PRECEDENCE)
4045
+        if (SCAN_HEURISTIC_PRECEDENCE)
4046 4046
         {
4047 4047
             /* we found a heuristic match, don't scan further,
4048 4048
          * but consider it a virus. */
... ...
@@ -4077,12 +4082,12 @@ static int cli_scanfile(const char *filename, cli_ctx *ctx)
4077 4077
     return ret;
4078 4078
 }
4079 4079
 
4080
-int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
4080
+int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options* scanoptions)
4081 4081
 {
4082 4082
     return cl_scanfile_callback(filename, virname, scanned, engine, scanoptions, NULL);
4083 4083
 }
4084 4084
 
4085
-int cl_scanfile_callback(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
4085
+int cl_scanfile_callback(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options* scanoptions, void *context)
4086 4086
 {
4087 4087
     int fd, ret;
4088 4088
     const char *fname = cli_to_utf8_maybe_alloc(filename);
... ...
@@ -146,7 +146,7 @@ int cli_parsetiff(cli_ctx *ctx)
146 146
                 if(entry.value + value_size > map->len) {
147 147
                     cli_warnmsg("cli_parsetiff: TFD entry field %u exceeds bounds of TIFF file [%llu > %llu]\n",
148 148
                                 i, (long long unsigned)(entry.value + value_size), (long long unsigned)map->len);
149
-                    return cli_append_virus(ctx, "Heuristic.TIFF.OutOfBoundsAccess");
149
+                    return cli_append_virus(ctx, "Heuristics.TIFF.OutOfBoundsAccess");
150 150
                 }
151 151
             }
152 152
         }
... ...
@@ -176,7 +176,7 @@ cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
176 176
 				if (!ctx->engine->keeptmp)
177 177
 					if (cli_unlink(fullname)) return CL_EUNLINK;
178 178
 				if (ret==CL_VIRUS) {
179
-				    if (!SCAN_ALL)
179
+				    if (!SCAN_ALLMATCHES)
180 180
 					return CL_VIRUS;
181 181
 				    else
182 182
 					num_viruses++;
... ...
@@ -300,7 +300,7 @@ cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
300 300
 			strncpy(name, block, 100);
301 301
 			name[100] = '\0';
302 302
 			if(cli_matchmeta(ctx, name, size, size, 0, files, 0, NULL) == CL_VIRUS) {
303
-			    if (!SCAN_ALL)
303
+			    if (!SCAN_ALLMATCHES)
304 304
 				return CL_VIRUS;
305 305
 			    else
306 306
 				num_viruses++;
... ...
@@ -542,7 +542,7 @@ static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int
542 542
 
543 543
   if(cli_matchmeta(ctx, name, LH_csize, LH_usize, (LH_flags & F_ENCR)!=0, fc, LH_crc32, NULL) == CL_VIRUS) {
544 544
       *ret = CL_VIRUS;
545
-      if (!SCAN_ALL)
545
+      if (!SCAN_ALLMATCHES)
546 546
           return 0;
547 547
       virus_found = 1;
548 548
   }
... ...
@@ -554,10 +554,10 @@ static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int
554 554
     return 0;
555 555
   }
556 556
 
557
-  if(detect_encrypted && (LH_flags & F_ENCR) && DETECT_ENCRYPTED) {
557
+  if(detect_encrypted && (LH_flags & F_ENCR) && SCAN_HEURISTIC_ENCRYPTED) {
558 558
     cli_dbgmsg("cli_unzip: Encrypted files found in archive.\n");
559 559
     *ret = cli_append_virus(ctx, "Heuristics.Encrypted.Zip");
560
-    if ((*ret == CL_VIRUS && !SCAN_ALL) || *ret != CL_CLEAN) {
560
+    if ((*ret == CL_VIRUS && !SCAN_ALLMATCHES) || *ret != CL_CLEAN) {
561 561
         fmap_unneed_off(map, loff, SIZEOF_LH);
562 562
         return 0;
563 563
     }
... ...
@@ -757,7 +757,7 @@ int cli_unzip(cli_ctx *ctx) {
757 757
           }
758 758
 #endif
759 759
           if (ret != CL_CLEAN) {
760
-              if (ret == CL_VIRUS && SCAN_ALL) {
760
+              if (ret == CL_VIRUS && SCAN_ALLMATCHES) {
761 761
                   ret = CL_CLEAN;
762 762
                   virus_found = 1;
763 763
               } else
... ...
@@ -772,7 +772,7 @@ int cli_unzip(cli_ctx *ctx) {
772 772
     while (ret==CL_CLEAN && lhoff<fsize && (coff=lhdr(map, lhoff, fsize-lhoff, &fu, fc+1, NULL, &ret, ctx, tmpd, 1, zip_scan_cb))) {
773 773
       fc++;
774 774
       lhoff+=coff;
775
-      if (SCAN_ALL && ret == CL_VIRUS) {
775
+      if (SCAN_ALLMATCHES && ret == CL_VIRUS) {
776 776
           ret = CL_CLEAN;
777 777
           virus_found = 1;
778 778
       }
... ...
@@ -285,7 +285,7 @@ static int xar_get_toc_data_values(xmlTextReaderPtr reader, size_t *length, size
285 285
      reader - xmlTextReaderPtr
286 286
      ctx - pointer to cli_ctx
287 287
   Returns:
288
-     CL_SUCCESS - subdoc found and clean scan (or virus found and SCAN_ALL), or no subdocument
288
+     CL_SUCCESS - subdoc found and clean scan (or virus found and SCAN_ALLMATCHES), or no subdocument
289 289
      other - error return code from cli_mem_scandesc()
290 290
 */                        
291 291
 static int xar_scan_subdocuments(xmlTextReaderPtr reader, cli_ctx *ctx)
... ...
@@ -316,7 +316,7 @@ static int xar_scan_subdocuments(xmlTextReaderPtr reader, cli_ctx *ctx)
316 316
             subdoc_len = xmlStrlen(subdoc);
317 317
             cli_dbgmsg("cli_scanxar: in-memory scan of xml subdocument, len %i.\n", subdoc_len);
318 318
             rc = cli_mem_scandesc(subdoc, subdoc_len, ctx);
319
-            if (rc == CL_VIRUS && SCAN_ALL)
319
+            if (rc == CL_VIRUS && SCAN_ALLMATCHES)
320 320
                 rc = CL_SUCCESS;
321 321
             
322 322
             /* make a file to leave if --leave-temps in effect */
... ...
@@ -524,7 +524,7 @@ int cli_scanxar(cli_ctx *ctx)
524 524
     cli_dbgmsg("cli_scanxar: scanning xar TOC xml in memory.\n"); 
525 525
     rc = cli_mem_scandesc(toc, hdr.toc_length_decompressed, ctx);
526 526
     if (rc != CL_SUCCESS) {
527
-        if (rc != CL_VIRUS || !SCAN_ALL)
527
+        if (rc != CL_VIRUS || !SCAN_ALLMATCHES)
528 528
             goto exit_toc;        
529 529
     }
530 530
 
... ...
@@ -855,7 +855,7 @@ int cli_scanxar(cli_ctx *ctx)
855 855
             if (rc != CL_SUCCESS) {
856 856
                 if (rc == CL_VIRUS) {
857 857
                     cli_dbgmsg("cli_scanxar: Infected with %s\n", cli_get_last_virus(ctx));
858
-                    if (!SCAN_ALL)
858
+                    if (!SCAN_ALLMATCHES)
859 859
                         goto exit_tmpfile;
860 860
                 } else if (rc != CL_BREAK) {
861 861
                     cli_dbgmsg("cli_scanxar: cli_magic_scandesc error %i\n", rc);
... ...
@@ -171,8 +171,12 @@ static int hashpe(const char *filename, unsigned int class, int type)
171 171
     const char *fmptr;
172 172
     struct cl_engine *engine;
173 173
     cli_ctx ctx;
174
+	struct cl_scan_options options;
174 175
     int fd, ret;
175 176
 
177
+	memset(&options, 0, sizeof(struct cl_scan_options));
178
+	ctx.options = &options;
179
+
176 180
     /* build engine */
177 181
     if(!(engine = cl_engine_new())) {
178 182
 	mprintf("!hashpe: Can't create new engine\n");
... ...
@@ -201,7 +205,7 @@ static int hashpe(const char *filename, unsigned int class, int type)
201 201
     /* prepare context */
202 202
     memset(&ctx, '\0', sizeof(cli_ctx));
203 203
     ctx.engine = engine;
204
-    ctx.options = CL_SCAN_STDOPT;
204
+    ctx.options->parse = ~0;
205 205
     ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
206 206
     if(!ctx.containers) {
207 207
 	cl_engine_free(engine);
... ...
@@ -2207,8 +2211,12 @@ static void matchsig(const char *sig, const char *offset, int fd)
2207 2207
 	STATBUF sb;
2208 2208
 	unsigned int matches = 0;
2209 2209
 	cli_ctx ctx;
2210
+	struct cl_scan_options options;
2210 2211
 	int ret;
2211 2212
 
2213
+	memset(&options, 0, sizeof(struct cl_scan_options));
2214
+	ctx.options = &options;
2215
+
2212 2216
     mprintf("SUBSIG: %s\n", sig);
2213 2217
 
2214 2218
     if(!(engine = cl_engine_new())) {
... ...
@@ -2236,7 +2244,7 @@ static void matchsig(const char *sig, const char *offset, int fd)
2236 2236
     }
2237 2237
     memset(&ctx, '\0', sizeof(cli_ctx));
2238 2238
     ctx.engine = engine;
2239
-    ctx.options = CL_SCAN_STDOPT;
2239
+    ctx.options->parse = ~0;
2240 2240
     ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
2241 2241
     if(!ctx.containers) {
2242 2242
 	cl_engine_free(engine);
... ...
@@ -3388,9 +3396,13 @@ static int dumpcerts(const struct optstruct *opts)
3388 3388
     const char * fmptr;
3389 3389
     struct cl_engine *engine;
3390 3390
     cli_ctx ctx;
3391
+	struct cl_scan_options options;
3391 3392
     int fd, ret;
3392 3393
     uint8_t shash1[SHA1_HASH_SIZE];
3393 3394
 
3395
+	memset(&options, 0, sizeof(struct cl_scan_options));
3396
+	ctx.options = &options;
3397
+	
3394 3398
     logg_file = NULL;
3395 3399
 
3396 3400
     filename = optget(opts, "print-certs")->strarg;
... ...
@@ -3430,7 +3442,7 @@ static int dumpcerts(const struct optstruct *opts)
3430 3430
     /* prepare context */
3431 3431
     memset(&ctx, '\0', sizeof(cli_ctx));
3432 3432
     ctx.engine = engine;
3433
-    ctx.options = CL_SCAN_STDOPT;
3433
+    ctx.options->parse = ~0;
3434 3434
     ctx.containers = cli_calloc(sizeof(cli_ctx_container), engine->maxreclevel + 2);
3435 3435
     if(!ctx.containers) {
3436 3436
 	cl_engine_free(engine);
... ...
@@ -62,9 +62,13 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit,
62 62
     int fdin = -1;
63 63
     char filestr[512];
64 64
     const char * virname = NULL;
65
+    struct cl_scan_options options;
65 66
 
66 67
     memset(&cctx, 0, sizeof(cctx));
67
-    cctx.options |= CL_SCAN_ALLMATCHES;
68
+    memset(&options, 0, sizeof(struct cl_scan_options));
69
+    cctx.options = &options;
70
+
71
+    cctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES;
68 72
     cctx.virname = &virname;
69 73
     cctx.engine = engine = cl_engine_new();
70 74
     fail_unless(!!cctx.engine, "cannot create engine");
... ...
@@ -160,7 +160,7 @@ static int get_test_file(int i, char *file, unsigned fsize, unsigned long *size)
160 160
 static struct cl_engine *g_engine;
161 161
 
162 162
 #ifdef CHECK_HAVE_LOOPS
163
-/* int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options) */
163
+/* int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, struct cl_scan_options* options) */
164 164
 START_TEST (test_cl_scandesc)
165 165
 {
166 166
     const char *virname = NULL;
... ...
@@ -168,10 +168,14 @@ START_TEST (test_cl_scandesc)
168 168
     unsigned long size;
169 169
     unsigned long int scanned = 0;
170 170
     int ret;
171
+    struct cl_scan_options options;
172
+
173
+    memset(&options, 0, sizeof(struct cl_scan_options));
174
+    options.parse |= ~0;
171 175
 
172 176
     int fd = get_test_file(_i, file, sizeof(file), &size);
173 177
     cli_dbgmsg("scanning (scandesc) %s\n", file);
174
-    ret = cl_scandesc(fd, &virname, &scanned, g_engine, CL_SCAN_STDOPT);
178
+    ret = cl_scandesc(fd, &virname, &scanned, g_engine, &options);
175 179
     cli_dbgmsg("scan end (scandesc) %s\n", file);
176 180
 
177 181
     if (!FALSE_NEGATIVE) {
... ...
@@ -189,10 +193,15 @@ START_TEST (test_cl_scandesc_allscan)
189 189
     unsigned long size;
190 190
     unsigned long int scanned = 0;
191 191
     int ret;
192
+    struct cl_scan_options options;
193
+
194
+    memset(&options, 0, sizeof(struct cl_scan_options));
195
+    options.parse |= ~0;
196
+    options.general |= CL_SCAN_GENERAL_ALLMATCHES;
192 197
 
193 198
     int fd = get_test_file(_i, file, sizeof(file), &size);
194 199
     cli_dbgmsg("scanning (scandesc) %s\n", file);
195
-    ret = cl_scandesc(fd, &virname, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT);
200
+    ret = cl_scandesc(fd, &virname, &scanned, g_engine, &options);
196 201
 
197 202
     cli_dbgmsg("scan end (scandesc) %s\n", file);
198 203
 
... ...
@@ -212,12 +221,16 @@ START_TEST (test_cl_scanfile)
212 212
     unsigned long size;
213 213
     unsigned long int scanned = 0;
214 214
     int ret;
215
+    struct cl_scan_options options;
216
+
217
+    memset(&options, 0, sizeof(struct cl_scan_options));
218
+    options.parse |= ~0;
215 219
 
216 220
     int fd = get_test_file(_i, file, sizeof(file), &size);
217 221
     close(fd);
218 222
 
219 223
     cli_dbgmsg("scanning (scanfile) %s\n", file);
220
-    ret = cl_scanfile(file, &virname, &scanned, g_engine, CL_SCAN_STDOPT);
224
+    ret = cl_scanfile(file, &virname, &scanned, g_engine, &options);
221 225
     cli_dbgmsg("scan end (scanfile) %s\n", file);
222 226
 
223 227
     if (!FALSE_NEGATIVE) {
... ...
@@ -234,12 +247,17 @@ START_TEST (test_cl_scanfile_allscan)
234 234
     unsigned long size;
235 235
     unsigned long int scanned = 0;
236 236
     int ret;
237
+    struct cl_scan_options options;
238
+
239
+    memset(&options, 0, sizeof(struct cl_scan_options));
240
+    options.parse |= ~0;
241
+    options.general |= CL_SCAN_GENERAL_ALLMATCHES;
237 242
 
238 243
     int fd = get_test_file(_i, file, sizeof(file), &size);
239 244
     close(fd);
240 245
 
241 246
     cli_dbgmsg("scanning (scanfile_allscan) %s\n", file);
242
-    ret = cl_scanfile(file, &virname, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT);
247
+    ret = cl_scanfile(file, &virname, &scanned, g_engine, &options);
243 248
     cli_dbgmsg("scan end (scanfile_allscan) %s\n", file);
244 249
 
245 250
     if (!FALSE_NEGATIVE) {
... ...
@@ -256,13 +274,17 @@ START_TEST (test_cl_scanfile_callback)
256 256
     unsigned long size;
257 257
     unsigned long int scanned = 0;
258 258
     int ret;
259
+    struct cl_scan_options options;
260
+
261
+    memset(&options, 0, sizeof(struct cl_scan_options));
262
+    options.parse |= ~0;
259 263
 
260 264
     int fd = get_test_file(_i, file, sizeof(file), &size);
261 265
     close(fd);
262 266
 
263 267
     cli_dbgmsg("scanning (scanfile_cb) %s\n", file);
264 268
     /* TODO: test callbacks */
265
-    ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, CL_SCAN_STDOPT, NULL);
269
+    ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, &options, NULL);
266 270
     cli_dbgmsg("scan end (scanfile_cb) %s\n", file);
267 271
 
268 272
     if (!FALSE_NEGATIVE) {
... ...
@@ -279,13 +301,18 @@ START_TEST (test_cl_scanfile_callback_allscan)
279 279
     unsigned long size;
280 280
     unsigned long int scanned = 0;
281 281
     int ret;
282
+    struct cl_scan_options options;
283
+
284
+    memset(&options, 0, sizeof(struct cl_scan_options));
285
+    options.parse |= ~0;
286
+    options.general |= CL_SCAN_GENERAL_ALLMATCHES;
282 287
 
283 288
     int fd = get_test_file(_i, file, sizeof(file), &size);
284 289
     close(fd);
285 290
 
286 291
     cli_dbgmsg("scanning (scanfile_cb_allscan) %s\n", file);
287 292
     /* TODO: test callbacks */
288
-    ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
293
+    ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, &options, NULL);
289 294
     cli_dbgmsg("scan end (scanfile_cb_allscan) %s\n", file);
290 295
 
291 296
     if (!FALSE_NEGATIVE) {
... ...
@@ -302,12 +329,16 @@ START_TEST (test_cl_scandesc_callback)
302 302
     unsigned long size;
303 303
     unsigned long int scanned = 0;
304 304
     int ret;
305
+    struct cl_scan_options options;
306
+
307
+    memset(&options, 0, sizeof(struct cl_scan_options));
308
+    options.parse |= ~0;
305 309
 
306 310
     int fd = get_test_file(_i, file, sizeof(file), &size);
307 311
 
308 312
     cli_dbgmsg("scanning (scandesc_cb) %s\n", file);
309 313
     /* TODO: test callbacks */
310
-    ret = cl_scandesc_callback(fd, &virname, &scanned, g_engine, CL_SCAN_STDOPT, NULL);
314
+    ret = cl_scandesc_callback(fd, &virname, &scanned, g_engine, &options, NULL);
311 315
     cli_dbgmsg("scan end (scandesc_cb) %s\n", file);
312 316
 
313 317
     if (!FALSE_NEGATIVE) {
... ...
@@ -325,12 +356,17 @@ START_TEST (test_cl_scandesc_callback_allscan)
325 325
     unsigned long size;
326 326
     unsigned long int scanned = 0;
327 327
     int ret;
328
+    struct cl_scan_options options;
329
+
330
+    memset(&options, 0, sizeof(struct cl_scan_options));
331
+    options.parse |= ~0;
332
+    options.general |= CL_SCAN_GENERAL_ALLMATCHES;
328 333
 
329 334
     int fd = get_test_file(_i, file, sizeof(file), &size);
330 335
 
331 336
     cli_dbgmsg("scanning (scandesc_cb_allscan) %s\n", file);
332 337
     /* TODO: test callbacks */
333
-    ret = cl_scandesc_callback(fd, &virname, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
338
+    ret = cl_scandesc_callback(fd, &virname, &scanned, g_engine, &options, NULL);
334 339
     cli_dbgmsg("scan end (scandesc_cb_allscan) %s\n", file);
335 340
 
336 341
     if (!FALSE_NEGATIVE) {
... ...
@@ -490,6 +526,10 @@ START_TEST (test_cl_scanmap_callback_handle)
490 490
     int ret;
491 491
     char file[256];
492 492
     unsigned long size;
493
+    struct cl_scan_options options;
494
+
495
+    memset(&options, 0, sizeof(struct cl_scan_options));
496
+    options.parse |= ~0;
493 497
 
494 498
     int fd = get_test_file(_i, file, sizeof(file), &size);
495 499
     /* intentionally use different way than scanners.c for testing */
... ...
@@ -497,7 +537,7 @@ START_TEST (test_cl_scanmap_callback_handle)
497 497
     fail_unless(!!map, "cl_fmap_open_handle");
498 498
 
499 499
     cli_dbgmsg("scanning (handle) %s\n", file);
500
-    ret = cl_scanmap_callback(map, &virname, &scanned, g_engine, CL_SCAN_STDOPT, NULL);
500
+    ret = cl_scanmap_callback(map, &virname, &scanned, g_engine, &options, NULL);
501 501
     cli_dbgmsg("scan end (handle) %s\n", file);
502 502
 
503 503
     if (!FALSE_NEGATIVE) {
... ...
@@ -516,6 +556,11 @@ START_TEST (test_cl_scanmap_callback_handle_allscan)
516 516
     int ret;
517 517
     char file[256];
518 518
     unsigned long size;
519
+    struct cl_scan_options options;
520
+
521
+    memset(&options, 0, sizeof(struct cl_scan_options));
522
+    options.parse |= ~0;
523
+    options.general |= CL_SCAN_GENERAL_ALLMATCHES;
519 524
 
520 525
     int fd = get_test_file(_i, file, sizeof(file), &size);
521 526
     /* intentionally use different way than scanners.c for testing */
... ...
@@ -523,7 +568,7 @@ START_TEST (test_cl_scanmap_callback_handle_allscan)
523 523
     fail_unless(!!map, "cl_fmap_open_handle %s");
524 524
 
525 525
     cli_dbgmsg("scanning (handle) allscan %s\n", file);
526
-    ret = cl_scanmap_callback(map, &virname, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
526
+    ret = cl_scanmap_callback(map, &virname, &scanned, g_engine, &options, NULL);
527 527
     cli_dbgmsg("scan end (handle) allscan %s\n", file);
528 528
 
529 529
     if (!FALSE_NEGATIVE) {
... ...
@@ -543,6 +588,10 @@ START_TEST (test_cl_scanmap_callback_mem)
543 543
     void *mem;
544 544
     unsigned long size;
545 545
     char file[256];
546
+    struct cl_scan_options options;
547
+
548
+    memset(&options, 0, sizeof(struct cl_scan_options));
549
+    options.parse |= ~0;
546 550
 
547 551
     int fd = get_test_file(_i, file, sizeof(file), &size);
548 552
 
... ...
@@ -554,7 +603,7 @@ START_TEST (test_cl_scanmap_callback_mem)
554 554
     fail_unless(!!map, "cl_fmap_open_mem");
555 555
 
556 556
     cli_dbgmsg("scanning (mem) %s\n", file);
557
-    ret = cl_scanmap_callback(map, &virname, &scanned, g_engine, CL_SCAN_STDOPT, NULL);
557
+    ret = cl_scanmap_callback(map, &virname, &scanned, g_engine, &options, NULL);
558 558
     cli_dbgmsg("scan end (mem) %s\n", file);
559 559
     if (!FALSE_NEGATIVE) {
560 560
       fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
... ...
@@ -576,6 +625,11 @@ START_TEST (test_cl_scanmap_callback_mem_allscan)
576 576
     void *mem;
577 577
     unsigned long size;
578 578
     char file[256];
579
+    struct cl_scan_options options;
580
+
581
+    memset(&options, 0, sizeof(struct cl_scan_options));
582
+    options.parse |= ~0;
583
+    options.general |= CL_SCAN_GENERAL_ALLMATCHES;
579 584
 
580 585
     int fd = get_test_file(_i, file, sizeof(file), &size);
581 586
 
... ...
@@ -587,7 +641,7 @@ START_TEST (test_cl_scanmap_callback_mem_allscan)
587 587
     fail_unless(!!map, "cl_fmap_open_mem %s");
588 588
 
589 589
     cli_dbgmsg("scanning (mem) allscan %s\n", file);
590
-    ret = cl_scanmap_callback(map, &virname, &scanned, g_engine, CL_SCAN_ALLMATCHES+CL_SCAN_STDOPT, NULL);
590
+    ret = cl_scanmap_callback(map, &virname, &scanned, g_engine, &options, NULL);
591 591
     cli_dbgmsg("scan end (mem) allscan %s\n", file);
592 592
     if (!FALSE_NEGATIVE) {
593 593
       fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
... ...
@@ -155,6 +155,8 @@ static const struct pcre_testdata_s {
155 155
 #endif /* HAVE_PCRE */
156 156
 
157 157
 static cli_ctx ctx;
158
+static struct cl_scan_options options;
159
+
158 160
 static fmap_t *thefmap = NULL;
159 161
 static const char *virname = NULL;
160 162
 static void setup(void)
... ...
@@ -162,6 +164,11 @@ static void setup(void)
162 162
 	struct cli_matcher *root;
163 163
 	virname = NULL;
164 164
 	thefmap = NULL;
165
+
166
+    memset(&ctx, 0, sizeof(ctx));
167
+    memset(&options, 0, sizeof(struct cl_scan_options));
168
+    ctx.options = &options;
169
+
165 170
 	ctx.virname = &virname;
166 171
 	ctx.fmap = &thefmap;
167 172
 	ctx.engine = cl_engine_new();
... ...
@@ -208,6 +215,7 @@ START_TEST (test_ac_scanbuff) {
208 208
     ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
209 209
     fail_unless(ret == CL_SUCCESS, "cli_ac_initdata() failed");
210 210
 
211
+    ctx.options->general &= ~CL_SCAN_GENERAL_ALLMATCHES; /* make sure all-match is disabled */
211 212
     for(i = 0; ac_testdata[i].data; i++) {
212 213
 	ret = cli_ac_scanbuff((const unsigned char*)ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
213 214
 	fail_unless_fmt(ret == CL_VIRUS, "cli_ac_scanbuff() failed for %s", ac_testdata[i].virname);
... ...
@@ -250,7 +258,7 @@ START_TEST (test_ac_scanbuff_allscan) {
250 250
     ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
251 251
     fail_unless(ret == CL_SUCCESS, "cli_ac_initdata() failed");
252 252
 
253
-    ctx.options |= CL_SCAN_ALLMATCHES;
253
+    ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES; /* enable all-match */
254 254
     for(i = 0; ac_testdata[i].data; i++) {
255 255
 	ret = cli_ac_scanbuff((const unsigned char*)ac_testdata[i].data, strlen(ac_testdata[i].data), &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
256 256
 	fail_unless_fmt(ret == CL_VIRUS, "cli_ac_scanbuff() failed for %s", ac_testdata[i].virname);
... ...
@@ -294,6 +302,7 @@ START_TEST (test_ac_scanbuff_ex) {
294 294
     ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
295 295
     fail_unless(ret == CL_SUCCESS, "[ac_ex] cli_ac_initdata() failed");
296 296
 
297
+    ctx.options->general &= ~CL_SCAN_GENERAL_ALLMATCHES; /* make sure all-match is disabled */
297 298
     for(i = 0; ac_sigopts_testdata[i].data; i++) {
298 299
 	ret = cli_ac_scanbuff((const unsigned char*)ac_sigopts_testdata[i].data, ac_sigopts_testdata[i].dlength, &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
299 300
 	fail_unless_fmt(ret == ac_sigopts_testdata[i].expected_result, "[ac_ex] cli_ac_scanbuff() failed for %s (%d != %d)", ac_sigopts_testdata[i].virname, ret, ac_sigopts_testdata[i].expected_result);
... ...
@@ -335,7 +344,7 @@ START_TEST (test_ac_scanbuff_allscan_ex) {
335 335
     ret = cli_ac_initdata(&mdata, root->ac_partsigs, 0, 0, CLI_DEFAULT_AC_TRACKLEN);
336 336
     fail_unless(ret == CL_SUCCESS, "[ac_ex] cli_ac_initdata() failed");
337 337
 
338
-    ctx.options |= CL_SCAN_ALLMATCHES;
338
+    ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES; /* enable all-match */
339 339
     for(i = 0; ac_sigopts_testdata[i].data; i++) {
340 340
 	ret = cli_ac_scanbuff((const unsigned char*)ac_sigopts_testdata[i].data, ac_sigopts_testdata[i].dlength, &virname, NULL, NULL, root, &mdata, 0, 0, NULL, AC_SCAN_VIR, NULL);
341 341
 	fail_unless_fmt(ret == ac_sigopts_testdata[i].expected_result, "[ac_ex] cli_ac_scanbuff() failed for %s (%d != %d)", ac_sigopts_testdata[i].virname, ret, ac_sigopts_testdata[i].expected_result);
... ...
@@ -374,6 +383,7 @@ START_TEST (test_bm_scanbuff) {
374 374
     ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, 0, "*", 0, NULL, 0);
375 375
     fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
376 376
 
377
+    ctx.options->general &= ~CL_SCAN_GENERAL_ALLMATCHES; /* make sure all-match is disabled */
377 378
     ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);
378 379
     fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
379 380
     fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
... ...
@@ -402,6 +412,7 @@ START_TEST (test_bm_scanbuff_allscan) {
402 402
     ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, 0, "*", 0, NULL, 0);
403 403
     fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed");
404 404
 
405
+    ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES; /* enable all-match */
405 406
     ret = cli_bm_scanbuff((const unsigned char*)"blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, NULL, NULL, NULL);
406 407
     fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed");
407 408
     fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n");
... ...
@@ -448,6 +459,7 @@ START_TEST (test_pcre_scanbuff) {
448 448
     ret = cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN);
449 449
     fail_unless(ret == CL_SUCCESS, "[pcre] cli_ac_initdata() failed");
450 450
 
451
+    ctx.options->general &= ~CL_SCAN_GENERAL_ALLMATCHES; /* make sure all-match is disabled */
451 452
     for(i = 0; pcre_testdata[i].data; i++) {
452 453
 	ret = cli_pcre_scanbuf((const unsigned char*)pcre_testdata[i].data, strlen(pcre_testdata[i].data), &virname, NULL, root, NULL, NULL, NULL);
453 454
 	fail_unless_fmt(ret == pcre_testdata[i].expected_result, "[pcre] cli_pcre_scanbuff() failed for %s (%d != %d)", pcre_testdata[i].virname, ret, pcre_testdata[i].expected_result);
... ...
@@ -500,7 +512,7 @@ START_TEST (test_pcre_scanbuff_allscan) {
500 500
     ret = cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN);
501 501
     fail_unless(ret == CL_SUCCESS, "[pcre] cli_ac_initdata() failed");
502 502
 
503
-    ctx.options |= CL_SCAN_ALLMATCHES;
503
+    ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES; /* enable all-match */
504 504
     for(i = 0; pcre_testdata[i].data; i++) {
505 505
 	ret = cli_pcre_scanbuf((const unsigned char*)pcre_testdata[i].data, strlen(pcre_testdata[i].data), &virname, NULL, root, NULL, NULL, NULL);
506 506
 	fail_unless_fmt(ret == pcre_testdata[i].expected_result, "[pcre] cli_pcre_scanbuff() failed for %s (%d != %d)", pcre_testdata[i].virname, ret, pcre_testdata[i].expected_result);
... ...
@@ -367,11 +367,14 @@ static void do_phishing_test(const struct rtest *rtest)
367 367
 {
368 368
 	char *realurl;
369 369
 	cli_ctx ctx;
370
+	struct cl_scan_options options;
370 371
 	const char *virname = NULL;
371 372
 	tag_arguments_t hrefs;
372 373
 	int rc;
373 374
 
374 375
 	memset(&ctx, 0, sizeof(ctx));
376
+	memset(&options, 0, sizeof(struct cl_scan_options));
377
+	ctx.options = &options;
375 378
 
376 379
 	realurl = cli_strdup(rtest->realurl);
377 380
 	fail_unless(!!realurl, "cli_strdup");
... ...
@@ -434,8 +437,11 @@ static void do_phishing_test_allscan(const struct rtest *rtest)
434 434
 	const char *virname = NULL;
435 435
 	tag_arguments_t hrefs;
436 436
 	int rc;
437
+    struct cl_scan_options options;
437 438
 
438 439
 	memset(&ctx, 0, sizeof(ctx));
440
+    memset(&options, 0, sizeof(struct cl_scan_options));
441
+    ctx.options = &options;
439 442
 
440 443
 	realurl = cli_strdup(rtest->realurl);
441 444
 	fail_unless(!!realurl, "cli_strdup");
... ...
@@ -453,7 +459,7 @@ static void do_phishing_test_allscan(const struct rtest *rtest)
453 453
 
454 454
 	ctx.engine = engine;
455 455
 	ctx.virname = &virname;
456
-	ctx.options |= CL_SCAN_ALLMATCHES;
456
+	ctx.options->general |= CL_SCAN_GENERAL_ALLMATCHES;
457 457
 
458 458
 	rc = phishingScan(&ctx, &hrefs);
459 459
 
... ...
@@ -130,7 +130,7 @@ FILETIME last_chk_time = {0, 0};
130 130
 typedef struct {
131 131
 	CLAM_SCAN_CALLBACK scancb;
132 132
 	void *scancb_ctx;
133
-	unsigned int scanopts;
133
+	struct cl_scan_options* scanopts;
134 134
 	_int64 *filetype;
135 135
 } instance;
136 136
 
... ...
@@ -562,31 +562,46 @@ int CLAMAPI Scan_Uninitialize(void) {
562 562
 
563 563
 int CLAMAPI Scan_CreateInstance(CClamAVScanner **ppScanner) {
564 564
 	instance *inst;
565
+	struct cl_scan_options *scanopts;
565 566
 
566 567
 	INFN();
567 568
 	if(!ppScanner)
568 569
 	FAIL(CL_ENULLARG, "NULL pScanner");
569 570
 	inst = (instance *)calloc(1, sizeof(*inst));
570 571
 	if(!inst)
571
-	FAIL(CL_EMEM, "CreateInstance: OOM");
572
+		FAIL(CL_EMEM, "CreateInstance: OOM");
573
+
574
+	scanopts = (struct cl_scan_options *)calloc(1, sizeof(struct cl_scan_options));
575
+	memset(scanopts, 0, sizeof(struct cl_scan_options));
576
+	if(!scanopts) {
577
+		free(inst);
578
+		FAIL(CL_EMEM, "CreateInstance: OOM");
579
+	}
580
+	inst->scanopts = scanopts;
581
+
572 582
 	if(lock_engine()) {
573
-	free(inst);
574
-	FAIL(CL_ELOCK, "Failed to lock engine");
583
+		free(inst->scanopts);
584
+		free(inst);
585
+		FAIL(CL_ELOCK, "CreateInstance: Failed to lock engine");
575 586
 	}
576 587
 	if(!engine) {
577
-	free(inst);
578
-	unlock_engine();
579
-	FAIL(CL_ESTATE, "Create instance called with no engine");
588
+		free(inst->scanopts);
589
+		free(inst);
590
+		unlock_engine();
591
+		FAIL(CL_ESTATE, "CreateInstance: Create instance called with no engine");
580 592
 	}
581 593
 	if(add_instance(inst)) {
582
-	free(inst);
583
-	unlock_engine();
584
-	FAIL(CL_EMEM, "add_instance failed");
594
+		free(inst->scanopts);
595
+		free(inst);
596
+		unlock_engine();
597
+		FAIL(CL_EMEM, "CreateInstance: add_instance failed");
585 598
 	}
586 599
 	unlock_engine();
587
-	inst->scanopts = CL_SCAN_STDOPT;
600
+	inst->scanopts->parser |= ~0;  /* enable all parsers */
601
+	inst->scanopts->general |= CL_SCAN_GENERAL_HEURISTICS;  /* enable heuristic alert options */
588 602
 	if (logg_verbose)
589
-	inst->scanopts |= CL_SCAN_PERFORMANCE_INFO;
603
+		inst->scanopts->dev |= CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO;
604
+
590 605
 	*ppScanner = (CClamAVScanner *)inst;
591 606
 	logg("Created new instance %p\n", inst);
592 607
 	WIN();
... ...
@@ -596,21 +611,23 @@ int CLAMAPI Scan_CreateInstance(CClamAVScanner **ppScanner) {
596 596
 // No point in retrying more times since we are shutting down anyway.
597 597
 int CLAMAPI Scan_DestroyInstance(CClamAVScanner *pScanner) {
598 598
 	int rc;
599
+	instance *inst = (instance*)pScanner;
599 600
 	INFN();
600 601
 	if(!pScanner)
601
-	FAIL(CL_ENULLARG, "NULL pScanner");
602
-	if((rc = del_instance((instance *)pScanner))) {
603
-	if (rc == CL_EBUSY) {
604
-		// wait for one of the scanner threads to finish, and retry again,
605
-		// that's better than caller always waiting 2 seconds to retry.
606
-		if (WaitForSingleObject(reload_event, 1000) != WAIT_OBJECT_0)
607
-		logg("Scan_DestroyInstance: timeout");
608
-		rc = del_instance((instance *)pScanner);
609
-	}
610
-	if (rc)
611
-		FAIL(rc, "del_instance failed for %p", pScanner);
612
-	}
613
-	free(pScanner);
602
+		FAIL(CL_ENULLARG, "NULL pScanner");
603
+	if((rc = del_instance(inst))) {
604
+		if (rc == CL_EBUSY) {
605
+			// wait for one of the scanner threads to finish, and retry again,
606
+			// that's better than caller always waiting 2 seconds to retry.
607
+			if (WaitForSingleObject(reload_event, 1000) != WAIT_OBJECT_0)
608
+			logg("Scan_DestroyInstance: timeout");
609
+			rc = del_instance(inst);
610
+		}
611
+		if (rc)
612
+			FAIL(rc, "del_instance failed for %p", pScanner);
613
+	}
614
+	free(inst->scanopts);
615
+	free(inst);
614 616
 	logg("in Scan_DestroyInstance: Instance %p destroyed\n", pScanner);
615 617
 	WIN();
616 618
 }
... ...
@@ -656,39 +673,39 @@ int CLAMAPI Scan_SetOption(CClamAVScanner *pScanner, int option, void *value, un
656 656
 	switch(option) {
657 657
 	case CLAM_OPTION_SCAN_ARCHIVE:
658 658
 		logg("CLAM_OPTION_SCAN_ARCHIVE: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
659
-		whichopt = CL_SCAN_ARCHIVE;
659
+		whichopt = CL_SCAN_PARSE_ARCHIVE;
660 660
 		break;
661 661
 	case CLAM_OPTION_SCAN_MAIL:
662 662
 		logg("CLAM_OPTION_SCAN_MAIL: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
663
-		whichopt = CL_SCAN_MAIL;
663
+		whichopt = CL_SCAN_PARSE_MAIL;
664 664
 		break;
665 665
 	case CLAM_OPTION_SCAN_OLE2:
666 666
 		logg("CLAM_OPTION_SCAN_OLE2: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
667
-		whichopt = CL_SCAN_OLE2;
667
+		whichopt = CL_SCAN_PARSE_OLE2;
668 668
 		break;
669 669
 	case CLAM_OPTION_SCAN_HTML:
670 670
 		logg("CLAM_OPTION_SCAN_HTML: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
671
-		whichopt = CL_SCAN_HTML;
671
+		whichopt = CL_SCAN_PARSE_HTML;
672 672
 		break;
673 673
 	case CLAM_OPTION_SCAN_PE:
674 674
 		logg("CLAM_OPTION_SCAN_PE: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
675
-		whichopt = CL_SCAN_PE;
675
+		whichopt = CL_SCAN_PARSE_PE;
676 676
 		break;
677 677
 	case CLAM_OPTION_SCAN_PDF:
678 678
 		logg("CLAM_OPTION_SCAN_PDF: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
679
-		whichopt = CL_SCAN_PDF;
679
+		whichopt = CL_SCAN_PARSE_PDF;
680 680
 		break;
681 681
 	case CLAM_OPTION_SCAN_ALGORITHMIC:
682 682
 		logg("CLAM_OPTION_SCAN_ALGORITHMIC: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
683
-		whichopt = CL_SCAN_ALGORITHMIC;
683
+		whichopt = CL_SCAN_GENERAL_HEURISTICS;
684 684
 		break;
685 685
 	case CLAM_OPTION_SCAN_ELF:
686 686
 		logg("CLAM_OPTION_SCAN_ELF: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
687
-		whichopt = CL_SCAN_ELF;
687
+		whichopt = CL_SCAN_PARSE_ELF;
688 688
 		break;
689 689
 	case CLAM_OPTION_SCAN_SWF:
690 690
 		logg("CLAM_OPTION_SCAN_SWF: %s on instance %p\n", newval ? "enabled" : "disabled", inst);
691
-		whichopt = CL_SCAN_SWF;
691
+		whichopt = CL_SCAN_PARSE_SWF;
692 692
 		break;
693 693
 	default:
694 694
 		unlock_instances();
... ...
@@ -722,31 +739,31 @@ int CLAMAPI Scan_GetOption(CClamAVScanner *pScanner, int option, void *value, un
722 722
 	}
723 723
 	switch(option) {
724 724
 	case CLAM_OPTION_SCAN_ARCHIVE:
725
-		whichopt = CL_SCAN_ARCHIVE;
725
+		whichopt = CL_SCAN_PARSE_ARCHIVE;
726 726
 		break;
727 727
 	case CLAM_OPTION_SCAN_MAIL:
728
-		whichopt = CL_SCAN_MAIL;
728
+		whichopt = CL_SCAN_PARSE_MAIL;
729 729
 		break;
730 730
 	case CLAM_OPTION_SCAN_OLE2:
731
-		whichopt = CL_SCAN_OLE2;
731
+		whichopt = CL_SCAN_PARSE_OLE2;
732 732
 		break;
733 733
 	case CLAM_OPTION_SCAN_HTML:
734
-		whichopt = CL_SCAN_HTML;
734
+		whichopt = CL_SCAN_PARSE_HTML;
735 735
 		break;
736 736
 	case CLAM_OPTION_SCAN_PE:
737
-		whichopt = CL_SCAN_PE;
737
+		whichopt = CL_SCAN_PARSE_PE;
738 738
 		break;
739 739
 	case CLAM_OPTION_SCAN_PDF:
740
-		whichopt = CL_SCAN_PDF;
740
+		whichopt = CL_SCAN_PARSE_PDF;
741 741
 		break;
742 742
 	case CLAM_OPTION_SCAN_ALGORITHMIC:
743
-		whichopt = CL_SCAN_ALGORITHMIC;
743
+		whichopt = CL_SCAN_GENERAL_HEURISTICS;
744 744
 		break;
745 745
 	case CLAM_OPTION_SCAN_ELF:
746
-		whichopt = CL_SCAN_ELF;
746
+		whichopt = CL_SCAN_PARSE_ELF;
747 747
 		break;
748 748
 	case CLAM_OPTION_SCAN_SWF:
749
-		whichopt = CL_SCAN_SWF;
749
+		whichopt = CL_SCAN_PARSE_SWF;
750 750
 		break;
751 751
 	default:
752 752
 		unlock_instances();
... ...
@@ -547,7 +547,7 @@ TCPAddr 127.0.0.1
547 547
 #PCREMaxFileSize 100M
548 548
 
549 549
 # When BlockMax is set, files exceeding the MaxFileSize, MaxScanSize, or MaxRecursion limit will be flagged
550
-# with the virus "Heuristic.Limits.Exceeded".
550
+# with the virus "Heuristics.Limits.Exceeded".
551 551
 # Default: no
552 552
 #BlockMax yes
553 553