Coverage Report

Created: 2026-03-11 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve-tool/sieve-tool.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "lib-signals.h"
6
#include "array.h"
7
#include "ioloop.h"
8
#include "ostream.h"
9
#include "hostpid.h"
10
#include "settings.h"
11
#include "dict.h"
12
#include "mail-namespace.h"
13
#include "mail-storage.h"
14
#include "mail-user.h"
15
#include "message-address.h"
16
#include "smtp-params.h"
17
#include "master-service.h"
18
#include "master-service-settings.h"
19
#include "mail-storage-service.h"
20
21
#include "sieve.h"
22
#include "sieve-plugins.h"
23
#include "sieve-extensions.h"
24
#include "sieve-storage.h"
25
26
#include "mail-raw.h"
27
28
#include "sieve-tool.h"
29
30
#include <stdio.h>
31
#include <unistd.h>
32
#include <fcntl.h>
33
#include <pwd.h>
34
#include <sysexits.h>
35
36
/*
37
 * Global state
38
 */
39
40
struct sieve_tool {
41
  pool_t pool;
42
  char *name;
43
44
  bool no_config;
45
46
  char *username;
47
  char *homedir;
48
49
  char *sieve_extensions;
50
  ARRAY_TYPE(const_string) sieve_plugins;
51
52
  sieve_tool_setting_callback_t setting_callback;
53
  void *setting_callback_context;
54
55
  struct sieve_instance *svinst;
56
57
  struct mail_storage_service_ctx *storage_service;
58
  struct mail_user *mail_user_dovecot;
59
  struct mail_user *mail_user;
60
61
  struct mail_user *mail_raw_user;
62
  struct mail_raw *mail_raw;
63
64
  bool fuzzer:1;
65
  bool debug:1;
66
};
67
68
struct sieve_tool *sieve_tool;
69
70
/*
71
 * Settings management
72
 */
73
74
static const char *
75
sieve_tool_sieve_get_homedir(struct sieve_instance *svinst ATTR_UNUSED,
76
           void *context)
77
0
{
78
0
  struct sieve_tool *tool = (struct sieve_tool *)context;
79
80
0
  return sieve_tool_get_homedir(tool);
81
0
}
82
83
const struct sieve_callbacks sieve_tool_callbacks = {
84
  sieve_tool_sieve_get_homedir,
85
};
86
87
/*
88
 * Initialization
89
 */
90
91
static void
92
sieve_tool_get_user_data(const char **username_r, const char **homedir_r)
93
0
{
94
0
  uid_t process_euid = geteuid();
95
0
  struct passwd *pw;
96
0
  const char *user = NULL, *home = NULL;
97
98
0
  user = getenv("USER");
99
0
  home = getenv("HOME");
100
101
0
  if (user == NULL || *user == '\0' || home == NULL || *home == '\0') {
102
0
    pw = getpwuid(process_euid);
103
0
    if (pw != NULL) {
104
0
      user = pw->pw_name;
105
0
      home = pw->pw_dir;
106
0
    }
107
0
  }
108
109
0
  if (username_r != NULL) {
110
0
    if (user == NULL || *user == '\0') {
111
0
      i_fatal("couldn't lookup our username (uid=%s)",
112
0
        dec2str(process_euid));
113
0
    }
114
115
0
    *username_r = t_strdup(user);
116
0
  }
117
118
0
  if (homedir_r != NULL)
119
0
    *homedir_r = t_strdup(home);
120
0
}
121
122
struct sieve_tool *
123
sieve_tool_init(const char *name, int *argc, char **argv[],
124
    const char *getopt_str, bool no_config)
