Coverage Report

Created: 2026-06-15 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/sieve-message.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "ioloop.h"
6
#include "mempool.h"
7
#include "array.h"
8
#include "str.h"
9
#include "str-sanitize.h"
10
#include "istream.h"
11
#include "time-util.h"
12
#include "rfc822-parser.h"
13
#include "message-date.h"
14
#include "message-parser.h"
15
#include "message-decoder.h"
16
#include "message-header-decode.h"
17
#include "mail-html2text.h"
18
#include "mail-storage.h"
19
#include "mail-storage-service.h"
20
#include "mail-user.h"
21
#include "smtp-params.h"
22
#include "master-service.h"
23
#include "master-service-settings.h"
24
#include "raw-storage.h"
25
26
#include "edit-mail.h"
27
28
#include "sieve-common.h"
29
#include "sieve-stringlist.h"
30
#include "sieve-error.h"
31
#include "sieve-extensions.h"
32
#include "sieve-code.h"
33
#include "sieve-address.h"
34
#include "sieve-address-parts.h"
35
#include "sieve-runtime.h"
36
#include "sieve-runtime-trace.h"
37
#include "sieve-match.h"
38
#include "sieve-interpreter.h"
39
40
#include "sieve-message.h"
41
42
/*
43
 * Message transmission
44
 */
45
46
const char *sieve_message_get_new_id(const struct sieve_instance *svinst)
47
0
{
48
0
  static int count = 0;
49
50
0
  return t_strdup_printf("<dovecot-sieve-%s-%s-%d@%s>",
51
0
             dec2str(ioloop_timeval.tv_sec),
52
0
             dec2str(ioloop_timeval.tv_usec),
53
0
             count++, svinst->hostname);
54
0
}
55
56
/*
57
 * Message context
58
 */
59
60
struct sieve_message_header {
61
  const char *name;
62
63
  const unsigned char *value, *utf8_value;
64
  size_t value_len, utf8_value_len;
65
};
66
67
struct sieve_message_part {
68
  struct sieve_message_part *parent, *next, *children;
69
70
  ARRAY(struct sieve_message_header) headers;
71
72
  const char *content_type;
73
  const char *content_disposition;
74
75
  const char *decoded_body;
76
  const char *text_body;
77
  size_t decoded_body_size;
78
  size_t text_body_size;
79
80
  bool have_body:1; /* there's the empty end-of-headers line */
81
  bool epilogue:1;  /* this is a multipart epilogue */
82
};
83
84
struct sieve_message_version {
85
  struct mail *mail;
86
  struct mailbox *box;
87
  struct mailbox_transaction_context *trans;
88
  struct edit_mail *edit_mail;
89
};
90
91
struct sieve_message_context {
92
  pool_t pool;
93
  pool_t context_pool;
94
  int refcount;
95
96
  struct sieve_instance *svinst;
97
  struct timeval time;
98
99
  struct mail_user *mail_user;
100
  const struct sieve_message_data *msgdata;
101
102
  /* Message versioning */
103
104
  struct mail_user *raw_mail_user;
105
  ARRAY(struct sieve_message_version) versions;
106
107
  /* Context data for extensions */
108
109
  ARRAY(void *) ext_contexts;
110
111
  /* Body */
112
113
  ARRAY(struct sieve_message_part *) cached_body_parts;
114
  ARRAY(struct sieve_message_part_data) return_body_parts;
115
  buffer_t *raw_body;
116
117
  bool edit_snapshot:1;
118
  bool substitute_snapshot:1;
119
};
120
121
/*
122
 * Message versions
123
 */
124
125
static inline struct sieve_message_version *
126
sieve_message_version_new(struct sieve_message_context *msgctx)
127
0
{
128
0
  return array_append_space(&msgctx->versions);
129
0
}
130
131
static inline struct sieve_message_version *
132
sieve_message_version_get(struct sieve_message_context *msgctx)
133
0
{
134
0
  struct sieve_message_version *versions;
135
0
  unsigned int count;
136
137
0
  versions = array_get_modifiable(&msgctx->versions, &count);
138
0
  if (count == 0)
139
0
    return array_append_space(&msgctx->versions);
140
141
0
  return &versions[count-1];
142
0
}
143
144
static inline void
145
sieve_message_version_free(struct sieve_message_version *version)
146
0
{
147
0
  if (version->edit_mail != NULL) {
148
0
    edit_mail_unwrap(&version->edit_mail);
149
0
    version->edit_mail = NULL;
150
0
  }
151
152
0
  if (version->mail != NULL) {
153
0
    mail_free(&version->mail);
154
0
    mailbox_transaction_rollback(&version->trans);
155
0
    mailbox_free(&version->box);
156
0
    version->mail = NULL;
157
0
  }
158
0
}
159
160
/*
161
 * Message context object
162
 */
163
164
struct sieve_message_context *
165
sieve_message_context_create(struct sieve_instance *svinst,
166
           struct mail_user *mail_user,
167
           const struct sieve_message_data *msgdata)
168
0
{
169
0
  struct sieve_message_context *msgctx;
170
171
0
  msgctx = i_new(struct sieve_message_context, 1);
172
0
  msgctx->refcount = 1;
173
0
  msgctx->svinst = svinst;
174
175
0
  msgctx->mail_user = mail_user;
176
0
  msgctx->msgdata = msgdata;
177
178
0
  i_gettimeofday(&msgctx->time);
179
180
0
  sieve_message_context_reset(msgctx);
181
182
0
  return msgctx;
183
0
}
184
185
void sieve_message_context_ref(struct sieve_message_context *msgctx)
186
0
{
187
0
  msgctx->refcount++;
188
0
}
189
190
static void sieve_message_context_clear(struct sieve_message_context *msgctx)
191
0
{
192
0
  struct sieve_message_version *versions;
193
0
  unsigned int count, i;
194
195
0
  if (msgctx->pool != NULL) {
196
0
    versions = array_get_modifiable(&msgctx->versions, &count);
197
198
0
    for (i = 0; i < count; i++)
199
0
      sieve_message_version_free(&versions[i]);
200
201
0
    pool_unref(&(msgctx->pool));
202
0
  }
203
0
}
204
205
void sieve_message_context_unref(struct sieve_message_context **msgctx)
206
0
{
207
0
  i_assert((*msgctx)->refcount > 0);
208
209
0
  if (--(*msgctx)->refcount != 0)
210
0
    return;
211
212
0
  if ((*msgctx)->raw_mail_user != NULL)
213
0
    mail_user_unref(&(*msgctx)->raw_mail_user);
214
215
0
  sieve_message_context_clear(*msgctx);
216
217
0
  if ((*msgctx)->context_pool != NULL)
218
0
    pool_unref(&((*msgctx)->context_pool));
219
220
0
  i_free(*msgctx);
221
0
  *msgctx = NULL;
222
0
}
223
224
static void sieve_message_context_flush(struct sieve_message_context *msgctx)
225
0
{
226
0
  pool_t pool;
227
228
0
  if (msgctx->context_pool != NULL)
229
0
    pool_unref(&(msgctx->context_pool));
230
231
0
  msgctx->context_pool = pool =
232
0
    pool_alloconly_create("sieve_message_context_data", 2048);
233
234
0
  p_array_init(&msgctx->ext_contexts, pool,
235
0
    sieve_extensions_get_count(msgctx->svinst));
236
237
0
  p_array_init(&msgctx->cached_body_parts, pool, 8);
238
0
  p_array_init(&msgctx->return_body_parts, pool, 8);
239
0
  msgctx->raw_body = NULL;
240
0
}
241
242
void sieve_message_context_reset(struct sieve_message_context *msgctx)
243
0
{
244
0
  sieve_message_context_clear(msgctx);
245
246
0
  msgctx->pool = pool_alloconly_create("sieve_message_context", 1024);
247
248
0
  p_array_init(&msgctx->versions, msgctx->pool, 4);
249
250
0
  sieve_message_context_flush(msgctx);
251
0
}
252
253
pool_t sieve_message_context_pool(struct sieve_message_context *msgctx)
254
0
{
255
0
  return msgctx->context_pool;
256
0
}
257
258
void sieve_message_context_time(struct sieve_message_context *msgctx,
259
        struct timeval *time)
260
0
{
261
0
  *time = msgctx->time;
262
0
}
263
264
/* Extension support */
265
266
void sieve_message_context_extension_set(struct sieve_message_context *msgctx,
267
           const struct sieve_extension *ext,
268
           void *context)
269
0
{
270
0
  if (ext->id < 0)
271
0
    return;
272
273
0
  array_idx_set(&msgctx->ext_contexts, (unsigned int)ext->id, &context);
274
0
}
275
276
void *sieve_message_context_extension_get(struct sieve_message_context *msgctx,
277
            const struct sieve_extension *ext)
