~ubuntu-branches/ubuntu/quantal/dovecot/quantal

« back to all changes in this revision

Viewing changes to sieve/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short, Scott Kitterman
  • Date: 2010-06-22 10:33:51 UTC
  • mfrom: (1.13.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20100622103351-ifbmnklp8kxrhb30
Tags: 1:1.2.12-0ubuntu1
* New upstream release:
  - deliver: Don't crash when a message with Auto-submitted: header gets
   rejected.
  - lib-storage: Fixed header searches to work correctly when there are
    multiple headers with same name.
  - dict client: Disconnect from dict server after 1 second of idling.
  - dict: If process crashed, it wasn't automatically restarted
  - dict file: If dict file's group permissions equal world permissions,
    don't try to change its gid.
  - maildir: Fixed a memory leak when copying with hardlinks.
  - maildir: Expunging last messages may have assert-crashed if their
    filenames had just changed.
 * Update sieve patch to 0.1.17
 * debian/dovecot-common.postinst: Add warning about expired certificate.
   (Debian Bug: #576455)
 * Silence lintian warnings.

 [Scott Kitterman]
 * Rename dovecot-postfix to mail-stack-delivery per server-maverick-mail-
   integration spec.
   - Update debian/rules
   - Convert existing package to a dummy package and add new binary in debian/control
   - Update maintainer scripts.
   - Move previously installed backups and config files to new package name
     space in preinst
   - Add new debian/mail-stack-delivery.prerm to handle downgrades
   - Rename debian/dovecot-postfix.* to debian/mail-stack-delivery.*

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 */
3
3
 
4
4
#include "lib.h"
 
5
#include "strfuncs.h"
5
6
 
6
7
#include "sieve-common.h"
7
8
#include "sieve-settings.h"
8
9
#include "sieve-error.h"
9
10
#include "sieve-extensions.h"
 
11
#include "sieve-message.h"
10
12
#include "sieve-interpreter.h"
11
13
 
12
14
#include "ext-spamvirustest-common.h"
20
22
 */
21
23
 
22
24
enum ext_spamvirustest_status_type {
23
 
        EXT_SPAMVIRUSTEST_STATUS_TYPE_VALUE,
 
25
        EXT_SPAMVIRUSTEST_STATUS_TYPE_SCORE,
24
26
        EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN,
25
 
        EXT_SPAMVIRUSTEST_STATUS_TYPE_YESNO,
 
27
        EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT,
26
28
};
27
29
 
28
30
struct ext_spamvirustest_header_spec {
34
36
struct ext_spamvirustest_data {
35
37
        pool_t pool;
36
38
 
 
39
        int reload;
 
40
 
37
41
        struct ext_spamvirustest_header_spec status_header;
38
42
        struct ext_spamvirustest_header_spec max_header;
39
43
 
40
44
        enum ext_spamvirustest_status_type status_type;
41
45
 
42
46
        float max_value;
43
 
        const char *yes_string;
 
47
 
 
48
        const char *text_values[11];
44
49
};
45
50
 
46
51
/*
59
64
                return TRUE;
60
65
        }
61
66
 
62
 
        errsize = regerror(ret, regexp, NULL, 0);
 
67
        errsize = regerror(ret, regexp, NULL, 0); 
63
68
 
64
69
        if ( errsize > 0 ) {
65
70
                char *errbuf = t_malloc(errsize);
66
71
 
67
72
                (void)regerror(ret, regexp, errbuf, errsize);
68
 
 
 
73
         
69
74
                /* We don't want the error to start with a capital letter */
70
75
                errbuf[0] = i_tolower(errbuf[0]);
71
76
 
79
84
(const char *string, int index, regmatch_t pmatch[], int nmatch)
80
85
{
81
86
        if ( index > -1 && index < nmatch && pmatch[index].rm_so != -1 ) {
82
 
                return t_strndup(string + pmatch[index].rm_so,
 
87
                return t_strndup(string + pmatch[index].rm_so, 
83
88
                                                pmatch[index].rm_eo - pmatch[index].rm_so);
84
89
        }
85
90
        return NULL;
90
95
 */
91
96
 
92
97
static bool ext_spamvirustest_header_spec_parse
93
 
(struct ext_spamvirustest_header_spec *spec, pool_t pool, const char *data,
 
98
(struct ext_spamvirustest_header_spec *spec, pool_t pool, const char *data, 
94
99
        const char **error_r)
95
100
{
96
101
        const char *p;
128
133
                return FALSE;
129
134
        }
130
135
        p++;
 
136
        while ( *p == ' ' || *p == '\t' ) p++;
131
137
 
132
138
        spec->regexp_match = TRUE;
133
139
        if ( !_regexp_compile(&spec->regexp, p, &regexp_error) ) {
134
 
                *error_r = t_strdup_printf("failed to compile regular expression '%s': "
 
140
                *error_r = t_strdup_printf("failed to compile regular expression '%s': " 
135
141
                        "%s", p, regexp_error);
136
142
                return FALSE;
137
143
        }
155
161
                *value_r = 0;
156
162
                return TRUE;
157
163
        }
158
 
 
 
164
        
159
165
        while ( *p == ch ) p++;
160
166
 
161
167
        if ( *p != '\0' ) {
179
185
        int digits;
180
186
 
181
187
        if ( *p == '\0' ) {
182
 
                *error_r = "empty value";
 
188
                *error_r = "empty value";               
183
189
                return FALSE;
184
190
        }
185
191
 
186
192
        if ( *p == '+' || *p == '-' ) {
187
193
                if ( *p == '-' )
188
194
                        sign = -1;
189
 
 
 
195
                
190
196
                p++;
191
197
        }
192
198
 
196
202
                value = value*10 + (*p-'0');
197
203
                if ( digits++ > 4 ) {
198
204
                        *error_r = t_strdup_printf
199
 
                                ("decimal value has too many digits before radix point: %s",
 
205
                                ("decimal value has too many digits before radix point: %s", 
200
206
                                        str_value);
201
 
                        return FALSE;
 
207
                        return FALSE;   
202
208
                }
203
209
                p++;
204
210
        }
213
219
 
214
220
                        if ( digits++ > 4 ) {
215
221
                                *error_r = t_strdup_printf
216
 
                                        ("decimal value has too many digits after radix point: %s",
 
222
                                        ("decimal value has too many digits after radix point: %s", 
217
223
                                                str_value);
218
224
                                return FALSE;
219
225
                        }
237
243
 * Extension initialization
238
244
 */
239
245
 
240
 
static bool ext_spamvirustest_config_load
241
 
(struct ext_spamvirustest_data *ext_data, const char *ext_name,
242
 
        const char *status_header, const char *max_header,
243
 
        const char *status_type, const char *max_value)
 
246
bool ext_spamvirustest_load
 
247
(const struct sieve_extension *ext, void **context)
244
248
{
 
249
        struct ext_spamvirustest_data *ext_data =
 
250
        (struct ext_spamvirustest_data *) *context;
 
251
    struct sieve_instance *svinst = ext->svinst;
 
252
        const char *ext_name, *status_header, *max_header, *status_type, 
 
253
                *max_value;
 
254
        enum ext_spamvirustest_status_type type;
245
255
        const char *error;
246
 
 
247
 
        if ( !ext_spamvirustest_header_spec_parse
248
 
                (&ext_data->status_header, ext_data->pool, status_header, &error) ) {
249
 
                sieve_sys_error("%s: invalid status header specification "
250
 
                        "'%s': %s", ext_name, status_header, error);
251
 
                return FALSE;
252
 
        }
253
 
 
254
 
        if ( max_header != NULL && !ext_spamvirustest_header_spec_parse
255
 
                (&ext_data->max_header, ext_data->pool, max_header, &error) ) {
256
 
                sieve_sys_error("%s: invalid max header specification "
257
 
                        "'%s': %s", ext_name, max_header, error);
258
 
                return FALSE;
259
 
        }
260
 
 
261
 
        if ( status_type == NULL || strcmp(status_type, "value") == 0 ) {
262
 
                ext_data->status_type = EXT_SPAMVIRUSTEST_STATUS_TYPE_VALUE;
263
 
        } else if ( strcmp(status_type, "strlen") == 0 ) {
264
 
                ext_data->status_type = EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN;
265
 
        } else if ( strcmp(status_type, "yesno") == 0 ) {
266
 
                ext_data->status_type = EXT_SPAMVIRUSTEST_STATUS_TYPE_YESNO;
267
 
        } else {
268
 
                sieve_sys_error("%s: invalid status type '%s'", ext_name, status_type);
269
 
                return FALSE;
270
 
        }
271
 
 
272
 
        if ( max_value != NULL ) {
273
 
                switch ( ext_data->status_type ) {
274
 
                case EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN:
275
 
                case EXT_SPAMVIRUSTEST_STATUS_TYPE_VALUE:
276
 
                        if ( !ext_spamvirustest_parse_decimal_value
277
 
                                (max_value, &ext_data->max_value, &error) ) {
278
 
                                sieve_sys_error("%s: invalid max value specification "
279
 
                                        "'%s': %s", ext_name, max_value, error);
280
 
                                return FALSE;
281
 
                        }
282
 
                        break;
283
 
                case EXT_SPAMVIRUSTEST_STATUS_TYPE_YESNO:
284
 
                        ext_data->yes_string = p_strdup(ext_data->pool, max_value);
285
 
                        ext_data->max_value = 1;
286
 
                        break;
287
 
                }
288
 
        }
289
 
 
290
 
        return TRUE;
291
 
}
292
 
 
293
 
static void ext_spamvirustest_config_free(struct ext_spamvirustest_data *ext_data)
294
 
{
295
 
        ext_spamvirustest_header_spec_free(&ext_data->status_header);
296
 
        ext_spamvirustest_header_spec_free(&ext_data->max_header);
297
 
}
298
 
 
299
 
bool ext_spamvirustest_load(const struct sieve_extension *ext, void **context)
300
 
{
301
 
        struct sieve_instance *svinst = ext->svinst;
302
 
        struct ext_spamvirustest_data *ext_data;
303
 
        const char *status_header, *max_header, *status_type, *max_value;
304
 
        const char *ext_name;
305
256
        pool_t pool;
 
257
        bool result = TRUE;
 
258
        int reload = 0;
306
259
 
307
260
        if ( *context != NULL ) {
 
261
                reload = ext_data->reload + 1;
308
262
                ext_spamvirustest_unload(ext);
309
263
                *context = NULL;
310
264
        }
311
265
 
312
 
        /* FIXME:
313
 
         *   Prevent loading of both spamtest and spamtestplus: let these share
 
266
        /* FIXME: 
 
267
         *   Prevent loading of both spamtest and spamtestplus: let these share 
314
268
         *   contexts.
315
269
         */
316
270
 
317
 
        if ( sieve_extension_is(ext, spamtest_extension) ||
 
271
        if ( sieve_extension_is(ext, spamtest_extension) || 
318
272
                sieve_extension_is(ext, spamtestplus_extension) ) {
319
273
                ext_name = spamtest_extension.name;
320
274
        } else {
325
279
 
326
280
        status_header = sieve_setting_get
327
281
                (svinst, t_strconcat("sieve_", ext_name, "_status_header", NULL));
 
282
        status_type = sieve_setting_get
 
283
                (svinst, t_strconcat("sieve_", ext_name, "_status_type", NULL));
328
284
        max_header = sieve_setting_get
329
285
                (svinst, t_strconcat("sieve_", ext_name, "_max_header", NULL));
330
 
        status_type = sieve_setting_get
331
 
                (svinst, t_strconcat("sieve_", ext_name, "_status_type", NULL));
332
286
        max_value = sieve_setting_get
333
287
                (svinst, t_strconcat("sieve_", ext_name, "_max_value", NULL));
334
288
 
 
289
        /* Base configuration */
 
290
 
 
291
        if ( status_header == NULL ) {
 
292
                return TRUE;
 
293
        }
 
294
 
 
295
        if ( status_type == NULL || strcmp(status_type, "score") == 0 ) {
 
296
                type = EXT_SPAMVIRUSTEST_STATUS_TYPE_SCORE;
 
297
        } else if ( strcmp(status_type, "strlen") == 0 ) {
 
298
                type = EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN;
 
299
        } else if ( strcmp(status_type, "text") == 0 ) {
 
300
                type = EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT;
 
301
        } else {
 
302
                sieve_sys_error("%s: invalid status type '%s'", ext_name, status_type);
 
303
                return FALSE;
 
304
        }
 
305
 
335
306
        /* Verify settings */
336
307
 
337
 
        if ( status_header == NULL ) {
338
 
                return TRUE;
339
 
        }
340
 
 
341
 
        if ( max_header != NULL && max_value != NULL ) {
342
 
                sieve_sys_error("%s: sieve_%s_max_header and sieve_%s_max_value "
343
 
                        "cannot both be configured", ext_name, ext_name, ext_name);
344
 
                return TRUE;
345
 
        }
346
 
 
347
 
        if ( max_header == NULL && max_value == NULL ) {
348
 
                sieve_sys_error("%s: none of sieve_%s_max_header or sieve_%s_max_value "
349
 
                        "is configured", ext_name, ext_name, ext_name);
350
 
                return TRUE;
351
 
        }
352
 
 
353
 
        /* Pre-process configuration */
 
308
        if ( type != EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT ) {
 
309
 
 
310
                if ( max_header != NULL && max_value != NULL ) {
 
311
                        sieve_sys_error("%s: sieve_%s_max_header and sieve_%s_max_value "
 
312
                                "cannot both be configured", ext_name, ext_name, ext_name);
 
313
                        return TRUE;
 
314
                }
 
315
 
 
316
                if ( max_header == NULL && max_value == NULL ) {
 
317
                        sieve_sys_error("%s: none of sieve_%s_max_header or sieve_%s_max_value "
 
318
                                "is configured", ext_name, ext_name, ext_name);
 
319
                        return TRUE;
 
320
                }
 
321
        } else {
 
322
                if ( max_header != NULL ) {
 
323
                        sieve_sys_warning("%s: setting sieve_%s_max_header has no meaning "
 
324
                                "for sieve_%s_status_type=text", ext_name, ext_name, ext_name);
 
325
                }
 
326
 
 
327
                if ( max_value != NULL ) {
 
328
                        sieve_sys_warning("%s: setting sieve_%s_max_value has no meaning "
 
329
                                "for sieve_%s_status_type=text", ext_name, ext_name, ext_name);
 
330
                }       
 
331
        }
354
332
 
355
333
        pool = pool_alloconly_create("spamvirustest_data", 512);
356
334
        ext_data = p_new(pool, struct ext_spamvirustest_data, 1);
357
335
        ext_data->pool = pool;
358
 
 
359
 
        if ( !ext_spamvirustest_config_load
360
 
                (ext_data, ext_name, status_header, max_header, status_type, max_value) ) {
 
336
        ext_data->reload = reload;
 
337
        ext_data->status_type = type;
 
338
 
 
339
        if ( !ext_spamvirustest_header_spec_parse
 
340
                (&ext_data->status_header, ext_data->pool, status_header, &error) ) {
 
341
                sieve_sys_error("%s: invalid status header specification "
 
342
                        "'%s': %s", ext_name, status_header, error);
 
343
                result = FALSE;
 
344
        }
 
345
 
 
346
        if ( result ) {
 
347
                if ( type != EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT ) {
 
348
                        /* Parse max header */
 
349
 
 
350
                        if ( max_header != NULL && !ext_spamvirustest_header_spec_parse
 
351
                                (&ext_data->max_header, ext_data->pool, max_header, &error) ) {
 
352
                                sieve_sys_error("%s: invalid max header specification "
 
353
                                        "'%s': %s", ext_name, max_header, error);
 
354
                                result = FALSE;
 
355
                        }
 
356
        
 
357
                        /* Parse max value */
 
358
 
 
359
                        if ( result && max_value != NULL ) {
 
360
                                if ( !ext_spamvirustest_parse_decimal_value
 
361
                                        (max_value, &ext_data->max_value, &error) ) {
 
362
                                        sieve_sys_error("%s: invalid max value specification "
 
363
                                                "'%s': %s", ext_name, max_value, error);
 
364
                                        result = FALSE;
 
365
                                }
 
366
                        }
 
367
 
 
368
                } else {
 
369
                        unsigned int i, max_text;
 
370
                
 
371
                        max_text = ( sieve_extension_is(ext, virustest_extension) ? 5 : 10 );
 
372
 
 
373
                        /* Get text values */
 
374
                        for ( i = 0; i <= max_text; i++ ) {
 
375
                                const char *value = sieve_setting_get
 
376
                                        (svinst, t_strdup_printf("sieve_%s_text_value%d", ext_name, i));                        
 
377
 
 
378
                                if ( value != NULL && *value != '\0' )
 
379
                                        ext_data->text_values[i] = p_strdup(ext_data->pool, value);
 
380
                        }
 
381
 
 
382
                        ext_data->max_value = 1;
 
383
                }
 
384
        }
 
385
 
 
386
        if ( result ) {
 
387
                *context = (void *) ext_data;
 
388
        } else {
361
389
                sieve_sys_warning("%s: extension not configured, "
362
390
                        "tests will always match against \"0\"", ext_name);
363
 
                ext_spamvirustest_config_free(ext_data);
364
 
                pool_unref(&pool);
 
391
                ext_spamvirustest_unload(ext);
365
392
                *context = NULL;
366
 
        } else {
367
 
                *context = (void *) ext_data;
368
393
        }
369
394
 
370
 
        return TRUE;
 
395
        return result;
371
396
}
372
397
 
373
398
void ext_spamvirustest_unload(const struct sieve_extension *ext)
374
399
{
375
 
        struct ext_spamvirustest_data *ext_data =
 
400
        struct ext_spamvirustest_data *ext_data = 
376
401
                (struct ext_spamvirustest_data *) ext->context;
377
 
 
 
402
        
378
403
        if ( ext_data != NULL ) {
379
404
                ext_spamvirustest_header_spec_free(&ext_data->status_header);
380
405
                ext_spamvirustest_header_spec_free(&ext_data->max_header);
381
 
 
382
406
                pool_unref(&ext_data->pool);
383
407
        }
384
408
}
385
409
 
386
410
/*
387
 
 * Score extraction
 
411
 * Runtime
388
412
 */
389
413
 
 
414
struct ext_spamvirustest_message_context {
 
415
        int reload;
 
416
        float score_ratio;
 
417
};
 
418
 
 
419
static const char *ext_spamvirustest_get_score
 
420
(const struct sieve_extension *ext, float score_ratio, bool percent)
 
421
{
 
422
        int score;
 
423
 
 
424
        if ( score_ratio < 0 )
 
425
                return "0";
 
426
 
 
427
        if ( score_ratio > 1 )
 
428
                score_ratio = 1;
 
429
 
 
430
        if ( percent )
 
431
                score = score_ratio * 100 + 0.001;
 
432
        else if ( sieve_extension_is(ext, virustest_extension) )
 
433
                score = score_ratio * 4 + 1.001;
 
434
        else
 
435
                score = score_ratio * 9 + 1.001;
 
436
 
 
437
        return t_strdup_printf("%d", score); 
 
438
}
 
439
 
390
440
const char *ext_spamvirustest_get_value
391
441
(const struct sieve_runtime_env *renv, const struct sieve_extension *ext,
392
442
         bool percent)
393
443
{
394
 
        static const char *VALUE_FAILED = "0";
395
 
        struct ext_spamvirustest_data *ext_data =
396
 
                (struct ext_spamvirustest_data *) ext->context;
 
444
        struct ext_spamvirustest_data *ext_data = 
 
445
                (struct ext_spamvirustest_data *) ext->context; 
397
446
        struct ext_spamvirustest_header_spec *status_header, *max_header;
398
447
        const struct sieve_message_data *msgdata = renv->msgdata;
 
448
        struct sieve_message_context *msgctx = renv->msgctx;
 
449
        struct ext_spamvirustest_message_context *mctx;
399
450
        const char *ext_name = sieve_extension_name(ext);
400
451
        regmatch_t match_values[2];
401
452
        const char *header_value, *error;
402
 
        const char *status = NULL, *max = NULL, *yes = NULL;
 
453
        const char *status = NULL, *max = NULL;
403
454
        float status_value, max_value;
404
 
        int value;
 
455
        unsigned int i, max_text;
 
456
        pool_t pool = sieve_interpreter_pool(renv->interp);
405
457
 
406
 
        /*
407
 
         * Check whether extension is properly configured
 
458
        /* 
 
459
         * Check whether extension is properly configured 
408
460
         */
409
461
        if ( ext_data == NULL ) {
410
462
                sieve_runtime_trace(renv, "%s: extension not configured", ext_name);
411
 
                return VALUE_FAILED;
412
 
        }
 
463
                return "0";
 
464
        }
 
465
 
 
466
        /*
 
467
         * Check wether a cached result is available
 
468
         */
 
469
        
 
470
        mctx =  (struct ext_spamvirustest_message_context *)
 
471
                sieve_message_context_extension_get(msgctx, ext);
 
472
 
 
473
        if ( mctx == NULL ) {
 
474
                mctx = p_new(pool, struct ext_spamvirustest_message_context, 1);
 
475
                sieve_message_context_extension_set(msgctx, ext, (void *)mctx);
 
476
        } else if ( mctx->reload == ext_data->reload ) {
 
477
                return ext_spamvirustest_get_score(ext, mctx->score_ratio, percent);            
 
478
        }
 
479
 
 
480
        mctx->reload = ext_data->reload;
 
481
 
 
482
        /*
 
483
         * Get max status value
 
484
         */             
413
485
 
414
486
        status_header = &ext_data->status_header;
415
487
        max_header = &ext_data->max_header;
416
488
 
417
 
        /*
418
 
         * Get max status value
419
 
         */
420
 
 
421
 
        if ( max_header->header_name != NULL ) {
422
 
                /* Get header from message */
423
 
                if ( mail_get_first_header_utf8
424
 
                        (msgdata->mail, max_header->header_name, &header_value) < 0 ||
425
 
                        header_value == NULL ) {
426
 
                        sieve_runtime_trace(renv, "%s: header '%s' not found in message",
427
 
                                ext_name, max_header->header_name);
428
 
                        return VALUE_FAILED;
429
 
                }
430
 
 
431
 
                if ( max_header->regexp_match ) {
432
 
                        /* Execute regex */
433
 
                        if ( regexec(&max_header->regexp, header_value, 2, match_values, 0)
434
 
                                != 0 ) {
435
 
                                sieve_runtime_trace(renv, "%s: regexp for header '%s' did not match "
436
 
                                        "on value '%s'", ext_name, max_header->header_name, header_value);
437
 
                                return VALUE_FAILED;
438
 
                        }
439
 
 
440
 
                        max = _regexp_match_get_value(header_value, 1, match_values, 2);
441
 
                        if ( max == NULL ) {
442
 
                                sieve_runtime_trace(renv, "%s: regexp did not return match value "
443
 
                                        "for string '%s'", ext_name, header_value);
444
 
                                return VALUE_FAILED;
445
 
                        }
446
 
                } else {
447
 
                        max = header_value;
448
 
                }
449
 
 
450
 
                switch ( ext_data->status_type ) {
451
 
                case EXT_SPAMVIRUSTEST_STATUS_TYPE_VALUE:
452
 
                case EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN:
 
489
        if ( ext_data->status_type != EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT ) {
 
490
                if ( max_header->header_name != NULL ) {
 
491
                        /* Get header from message */
 
492
                        if ( mail_get_first_header_utf8
 
493
                                (msgdata->mail, max_header->header_name, &header_value) < 0 ||
 
494
                                header_value == NULL ) {
 
495
                                sieve_runtime_trace(renv, "%s: header '%s' not found in message", 
 
496
                                        ext_name, max_header->header_name);
 
497
                                goto failed;
 
498
                        } 
 
499
 
 
500
                        if ( max_header->regexp_match ) {
 
501
                                /* Execute regex */
 
502
                                if ( regexec(&max_header->regexp, header_value, 2, match_values, 0) 
 
503
                                        != 0 ) {
 
504
                                        sieve_runtime_trace(renv, "%s: regexp for header '%s' did not match "
 
505
                                                "on value '%s'", ext_name, max_header->header_name, header_value);
 
506
                                        goto failed;
 
507
                                }
 
508
 
 
509
                                max = _regexp_match_get_value(header_value, 1, match_values, 2);
 
510
                                if ( max == NULL ) {
 
511
                                        sieve_runtime_trace(renv, "%s: regexp did not return match value "
 
512
                                                "for string '%s'", ext_name, header_value);
 
513
                                        goto failed;
 
514
                                }
 
515
                        } else {
 
516
                                max = header_value;
 
517
                        }
 
518
 
453
519
                        if ( !ext_spamvirustest_parse_decimal_value(max, &max_value, &error) ) {
454
 
                                sieve_runtime_trace(renv, "%s: failed to parse maximum value: %s",
 
520
                                sieve_runtime_trace(renv, "%s: failed to parse maximum value: %s", 
455
521
                                        ext_name, error);
456
 
                                return VALUE_FAILED;
 
522
                                goto failed;
457
523
                        }
458
 
                        break;
459
 
                case EXT_SPAMVIRUSTEST_STATUS_TYPE_YESNO:
460
 
                        yes = max;
461
 
                        max_value = 1;
462
 
                        break;
 
524
                } else {
 
525
                        max_value = ext_data->max_value;
 
526
                }
 
527
 
 
528
                if ( max_value == 0 ) {
 
529
                        sieve_runtime_trace(renv, "%s: max value is 0", ext_name);
 
530
                        goto failed;
463
531
                }
464
532
        } else {
465
 
                yes = ext_data->yes_string;
466
 
                max_value = ext_data->max_value;
467
 
        }
468
 
 
469
 
        if ( max_value == 0 ) {
470
 
                sieve_runtime_trace(renv, "%s: max value is 0", ext_name);
471
 
                return VALUE_FAILED;
 
533
                max_value = ( sieve_extension_is(ext, virustest_extension) ? 5 : 10 );
472
534
        }
473
535
 
474
536
        /*
479
541
        if ( mail_get_first_header_utf8
480
542
                (msgdata->mail, status_header->header_name, &header_value) < 0 ||
481
543
                header_value == NULL ) {
482
 
                sieve_runtime_trace(renv, "%s: header '%s' not found in message",
 
544
                sieve_runtime_trace(renv, "%s: header '%s' not found in message", 
483
545
                        ext_name, status_header->header_name);
484
 
                return VALUE_FAILED;
 
546
                goto failed;
485
547
        }
486
548
 
487
549
        /* Execute regex */
488
550
        if ( status_header->regexp_match ) {
489
 
                if ( regexec(&status_header->regexp, header_value, 2, match_values, 0)
 
551
                if ( regexec(&status_header->regexp, header_value, 2, match_values, 0) 
490
552
                        != 0 ) {
491
553
                        sieve_runtime_trace(renv, "%s: regexp for header '%s' did not match "
492
554
                                "on value '%s'", ext_name, status_header->header_name, header_value);
493
 
                        return VALUE_FAILED;
494
 
                }
495
 
 
 
555
                        goto failed;
 
556
                } 
 
557
                
496
558
                status = _regexp_match_get_value(header_value, 1, match_values, 2);
497
559
                if ( status == NULL ) {
498
560
                        sieve_runtime_trace(renv, "%s: regexp did not return match value "
499
561
                                "for string '%s'", ext_name, header_value);
500
 
                        return VALUE_FAILED;
 
562
                        goto failed;
501
563
                }
502
564
        } else {
503
565
                status = header_value;
504
566
        }
505
567
 
506
568
        switch ( ext_data->status_type ) {
507
 
        case EXT_SPAMVIRUSTEST_STATUS_TYPE_VALUE:
508
 
                if ( !ext_spamvirustest_parse_decimal_value(status, &status_value, &error)
509
 
                        ) {
510
 
                        sieve_runtime_trace(renv, "%s: failed to parse status value '%s': %s",
 
569
        case EXT_SPAMVIRUSTEST_STATUS_TYPE_SCORE:
 
570
                if ( !ext_spamvirustest_parse_decimal_value
 
571
                        (status, &status_value, &error) ) {
 
572
                        sieve_runtime_trace(renv, "%s: failed to parse status value '%s': %s", 
511
573
                                ext_name, status, error);
512
 
                        return VALUE_FAILED;
 
574
                        goto failed;
513
575
                }
514
576
                break;
515
577
        case EXT_SPAMVIRUSTEST_STATUS_TYPE_STRLEN:
516
 
                if ( !ext_spamvirustest_parse_strlen_value(status, &status_value, &error)
517
 
                        ) {
518
 
                        sieve_runtime_trace(renv, "%s: failed to parse status value '%s': %s",
 
578
                if ( !ext_spamvirustest_parse_strlen_value
 
579
                        (status, &status_value, &error) ) {
 
580
                        sieve_runtime_trace(renv, "%s: failed to parse status value '%s': %s", 
519
581
                                ext_name, status, error);
520
 
                        return VALUE_FAILED;
521
 
                }
522
 
                break;
523
 
        case EXT_SPAMVIRUSTEST_STATUS_TYPE_YESNO:
524
 
                if ( strcmp(status, yes) == 0 )
525
 
                        status_value = 1;
526
 
                else
527
 
                        status_value = 0;
 
582
                        goto failed;
 
583
                }
 
584
                break;
 
585
        case EXT_SPAMVIRUSTEST_STATUS_TYPE_TEXT:
 
586
                max_text = ( sieve_extension_is(ext, virustest_extension) ? 5 : 10 );
 
587
                status_value = 0;
 
588
 
 
589
                i = 0; 
 
590
                while ( i <= max_text ) {
 
591
                        if ( ext_data->text_values[i] != NULL &&
 
592
                                strcmp(status, ext_data->text_values[i]) == 0 ) {
 
593
                                status_value = (float) i;
 
594
                                break;
 
595
                        }
 
596
                        i++;
 
597
                }
 
598
 
 
599
                if ( i > max_text ) {
 
600
                        sieve_runtime_trace(renv, "%s: failed to match textstatus value '%s'", 
 
601
                                ext_name, status);
 
602
                        goto failed;    
 
603
                }               
 
604
                break;
 
605
        default:
 
606
                i_unreached();
528
607
                break;
529
608
        }
530
 
 
 
609
        
531
610
        /* Calculate value */
532
 
        if ( status_value < 0 ) {
533
 
                value = 1;
534
 
        } else if ( status_value > max_value ) {
535
 
                if ( percent )
536
 
                        value = 100;
537
 
                else
538
 
                        value = 10;
539
 
        } else {
540
 
                if ( percent )
541
 
                        value = (status_value / max_value) * 99 + 1;
542
 
                else
543
 
                        value = (status_value / max_value) * 9 + 1;
544
 
        }
545
 
 
546
 
        return t_strdup_printf("%d", value);;
 
611
        if ( status_value < 0 )
 
612
                mctx->score_ratio = 0;
 
613
        else if ( status_value > max_value )
 
614
                mctx->score_ratio = 1;
 
615
        else
 
616
                mctx->score_ratio = (status_value / max_value);
 
617
 
 
618
        return ext_spamvirustest_get_score(ext, mctx->score_ratio, percent);
 
619
 
 
620
failed:
 
621
        mctx->score_ratio = -1;
 
622
        return "0";
547
623
}
548
624
 
549
625