Coverage Report

Created: 2026-08-08 06:43

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