278
0
{
279
0
  void *const *ctx;
280
281
0
  if  (ext->id < 0 || ext->id >= (int)array_count(&msgctx->ext_contexts))
282
0
    return NULL;
283
284
0
  ctx = array_idx(&msgctx->ext_contexts, (unsigned int)ext->id);
285
0
  return *ctx;
286
0
}
287
288
/* Envelope */
289
290
const struct smtp_address *
291
sieve_message_get_orig_recipient(struct sieve_message_context *msgctx)
292
0
{
293
0
  const struct sieve_message_data *msgdata = msgctx->msgdata;
294
0
  const struct smtp_address *orcpt_to = NULL;
295
296
0
  if (msgdata->envelope.rcpt_params != NULL) {
297
0
    orcpt_to = msgdata->envelope.rcpt_params->orcpt.addr;
298
0
    if (!smtp_address_isnull(orcpt_to))
299
0
      return orcpt_to;
300
0
  }
301
302
0
  orcpt_to = msgdata->envelope.rcpt_to;
303
0
  return (!smtp_address_isnull(orcpt_to) ? orcpt_to : NULL);
304
0
}
305
306
const struct smtp_address *
307
sieve_message_get_final_recipient(struct sieve_message_context *msgctx)
308
0
{
309
0
  const struct sieve_message_data *msgdata = msgctx->msgdata;
310
0
  const struct smtp_address *rcpt_to = msgdata->envelope.rcpt_to;
311
312
0
  return (!smtp_address_isnull(rcpt_to) ? rcpt_to : NULL);
313
0
}
314
315
const struct smtp_address *
316
sieve_message_get_sender(struct sieve_message_context *msgctx)
317
0
{
318
0
  const struct sieve_message_data *msgdata = msgctx->msgdata;
319
0
  const struct smtp_address *mail_from = msgdata->envelope.mail_from;
320
321
0
  return (!smtp_address_isnull(mail_from) ? mail_from : NULL);
322
0
}
323
324
/*
325
 * Mail
326
 */
327
328
int sieve_message_substitute(struct sieve_message_context *msgctx,
329
           struct istream *input)
330
0
{
331
0
  static const char *wanted_headers[] = {
332
0
    "From", "Message-ID", "Subject", "Return-Path", NULL
333
0
  };
334
0
  static const struct smtp_address default_sender = {
335
0
    .localpart = DEFAULT_ENVELOPE_SENDER,
336
0
    .domain = NULL,
337
0
  };
338
0
  struct mail_user *mail_user = msgctx->mail_user;
339
0
  struct sieve_message_version *version;
340
0
  struct mailbox_header_lookup_ctx *headers_ctx;
341
0
  struct mailbox *box = NULL;
342
0
  const struct smtp_address *sender;
343
0
  int ret;
344
345
0
  i_assert(input->blocking);
346
347
0
  if (msgctx->raw_mail_user == NULL) {
348
0
    struct mail_storage_service_ctx *storage_service =
349
0
      mail_storage_service_user_get_service_ctx(
350
0
        mail_user->service_user);
351
0
    struct settings_instance *set_instance =
352
0
      mail_storage_service_user_get_settings_instance(mail_user->service_user);
353
0
    msgctx->raw_mail_user =
354
0
      raw_storage_create_from_set(storage_service, set_instance);
355
0
  }
356
357
0
  i_stream_seek(input, 0);
358
0
  sender = sieve_message_get_sender(msgctx);
359
0
  sender = (sender == NULL ? &default_sender : sender);
360
0
  ret = raw_mailbox_alloc_stream(msgctx->raw_mail_user, input, (time_t)-1,
361
0
               smtp_address_encode(sender), &box);
362
363
0
  if (ret < 0) {
364
0
    e_error(msgctx->svinst->event,
365
0
      "can't open substituted mail as raw: %s",
366
0
      mailbox_get_last_internal_error(box, NULL));
367
0
    return -1;
368
0
  }
369
370
0
  if (msgctx->substitute_snapshot) {
371
0
    version = sieve_message_version_new(msgctx);
372
0
  } else {
373
0
    version = sieve_message_version_get(msgctx);
374
0
    sieve_message_version_free(version);
375
0
  }
376
377
0
  version->box = box;
378
0
  version->trans = mailbox_transaction_begin(box, 0, __func__);
379
0
  headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
380
0
  version->mail = mail_alloc(version->trans, 0, headers_ctx);
381
0
  mailbox_header_lookup_unref(&headers_ctx);
382
0
  mail_set_seq(version->mail, 1);
383
384
0
  sieve_message_context_flush(msgctx);
385
386
0
  msgctx->substitute_snapshot = FALSE;
387
0
  msgctx->edit_snapshot = FALSE;
388
0
  return 1;
389
0
}
390
391
struct mail *sieve_message_get_mail(struct sieve_message_context *msgctx)
392
0
{
393
0
  const struct sieve_message_version *versions;
394
0
  unsigned int count;
395
396
0
  versions = array_get(&msgctx->versions, &count);
397
0
  if (count == 0)
398
0
    return msgctx->msgdata->mail;
399
400
0
  if (versions[count-1].edit_mail != NULL)
401
0
    return edit_mail_get_mail(versions[count-1].edit_mail);
402
0
  return versions[count-1].mail;
403
0
}
404
405
struct edit_mail *sieve_message_edit(struct sieve_message_context *msgctx)
406
0
{
407
0
  struct sieve_message_version *version;
408
409
0
  version = sieve_message_version_get(msgctx);
410
411
0
  if (version->edit_mail == NULL) {
412
0
    version->edit_mail = edit_mail_wrap(
413
0
      (version->mail == NULL ?
414
0
       msgctx->msgdata->mail : version->mail));
415
0
  } else if (msgctx->edit_snapshot) {
416
0
    version->edit_mail = edit_mail_snapshot(version->edit_mail);
417
0
  }
418
419
0
  msgctx->edit_snapshot = FALSE;
420
0
  return version->edit_mail;
421
0
}
422
423
void sieve_message_snapshot(struct sieve_message_context *msgctx)
424
0
{
425
0
  msgctx->edit_snapshot = TRUE;
426
0
  msgctx->substitute_snapshot = TRUE;
427
0
}
428
429
/*
430
 * Message header list
431
 */
432
433
/* Forward declarations */
434
435
static int
436
sieve_message_header_list_next_item(struct sieve_header_list *_hdrlist,
437
            const char **name_r, string_t **value_r);
438
static int
439
sieve_message_header_list_next_value(struct sieve_stringlist *_strlist,
440
             string_t **value_r);
441
static void
442
sieve_message_header_list_reset(struct sieve_stringlist *_strlist);
443
444
/* String list object */
445
446
struct sieve_message_header_list {
447
  struct sieve_header_list hdrlist;
448
449
  struct sieve_stringlist *field_names;
450
451
  const char *header_name;
452
  const char *const *headers;
453
  int headers_index;
454
455
  bool mime_decode:1;
456
};
457
458
struct sieve_header_list *
459
sieve_message_header_list_create(const struct sieve_runtime_env *renv,
460
         struct sieve_stringlist *field_names,
461
         bool mime_decode)
462
0
{
463
0
  struct sieve_message_header_list *hdrlist;
464
465
0
  hdrlist = t_new(struct sieve_message_header_list, 1);
466
0
  hdrlist->hdrlist.strlist.runenv = renv;
467
0
  hdrlist->hdrlist.strlist.exec_status = SIEVE_EXEC_OK;
468
0
  hdrlist->hdrlist.strlist.next_item =
469
0
    sieve_message_header_list_next_value;
470
0
  hdrlist->hdrlist.strlist.reset = sieve_message_header_list_reset;
471
0
  hdrlist->hdrlist.next_item = sieve_message_header_list_next_item;
472
0
  hdrlist->field_names = field_names;
473
0
  hdrlist->mime_decode = mime_decode;
474
475
0
  return &hdrlist->hdrlist;
476
0
}
477
478
// NOTE: get rid of this once we have a proper Sieve string type
479
static inline string_t *_header_right_trim(const char *raw)
480
0
{
481
0
  string_t *result;
482
0
  const char *p, *pend;
483
484
0
  pend = raw + strlen(raw);
485
0
  if (raw == pend) {
486
0
    result = t_str_new(1);
487
0
  } else {
488
0
    for (p = pend-1; p >= raw; p--) {
489
0
      if (*p != ' ' && *p != '\t')
490
0
        break;
491
0
    }
492
0
    result = t_str_new(p - raw + 1);
493
0
    str_append_data(result, raw, p - raw + 1);
494
0
  }
495
0
  return result;
496
0
}
497
498
/* String list implementation */
499
500
static int
501
sieve_message_header_list_next_item(struct sieve_header_list *_hdrlist,
502
            const char **name_r, string_t **value_r)
