1/* This file is part of Mailfromd.             -*- c -*-
2   Copyright (C) 2007-2021 Sergey Poznyakoff
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 3, or (at your option)
7   any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17MF_BUILTIN_MODULE
18
19#include <mailutils/mailutils.h>
20#include <mflib/sieve.h>
21#include "msg.h"
22
23static void
24_sieve_text_action_log(mu_sieve_machine_t mach,
25		       const char *action, const char *fmt, va_list ap)
26{
27	mu_stream_t stream;
28	eval_environ_t env = mu_sieve_get_data (mach);
29	const char *id;
30
31	mu_sieve_get_diag_stream(mach, &stream);
32	mu_stream_printf(stream, "\033s<%d>", MU_LOG_NOTICE);
33	id = mailfromd_msgid(env_get_context(env));
34	if (id && id[0])
35		/* ID includes trailing semicolon */
36		mu_stream_printf(stream, "%s", id);
37	mu_stream_printf(stream, "%s", action);
38	if (fmt && fmt[0]) {
39		mu_stream_printf(stream, "; ");
40		mu_stream_vprintf(stream, fmt, ap);
41	}
42	mu_stream_printf(stream, "\n");
43}
44
45static void
46_sieve_file_action_log(mu_sieve_machine_t mach,
47		       const char *action, const char *fmt, va_list ap)
48{
49	mu_stream_t stream;
50	eval_environ_t env = mu_sieve_get_data(mach);
51	struct mu_locus_range locus;
52
53	_sieve_text_action_log(mach, action, fmt, ap);
54
55	mu_sieve_get_diag_stream(mach, &stream);
56	env_get_locus(env, &locus);
57	mu_stream_printf(stream, "\033f<%lu>%s\033l<%u>\033s<%d>\033O<%d>%s\n",
58			 (unsigned long) strlen(locus.beg.mu_file),
59			 locus.beg.mu_file,
60			 locus.beg.mu_line,
61			 MU_LOG_NOTICE,
62		         MU_LOGMODE_LOCUS|MU_LOGMODE_SEVERITY,
63			 _("sieve called from here"));
64}
65
66static void
67mach_cleanup(void *ptr)
68{
69	mu_sieve_machine_t mach = ptr;
70	mu_sieve_machine_destroy(&mach);
71}
72
73static void
74modify_debug_flags(mu_debug_level_t set, mu_debug_level_t clr)
75{
76	mu_debug_level_t lev;
77
78	mu_debug_get_category_level(mu_sieve_debug_handle, &lev);
79	mu_debug_set_category_level(mu_sieve_debug_handle, (lev & ~clr) | set);
80}
81
82MF_DEFUN(sieve, NUMBER, NUMBER nmsg, STRING script, OPTIONAL, NUMBER flags,
83	 STRING file, NUMBER line, NUMBER col)
84{
85	mu_sieve_machine_t mach;
86	int rc;
87	int retval = 0;
88	int f = MF_OPTVAL(flags);
89	mu_attribute_t attr;
90	mu_message_t msg;
91	const char *s;
92
93	rc = mu_sieve_machine_create(&mach);
94	MF_ASSERT(rc == 0, mfe_failure,
95		  _("failed to initialize sieve machine: %s"),
96		  mu_strerror(rc));
97	MF_DCL_CLEANUP(mach, mach_cleanup);
98
99	if (f & MF_SIEVE_DEBUG_TRACE)
100		modify_debug_flags(MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE4), 0);
101	if (f & MF_SIEVE_DEBUG_INSTR)
102		modify_debug_flags(MU_DEBUG_LEVEL_MASK(MU_DEBUG_TRACE9), 0);
103
104	mu_sieve_set_environ(mach, "location", "MTA");
105	mu_sieve_set_environ(mach, "phase", "pre");
106	s = env_get_macro(env, "client_addr");
107	if (s)
108		mu_sieve_set_environ(mach, "remote-ip", s);
109	s = env_get_macro(env, "client_ptr");
110	if (s)
111		mu_sieve_set_environ(mach, "remote-host", s);
112
113	mu_sieve_set_data(mach, env);
114
115	if (f & MF_SIEVE_TEXT) {
116		struct mu_locus_range locus = MU_LOCUS_RANGE_INITIALIZER;
117		struct mu_locus_point pt;
118
119		env_get_locus(env, &locus);
120		if (f & MF_SIEVE_LOG)
121			mu_sieve_set_logger(mach, _sieve_text_action_log);
122		pt.mu_file = MF_OPTVAL(file, locus.beg.mu_file);
123		pt.mu_line = MF_OPTVAL(line, locus.beg.mu_line);
124		pt.mu_col = MF_OPTVAL(col, locus.beg.mu_col);
125		rc = mu_sieve_compile_text(mach, script, strlen(script), &pt);
126	} else {
127		if (f & MF_SIEVE_LOG)
128			mu_sieve_set_logger(mach, _sieve_file_action_log);
129		rc = mu_sieve_compile(mach, script);
130	}
131
132	MF_ASSERT(rc == 0,
133		  mfe_failure,
134		  _("compilation of Sieve script %s failed"),
135		  script);
136
137	msg = bi_message_from_descr(env, nmsg);
138
139	mu_message_get_attribute(msg, &attr);
140	mu_attribute_unset_deleted(attr);
141	rc = mu_sieve_message(mach, msg);
142	MF_ASSERT(rc == 0,
143		  mfe_failure,
144		  _("sieving failed: %s"),
145		  mu_strerror(rc));
146	retval = !(mu_attribute_is_deleted(attr) == 0);
147
148	MF_RETURN(retval);
149}
150END
151
152