125
0
{
126
0
  struct sieve_tool *tool;
127
0
  enum master_service_flags service_flags =
128
0
    MASTER_SERVICE_FLAG_STANDALONE |
129
0
    MASTER_SERVICE_FLAG_DONT_SEND_STATS |
130
0
    MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME;
131
0
  pool_t pool;
132
133
0
  if (no_config)
134
0
    service_flags |= MASTER_SERVICE_FLAG_CONFIG_DEFAULTS;
135
136
0
  getopt_str = t_strconcat(getopt_str, "DP:x:", NULL);
137
0
  master_service = master_service_init(name, service_flags,
138
0
               argc, argv, getopt_str);
139
140
0
  pool = pool_alloconly_create("sieve tool", 8192);
141
0
  tool = p_new(pool, struct sieve_tool, 1);
142
0
  tool->pool = pool;
143
0
  tool->name = p_strdup(tool->pool, name);
144
0
  tool->no_config = no_config;
145
146
0
  p_array_init(&tool->sieve_plugins, pool, 16);
147
0
  return tool;
148
0
}
149
150
151
struct sieve_tool *sieve_tool_init_fuzzer(const char *name)
152
0
{
153
0
  struct sieve_tool *tool;
154
0
  enum master_service_flags service_flags =
155
0
    MASTER_SERVICE_FLAG_STANDALONE |
156
0
    MASTER_SERVICE_FLAG_DONT_SEND_STATS |
157
0
    MASTER_SERVICE_FLAG_NO_INIT_DATASTACK_FRAME |
158
0
    MASTER_SERVICE_FLAG_CONFIG_BUILTIN;
159
0
  pool_t pool;
160
161
0
  pool = pool_alloconly_create("sieve tool", 8192);
162
0
  char *arg = p_strdup(pool, name);
163
0
  char **argv = p_new(pool, char *, 2);
164
0
  argv[0] = arg;
165
0
  int argc = 1;
166
0
  master_service = master_service_init(name, service_flags,
167
0
               &argc, &argv, "");
168
169
0
  tool = p_new(pool, struct sieve_tool, 1);
170
0
  tool->pool = pool;
171
0
  tool->name = arg;
172
0
  tool->fuzzer = TRUE;
173
0
  tool->no_config = TRUE;
174
175
0
  p_array_init(&tool->sieve_plugins, pool, 16);
176
0
  return tool;
177
0
}
178
179
int sieve_tool_getopt(struct sieve_tool *tool)
180
0
{
181
0
  int c;
182
183
0
  i_assert(!tool->fuzzer);
184
0
  while ((c = master_getopt(master_service)) > 0) {
185
0
    switch (c) {
186
0
    case 'x':
187
      /* Extensions */
188
0
      if (tool->sieve_extensions != NULL) {
189
0
        i_fatal_status(
190
0
          EX_USAGE,
191
0
          "duplicate -x option specified, "
192
0
          "but only one allowed.");
193
0
      }
194
0
      tool->sieve_extensions = p_strdup(tool->pool, optarg);
195
0
      break;
196
0
    case 'u':
197
0
      if (tool->username == NULL)
198
0
        tool->username = p_strdup(tool->pool, optarg);
199
0
      break;
200
0
    case 'P': {
201
      /* Plugin */
202
0
      const char *plugin;
203
204
0
      plugin = p_strdup(tool->pool, optarg);
205
0
      array_append(&tool->sieve_plugins, &plugin, 1);
206
0
      break;
207
0
    }
208
0
    case 'D':
209
0
      tool->debug = TRUE;
210
0
      break;
211
0
    default:
212
0
      return c;
213
0
    }
214
0
  }
215
216
0
  return c;
217
0
}
218
219
static void sieve_tool_load_plugins(struct sieve_tool *tool)
220
0
{
221
0
  unsigned int i, count;
222
0
  const char *const *plugins;
223
224
0
  plugins = array_get(&tool->sieve_plugins, &count);
225
0
  for (i = 0; i < count; i++) {
226
0
    const char *path, *file = strrchr(plugins[i], '/');
227
228
0
    if (file != NULL) {
229
0
      path = t_strdup_until(plugins[i], file);
230
0
      file = file+1;
231
0
    } else {
232
0
      path = NULL;
233
0
      file = plugins[i];
234
0
    }
235
236
0
    sieve_plugins_load(tool->svinst, path, file);
237
0
  }
238
0
}
239
240
struct sieve_instance *
241
sieve_tool_init_finish(struct sieve_tool *tool, bool init_mailstore,
242
           bool preserve_root)