503
0
{
504
0
  struct sieve_message_header_list *hdrlist =
505
0
    (struct sieve_message_header_list *)_hdrlist;
506
0
  const struct sieve_runtime_env *renv = _hdrlist->strlist.runenv;
507
0
  struct mail *mail = sieve_message_get_mail(renv->msgctx);
508
509
0
  if (name_r != NULL)
510
0
    *name_r = NULL;
511
0
  *value_r = NULL;
512
513
  /* Check for end of current header list */
514
0
  if (hdrlist->headers == NULL) {
515
0
    hdrlist->headers_index = 0;
516
0
  } else if (hdrlist->headers[hdrlist->headers_index] == NULL) {
517
0
    hdrlist->headers = NULL;
518
0
    hdrlist->headers_index = 0;
519
0
  }
520
521
  /* Fetch next header */
522
0
  while (hdrlist->headers == NULL) {
523
0
    string_t *hdr_item = NULL;
524
0
    int ret;
525
526
    /* Read next header name from source list */
527
0
    if ((ret = sieve_stringlist_next_item(hdrlist->field_names,
528
0
                  &hdr_item)) <= 0)
529
0
      return ret;
530
531
0
    hdrlist->header_name = str_c(hdr_item);
532
533
0
    if (_hdrlist->strlist.trace) {
534
0
      sieve_runtime_trace
535
0
        (renv, 0,
536
0
        "extracting '%s' headers from message",
537
0
        str_sanitize(str_c(hdr_item), 80));
538
0
    }
539
540
    /* Fetch all matching headers from the e-mail */
541
0
    if (hdrlist->mime_decode) {
542
0
      ret = mail_get_headers_utf8(mail, str_c(hdr_item),
543
0
                &hdrlist->headers);
544
0
    } else {
545
0
      ret = mail_get_headers(mail, str_c(hdr_item),
546
0
                 &hdrlist->headers);
547
0
    }
548
549
0
    if (ret < 0) {
550
0
      _hdrlist->strlist.exec_status =
551
0
        sieve_runtime_mail_error(
552
0
          renv, mail,
553
0
          "failed to read header field '%s'",
554
0
          str_c(hdr_item));
555
0
      return -1;
556
0
    }
557
558
0
    i_assert(hdrlist->headers != NULL);
559
0
    if (ret == 0 || hdrlist->headers[0] == NULL) {
560
      /* Try next item when no headers found */
561
0
      hdrlist->headers = NULL;
562
0
    }
563
0
  }
564
565
  /* Return next item */
566
0
  if (name_r != NULL)
567
0
    *name_r = hdrlist->header_name;
568
0
  *value_r = _header_right_trim(
569
0
    hdrlist->headers[hdrlist->headers_index++]);
570
0
  return 1;
571
0
}
572
573
static int
574
sieve_message_header_list_next_value(struct sieve_stringlist *_strlist,
575
             string_t **value_r)
576
0
{
577
0
  struct sieve_header_list *hdrlist =
578
0
    (struct sieve_header_list *)_strlist;
579
580
0
  return sieve_message_header_list_next_item(hdrlist, NULL, value_r);
581
0
}
582
583
static void
584
sieve_message_header_list_reset(struct sieve_stringlist *strlist)
585
0
{
586
0
  struct sieve_message_header_list *hdrlist =
587
0
    (struct sieve_message_header_list *)strlist;
588
589
0
  hdrlist->headers = NULL;
590
0
  hdrlist->headers_index = 0;
591
0
  sieve_stringlist_reset(hdrlist->field_names);
592
0
}
593
594
/*
595
 * Header override operand
596
 */
597
598
const struct sieve_operand_class sieve_message_override_operand_class =
599
  { "header-override" };
600
601
bool sieve_opr_message_override_dump(const struct sieve_dumptime_env *denv,
602
             sieve_size_t *address)
603
0
{
604
0
  struct sieve_message_override svmo;
605
0
  const struct sieve_message_override_def *hodef;
606
607
0
  if (!sieve_opr_object_dump(denv, &sieve_message_override_operand_class,
608
0
           address, &svmo.object))
609
0
    return FALSE;
610
611
0
  hodef = svmo.def =
612
0
    (const struct sieve_message_override_def *)svmo.object.def;
613
614
0
  if (hodef->dump_context != NULL) {
615
0
    sieve_code_descend(denv);
616
0
    if (!hodef->dump_context(&svmo, denv, address))
617
0
      return FALSE;
618
0
    sieve_code_ascend(denv);
619
0
  }
620
0
  return TRUE;
621
0
}
622
623
int sieve_opr_message_override_read(const struct sieve_runtime_env *renv,
624
            sieve_size_t *address,
625
            struct sieve_message_override *svmo)
626
0
{
627
0
  const struct sieve_message_override_def *hodef;
628
0
  int ret;
629
630
0
  svmo->context = NULL;
631
632
0
  if (!sieve_opr_object_read(renv, &sieve_message_override_operand_class,
633
0
           address, &svmo->object))
634
0
    return SIEVE_EXEC_BIN_CORRUPT;
635
636
0
  hodef = svmo->def =
637
0
    (const struct sieve_message_override_def *)svmo->object.def;
638
639
0
  if (hodef->read_context != NULL &&
640
0
      (ret = hodef->read_context(svmo, renv, address,
641
0
               &svmo->context)) <= 0)
642
0
    return ret;
643
0
  return SIEVE_EXEC_OK;
644
0
}
645
646
/*
647
 * Optional operands
648
 */
649
650
int sieve_message_opr_optional_dump(const struct sieve_dumptime_env *denv,
651
            sieve_size_t *address,
652
            signed int *opt_code)
653
0
{
654
0
  signed int _opt_code = 0;
655
0
  bool final = FALSE, opok = TRUE;
656
657
0
  if (opt_code == NULL) {
658
0
    opt_code = &_opt_code;
659
0
    final = TRUE;
660
0
  }
661
662
0
  while (opok) {
663
0
    int opt;
664
665
0
    if ((opt = sieve_addrmatch_opr_optional_dump(denv, address,
666
0
                   opt_code)) <= 0)
667
0
      return opt;
668
669
0
    if (*opt_code == SIEVE_OPT_MESSAGE_OVERRIDE) {
670
0
      opok = sieve_opr_message_override_dump(denv, address);
671
0
    } else {
672
0
      return (final ? -1 : 1);
673
0
    }
674
0
  }
675
0
  return -1;
676
0
}
677
678
int sieve_message_opr_optional_read(const struct sieve_runtime_env *renv,
679
            sieve_size_t *address,
680
            signed int *opt_code, int *exec_status,
681
            struct sieve_address_part *addrp,
682
            struct sieve_match_type *mcht,
683
            struct sieve_comparator *cmp,
684
            ARRAY_TYPE(sieve_message_override) *svmos)
685
0
{
686
0
  signed int _opt_code = 0;
687
0
  bool final = FALSE;
688
0
  int ret;
689
690
0
  if (opt_code == NULL) {
691
0
    opt_code = &_opt_code;
692
0
    final = TRUE;
693
0
  }
694
695
0
  if (exec_status != NULL)
696
0
    *exec_status = SIEVE_EXEC_OK;
697
698
0
  for (;;) {
699
0
    int opt;
700
701
0
    if ((opt = sieve_addrmatch_opr_optional_read(
702
0
      renv, address, opt_code, exec_status,
703
0
      addrp, mcht, cmp)) <= 0)
704
0
      return opt;
705
706
0
    if (*opt_code == SIEVE_OPT_MESSAGE_OVERRIDE) {
707
0
      struct sieve_message_override svmo;
708
0
      const struct sieve_message_override *svmo_idx;
709
0
      unsigned int count, i;
710
711
0
      if ((ret = sieve_opr_message_override_read(
712
0
        renv, address, &svmo)) <= 0) {
713
0
        if (exec_status != NULL)
714
0
          *exec_status = ret;
715
0
        return -1;
716
0
      }
717
718
0
      if (!array_is_created(svmos))
719
0
        t_array_init(svmos, 8);
720
      /* insert in sorted sequence */
721
0
      svmo_idx = array_get(svmos, &count);
722
0
      for (i = 0; i < count; i++) {
723
0
        if (svmo.def->sequence <
724
0
            svmo_idx[i].def->sequence) {
725
0
          array_insert(svmos, i, &svmo, 1);
726
0
          break;
727
0
        }
728
0
      }
729
0
      if (count == i)
730
0
        array_append(svmos, &svmo, 1);
731
0
    } else {
732
0
      if (final) {
733
0
        sieve_runtime_trace_error(
734
0
          renv, "invalid optional operand");
735
0
        if (exec_status != NULL)
736
0
          *exec_status = SIEVE_EXEC_BIN_CORRUPT;
737
0
        return -1;
738
0
      }
739
0
      return 1;
740
0
    }
741
0
  }
742
0
  i_unreached();
743
0
}
744
745
/*
746
 * Message header
747
 */
