~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to pigeonhole/src/lib-sieve/cmd-redirect.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-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/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.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2012 Pigeonhole authors, see the included COPYING file
 
1
/* Copyright (c) 2002-2013 Pigeonhole authors, see the included COPYING file
2
2
 */
3
3
 
4
4
#include "lib.h"
5
5
#include "ioloop.h"
6
6
#include "str-sanitize.h"
7
7
#include "istream.h"
8
 
#include "istream-crlf.h"
9
8
#include "istream-header-filter.h"
 
9
#include "ostream.h"
10
10
 
11
11
#include "rfc2822.h"
12
12
 
17
17
#include "sieve-code.h"
18
18
#include "sieve-message.h"
19
19
#include "sieve-actions.h"
20
 
#include "sieve-validator.h" 
 
20
#include "sieve-validator.h"
21
21
#include "sieve-generator.h"
22
22
#include "sieve-interpreter.h"
23
23
#include "sieve-code-dumper.h"
27
27
 
28
28
#include <stdio.h>
29
29
 
30
 
/* 
31
 
 * Configuration 
 
30
/*
 
31
 * Configuration
32
32
 */
33
33
 
34
34
#define CMD_REDIRECT_DUPLICATE_KEEP (3600 * 24)
35
35
 
36
 
/* 
37
 
 * Redirect command 
38
 
 * 
 
36
/*
 
37
 * Redirect command
 
38
 *
39
39
 * Syntax
40
40
 *   redirect <address: string>
41
41
 */
45
45
static bool cmd_redirect_generate
46
46
        (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd);
47
47
 
48
 