243
0
{
244
0
  enum mail_storage_service_flags storage_service_flags =
245
0
    MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR |
246
0
    MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT;
247
0
  struct mail_storage_service_input service_input;
248
0
  struct sieve_environment svenv;
249
0
  const char *username = tool->username;
250
0
  const char *homedir = tool->homedir;
251
0
  const char *errstr;
252
253
0
  if (master_service_settings_read_simple(master_service, &errstr) < 0)
254
0
    i_fatal("%s", errstr);
255
256
0
  master_service_init_finish(master_service);
257
258
0
  if (tool->fuzzer) {
259
0
    username = tool->username = "fuzzer";
260
0
    tool->homedir = "/tmp";
261
0
  } else if (username == NULL) {
262
0
    sieve_tool_get_user_data(&username, &homedir);
263
264
0
    username = tool->username = p_strdup(tool->pool, username);
265
266
0
    tool->homedir = p_strdup(tool->pool, homedir);
267
268
0
    if (!tool->fuzzer && preserve_root) {
269
0
      storage_service_flags |=
270
0
        MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS;
271
0
    }
272
0
  } else {
273
0
    storage_service_flags |=
274
0
      MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
275
0
  }
276
277
0
  if (tool->fuzzer || !init_mailstore)
278
0
    storage_service_flags |=
279
0
      MAIL_STORAGE_SERVICE_FLAG_NO_NAMESPACES;
280
281
0
  const char *const code_override_fields[] = {
282
0
    (tool->homedir == NULL ? NULL :
283
0
     t_strconcat("mail_home=", tool->homedir, NULL)),
284
0
    NULL
285
0
  };
286
287
0
  i_zero(&service_input);
288
0
  service_input.service = tool->name;
289
0
  service_input.username = username;
290
0
  service_input.code_override_fields = code_override_fields;
291
292
0
  tool->storage_service = mail_storage_service_init(
293
0
    master_service, storage_service_flags);
294
0
  if (mail_storage_service_lookup_next(
295
0
    tool->storage_service, &service_input,
296
0
    &tool->mail_user_dovecot, &errstr) <= 0)
297
0
    i_fatal("%s", errstr);
298
299
0
  i_zero(&svenv);
300
0
  svenv.username = username;
301
0
  (void)mail_user_get_home(tool->mail_user_dovecot, &svenv.home_dir);
302
0
  svenv.hostname = my_hostdomain();
303
0
  svenv.base_dir = tool->mail_user_dovecot->set->base_dir;
304
0
  svenv.temp_dir = tool->mail_user_dovecot->set->mail_temp_dir;
305
0
  svenv.event_parent = tool->mail_user_dovecot->event;
306
0
  svenv.flags = SIEVE_FLAG_COMMAND_LINE;
307
0
  svenv.location = SIEVE_ENV_LOCATION_MS;
308
0
  svenv.delivery_phase = SIEVE_DELIVERY_PHASE_POST;
309
310
  /* Initialize Sieve Engine */
311
0
  if (sieve_init(&svenv, &sieve_tool_callbacks, tool, tool->debug,
312
0
           &tool->svinst) < 0)
313
0
    i_fatal("Failed to initialize Sieve");
314
315
  /* Load Sieve plugins */
316
0
  if (array_count(&tool->sieve_plugins) > 0)
317
0
    sieve_tool_load_plugins(tool);
318
319
  /* Set active Sieve extensions */
320
0
  if (tool->sieve_extensions != NULL) {
321
0
    sieve_set_extensions(tool->svinst, tool->sieve_extensions);
322
0
  } else if (tool->no_config) {
323
0
    sieve_set_extensions(tool->svinst, NULL);
324
0
  }
325
326
0
  return tool->svinst;
327
0
}
328
329
void sieve_tool_deinit(struct sieve_tool **_tool)
330
0
{
331
0
  struct sieve_tool *tool = *_tool;
332
333
0
  *_tool = NULL;
334
335
  /* Deinitialize Sieve engine */
336
0
  sieve_deinit(&tool->svinst);
337
338
  /* Free raw mail */
339
340
0
  if (tool->mail_raw != NULL)
341
0
    mail_raw_close(&tool->mail_raw);
342
343
0
  if (tool->mail_raw_user != NULL)
344
0
    mail_user_unref(&tool->mail_raw_user);
345
346
  /* Free mail service */
347
348
0
  if (tool->mail_user != NULL)
349
0
    mail_user_unref(&tool->mail_user);
350
0
  if (tool->mail_user_dovecot != NULL)
351
0
    mail_user_unref(&tool->mail_user_dovecot);
352
353
0
  mail_storage_service_deinit(&tool->storage_service);
354
355
  /* Free sieve tool object */
356
357
0
  pool_unref(&tool->pool);
358
359
  /* Deinitialize service */
360
0
  master_service_deinit(&master_service);
361
0
}
362
363
/*
364
 * Mail environment
365
 */