748
749
int sieve_message_get_header_fields(const struct sieve_runtime_env *renv,
750
            struct sieve_stringlist *field_names,
751
            ARRAY_TYPE(sieve_message_override) *svmos,
752
            bool mime_decode,
753
            struct sieve_stringlist **fields_r)
754
0
{
755
0
  const struct sieve_message_override *svmo;
756
0
  unsigned int count, i;
757
0
  int ret;
758
759
0
  if (svmos == NULL || !array_is_created(svmos) ||
760
0
      array_count(svmos) == 0) {
761
0
    struct sieve_header_list *headers;
762
763
0
    headers = sieve_message_header_list_create(
764
0
      renv, field_names, mime_decode);
765
0
    *fields_r = &headers->strlist;
766
0
    return SIEVE_EXEC_OK;
767
0
  }
768
769
0
  svmo = array_get(svmos, &count);
770
0
  if (svmo[0].def->sequence == 0 &&
771
0
      svmo[0].def->header_override != NULL) {
772
0
    *fields_r = field_names;
773
0
  } else {
774
0
    struct sieve_header_list *headers;
775
776
0
    headers = sieve_message_header_list_create(renv, field_names,
777
0
                 mime_decode);
778
0
    *fields_r = &headers->strlist;
779
0
  }
780
781
0
  for (i = 0; i < count; i++) {
782
0
    if (svmo[i].def->header_override != NULL &&
783
0
        (ret = svmo[i].def->header_override(
784
0
      &svmo[i], renv, mime_decode, fields_r)) <= 0)
785
0
      return ret;
786
0
  }
787
0
  return SIEVE_EXEC_OK;
788
0
}
789
790
/*
791
 * Message part
792
 */
793
794
struct sieve_message_part *
795
sieve_message_part_parent(struct sieve_message_part *mpart)
796
0
{
797
0
  return mpart->parent;
798
0
}
799
800
struct sieve_message_part *
801
sieve_message_part_next(struct sieve_message_part *mpart)
802
0
{
803
0
  return mpart->next;
804
0
}
805
806
struct sieve_message_part *
807
sieve_message_part_children(struct sieve_message_part *mpart)
808
0
{
809
0
  return mpart->children;
810
0
}
811
812
const char *
813
sieve_message_part_content_type(struct sieve_message_part *mpart)
814
0
{
815
0
  return mpart->content_type;
816
0
}
817
818
const char *
819
sieve_message_part_content_disposition(struct sieve_message_part *mpart)
820
0
{
821
0
  return mpart->content_disposition;
822
0
}
823
824
int sieve_message_part_get_first_header(struct sieve_message_part *mpart,
825
          const char *field,
826
          const char **value_r)
827
0
{
828
0
  const struct sieve_message_header *headers;
829
0
  unsigned int i, count;
830
831
0
  headers = array_get(&mpart->headers, &count);
832
0
  for (i = 0; i < count; i++) {
833
0
    if (strcasecmp(headers[i].name, field) == 0) {
834
0
      i_assert(headers[i].value[headers[i].value_len] == '\0');
835
0
      *value_r = (const char *)headers[i].value;
836
0
      return 1;
837
0
    }
838
0
  }
839
840
0
  *value_r = NULL;
841
0
  return 0;
842
0
}
843
844
void sieve_message_part_get_data(struct sieve_message_part *mpart,
845
         struct sieve_message_part_data *data,
846
         bool text)
847
0
{
848
0
  i_zero(data);
849
0
  data->content_type = mpart->content_type;
850
0
  data->content_disposition = mpart->content_disposition;
851
852
0
  if (!text) {
853
0
    data->content = mpart->decoded_body;
854
0
    data->size = mpart->decoded_body_size;
855
0
  } else if (mpart->children != NULL) {
856
0
    data->content = "";
857
0
    data->size = 0;
858
0
  } else {
859
0
    data->content = mpart->text_body;
860
0
    data->size = mpart->text_body_size;
861
0
  }
862
0
}
863
864
/*
865
 * Message body
866
 */
867
868
static void str_replace_nuls(string_t *str)
869
0
{
870
0
  char *data = str_c_modifiable(str);
871
0
  unsigned int i, len = str_len(str);
872
873
0
  for (i = 0; i < len; i++) {
874
0
    if (data[i] == '\0')
875
0
      data[i] = ' ';
876
0
  }
877
0
}
878
879
static bool
880
_is_wanted_content_type(const char *const *wanted_types,
881
      const char *content_type) ATTR_NULL(1)
882
0
{
883
0
  const char *subtype;
884
0
  size_t type_len;
885
886
0
  if (wanted_types == NULL)
887
0
    return TRUE;
888
889
0
  subtype = strchr(content_type, '/');
890
0
  type_len = (subtype == NULL ?
891
0
        strlen(content_type) : (size_t)(subtype - content_type));
892
893
0
  i_assert(wanted_types != NULL);
894
895
0
  for (; *wanted_types != NULL; wanted_types++) {
896
0
    const char *wanted_subtype;
897
898
0
    if (**wanted_types == '\0') {
899
      /* empty string matches everything */
900
0
      return TRUE;
901
0
    }
902
903
0
    wanted_subtype = strchr(*wanted_types, '/');
904
0
    if (wanted_subtype == NULL) {
905
      /* match only main type */
906
0
      if (strlen(*wanted_types) == type_len &&
907
0
          strncasecmp(*wanted_types, content_type,
908
0
          type_len) == 0)
909
0
        return TRUE;
910
0
    } else {
911
      /* match whole type/subtype */
912
0
      if (strcasecmp(*wanted_types, content_type) == 0)
913
0
        return TRUE;
914
0
    }
915
0
  }
916
0
  return FALSE;
917
0
}
918
919
static bool
920
sieve_message_body_get_return_parts(const struct sieve_runtime_env *renv,
921
            const char *const *wanted_types,
922
            bool extract_text)
923
0
{
924
0
  struct sieve_message_context *msgctx = renv->msgctx;
925
0
  struct sieve_message_part *const *body_parts;
926
0
  unsigned int i, count;
927
0
  struct sieve_message_part_data *return_part;
928
929
  /* Check whether any body parts are cached already */
930
0
  body_parts = array_get(&msgctx->cached_body_parts, &count);
931
0
  if (count == 0)
932
0
    return FALSE;
933
934
  /* Clear result array */
935
0
  array_clear(&msgctx->return_body_parts);
936
937
  /* Fill result array with requested content_types */
938
0
  for (i = 0; i < count; i++) {
939
0
    if (!body_parts[i]->have_body) {
940
      /* Part has no body; according to RFC this MUST not
941
         match to anything and therefore it is not included in
942
         the result. */
943
0
      continue;
944
0
    }
945
946
    /* Skip content types that are not requested */
947
0
    if (!_is_wanted_content_type(wanted_types,
948
0
               body_parts[i]->content_type))
949
0
      continue;
950
951
    /* Add new item to the result */
952
0
    return_part = array_append_space(&msgctx->return_body_parts);
953
0
    return_part->content_type = body_parts[i]->content_type;
954
0
    return_part->content_disposition =
955
0
      body_parts[i]->content_disposition;
956
957
    /* Depending on whether a decoded body part is requested, the
958
       appropriate cache item is read. If it is missing, this
959
       function fails and the cache needs to be completed by
960
       sieve_message_parts_add_missing().
961
     */
962
0
    if (extract_text) {
963
0
      if (body_parts[i]->text_body == NULL)
964
0
        return FALSE;
965
0
      return_part->content = body_parts[i]->text_body;
966
0
      return_part->size = body_parts[i]->text_body_size;
967
0
    } else {
968
0
      if (body_parts[i]->decoded_body == NULL)
969
0
        return FALSE;
970
0
      return_part->content = body_parts[i]->decoded_body;
971
0
      return_part->size = body_parts[i]->decoded_body_size;
972
0
    }
973
0
  }
974
0
  return TRUE;
975
0
}
976
977
static void
978
sieve_message_part_save(const struct sieve_runtime_env *renv, buffer_t *buf,
979
      struct sieve_message_part *body_part, bool extract_text)
