~james-page/ubuntu/raring/dovecot/autopkgtest

« back to all changes in this revision

Viewing changes to pigeonhole/src/sieve-tools/sieve-filter.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-06-11 11:11:54 UTC
  • mfrom: (1.15.2) (4.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120611111154-678cwbdj6ktgsv1h
Tags: 1:2.1.7-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/{control,rules}: enable PIE hardening.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + d/control: Added Pre-Depends: dpkg (>= 1.15.6) to dovecot-dbg to support
    xz compression in Ubuntu.
  + d/control: Demote dovecot-common Recommends: to Suggests: to prevent
    install of extra packages on upgrade.
  + d/patches/dovecot-drac.patch: Updated with version for dovecot >= 2.0.0.
  + d/control: Drop B-D on systemd.
* Dropped changes:
  + d/patches/fix-racey-restart.patch: part of 2.1.x, no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
        printf(
37
37
"Usage: sieve-filter [-c <config-file>] [-C] [-D] [-e] [-m <default-mailbox>]\n"
38
38
"                    [-P <plugin>] [-q <output-mailbox>] [-Q <mail-command>]\n"
39
 
"                    [-s <script-file>] [-u <user>] [-W] [-x <extensions>]\n"
40
 
"                    <script-file> <source-mailbox> <source-action>\n"
 
39
"                    [-s <script-file>] [-u <user>] [-v] [-W] [-x <extensions>]\n"
 
40
"                    <script-file> <source-mailbox> [<discard-action>]\n"
41
41
        );
42
42
}
43
43
 
44
 
enum sieve_filter_source_action {
45
 
        SIEVE_FILTER_SACT_KEEP,          /* Always keep messages in source folder */ 
46
 
        SIEVE_FILTER_SACT_MOVE,          /* Move discarded messages to Trash folder */      
47
 
        SIEVE_FILTER_SACT_DELETE,        /* Flag discarded messages as \DELETED */
48
 
        SIEVE_FILTER_SACT_EXPUNGE        /* Expunge discarded messages */
 
44
enum sieve_filter_discard_action {
 
45
        SIEVE_FILTER_DACT_KEEP,        /* Keep discarded messages in source folder */ 
 
46
        SIEVE_FILTER_DACT_MOVE,        /* Move discarded messages to Trash folder */      
 
47
        SIEVE_FILTER_DACT_DELETE,      /* Flag discarded messages as \DELETED */
 
48
        SIEVE_FILTER_DACT_EXPUNGE      /* Expunge discarded messages */
49
49
};
50
50
 
51
51
struct sieve_filter_data {
52
 
        enum sieve_filter_source_action source_action;
 
52
        enum sieve_filter_discard_action discard_action;
53
53
        struct mailbox *move_mailbox;
54
54
 
55
55
        struct sieve_script_env *senv;
58
58
 
59
59
        unsigned int execute:1;
60
60
        unsigned int source_write:1;
61
 
        unsigned int move_mode:1;
62
61
};
63
62
 
64
63
struct sieve_filter_context {
77
76
        struct sieve_exec_status estatus;
78
77
        struct sieve_binary *sbin;
79
78
        struct sieve_message_data msgdata;
80
 
        const char *recipient, *sender;
 
79
        const char *recipient = NULL, *sender = NULL;
81
80
        bool execute = sfctx->data->execute;
82
81
        bool source_write = sfctx->data->source_write;
83
 