366
367
void sieve_tool_init_mail_user(struct sieve_tool *tool)
368
0
{
369
0
  struct mail_user *mail_user_dovecot = tool->mail_user_dovecot;
370
0
  const char *username = tool->username;
371
0
  struct mail_namespace *ns = NULL;
372
0
  const char *home = NULL, *errstr = NULL;
373
374
0
  struct settings_instance *set_instance =
375
0
    mail_storage_service_user_get_settings_instance(
376
0
      mail_user_dovecot->service_user);
377
0
  struct mail_storage_service_input input = {
378
0
    .username = username,
379
0
    .set_instance = set_instance,
380
0
    .no_userdb_lookup = TRUE,
381
0
  };
382
0
  if (mail_storage_service_lookup_next(tool->storage_service, &input,
383
0
               &tool->mail_user, &errstr) < 0)
384
0
    i_fatal("Test user lookup failed: %s", errstr);
385
386
0
  home = sieve_tool_get_homedir(sieve_tool);
387
0
  if (home != NULL)
388
0
    mail_user_set_home(tool->mail_user, home);
389
390
0
  if (mail_user_init(tool->mail_user, &errstr) < 0)
391
0
    i_fatal("Test user initialization failed: %s", errstr);
392
393
0
  if (mail_namespaces_init_location(tool->mail_user,
394
0
            tool->mail_user->event, &errstr) < 0)
395
0
    i_fatal("Test storage creation failed: %s", errstr);
396
397
0
  ns = tool->mail_user->namespaces;
398
0
  ns->flags |= NAMESPACE_FLAG_NOQUOTA | NAMESPACE_FLAG_NOACL;
399
0
}
400
401
static void sieve_tool_init_mail_raw_user(struct sieve_tool *tool)
402
0
{
403
0
  if (tool->mail_raw_user == NULL) {
404
0
    tool->mail_raw_user = mail_raw_user_create(
405
0
      tool->mail_user_dovecot);
406
0
  }
407
0
}
408
409
struct mail *
410
sieve_tool_open_file_as_mail(struct sieve_tool *tool, const char *path)
411
0
{
412
0
  sieve_tool_init_mail_raw_user(tool);
413
414
0
  if (tool->mail_raw != NULL)
415
0
    mail_raw_close(&tool->mail_raw);
416
417
0
  tool->mail_raw = mail_raw_open_file(tool->mail_raw_user, path);
418
419
0
  return tool->mail_raw->mail;
420
0
}
421
422
struct mail *
423
sieve_tool_open_data_as_mail(struct sieve_tool *tool, string_t *mail_data)
424
0
{
425
0
  sieve_tool_init_mail_raw_user(tool);
426
427
0
  if (tool->mail_raw != NULL)
428
0
    mail_raw_close(&tool->mail_raw);
429
430
0
  tool->mail_raw = mail_raw_open_data(tool->mail_raw_user, mail_data);
431
432
0
  return tool->mail_raw->mail;
433
0
}
434
435
/*
436
 * Configuration
437
 */
438
439
void sieve_tool_set_homedir(struct sieve_tool *tool, const char *homedir)
440
0
{
441
0
  i_assert(!tool->fuzzer);
442
443
0
  if (tool->homedir != NULL && strcmp(homedir, tool->homedir) == 0)
444
0
    return;
445
446
0
  tool->homedir = p_strdup(tool->pool, homedir);
447
448
0
  if (tool->mail_user_dovecot != NULL)
449
0
    mail_user_set_home(tool->mail_user_dovecot, tool->homedir);
450
0
  if (tool->mail_user != NULL)
451
0
    mail_user_set_home(tool->mail_user, tool->homedir);
452
0
}
453
454
void sieve_tool_set_setting_callback(struct sieve_tool *tool,
455
             sieve_tool_setting_callback_t callback,
456
             void *context)
457
0
{
458
0
  tool->setting_callback = callback;
459
0
  tool->setting_callback_context = context;
460
0
}
461
462
/*
463
 * Accessors
464
 */