980
0
{
981
0
  struct sieve_message_context *msgctx = renv->msgctx;
982
0
  pool_t pool = msgctx->context_pool;
983
0
  buffer_t *result_buf, *text_buf = NULL;
984
0
  char *part_data;
985
0
  size_t part_size;
986
987
  /* Extract text if requested */
988
0
  result_buf = buf;
989
0
  if (extract_text && body_part->children == NULL &&
990
0
      !body_part->epilogue) {
991
0
    if (buf->used > 0 &&
992
0
        mail_html2text_content_type_match(body_part->content_type)) {
993
0
      struct mail_html2text *html2text;
994
995
0
      text_buf = buffer_create_dynamic(default_pool, 4096);
996
997
      /* Remove HTML markup */
998
0
      html2text = mail_html2text_init(0);
999
0
      mail_html2text_more(html2text, buf->data, buf->used,
1000
0
              text_buf);
1001
0
      mail_html2text_deinit(&html2text);
1002
1003
0
      result_buf = text_buf;
1004
0
    }
1005
0
  }
1006
1007
  /* Add terminating NUL to the body part buffer */
1008
0
  buffer_append_c(result_buf, '\0');
1009
1010
  /* Make copy of the buffer */
1011
0
  part_data = p_malloc(pool, result_buf->used);
1012
0
  memcpy(part_data, result_buf->data, result_buf->used);
1013
0
  part_size = result_buf->used - 1;
1014
1015
  /* Free text buffer if used */
1016
0
  if (text_buf != NULL)
1017
0
    buffer_free(&text_buf);
1018
1019
  /* Depending on whether the part is processed into text, store message
1020
     body in the appropriate cache location. */
1021
0
  if (!extract_text) {
1022
0
    body_part->decoded_body = part_data;
1023
0
    body_part->decoded_body_size = part_size;
1024
0
  } else {
1025
0
    body_part->text_body = part_data;
1026
0
    body_part->text_body_size = part_size;
1027
0
  }
1028
1029
  /* Clear buffer */
1030
0
  buffer_set_used_size(buf, 0);
1031
0
}
1032
1033
static const char *_parse_content_type(const struct message_header_line *hdr)
1034
0
{
1035
0
  struct rfc822_parser_context parser;
1036
0
  string_t *content_type;
1037
1038
  /* Initialize parsing */
1039
0
  rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
1040
0
  (void)rfc822_skip_lwsp(&parser);
1041
1042
  /* Parse content type */
1043
0
  content_type = t_str_new(64);
1044
0
  if (rfc822_parse_content_type(&parser, content_type) < 0)
1045
0
    return "";
1046
1047
  /* Content-type value must end here, otherwise it is invalid after all
1048
   */
1049
0
  (void)rfc822_skip_lwsp(&parser);
1050
0
  if (parser.data != parser.end && *parser.data != ';')
1051
0
    return "";
1052
1053
  /* Success */
1054
0
  return str_c(content_type);
1055
0
}
1056
1057
static const char *
1058
_parse_content_disposition(const struct message_header_line *hdr)
1059
0
{
1060
0
  struct rfc822_parser_context parser;
1061
0
  string_t *content_disp;
1062
1063
  /* Initialize parsing */
1064
0
  rfc822_parser_init(&parser, hdr->full_value, hdr->full_value_len, NULL);
1065
0
  (void)rfc822_skip_lwsp(&parser);
1066
1067
  /* Parse content type */
1068
0
  content_disp = t_str_new(64);
1069
0
  if (rfc822_parse_mime_token(&parser, content_disp) < 0)
1070
0
    return "";
1071
1072
  /* Content-type value must end here, otherwise it is invalid after all */
1073
0
  (void)rfc822_skip_lwsp(&parser);
1074
0
  if (parser.data != parser.end && *parser.data != ';')
1075
0
    return "";
1076
1077
  /* Success */
1078
0
  return str_c(content_disp);
1079
0
}
1080
1081
/* sieve_message_parts_add_missing():
1082
 *   Add requested message body parts to the cache that are missing.
1083
 */
1084
static int
1085
sieve_message_parts_add_missing(const struct sieve_runtime_env *renv,
1086
        const char *const *content_types,
1087
        bool extract_text, bool iter_all) ATTR_NULL(2)