const struct sieve_command_def cmd_redirect = { 
49
 
        "redirect", 
 
48
const struct sieve_command_def cmd_redirect = {
 
49
        "redirect",
50
50
        SCT_COMMAND,
51
 
        1, 0, FALSE, FALSE, 
 
51
        1, 0, FALSE, FALSE,
52
52
        NULL, NULL,
53
53
        cmd_redirect_validate,
54
54
        NULL,
55
 
        cmd_redirect_generate, 
56
 
        NULL 
 
55
        cmd_redirect_generate,
 
56
        NULL
57
57
};
58
58
 
59
 
/* 
60
 
 * Redirect operation 
 
59
/*
 
60
 * Redirect operation
61
61
 */
62
62
 
63
63
static bool cmd_redirect_operation_dump
65
65
static int cmd_redirect_operation_execute
66
66
        (const struct sieve_runtime_env *renv, sieve_size_t *address);
67
67
 
68
 
const struct sieve_operation_def cmd_redirect_operation = { 
 
68
const struct sieve_operation_def cmd_redirect_operation = {
69
69
        "REDIRECT",
70
 
        NULL, 
 
70
        NULL,
71
71
        SIEVE_OPERATION_REDIRECT,
72
 
        cmd_redirect_operation_dump, 
73
 
        cmd_redirect_operation_execute 
 
72
        cmd_redirect_operation_dump,
 
73
        cmd_redirect_operation_execute
74
74
};
75
75
 
76
 
/* 
77
 
 * Redirect action 
 
76
/*
 
77
 * Redirect action
78
78
 */
79
79
 
80
80
static bool act_redirect_equals
81
 
        (const struct sieve_script_env *senv, const struct sieve_action *act1, 
 
81
        (const struct sieve_script_env *senv, const struct sieve_action *act1,
82
82
                const struct sieve_action *act2);
83
83
static int act_redirect_check_duplicate
84
84
        (const struct sieve_runtime_env *renv,
85
 
                const struct sieve_action *act, 
 
85
                const struct sieve_action *act,
86
86
                const struct sieve_action *act_other);
87
87
static void act_redirect_print
88
88
        (const struct sieve_action *action, const struct sieve_result_print_env *rpenv,
89
 
                bool *keep);    
90
 
static bool act_redirect_commit
 
89
                bool *keep);
 
90
static int act_redirect_commit
91
91
        (const struct sieve_action *action, const struct sieve_action_exec_env *aenv,
92
92
                void *tr_context, bool *keep);
93
 
                
 
93
 
94
94
const struct sieve_action_def act_redirect = {
95
95
        "redirect",
96
96
        SIEVE_ACTFLAG_TRIES_DELIVER,
97
97
        act_redirect_equals,
98
 
        act_redirect_check_duplicate, 
 
98
        act_redirect_check_duplicate,
99
99
        NULL,
100
100
        act_redirect_print,
101
101
        NULL, NULL,
107
107
        const char *to_address;
108
108
};
109
109
 
110
 
/* 
111
 
 * Validation 
 
110
/*
 
111
 * Validation
112
112
 */
113
113
 
114
114
static bool cmd_redirect_validate
115
 
(struct sieve_validator *validator, struct sieve_command *cmd) 
 
115
(struct sieve_validator *validator, struct sieve_command *cmd)
116
116
{
117
117
        struct sieve_instance *svinst = sieve_validator_svinst(validator);
118
118
        struct sieve_ast_argument *arg = cmd->first_positional;
166
166
/*
167
167
 * Code generation
168
168
 */
169
 
 
 
169
 
170
170
static bool cmd_redirect_generate
171
 
(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) 
 
171
(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
172
172
{
173
173
        sieve_operation_emit(cgenv->sblock, NULL,  &cmd_redirect_operation);
174
174
 
176
176
        return sieve_generate_arguments(cgenv, cmd, NULL);
177
177
}
178
178
 
179
 
/* 
 
179
/*
180
180
 * Code dump
181
181
 */
182
 
 
 
182
 
183
183
static bool cmd_redirect_operation_dump
184
184
(const struct sieve_dumptime_env *denv, sieve_size_t *address)
185
185
{
213
213
         */
214
214
 
215
215
        /* Optional operands (side effects only) */
216
 
        if ( sieve_action_opr_optional_read(renv, address, NULL, &ret, &slist) != 0 ) 
 
216
        if ( sieve_action_opr_optional_read(renv, address, NULL, &ret, &slist) != 0 )
217
217
                return ret;
218
218
 
219
219
        /* Read the address */
273
273
 */
274
274
 
275
275
static bool act_redirect_equals
276
 
(const struct sieve_script_env *senv ATTR_UNUSED, 
 
276
(const struct sieve_script_env *senv ATTR_UNUSED,
277
277
        const struct sieve_action *act1, const struct sieve_action *act2)
278
278
{
279
279
        struct act_redirect_context *rd_ctx1 =
280
280
                (struct act_redirect_context *) act1->context;
281
 
        struct act_redirect_context *rd_ctx2 = 
 
281
        struct act_redirect_context *rd_ctx2 =
282
282
                (struct act_redirect_context *) act2->context;
283
283
 
284
284
        /* Address is already normalized */
285
285
        return ( sieve_address_compare
286
286
                (rd_ctx1->to_address, rd_ctx2->to_address, TRUE) == 0 );
287
287
}
288
 
 
 
288
 
289
289
static int act_redirect_check_duplicate
290
290
(const struct sieve_runtime_env *renv ATTR_UNUSED,
291
 
        const struct sieve_action *act, 
 
291
        const struct sieve_action *act,
292
292
        const struct sieve_action *act_other)
293
293
{
294
294
        return ( act_redirect_equals(renv->scriptenv, act, act_other) ? 1 : 0 );
295
295
}
296
296
 
297
297
static void act_redirect_print
298
 
(const struct sieve_action *action, 
299
 
        const struct sieve_result_print_env *rpenv, bool *keep) 
 
298
(const struct sieve_action *action,
 
299
        const struct sieve_result_print_env *rpenv, bool *keep)
300
300
{
301
 
        struct act_redirect_context *ctx = 
 
301
        struct act_redirect_context *ctx =
302
302
                (struct act_redirect_context *) action->context;
303
 
        
304
 
        sieve_result_action_printf(rpenv, "redirect message to: %s", 
 
303
 
 
304
        sieve_result_action_printf(rpenv, "redirect message to: %s",
305
305
                str_sanitize(ctx->to_address, 128));
306
 
        
 
306
 
307
307
        *keep = FALSE;
308
308
}
309
309
 
310
 
static bool act_redirect_send   
 
310
static int act_redirect_send
311
311
(const struct sieve_action_exec_env *aenv, struct mail *mail,
312
312
        struct act_redirect_context *ctx)
313
313
{
314
 
        static const char *hide_headers[] = 
 
314
        static const char *hide_headers[] =
315
315
                { "Return-Path", "X-Sieve", "X-Sieve-Redirected-From" };
316
316
 
317
317
        struct sieve_message_context *msgctx = aenv->msgctx;
318
318
        const struct sieve_script_env *senv = aenv->scriptenv;
319
319
        const char *sender = sieve_message_get_sender(msgctx);
320
320
        const char *recipient = sieve_message_get_final_recipient(msgctx);
321
 
        struct istream *input, *crlf_input;
 
321
        struct istream *input;
 
322
        struct ostream *output;
322
323
        void *smtp_handle;
323
 
        FILE *f;
324
 
        const unsigned char *data;
325
 
        size_t size;
326
 
        
 
324
 
327
325
        /* Just to be sure */
328
326
        if ( !sieve_smtp_available(senv) ) {
329
327
                sieve_result_global_warning
330
328
                        (aenv, "redirect action has no means to send mail.");
331
 
                return TRUE;
 
329
                return SIEVE_EXEC_FAILURE;
332
330
        }
333
 
        
 
331
 
334
332
        if (mail_get_stream(mail, NULL, NULL, &input) < 0)
335
 
                return FALSE;
336
 
                
 
333
                return SIEVE_EXEC_TEMP_FAILURE;
 
334
 
337
335
        /* Open SMTP transport */
338
 
        smtp_handle = sieve_smtp_open(senv, ctx->to_address, sender, &f);
 
336
        smtp_handle = sieve_smtp_open(senv, ctx->to_address, sender, &output);
339
337
 
340
338
        /* Remove unwanted headers */
341
339
        input = i_stream_create_header_filter
342
 
                (input, HEADER_FILTER_EXCLUDE, hide_headers,
343
 
                        N_ELEMENTS(hide_headers), null_header_filter_callback, NULL);
344
 
        
345
 
        /* Make sure the message contains CRLF consistently */
346
 
        crlf_input = i_stream_create_crlf(input);
347
 
 
348
 
        /* Prepend sieve headers (should not affect signatures) */
349
 
        rfc2822_header_field_write(f, "X-Sieve", SIEVE_IMPLEMENTATION);
350
 
        if ( recipient != NULL )
351
 
                rfc2822_header_field_write(f, "X-Sieve-Redirected-From", recipient);
352
 
 
353
 
        /* Pipe the message to the outgoing SMTP transport */
354
 
        while (i_stream_read_data(crlf_input, &data, &size, 0) > 0) {   
355
 
                if (fwrite(data, size, 1, f) == 0)
356
 
                        break;
357
 
                i_stream_skip(crlf_input, size);
358
 
        }
359
 
 
360
 
        // FIXME: handle stream error. Currently, we have no means to abort here.
361
 
 
362
 
        i_stream_unref(&crlf_input);
363
 
        i_stream_unref(&input);
 
340
                (input, HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR, hide_headers,
 
341
                        N_ELEMENTS(hide_headers), *null_header_filter_callback, (void *)NULL);
 
342
 
 
343
        T_BEGIN {
 
344
                string_t *hdr = t_str_new(256);
 
345
 
 
346
                /* Prepend sieve headers (should not affect signatures) */
 
347
                rfc2822_header_append(hdr, "X-Sieve", SIEVE_IMPLEMENTATION, FALSE, NULL);
 
348
                if ( recipient != NULL ) {
 
349
                        rfc2822_header_append
 
350
                                (hdr, "X-Sieve-Redirected-From", recipient, FALSE, NULL);
 
351
                }
 
352
                o_stream_send(output, str_data(hdr), str_len(hdr));
 
353
        } T_END;
 
354
 
 
355
        o_stream_send_istream(output, input);
 
356
  i_stream_unref(&input);
364
357
 
365
358
        /* Close SMTP transport */
366
359
        if ( !sieve_smtp_close(senv, smtp_handle) ) {
367
 
                sieve_result_global_error(aenv, 
 
360
                sieve_result_global_error(aenv,
368
361
                        "failed to redirect message to <%s> "
369
362
                        "(refer to server log for more information)",
370
363
                        str_sanitize(ctx->to_address, 80));
371
 
                return FALSE;
 
364
                return SIEVE_EXEC_FAILURE;
372
365
        }
373
 
        
374
 
        return TRUE;
 
366
 
 
367
        return SIEVE_EXEC_OK;
375
368
}
376
369
 
377
 
static bool act_redirect_commit
378
 
(const struct sieve_action *action, 
 
370
static int act_redirect_commit
 
371
(const struct sieve_action *action,
379
372
        const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED,
380
373
        bool *keep)
381
374
{
385
378
                action->mail : sieve_message_get_mail(aenv->msgctx) );
386
379
        const struct sieve_message_data *msgdata = aenv->msgdata;
387
380
        const struct sieve_script_env *senv = aenv->scriptenv;
 
381
        const char *orig_recipient = sieve_message_get_orig_recipient(aenv->msgctx);
388
382
        const char *dupeid;
 
383
        int ret;
389
384
 
390
385
        /* Prevent mail loops if possible */
391
 
        dupeid = msgdata->id == NULL ? 
392
 
                NULL : t_strdup_printf("%s-%s", msgdata->id, ctx->to_address);
 
386
        dupeid = msgdata->id == NULL ? NULL : t_strdup_printf
 
387
                ("%s-%s-%s", msgdata->id, orig_recipient, ctx->to_address);
393
388
        if (dupeid != NULL) {
394
389
                /* Check whether we've seen this message before */
395
390
                if (sieve_action_duplicate_check(senv, dupeid, strlen(dupeid))) {
396
391
                        sieve_result_global_log(aenv, "discarded duplicate forward to <%s>",
397
392
                                str_sanitize(ctx->to_address, 128));
398
 
                        return TRUE;
 
393
                        *keep = FALSE;
 
394
                        return SIEVE_EXEC_OK;
399
395
                }
400
396
        }
401
397
 
402
398
        /* Try to forward the message */
403
 
        if ( act_redirect_send(aenv, mail, ctx) ) {
 
399
        if ( (ret=act_redirect_send(aenv, mail, ctx)) == SIEVE_EXEC_OK) {
404
400
 
405
401
                /* Mark this message id as forwarded to the specified destination */
406
402
                if (dupeid != NULL) {
408
404
                                ioloop_time + CMD_REDIRECT_DUPLICATE_KEEP);
409
405
                }
410
406
 
411
 
                sieve_result_global_log(aenv, "forwarded to <%s>", 
412
 
                        str_sanitize(ctx->to_address, 128));    
 
407
                sieve_result_global_log(aenv, "forwarded to <%s>",
 
408
                        str_sanitize(ctx->to_address, 128));
413
409
 
414
410
                /* Indicate that message was successfully forwarded */
415
411
                aenv->exec_status->message_forwarded = TRUE;
417
413
                /* Cancel implicit keep */
418
414
                *keep = FALSE;
419
415
 
420
 
                return TRUE;
 
416
                return SIEVE_EXEC_OK;
421
417
        }
422
 
 
423
 
        return FALSE;
 
418
 
 
419
        return ret;
424
420
}
425
421
 
426
422