465
466
const char *sieve_tool_get_username(struct sieve_tool *tool)
467
0
{
468
0
  const char *username;
469
470
0
  if (tool->username == NULL) {
471
0
    sieve_tool_get_user_data(&username, NULL);
472
0
    return username;
473
0
  }
474
475
0
  return tool->username;
476
0
}
477
478
const char *sieve_tool_get_homedir(struct sieve_tool *tool)
479
0
{
480
0
  const char *homedir = NULL;
481
482
0
  if (tool->homedir != NULL)
483
0
    return tool->homedir;
484
485
0
  if (tool->mail_user_dovecot != NULL &&
486
0
      mail_user_get_home(tool->mail_user_dovecot, &homedir) > 0)
487
0
    return tool->homedir;
488
489
0
  sieve_tool_get_user_data(NULL, &homedir);
490
0
  return homedir;
491
0
}
492
493
struct mail_user *sieve_tool_get_mail_user(struct sieve_tool *tool)
494
0
{
495
0
  return (tool->mail_user == NULL ?
496
0
    tool->mail_user_dovecot : tool->mail_user);
497
0
}
498
499
struct mail_user *sieve_tool_get_mail_raw_user(struct sieve_tool *tool)
500
0
{
501
0
  sieve_tool_init_mail_raw_user(tool);
502
0
  return tool->mail_raw_user;
503
0
}
504
505
struct mail_storage_service_ctx *
506
sieve_tool_get_mail_storage_service(struct sieve_tool *tool)
507
0
{
508
0
  sieve_tool_init_mail_raw_user(tool);
509
0
  return tool->storage_service;
510
0
}
511
512
/*
513
 * Commonly needed functionality
514
 */
515
516
static const struct smtp_address *
517
sieve_tool_get_address(struct mail *mail, const char *header)
518
0
{
519
0
  struct message_address *addr;
520
0
  struct smtp_address *smtp_addr;
521
0
  const char *str;
522
523
0
  if (mail_get_first_header(mail, header, &str) <= 0)
524
0
    return NULL;
525
0
  addr = message_address_parse(pool_datastack_create(),
526
0
             (const unsigned char *)str,
527
0
             strlen(str), 1, 0);
528
0
  if (addr == NULL || addr->mailbox == NULL ||
529
0
      addr->domain == NULL || *addr->mailbox == '\0' ||
530
0
      *addr->domain == '\0')
531
0
    return NULL;
532
0
  if (smtp_address_create_from_msg_temp(addr, &smtp_addr) < 0)
533
0
    return NULL;
534
0
  return smtp_addr;
535
0
}
536
537
void sieve_tool_get_envelope_data(struct sieve_message_data *msgdata,
538
          struct mail *mail,
539
          const struct smtp_address *sender,
540
          const struct smtp_address *rcpt_orig,
541
          const struct smtp_address *rcpt_final)
542
0
{
543
0
  struct smtp_params_rcpt *rcpt_params;
544
545
  /* Get sender address */
546
0
  if (sender == NULL)
547
0
    sender = sieve_tool_get_address(mail, "Return-path");
548
0
  if (sender == NULL)
549
0
    sender = sieve_tool_get_address(mail, "Sender");
550
0
  if (sender == NULL)
551
0
    sender = sieve_tool_get_address(mail, "From");
552
0
  if (sender == NULL)
553
0
    sender = smtp_address_create_temp("sender", "example.com");
554
555
  /* Get recipient address */
556
0
  if (rcpt_final == NULL)
557
0
    rcpt_final = sieve_tool_get_address(mail, "Envelope-To");
558
0
  if (rcpt_final == NULL)
559
0
    rcpt_final = sieve_tool_get_address(mail, "To");
560
0
  if (rcpt_final == NULL) {
561
0
    rcpt_final = smtp_address_create_temp("recipient",
562
0
                  "example.com");
563
0
  }
564
0
  if (rcpt_orig == NULL)
565
0
    rcpt_orig = rcpt_final;
566
567
0
  msgdata->envelope.mail_from = sender;
568
0
  msgdata->envelope.rcpt_to = rcpt_final;
569
570
0
  rcpt_params = t_new(struct smtp_params_rcpt, 1);
571
0
  rcpt_params->orcpt.addr = rcpt_orig;
572
573
0
  msgdata->envelope.rcpt_params = rcpt_params;
574
0
}
575
576
/*
577
 * File I/O
578
 */