1088
0
{
1089
0
  struct sieve_message_context *msgctx = renv->msgctx;
1090
0
  pool_t pool = msgctx->context_pool;
1091
0
  struct mail *mail = sieve_message_get_mail(renv->msgctx);
1092
0
  struct message_parser_settings mparser_set = {
1093
0
    .hdr_flags = MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP,
1094
0
    .flags = MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS,
1095
0
  };
1096
0
  ARRAY(struct sieve_message_header) headers;
1097
0
  struct sieve_message_part *body_part, *header_part, *last_part;
1098
0
  struct message_parser_ctx *parser;
1099
0
  struct message_decoder_context *decoder;
1100
0
  struct message_block block, decoded;
1101
0
  struct message_part *mparts, *prev_mpart = NULL;
1102
0
  buffer_t *buf;
1103
0
  struct istream *input;
1104
0
  unsigned int idx = 0;
1105
0
  bool save_body = FALSE, have_all;
1106
0
  string_t *hdr_content = NULL;
1107
1108
  /* First check whether any are missing */
1109
0
  if (!iter_all && sieve_message_body_get_return_parts(
1110
0
    renv, content_types, extract_text)) {
1111
    /* Cache hit; all are present */
1112
0
    return SIEVE_EXEC_OK;
1113
0
  }
1114
1115
  /* Get the message stream */
1116
0
  if (mail_get_stream(mail, NULL, NULL, &input) < 0) {
1117
0
    return sieve_runtime_mail_error(
1118
0
      renv, mail, "failed to open input message");
1119
0
  }
1120
0
  if (mail_get_parts(mail, &mparts) < 0) {
1121
0
    return sieve_runtime_mail_error(
1122
0
      renv, mail, "failed to parse input message parts");
1123
0
  }
1124
1125
0
  buf = buffer_create_dynamic(default_pool, 4096);
1126
0
  body_part = header_part = last_part = NULL;
1127
1128
0
  if (iter_all) {
1129
0
    t_array_init(&headers, 64);
1130
0
    hdr_content = t_str_new(512);
1131
0
    mparser_set.hdr_flags |= MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE;
1132
0
  } else {
1133
0
    i_zero(&headers);
1134
0
  }
1135
1136
  /* Initialize body decoder */
1137
0
  decoder = message_decoder_init(NULL, 0);
1138
1139
  // FIXME: currently not tested with edit-mail.
1140
    //parser = message_parser_init_from_parts(parts, input,
1141
    // hparser_flags, mparser_flags);
1142
0
  parser = message_parser_init(pool_datastack_create(),
1143
0
             input, &mparser_set);
1144
0
  while (message_parser_parse_next_block(parser, &block) > 0) {
1145
0
    struct sieve_message_part **body_part_idx;
1146
0
    struct message_header_line *hdr = block.hdr;
1147
0
    struct sieve_message_header *header;
1148
0
    unsigned char *data;
1149
1150
0
    if (block.part != prev_mpart) {
1151
0
      bool message_rfc822 = FALSE;
1152
1153
      /* Save previous body part */
1154
0
      if (body_part != NULL) {
1155
        /* Treat message/rfc822 separately; headers
1156
           become content */
1157
0
        if (block.part->parent == prev_mpart &&
1158
0
            strcmp(body_part->content_type,
1159
0
             "message/rfc822") == 0) {
1160
0
          message_rfc822 = TRUE;
1161
0
        } else if (save_body) {
1162
0
          sieve_message_part_save(
1163
0
            renv, buf, body_part,
1164
0
            extract_text);
1165
0
        }
1166
0
        if (iter_all &&
1167
0
            !array_is_created(&body_part->headers) &&
1168
0
            array_count(&headers) > 0) {
1169
0
          p_array_init(&body_part->headers, pool,
1170
0
                 array_count(&headers));
1171
0
          array_copy(&body_part->headers.arr, 0,
1172
0
               &headers.arr, 0,
1173
0
               array_count(&headers));
1174
0
        }
1175
0
      }
1176
1177
      /* Start processing next part */
1178
0
      body_part_idx = array_idx_get_space(
1179
0
        &msgctx->cached_body_parts, idx);
1180
0
      if (*body_part_idx == NULL) {
1181
0
        *body_part_idx = p_new(
1182
0
          pool, struct sieve_message_part, 1);
1183
0
      }
1184
0
      body_part = *body_part_idx;
1185
0
      body_part->content_type = "text/plain";
1186
0
      if (iter_all)
1187
0
        array_clear(&headers);
1188
1189
      /* Copy tree structure */
1190
0
      if (block.part->context != NULL) {
1191
0
        struct sieve_message_part *epipart =
1192
0
          (struct sieve_message_part *)
1193
0
            block.part->context;
1194
0
        i_assert(epipart != NULL);
1195
1196
        /* multipart epilogue */
1197
0
        body_part->content_type = epipart->content_type;
1198
0
        body_part->have_body = TRUE;
1199
0
        body_part->epilogue = TRUE;
1200
0
        save_body = iter_all ||
1201
0
          _is_wanted_content_type(content_types,
1202
0
                body_part->content_type);
1203
1204
0
      } else {
1205
0
        struct sieve_message_part *parent = NULL;
1206
1207
0
        if (block.part->parent != NULL) {
1208
0
          body_part->parent = parent =
1209
0
            (struct sieve_message_part *)
1210
0
              block.part->parent->context;
1211
0
        }
1212
1213
        /* new part */
1214
0
        block.part->context = body_part;
1215
1216
0
        if (last_part != NULL) {
1217
0
          i_assert(parent != NULL);
1218
0
          if (last_part->parent == parent) {
1219
0
            last_part->next = body_part;
1220
0
          } else if (parent->children == NULL) {
1221
0
            parent->children = body_part;
1222
0
          } else {
1223
0
            struct sieve_message_part *child = parent->children;
1224
0
            while (child->next != NULL && child != body_part)
1225
0
              child = child->next;
1226
0
            if (child != body_part)
1227
0
              child->next = body_part;
1228
0
          }
1229
0
        }
1230
0
      }
1231
0
      last_part = body_part;
1232
1233
      /* If this is message/rfc822 content, retain the
1234
         enveloping part for storing headers as content.
1235
       */
1236
0
      if (message_rfc822) {
1237
0
        i_assert(idx > 0);
1238
0
        body_part_idx = array_idx_modifiable(
1239
0
          &msgctx->cached_body_parts, idx-1);
1240
0
        header_part = *body_part_idx;
1241
0
      } else {
1242
0
        header_part = NULL;
1243
0
      }
1244
1245
0
      prev_mpart = block.part;
1246
0
      idx++;
1247
0
    }
1248
1249
0
    if (hdr != NULL || block.size == 0) {
1250
0
      enum {
1251
0
        _HDR_CONTENT_TYPE,
1252
0
        _HDR_CONTENT_DISPOSITION,
1253
0
        _HDR_OTHER
1254
0
      } hdr_field;
1255
1256
      /* Reading headers */
1257
0
      i_assert(body_part != NULL);
1258
1259
      /* Decode block */
1260
0
      (void)message_decoder_decode_next_block(decoder, &block,
1261
0
                &decoded);
1262
1263
      /* Check for end of headers */
1264
0
      if (hdr == NULL) {
1265
        /* Save headers for message/rfc822 part */
1266
0
        if (header_part != NULL) {
1267
0
          sieve_message_part_save(renv, buf,
1268
0
                header_part,
1269
0
                FALSE);
1270
0
          header_part = NULL;
1271
0
        }
1272
1273
        /* Save bodies only if we have a wanted content
1274
           type */
1275
0
        save_body = iter_all ||
1276
0
          _is_wanted_content_type(content_types,
1277
0
                body_part->content_type);
1278
0
        continue;
1279
0
      }
1280
1281
      /* Encountered the empty line that indicates the end of
1282
         the headers and the start of the body
1283
       */
1284
0
      if (hdr->eoh) {
1285
0
        body_part->have_body = TRUE;
1286
0
        continue;
1287
0
      } else if (header_part != NULL) {
1288
        /* Save message/rfc822 header as part content */
1289
0
        if (hdr->continued) {
1290
0
          buffer_append(buf, hdr->value,
1291
0
                  hdr->value_len);
1292
0
        } else {
1293
0
          buffer_append(buf, hdr->name,
1294
0
                  hdr->name_len);
1295
0
          buffer_append(buf, hdr->middle,
1296
0
                  hdr->middle_len);
1297
0
          buffer_append(buf, hdr->value,
1298
0
                  hdr->value_len);
1299
0
        }
1300
0
        if (!hdr->no_newline)
1301
0
          buffer_append(buf, "\r\n", 2);
1302
0
      }
1303
1304
0
      if (strcasecmp(hdr->name, "Content-Type") == 0)
1305
0
        hdr_field = _HDR_CONTENT_TYPE;
1306
0
      else if (strcasecmp(hdr->name,
1307
0
              "Content-Disposition") == 0)
1308
0
        hdr_field = _HDR_CONTENT_DISPOSITION;
1309
0
      else if (iter_all &&
1310
0
         !array_is_created(&body_part->headers))
1311
0
        hdr_field = _HDR_OTHER;
1312
0
      else {
1313
        /* Not interested in this header */
1314
0
        continue;
1315
0
      }
1316
1317
      /* Header can have folding whitespace. Acquire the full
1318
         value before continuing
1319
       */
1320
0
      if (hdr->continues) {
1321
0
        hdr->use_full_value = TRUE;
1322
0
        continue;
1323
0
      }
1324
1325
0
      if (iter_all &&
1326
0
          !array_is_created(&body_part->headers)) {
1327
0
        const unsigned char *value, *vp;
1328
0
        size_t vlen;
1329
1330
        /* Add header */
1331
0
        header = array_append_space(&headers);
1332
0
        header->name = p_strdup(pool, hdr->name);
1333
1334
        /* Trim end of field value (not done by parser)
1335
         */
1336
0
        value = hdr->full_value;
1337
0
        vp = value + hdr->full_value_len;
1338
0
        while (vp > value &&
1339
0
               (vp[-1] == '\t' || vp[-1] == ' '))
1340
0
          vp--;
1341
0
        vlen = (size_t)(vp - value);
1342
1343
        /* Decode MIME encoded-words. */
1344
0
        str_truncate(hdr_content, 0);
1345
0
        message_header_decode_utf8(value, vlen,
1346
0
                 hdr_content, NULL);
1347
0
        if (vlen != str_len(hdr_content) ||
1348
0
            strncmp(str_c(hdr_content),
1349
0
              (const char *)value, vlen) != 0) {
1350
0
          if (strlen(str_c(hdr_content)) !=
1351
0
              str_len(hdr_content)) {
1352
            /* replace NULs with spaces */
1353
0
            str_replace_nuls(hdr_content);
1354
0
          }
1355
          /* store raw */
1356
0
          data = p_malloc(pool, vlen + 1);
1357
0
          data[vlen] = '\0';
1358
0
          header->value = memcpy(data, value, vlen);
1359
0
          header->value_len = vlen;
1360
          /* store decoded */
1361
0
          data = p_malloc(pool, str_len(hdr_content) + 1);
1362
0
          data[str_len(hdr_content)] = '\0';
1363
0
          header->utf8_value = memcpy(
1364
0
            data, str_data(hdr_content),
1365
0
            str_len(hdr_content));
1366
0
          header->utf8_value_len = str_len(hdr_content);
1367
0
        } else {
1368
          /* raw == decoded */
1369
0
          data = p_malloc(pool, vlen + 1);
1370
0
          data[vlen] = '\0';
1371
0
          header->value = header->utf8_value =
1372
0
            memcpy(data, value, vlen);
1373
0
          header->value_len = header->utf8_value_len = vlen;
1374
0
        }
1375
1376
0
        if (hdr_field == _HDR_OTHER)
1377
0
          continue;
1378
0
      }
1379
1380
      /* Parse the content type from the Content-type header */
1381
0
      T_BEGIN {
1382
0
        switch (hdr_field) {
1383
0
        case _HDR_CONTENT_TYPE:
1384
0
          body_part->content_type =
1385
0
            p_strdup(pool, _parse_content_type(block.hdr));
1386
0
          break;
1387
0
        case _HDR_CONTENT_DISPOSITION:
1388
0
          body_part->content_disposition =
1389
0
            p_strdup(pool, _parse_content_disposition(block.hdr));
1390
0
          break;
1391
0
        default:
1392
0
          i_unreached();
1393
0
        }
1394
0
      } T_END;
1395
1396
0
      continue;
1397
0
    }
1398
1399
    /* Reading body */
1400
0
    if (save_body) {
1401
0
      (void)message_decoder_decode_next_block(
1402
0
        decoder, &block, &decoded);
1403
0
      buffer_append(buf, decoded.data, decoded.size);
1404
0
    }
1405
0
  }
1406
1407
  /* Even with an empty message there was at least the "end of headers"
1408
     block, which set the body_part. */
1409
0
  i_assert(body_part != NULL);
1410
1411
  /* Save last body part if necessary */
1412
0
  if (header_part != NULL)
1413
0
    sieve_message_part_save(renv, buf, header_part, FALSE);
1414
0
  else if (save_body)
1415
0
    sieve_message_part_save(renv, buf, body_part, extract_text);
1416
1417
0
  if (iter_all && !array_is_created(&body_part->headers) &&
1418
0
      array_count(&headers) > 0) {
1419
0
    p_array_init(&body_part->headers, pool, array_count(&headers));
1420
0
    array_copy(&body_part->headers.arr, 0,
1421
0
         &headers.arr, 0, array_count(&headers));
1422
0
  }
1423
1424
  /* Try to fill the return_body_parts array once more */
1425
0
  have_all = iter_all ||
1426
0
    sieve_message_body_get_return_parts(renv, content_types,
1427
0
                extract_text);
1428
1429
  /* This time, failure is a bug */
1430
0
  i_assert(have_all);
1431
1432
  /* Cleanup */
1433
0
  (void)message_parser_deinit(&parser, &mparts);
1434
0
  message_decoder_deinit(&decoder);
1435
0
  buffer_free(&buf);
1436
1437
  /* Return status */
1438
0
  if (input->stream_errno != 0) {
1439
0
    sieve_runtime_critical(renv, NULL,
1440
0
               "failed to read input message",
1441
0
               "read(%s) failed: %s",
1442
0
               i_stream_get_name(input),
1443
0
               i_stream_get_error(input));
1444
0
    return SIEVE_EXEC_TEMP_FAILURE;
1445
0
  }
1446
0
  return SIEVE_EXEC_OK;
1447
0
}
1448
1449
int sieve_message_body_get_content(const struct sieve_runtime_env *renv,
1450
           const char *const *content_types,
1451
           struct sieve_message_part_data **parts_r)