        bool move_mode = sfctx->data->move_mode;
 
82
        const char *subject, *date;
 
83
        uoff_t size = 0;
84
84
        int ret;
85
85
 
86
86
        sieve_tool_get_envelope_data(mail, &recipient, &sender);
97
97
        msgdata.final_envelope_to = recipient;
98
98
        msgdata.auth_user = senv->username;
99
99
        (void)mail_get_first_header(mail, "Message-ID", &msgdata.id);
 
100
                                        
 
101
        if ( mail_get_virtual_size(mail, &size) < 0 ) {
 
102
                if ( mail->expunged )
 
103
                        return 1;
 
104
                
 
105
                sieve_error(ehandler, NULL, "failed to obtain message size; "
 
106
                        "skipping this message (id=%s)", 
 
107
                        ( msgdata.id == NULL ? "none" : msgdata.id ));
 
108
                return 0;
 
109
        }
 
110
 
 
111
        if ( mail_get_first_header(mail, "date", &date) <= 0 )
 
112
                date = "";
 
113
        if ( mail_get_first_header(mail, "subject", &subject) <= 0 ) 
 
114
                subject = "";
100
115
 
101
116
        /* Single script */
102
117
        sbin = sfctx->data->main_sbin;
103
118
 
104
119
        /* Execute script */
105
120
        if ( execute ) {
106
 
                ret = sieve_execute(sbin, &msgdata, senv, ehandler, NULL);
 
121
                sieve_info(ehandler, NULL,
 
122
                        "filtering: [%s; %"PRIuUOFF_T" bytes] `%s'", date, size,
 
123
                        str_sanitize(subject, 40));
 
124
 
 
125
                ret = sieve_execute(sbin, &msgdata, senv, ehandler, 0, NULL);
107
126
        } else {
 
127
                (void)o_stream_send_str(sfctx->teststream,
 
128
                        t_strdup_printf(">> Filtering message:\n\n"
 
129
                                "  ID:      %s\n"
 
130
                          "  Date:    %s\n"
 
131
        "  Size:    %"PRIuUOFF_T" bytes\n"
 
132
                                "  Subject: %s\n", ( msgdata.id == NULL ? "none" : msgdata.id ),
 
133
                                date, size, str_sanitize(subject, 40)));
 
134
 
108
135
                ret = sieve_test
109
 
                        (sbin, &msgdata, senv, ehandler, sfctx->teststream, NULL);
 
136
                        (sbin, &msgdata, senv, ehandler, sfctx->teststream, 0, NULL);
110
137
        }
111
138
 
112
139
        /* Handle message in source folder */
113
140
        if ( ret > 0 ) {
114
141
                struct mailbox *move_box = sfctx->data->move_mailbox;
115
 
                enum sieve_filter_source_action source_action =
116
 
                        sfctx->data->source_action;
 
142
                enum sieve_filter_discard_action discard_action =
 
143
                        sfctx->data->discard_action;
117
144
 
118
145
                if ( !source_write ) {
119
 
                        /* Do nothing */
 
146
                        /* READ-ONLY; Do nothing */
120
147
 
121
148
                } else if ( estatus.keep_original  ) {
 
149
                        /* Explicitly `stored' in source box; just keep it there */
122
150
                        sieve_info(ehandler, NULL, "message kept in source mailbox");
123
151
 
124
 
                } else if ( move_mode && estatus.message_saved ) {
 
152
                } else if ( estatus.message_saved ) {
125
153
                        sieve_info(ehandler, NULL,
126
154
                                "message expunged from source mailbox upon successful move");
127
155
 
129
157
                                mail_expunge(mail);
130
158
 
131
159
                } else {
132
 
                        switch ( source_action ) {
 
160
 
 
161
                        switch ( discard_action ) {
133
162
                        /* Leave it there */
134
 
                        case SIEVE_FILTER_SACT_KEEP:
 
163
                        case SIEVE_FILTER_DACT_KEEP:
135
164
                                sieve_info(ehandler, NULL, "message left in source mailbox");
136
165
                                break;
137
166
                        /* Move message to indicated folder */
138
 
                        case SIEVE_FILTER_SACT_MOVE:                    
 
167
                        case SIEVE_FILTER_DACT_MOVE:                    
139
168
                                sieve_info(ehandler, NULL, 
140
169
                                        "message in source mailbox moved to mailbox '%s'",
141
170
                                        mailbox_get_name(move_box));
144
173
                                        struct mailbox_transaction_context *t = sfctx->move_trans;
145
174
                                        struct mail_save_context *save_ctx;
146
175
        
147
 
                                    save_ctx = mailbox_save_alloc(t);
 
176
                                        save_ctx = mailbox_save_alloc(t);
148
177
 
149
178
                                        if ( mailbox_copy(&save_ctx, mail) < 0 ) {
150
179
                                                enum mail_error error;
163
192
                                }
164
193
                                break;
165
194
                        /* Flag message as \DELETED */
166
 
                        case SIEVE_FILTER_SACT_DELETE:                                  
 
195
                        case SIEVE_FILTER_DACT_DELETE:                                  
167
196
                                sieve_info(ehandler, NULL, "message flagged as deleted in source mailbox");
168
197
                                if ( execute )
169
198
                                        mail_update_flags(mail, MODIFY_ADD, MAIL_DELETED);
170
199
                                break;
171
200
                        /* Expunge the message immediately */
172
 
                        case SIEVE_FILTER_SACT_EXPUNGE:
 
201
                        case SIEVE_FILTER_DACT_EXPUNGE:
173
202
                                sieve_info(ehandler, NULL, "message expunged from source mailbox");
174
203
                                if ( execute )
175
204
                                        mail_expunge(mail);
182
211
                }
183
212
        }
184
213
 
185
 
        return ret;
 
214
        switch ( ret ) {
 
215
        case SIEVE_EXEC_OK:
 
216
                break;
 
217
        case SIEVE_EXEC_BIN_CORRUPT:
 
218
                sieve_error(ehandler, NULL, "sieve script binary is corrupt");
 
219
                return -1;              
 
220
        case SIEVE_EXEC_FAILURE:
 
221
        case SIEVE_EXEC_KEEP_FAILED:
 
222
                sieve_error(ehandler, NULL,
 
223
                        "sieve script execution failed for this message; "
 
224
                        "message left in source mailbox");
 
225
                return 0;
 
226
        default:
 
227
                sieve_error(ehandler, NULL,
 
228
                        "sieve execution result: unrecognized return value?!"); 
 
229
                return -1;
 
230
        }
 
231
 
 
232
        return 1;
186
233
}
187
234
 
188
235
/* FIXME: introduce this into Dovecot */
194
241
        arg = p_new(args->pool, struct mail_search_arg, 1);
195
242
        arg->type = SEARCH_FLAGS;
196
243
        arg->value.flags = flags;
197
 
        arg->not = not;
 
244
        arg->match_not = not;
198
245
 
199
246
        arg->next = args->args;
200
247
        args->args = arg;
241
288
        mail_search_build_add_flags(search_args, MAIL_DELETED, TRUE);
242
289
 
243
290
        t = mailbox_transaction_begin(src_box, 0);
244
 
        search_ctx = mailbox_search_init(t, search_args, NULL);
 
291
        search_ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
245
292
        mail_search_args_unref(&search_args);
246
293
 
247
294
        /* Iterate through all requested messages */
248
295
 
249
 
        mail = mail_alloc(t, 0, NULL);
250
 
        while ( ret > 0 && mailbox_search_next(search_ctx, mail) > 0 ) {
251
 
                const char *subject, *date;
252
 
                uoff_t size = 0;
253
 
                                        
254
 
                /* Request message size */
255
 
 
256
 
                if ( mail_get_virtual_size(mail, &size) < 0 ) {
257
 
                        if ( mail->expunged )
258
 
                                continue;
259
 
                        
260
 
                        sieve_error(ehandler, NULL, "failed to obtain message size");
261
 
                        continue;
262
 
                }
263
 
 
264
 
                if ( mail_get_first_header(mail, "date", &date) <= 0 )
265
 
                        date = "";
266
 
                if ( mail_get_first_header(mail, "subject", &subject) <= 0 ) 
267
 
                        subject = "";
268
 
                
269
 
                sieve_info(ehandler, NULL,
270
 
                        "filtering: [%s; %"PRIuUOFF_T" bytes] %s", date, size,
271
 
                        str_sanitize(subject, 40));
272
 
        
 
296
        while ( ret >= 0 && mailbox_search_next(search_ctx, &mail) > 0 ) {
273
297
                ret = filter_message(&sfctx, mail);
274
298
        }
275
 
        mail_free(&mail);
276
299
        
277
300
        /* Cleanup */
278
301
 
281
304
        }
282
305
 
283
306
        if ( sfctx.move_trans != NULL ) {
284
 
                if ( ret < 0 ) {
285
 
                        mailbox_transaction_rollback(&sfctx.move_trans);
286
 
                } else {
287
 
                        if ( mailbox_transaction_commit(&sfctx.move_trans) < 0 ) {
288
 
                                ret = -1;
289
 
                        }
290
 
                }
291
 
        }
292
 
 
293
 
        if ( ret < 0 ) {
294
 
                mailbox_transaction_rollback(&t);
295
 
        } else {
296
 
                if ( mailbox_transaction_commit(&t) < 0 ) {
 
307
                if ( mailbox_transaction_commit(&sfctx.move_trans) < 0 ) {
297
308
                        ret = -1;
298
309
                }
299
310
        }
300
311
 
 
312
        if ( mailbox_transaction_commit(&t) < 0 ) {
 
313
                ret = -1;
 
314
        }
 
315
 
301
316
        if ( sfctx.teststream != NULL )
302
317
                o_stream_destroy(&sfctx.teststream);
303
318
 
335
350
        ARRAY_TYPE (const_string) scriptfiles;
336
351
        const char *scriptfile, *src_mailbox, *dst_mailbox, *move_mailbox;
337
352
        struct sieve_filter_data sfdata;
338
 
        enum sieve_filter_source_action source_action = SIEVE_FILTER_SACT_KEEP;
 
353
        enum sieve_filter_discard_action discard_action = SIEVE_FILTER_DACT_KEEP;
339
354
        struct mail_user *mail_user;
340
355
        struct sieve_binary *main_sbin;
341
356
        struct sieve_script_env scriptenv;
342
357
        struct sieve_error_handler *ehandler;
343
 
        bool force_compile, execute, source_write, move_mode;
 
358
        bool force_compile, execute, source_write, verbose;
344
359
        struct mail_namespace *ns;
345
360
        struct mailbox *src_box = NULL, *move_box = NULL;
346
 
        enum mailbox_flags open_flags =
347
 
                MAILBOX_FLAG_KEEP_RECENT | MAILBOX_FLAG_IGNORE_ACLS;
 
361
        enum mailbox_flags open_flags = MAILBOX_FLAG_IGNORE_ACLS;
348
362
        enum mail_error error;
349
363
        int c;
350
364
 
351
365
        sieve_tool = sieve_tool_init("sieve-filter", &argc, &argv, 
352
 
                "m:s:x:P:u:q:Q:DCeWM", FALSE);
 
366
                "m:s:x:P:u:q:Q:DCevW", FALSE);
353
367
 
354
368
        t_array_init(&scriptfiles, 16);
355
369
 
356
370
        /* Parse arguments */
357
371
        scriptfile =  NULL;
358
372
        src_mailbox = dst_mailbox = move_mailbox = NULL;
359
 
        force_compile = execute = source_write = move_mode = FALSE;
 
373
        force_compile = execute = source_write = verbose = FALSE;
360
374
        while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
361
375
                switch (c) {
362
376
                case 'm':
392
406
                        /* force script compile */
393
407
                        force_compile = TRUE;
394
408
                        break;
395
 
                case 'M':
396
 
                        /* move mode */
397
 
                        move_mode = TRUE;
398
 
                        break;
399
409
                case 'W':
400
410
                        /* enable source mailbox write */
401
411
                        source_write = TRUE;
402
412
                        break;
 
413
                case 'v':
 
414
                        /* enable verbose output */
 
415
                        verbose = TRUE;
 
416
                        break;
403
417
                default:
404
418
                        /* unrecognized option */
405
419
                        print_help();
429
443
                const char *srcact = argv[optind++];
430
444
 
431
445
                if ( strcmp(srcact, "keep") == 0 ) {
432
 
                        source_action = SIEVE_FILTER_SACT_KEEP;
 
446
                        discard_action = SIEVE_FILTER_DACT_KEEP;
433
447
                } else if ( strcmp(srcact, "move") == 0 ) {
434
 
                        source_action = SIEVE_FILTER_SACT_MOVE;
 
448
                        discard_action = SIEVE_FILTER_DACT_MOVE;
435
449
                        if ( optind < argc ) {
436
450
                                move_mailbox = t_strdup(argv[optind++]);
437
451
                        } else {
438
452
                                print_help();
439
453
                                i_fatal_status(EX_USAGE,
440
 
                                        "Invalid <source-action> argument: "
 
454
                                        "Invalid <discard-action> argument: "
441
455
                                        "the `move' action requires mailbox argument");
442
456
                        }
443
 
                } else if ( strcmp(srcact, "flag") == 0 ) {
444
 
                        source_action = SIEVE_FILTER_SACT_DELETE;
 
457
                } else if ( strcmp(srcact, "delete") == 0 ) {
 
458
                        discard_action = SIEVE_FILTER_DACT_DELETE;
445
459
                } else if ( strcmp(srcact, "expunge") == 0 ) {
446
 
                        source_action = SIEVE_FILTER_SACT_EXPUNGE;
 
460
                        discard_action = SIEVE_FILTER_DACT_EXPUNGE;
447
461
                } else {
448
462
                        print_help();
449
 
                        i_fatal_status(EX_USAGE, "Invalid <source-action> argument");
 
463
                        i_fatal_status(EX_USAGE, "Invalid <discard-action> argument");
450
464
                }
451
465
        } 
452
466
 
462
476
        /* Finish tool initialization */
463
477
        svinst = sieve_tool_init_finish(sieve_tool, TRUE);
464
478
 
465
 
        /* Enable debug extension */
466
 
        sieve_enable_debug_extension(svinst);
 
479
        /* Enable debug extension */
 
480
        sieve_enable_debug_extension(svinst);
467
481
 
468
482
        /* Create error handler */
469
483
        ehandler = sieve_stderr_ehandler_create(svinst, 0);
470
484
        sieve_system_ehandler_set(ehandler);
471
 
        sieve_error_handler_accept_infolog(ehandler, TRUE);
 
485
        sieve_error_handler_accept_infolog(ehandler, verbose);
472
486
 
473
487
        /* Compile main sieve script */
474
488
        if ( force_compile ) {
485
499
        /* Open the source mailbox */   
486
500
 
487
501
        src_mailbox = mailbox_name_to_mutf7(src_mailbox);
488
 
        ns = mail_namespace_find(mail_user->namespaces, &src_mailbox);
 
502
        ns = mail_namespace_find(mail_user->namespaces, src_mailbox);
489
503
        if ( ns == NULL )
490
504
                i_fatal("Unknown namespace for source mailbox '%s'", src_mailbox);
491
505
 
500
514
        
501
515
        /* Open move box if necessary */
502
516
 
503
 
        if ( execute && source_action == SIEVE_FILTER_SACT_MOVE &&
 
517
        if ( execute && discard_action == SIEVE_FILTER_DACT_MOVE &&
504
518
                move_mailbox != NULL ) {
505
519
                move_mailbox = mailbox_name_to_mutf7(move_mailbox);
506
 
                ns = mail_namespace_find(mail_user->namespaces, &move_mailbox);
 
520
                ns = mail_namespace_find(mail_user->namespaces, move_mailbox);
507
521
                if ( ns == NULL )
508
522
                        i_fatal("Unknown namespace for mailbox '%s'", move_mailbox);
509
523
 
532
546
        /* Compose filter context */
533
547
        memset(&sfdata, 0, sizeof(sfdata));
534
548
        sfdata.senv = &scriptenv;
535
 
        sfdata.source_action = source_action;
 
549
        sfdata.discard_action = discard_action;
536
550
        sfdata.move_mailbox = move_box;
537
551
        sfdata.main_sbin = main_sbin;
538
552
        sfdata.ehandler = ehandler;
539
553
        sfdata.execute = execute;
540
554
        sfdata.source_write = source_write;
541
 
        sfdata.move_mode = move_mode;
542
555
 
543
556
        /* Apply Sieve filter to all messages found */
544
557
        (void) filter_mailbox(&sfdata, src_box);