579
580
struct ostream *sieve_tool_open_output_stream(const char *filename)
581
0
{
582
0
  struct ostream *outstream;
583
0
  int fd;
584
585
0
  if (strcmp(filename, "-") == 0)
586
0
    outstream = o_stream_create_fd(1, 0);
587
0
  else {
588
0
    fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_NOFOLLOW, 0600);
589
0
    if (fd < 0)
590
0
      i_fatal("failed to open file for writing: %m");
591
592
0
    outstream = o_stream_create_fd_autoclose(&fd, 0);
593
0
  }
594
595
0
  return outstream;
596
0
}
597
598
/*
599
 * Sieve script handling
600
 */
601
602
static void
603
sieve_tool_script_parse_location(struct sieve_tool *tool, const char *location,
604
         const char **storage_name_r)
605
0
{
606
0
  struct sieve_instance *svinst = tool->svinst;
607
0
  const char *data = strchr(location, ':');
608
0
  const char *script_driver = "file";
609
0
  const char *script_path = NULL;
610
0
  const char *storage_name = "_file";
611
612
0
  if (data != NULL) {
613
0
    script_driver = t_strdup_until(location, data++);
614
0
    if (strcmp(script_driver, "file") == 0)
615
0
      script_path = data;
616
0
    else
617
0
      storage_name = data;
618
0
  } else {
619
0
    script_path = location;
620
0
  }
621
622
0
  struct settings_instance *set_instance =
623
0
    settings_instance_find(svinst->event);
624
0
  const char *prefix = t_strdup_printf("sieve_script/%s", storage_name);
625
626
0
  settings_override(set_instance, "sieve_script+", storage_name,
627
0
        SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
628
0
  settings_override(set_instance,
629
0
        t_strdup_printf("%s/sieve_script_storage", prefix),
630
0
        storage_name, SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
631
0
  settings_override(set_instance,
632
0
        t_strdup_printf("%s/sieve_script_type", prefix),
633
0
        "command-line", SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
634
0
  settings_override(set_instance,
635
0
        t_strdup_printf("%s/sieve_script_driver", prefix),
636
0
        script_driver, SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
637
0
  if (script_path != NULL) {
638
0
    settings_override(
639
0
      set_instance, t_strdup_printf("%s/sieve_script_path",
640
0
                  prefix),
641
0
      script_path, SETTINGS_OVERRIDE_TYPE_2ND_CLI_PARAM);
642
0
  }
643
644
0
  *storage_name_r = storage_name;
645
0
}
646
647
struct sieve_binary *
648
sieve_tool_script_compile(struct sieve_tool *tool, const char *location)
649
0
{
650
0
  struct sieve_instance *svinst = tool->svinst;
651
0
  struct sieve_error_handler *ehandler;
652
0
  enum sieve_error error_code;
653
0
  struct sieve_binary *sbin = NULL;
654
655
0
  ehandler = sieve_stderr_ehandler_create(svinst, 0);
656
0
  sieve_error_handler_accept_infolog(ehandler, TRUE);
657
0
  sieve_error_handler_accept_debuglog(ehandler, svinst->debug);
658
659
0
  if (sieve_storage_name_is_valid(location) &&
660
0
      sieve_compile(svinst, SIEVE_SCRIPT_CAUSE_ANY, location, NULL,
661
0
        ehandler, 0, &sbin, &error_code) < 0 &&
662
0
      error_code != SIEVE_ERROR_NOT_FOUND)
663
0
    i_fatal("failed to compile sieve script storage");
664
665
0
  if (sbin == NULL) {
666
0
    const char *storage_name;
667
668
0
    sieve_tool_script_parse_location(tool, location, &storage_name);
669
0
    if (sieve_compile(svinst, SIEVE_SCRIPT_CAUSE_ANY, storage_name,
670
0
          NULL, ehandler, 0, &sbin, NULL) < 0)
671
0
      i_fatal("failed to compile sieve script");
672
0
  }
673
0
  i_assert(sbin != NULL);
674
675
0
  sieve_error_handler_unref(&ehandler);
676
0
  return sbin;
677
0
}
678
679
struct sieve_binary *
680
sieve_tool_script_open(struct sieve_tool *tool, const char *location)
681
0
{
682
0
  struct sieve_instance *svinst = tool->svinst;
683
0
  struct sieve_error_handler *ehandler;
684
0
  enum sieve_error error_code;
685
0
  struct sieve_binary *sbin = NULL;
686
687
0
  ehandler = sieve_stderr_ehandler_create(svinst, 0);
688
0
  sieve_error_handler_accept_infolog(ehandler, TRUE);
689
0
  sieve_error_handler_accept_debuglog(ehandler, svinst->debug);
690
691
0
  if (sieve_storage_name_is_valid(location) &&
692
0
      sieve_open(svinst, SIEVE_SCRIPT_CAUSE_ANY, location, NULL,
693
0
           ehandler, 0, &sbin, &error_code) < 0 &&
694
0
      error_code != SIEVE_ERROR_NOT_FOUND)
695
0
    i_fatal("failed to open sieve script storage");
696
697
0
  if  (sbin == NULL) {
698
0
    const char *storage_name;
699
700
0
    sieve_tool_script_parse_location(tool, location, &storage_name);
701
0
    if (sieve_open(svinst, SIEVE_SCRIPT_CAUSE_ANY, storage_name,
702
0
             NULL, ehandler, 0, &sbin, NULL) < 0)
703
0
      i_fatal("failed to open sieve script");
704
0
  }
705
0
  i_assert(sbin != NULL);
706
707
0
  sieve_error_handler_unref(&ehandler);
708
709
0
  sieve_save(sbin, FALSE, NULL);
710
0
  return sbin;
711
0
}
712
713
void sieve_tool_dump_binary_to(struct sieve_binary *sbin,
714
             const char *filename, bool hexdump)
715
0
{
716
0
  struct ostream *dumpstream;
717
718
0
  if (filename == NULL)
719
0
    return;
720
721
0
  dumpstream = sieve_tool_open_output_stream(filename);
722
0
  if (dumpstream != NULL) {
723
0
    if (hexdump)
724
0
      (void)sieve_hexdump(sbin, dumpstream);
725
0
    else
726
0
      (void)sieve_dump(sbin, dumpstream, FALSE);
727
0
    if (o_stream_finish(dumpstream) < 0) {
728
0
      i_fatal("write(%s) failed: %s", filename,
729
0
        o_stream_get_error(dumpstream));
730
0
    }
731
0
    o_stream_destroy(&dumpstream);
732
0
  } else {
733
0
    i_fatal("Failed to create stream for sieve code dump.");
734
0
  }
735
0
}
736
737
/*
738
 * Commandline option parsing
739
 */
740
741
void sieve_tool_parse_trace_option(struct sieve_trace_config *tr_config,
742
           const char *tr_option)
743
0
{
744
0
  const char *lvl;
745
746
0
  if (str_begins(tr_option, "level=", &lvl)) {
747
0
    if (strcmp(lvl, "none") == 0) {
748
0
      tr_config->level = SIEVE_TRLVL_NONE;
749
0
    } else if (strcmp(lvl, "actions") == 0) {
750
0
      tr_config->level = SIEVE_TRLVL_ACTIONS;
751
0
    } else if (strcmp(lvl, "commands") == 0) {
752
0
      tr_config->level = SIEVE_TRLVL_COMMANDS;
753
0
    } else if (strcmp(lvl, "tests") == 0) {
754
0
      tr_config->level = SIEVE_TRLVL_TESTS;
755
0
    } else if (strcmp(lvl, "matching") == 0) {
756
0
      tr_config->level = SIEVE_TRLVL_MATCHING;
757
0
    } else {
758
0
      i_fatal_status(EX_USAGE,
759
0
               "Unknown -tlevel= trace level: %s", lvl);
760
0
    }
761
0
  } else if (strcmp(tr_option, "debug") == 0) {
762
0
    tr_config->flags |= SIEVE_TRFLG_DEBUG;
763
0
  } else if (strcmp(tr_option, "addresses") == 0) {
764
0
    tr_config->flags |= SIEVE_TRFLG_ADDRESSES;
765
0
  } else {
766
    i_fatal_status(EX_USAGE, "Unknown -t trace option value: %s",
767
0
             tr_option);
768
0
  }
769
0
}