1452
0
{
1453
0
  struct sieve_message_context *msgctx = renv->msgctx;
1454
0
  int status;
1455
1456
0
  T_BEGIN {
1457
    /* Fill the return_body_parts array */
1458
0
    status = sieve_message_parts_add_missing(renv, content_types,
1459
0
               FALSE, FALSE);
1460
0
  } T_END;
1461
1462
  /* Check status */
1463
0
  if (status <= 0)
1464
0
    return status;
1465
1466
  /* Return the array of body items */
1467
0
  (void)array_append_space(&msgctx->return_body_parts); /* NULL-terminate */
1468
0
  *parts_r = array_idx_modifiable(&msgctx->return_body_parts, 0);
1469
1470
0
  return status;
1471
0
}
1472
1473
int sieve_message_body_get_text(const struct sieve_runtime_env *renv,
1474
        struct sieve_message_part_data **parts_r)
1475
0
{
1476
0
  static const char *const _text_content_types[] =
1477
0
    { "application/xhtml+xml", "text", NULL };
1478
0
  struct sieve_message_context *msgctx = renv->msgctx;
1479
0
  int status;
1480
1481
  /* We currently only support extracting plain text from:
1482
1483
      - text/html -> HTML
1484
      - application/xhtml+xml -> XHTML
1485
1486
     Other text types are read as is. Any non-text types are skipped.
1487
   */
1488
1489
0
  T_BEGIN {
1490
    /* Fill the return_body_parts array */
1491
0
    status = sieve_message_parts_add_missing(
1492
0
      renv, _text_content_types, TRUE, FALSE);
1493
0
  } T_END;
1494
1495
  /* Check status */
1496
0
  if (status <= 0)
1497
0
    return status;
1498
1499
  /* Return the array of body items */
1500
0
  (void)array_append_space(&msgctx->return_body_parts); /* NULL-terminate */
1501
0
  *parts_r = array_idx_modifiable(&msgctx->return_body_parts, 0);
1502
1503
0
  return status;
1504
0
}
1505
1506
int sieve_message_body_get_raw(const struct sieve_runtime_env *renv,
1507
             struct sieve_message_part_data **parts_r)
1508
0
{
1509
0
  struct sieve_message_context *msgctx = renv->msgctx;
1510
0
  struct sieve_message_part_data *return_part;
1511
0
  buffer_t *buf;
1512
1513
0
  if (msgctx->raw_body == NULL) {
1514
0
    struct mail *mail = sieve_message_get_mail(renv->msgctx);
1515
0
    struct istream *input;
1516
0
    struct message_size hdr_size, body_size;
1517
0
    const unsigned char *data;
1518
0
    size_t size;
1519
0
    int ret;
1520
1521
0
    msgctx->raw_body = buf =
1522
0
      buffer_create_dynamic(msgctx->context_pool, 1024*64);
1523
1524
    /* Get stream for message */
1525
0
    if (mail_get_stream(mail, &hdr_size, &body_size, &input) < 0) {
1526
0
      return sieve_runtime_mail_error(
1527
0
        renv, mail, "failed to open input message");
1528
0
    }
1529
1530
    /* Skip stream to beginning of body */
1531
0
    i_stream_skip(input, hdr_size.physical_size);
1532
1533
    /* Read raw message body */
1534
0
    while ((ret = i_stream_read_more(input, &data, &size)) > 0) {
1535
0
      buffer_append(buf, data, size);
1536
1537
0
      i_stream_skip(input, size);
1538
0
    }
1539
1540
0
    if (ret < 0 && input->stream_errno != 0) {
1541
0
      sieve_runtime_critical(
1542
0
        renv, NULL, "failed to read input message",
1543
0
        "read(%s) failed: %s",
1544
0
        i_stream_get_name(input),
1545
0
        i_stream_get_error(input));
1546
0
      return SIEVE_EXEC_TEMP_FAILURE;
1547
0
    }
1548
1549
    /* Add terminating NUL to the body part buffer */
1550
0
    buffer_append_c(buf, '\0');
1551
1552
0
  } else {
1553
0
    buf = msgctx->raw_body;
1554
0
  }
1555
1556
  /* Clear result array */
1557
0
  array_clear(&msgctx->return_body_parts);
1558
1559
0
  if (buf->used > 1) {
1560
0
    const char *data = (const char *)buf->data;
1561
0
    size_t size = buf->used - 1;
1562
1563
0
    i_assert(data[size] == '\0');
1564
1565
    /* Add single item to the result */
1566
0
    return_part = array_append_space(&msgctx->return_body_parts);
1567
0
    return_part->content = data;
1568
0
    return_part->size = size;
1569
0
  }
1570
1571
  /* Return the array of body items */
1572
0
  (void)array_append_space(&msgctx->return_body_parts); /* NULL-terminate */
1573
0
  *parts_r = array_idx_modifiable(&msgctx->return_body_parts, 0);
1574
1575
0
  return SIEVE_EXEC_OK;
1576
0
}
1577
1578
/*
1579
 * Message part iterator
1580
 */
1581
1582
int sieve_message_part_iter_init(struct sieve_message_part_iter *iter,
1583
         const struct sieve_runtime_env *renv)
1584
0
{
1585
0
  struct sieve_message_context *msgctx = renv->msgctx;
1586
0
  struct sieve_message_part *const *parts;
1587
0
  unsigned int count;
1588
0
  int status;
1589
1590
0
  T_BEGIN {
1591
    /* Fill the return_body_parts array */
1592
0
    status = sieve_message_parts_add_missing(
1593
0
      renv, NULL, TRUE, TRUE);
1594
0
  } T_END;
1595
1596
  /* Check status */
1597
0
  if (status <= 0)
1598
0
    return status;
1599
1600
0
  i_zero(iter);
1601
0
  iter->renv = renv;
1602
0
  iter->index = 0;
1603
0
  iter->offset = 0;
1604
1605
0
  parts = array_get(&msgctx->cached_body_parts, &count);
1606
0
  if (count == 0)
1607
0
    iter->root = NULL;
1608
0
  else
1609
0
    iter->root = parts[0];
1610
1611
0
  return SIEVE_EXEC_OK;
1612
0
}
1613
1614
void sieve_message_part_iter_subtree(struct sieve_message_part_iter *iter,
1615
             struct sieve_message_part_iter *subtree)
1616
0
{
1617
0
  const struct sieve_runtime_env *renv = iter->renv;
1618
0
  struct sieve_message_context *msgctx = renv->msgctx;
1619
0
  struct sieve_message_part *const *parts;
1620
0
  unsigned int count;
1621
1622
0
  *subtree = *iter;
1623
1624
0
  parts = array_get(&msgctx->cached_body_parts, &count);
1625
0
  if (subtree->index >= count)
1626
0
    subtree->root = NULL;
1627
0
  else
1628
0
    subtree->root = parts[subtree->index];
1629
0
  subtree->offset = subtree->index;
1630
0
}
1631
1632
void sieve_message_part_iter_children(struct sieve_message_part_iter *iter,
1633
              struct sieve_message_part_iter *child)
1634
0
{
1635
0
  const struct sieve_runtime_env *renv = iter->renv;
1636
0
  struct sieve_message_context *msgctx = renv->msgctx;
1637
0
  struct sieve_message_part *const *parts;
1638
0
  unsigned int count;
1639
1640
0
  *child = *iter;
1641
1642
0
  parts = array_get(&msgctx->cached_body_parts, &count);
1643
0
  if ((child->index+1) >= count || parts[child->index]->children == NULL)
1644
0
    child->root = NULL;
1645
0
  else
1646
0
    child->root = parts[child->index++];
1647
0
  child->offset = child->index;
1648
0
}
1649
1650
struct sieve_message_part *
1651
sieve_message_part_iter_current(struct sieve_message_part_iter *iter)
1652
0
{
1653
0
  const struct sieve_runtime_env *renv = iter->renv;
1654
0
  struct sieve_message_context *msgctx = renv->msgctx;
1655
0
  struct sieve_message_part *const *parts;
1656
0
  unsigned int count;
1657
1658
0
  if (iter->root == NULL)
1659
0
    return NULL;
1660
1661
0
  parts = array_get(&msgctx->cached_body_parts, &count);
1662
0
  if (iter->index >= count)
1663
0
    return NULL;
1664
0
  do {
1665
0
    if (parts[iter->index] == iter->root->next)
1666
0
      return NULL;
1667
0
    if (parts[iter->index] == iter->root->parent)
1668
0
      return NULL;
1669
0
  } while (parts[iter->index]->epilogue && ++iter->index < count);
1670
0
  if (iter->index >= count)
1671
0
    return NULL;
1672
0
  return parts[iter->index];
1673
0
}
1674
1675
struct sieve_message_part *
1676
sieve_message_part_iter_next(struct sieve_message_part_iter *iter)
1677
0
{
1678
0
  const struct sieve_runtime_env *renv = iter->renv;
1679
0
  struct sieve_message_context *msgctx = renv->msgctx;
1680
1681
0
  if (iter->index >= array_count(&msgctx->cached_body_parts))
1682
0
    return NULL;
1683
0
  iter->index++;
1684
1685
0
  return sieve_message_part_iter_current(iter);
1686
0
}
1687
1688
void sieve_message_part_iter_reset(struct sieve_message_part_iter *iter)
1689
0
{
1690
0
  iter->index = iter->offset;
1691
0
}
1692
1693
/*
1694
 * MIME header list
1695
 */
1696
1697
/* Forward declarations */
1698
1699
static int
1700
sieve_mime_header_list_next_item(struct sieve_header_list *_hdrlist,
1701
         const char **name_r, string_t **value_r);
1702
static int
1703
sieve_mime_header_list_next_value(struct sieve_stringlist *_strlist,
1704
          string_t **value_r);
1705
static void sieve_mime_header_list_reset(struct sieve_stringlist *_strlist);
1706
1707
/* Header list object */
1708
1709
struct sieve_mime_header_list {
1710
  struct sieve_header_list hdrlist;
1711
1712
  struct sieve_stringlist *field_names;
1713
1714
  struct sieve_message_part_iter part_iter;
1715
1716
  const char *header_name;
1717
  const struct sieve_message_header *headers;
1718
  unsigned int headers_index, headers_count;
1719
1720
  bool mime_decode:1;
1721
  bool children:1;
1722
};
1723
1724
struct sieve_header_list *
1725
sieve_mime_header_list_create(const struct sieve_runtime_env *renv,
1726
            struct sieve_stringlist *field_names,
1727
            struct sieve_message_part_iter *part_iter,
1728
            bool mime_decode, bool children)
1729
0
{
1730
0
  struct sieve_mime_header_list *hdrlist;
1731
1732
0
  hdrlist = t_new(struct sieve_mime_header_list, 1);
1733
0
  hdrlist->hdrlist.strlist.runenv = renv;
1734
0
  hdrlist->hdrlist.strlist.exec_status = SIEVE_EXEC_OK;
1735
0
  hdrlist->hdrlist.strlist.next_item = sieve_mime_header_list_next_value;
1736
0
  hdrlist->hdrlist.strlist.reset = sieve_mime_header_list_reset;
1737
0
  hdrlist->hdrlist.next_item = sieve_mime_header_list_next_item;
1738
0
  hdrlist->field_names = field_names;
1739
0
  hdrlist->mime_decode = mime_decode;
1740
0
  hdrlist->children = children;
1741
1742
0
  sieve_message_part_iter_subtree(part_iter, &hdrlist->part_iter);
1743
1744
0
  return &hdrlist->hdrlist;
1745
0
}
1746
1747
/* MIME list implementation */
1748
1749
static void
1750
sieve_mime_header_list_next_name(struct sieve_mime_header_list *hdrlist)
1751
0
{
1752
0
  struct sieve_message_part *mpart;
1753
1754
0
  sieve_message_part_iter_reset(&hdrlist->part_iter);
1755
0
  mpart = sieve_message_part_iter_current(&hdrlist->part_iter);
1756
1757
0
  if (mpart != NULL && array_is_created(&mpart->headers)) {
1758
0
    hdrlist->headers = array_get(&mpart->headers,
1759
0
               &hdrlist->headers_count);
1760
0
    hdrlist->headers_index = 0;
1761
0
  }
1762
0
}
1763
1764
static int
1765
sieve_mime_header_list_next_item(struct sieve_header_list *_hdrlist,
1766
         const char **name_r, string_t **value_r)
1767
0
{
1768
0
  struct sieve_mime_header_list *hdrlist =
1769
0
    (struct sieve_mime_header_list *)_hdrlist;
1770
0
  const struct sieve_runtime_env *renv = _hdrlist->strlist.runenv;
1771
1772
0
  if (name_r != NULL)
1773
0
    *name_r = NULL;
1774
0
  *value_r = NULL;
1775
1776
0
  for (;;) {
1777
    /* Check for end of current header list */
1778
0
    if (hdrlist->headers_count == 0 ||
1779
0
        hdrlist->headers_index >= hdrlist->headers_count) {
1780
0
      hdrlist->headers_count = 0;
1781
0
      hdrlist->headers_index = 0;
1782
0
      hdrlist->headers = NULL;
1783
0
    }
1784
1785
    /* Fetch more headers */
1786
0
    while (hdrlist->headers_count == 0) {
1787
0
      string_t *hdr_item = NULL;
1788
0
      int ret;
1789
1790
0
      if (hdrlist->header_name != NULL && hdrlist->children) {
1791
0
        struct sieve_message_part *mpart;
1792
1793
0
        mpart = sieve_message_part_iter_next(
1794
0
          &hdrlist->part_iter);
1795
0
        if (mpart != NULL &&
1796
0
            array_is_created(&mpart->headers)) {
1797
0
          hdrlist->headers = array_get(
1798
0
            &mpart->headers,
1799
0
            &hdrlist->headers_count);
1800
0
          hdrlist->headers_index = 0;
1801
0
        }
1802
0
        if (hdrlist->headers_count > 0) {
1803
0
          if (_hdrlist->strlist.trace) {
1804
0
            sieve_runtime_trace(
1805
0
              renv, 0,
1806
0
              "moving to next message part");
1807
0
          }
1808
0
          break;
1809
0
        }
1810
0
      }
1811
1812
      /* Read next header name from source list */
1813
0
      if ((ret = sieve_stringlist_next_item(
1814
0
        hdrlist->field_names, &hdr_item)) <= 0)
1815
0
        return ret;
1816
1817
0
      hdrlist->header_name = str_c(hdr_item);
1818
1819
0
      if (_hdrlist->strlist.trace) {
1820
0
        sieve_runtime_trace(
1821
0
          renv, 0,
1822
0
          "extracting '%s' headers from message part",
1823
0
          str_sanitize(str_c(hdr_item), 80));
1824
0
      }
1825
1826
0
      sieve_mime_header_list_next_name(hdrlist);
1827
0
    }
1828
1829
0
    for (; hdrlist->headers_index < hdrlist->headers_count;
1830
0
         hdrlist->headers_index++) {
1831
0
      const struct sieve_message_header *header =
1832
0
        &hdrlist->headers[hdrlist->headers_index];
1833
1834
0
      if (strcasecmp(header->name, hdrlist->header_name) == 0) {
1835
0
        if (name_r != NULL)
1836
0
          *name_r = hdrlist->header_name;
1837
0
        if (hdrlist->mime_decode) {
1838
0
          *value_r = t_str_new_const(
1839
0
            (const char *)header->utf8_value,
1840
0
            header->utf8_value_len);
1841
0
        } else {
1842
0
          *value_r = t_str_new_const(
1843
0
            (const char *)header->value,
1844
0
            header->value_len);
1845
0
        }
1846
0
        hdrlist->headers_index++;
1847
0
        return 1;
1848
0
      }
1849
0
    }
1850
0
  }
1851
1852
0
  i_unreached();
1853
0
}
1854
1855
static int
1856
sieve_mime_header_list_next_value(struct sieve_stringlist *_strlist,
1857
          string_t **value_r)
1858
0
{
1859
0
  struct sieve_header_list *hdrlist =
1860
0
    (struct sieve_header_list *)_strlist;
1861
1862
0
  return sieve_mime_header_list_next_item(hdrlist, NULL, value_r);
1863
0
}
1864
1865
static void
1866
sieve_mime_header_list_reset(struct sieve_stringlist *strlist)
1867
0
{
1868
0
  struct sieve_mime_header_list *hdrlist =
1869
0
    (struct sieve_mime_header_list *)strlist;
1870
1871
0
  sieve_stringlist_reset(hdrlist->field_names);
1872
  hdrlist->header_name = NULL;
1873
0
}