2
* mailing backend for dovecot antispam plugin
4
* Copyright (C) 2007 Johannes Berg <johannes@sipsolutions.net>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License Version 2 as
8
* published by the Free Software Foundation.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27
#include "mail-storage-private.h"
31
#include "antispam-plugin.h"
33
static const char *spam_arg = NULL;
34
static const char *ham_arg = NULL;
35
static const char *pipe_binary = "/usr/sbin/sendmail";
36
static const char *tmpdir = "/tmp";
37
static char **extra_args = NULL;
38
static int extra_args_num = 0;
40
static int run_pipe(int mailfd, enum classification wanted)
63
debug("running mailtrain backend program %s", pipe_binary);
66
if (waitpid(pid, &status, 0) == -1)
68
if (!WIFEXITED(status))
70
return WEXITSTATUS(status);
73
int sz = sizeof(char *) * (2 + extra_args_num + 1);
79
argv[0] = (char *) pipe_binary;
81
for (i = 0; i < extra_args_num; i++)
82
argv[i + 1] = (char *) extra_args[i];
84
argv[i + 1] = (char *) dest;
87
fd = open("/dev/null", O_WRONLY);
91
execv(pipe_binary, argv);
98
struct antispam_transaction_context {
104
static struct antispam_transaction_context *
105
backend_start(struct mailbox *box __attr_unused__)
107
struct antispam_transaction_context *ast;
110
ast = i_new(struct antispam_transaction_context, 1);
114
tmp = i_strconcat(tmpdir, "/antispam-mail-XXXXXX", NULL);
116
ast->tmpdir = mkdtemp(tmp);
120
ast->tmplen = strlen(ast->tmpdir);
125
static int process_tmpdir(struct mailbox_transaction_context *ctx,
126
struct antispam_transaction_context *ast)
128
int cnt = ast->count;
131
enum classification wanted;
136
buf = t_malloc(20 + ast->tmplen);
138
while (rc == 0 && cnt > 0) {
140
i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d",
143
fd = open(buf, O_RDONLY);
144
read(fd, &wanted, sizeof(wanted));
146
if ((rc = run_pipe(fd, wanted))) {
147
mail_storage_set_error(ctx->box->storage,
149
"failed to send mail");
150
debug("run program failed with exit code %d\n", rc);
162
static void clear_tmpdir(struct antispam_transaction_context *ast)
168
buf = t_malloc(20 + ast->tmplen);
170
while (ast->count > 0) {
172
i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d",
173
ast->tmpdir, ast->count);
181
static void backend_rollback(struct antispam_transaction_context *ast)
192
static int backend_commit(struct mailbox_transaction_context *ctx,
193
struct antispam_transaction_context *ast)
202
ret = process_tmpdir(ctx, ast);
212
static int backend_handle_mail(struct mailbox_transaction_context *t,
213
struct antispam_transaction_context *ast,
214
struct mail *mail, enum classification wanted)
216
struct istream *mailstream;
217
struct ostream *outstream;
220
const unsigned char *beginning;
225
mail_storage_set_error(t->box->storage,
227
"Failed to initialise temporary dir");
231
if (!ham_arg || !spam_arg) {
232
mail_storage_set_error(t->box->storage,
234
"antispam plugin not configured");
238
mailstream = get_mail_stream(mail);
240
mail_storage_set_error(t->box->storage,
242
"Failed to get mail contents");
248
buf = t_malloc(20 + ast->tmplen);
249
i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d", ast->tmpdir, ast->count);
251
fd = creat(buf, 0600);
253
mail_storage_set_error(t->box->storage,
255
"Failed to create temporary file");
262
outstream = o_stream_create_from_fd(fd, t->box->pool);
265
mail_storage_set_error(t->box->storage,
267
"Failed to stream temporary file");
271
if (o_stream_send(outstream, &wanted, sizeof(wanted))
274
mail_storage_set_error(t->box->storage,
276
"Failed to write marker to temp file");
280
if (i_stream_read_data(mailstream, &beginning, &size, 5) < 0 ||
283
mail_storage_set_error(t->box->storage,
285
"Failed to read mail beginning");
289
/* "From "? skip line */
290
if (memcmp("From ", beginning, 5) == 0)
291
i_stream_read_next_line(mailstream);
293
if (o_stream_send_istream(outstream, mailstream) < 0) {
295
mail_storage_set_error(t->box->storage,
297
"Failed to copy to temporary file");
304
o_stream_destroy(&outstream);
313
static void backend_init(pool_t pool __attr_unused__)
318
tmp = get_setting("PIPE_PROGRAM_SPAM_ARG");
320
tmp = get_setting("MAIL_SPAM");
323
debug("pipe backend spam argument = %s\n", tmp);
326
tmp = get_setting("PIPE_PROGRAM_NOTSPAM_ARG");
328
tmp = get_setting("MAIL_NOTSPAM");
331
debug("pipe backend not-spam argument = %s\n", tmp);
334
tmp = get_setting("PIPE_PROGRAM");
336
tmp = get_setting("MAIL_SENDMAIL");
339
debug("pipe backend program = %s\n", tmp);
342
tmp = get_setting("PIPE_PROGRAM_ARGS");
344
tmp = get_setting("MAIL_SENDMAIL_ARGS");
346
extra_args = p_strsplit(pool, tmp, ";");
347
extra_args_num = str_array_length(
348
(const char *const *)extra_args);
349
for (i = 0; i < extra_args_num; i++)
350
debug("pipe backend program arg[%d] = %s\n",
354
tmp = get_setting("PIPE_TMPDIR");
356
tmp = get_setting("MAIL_TMPDIR");
359
debug("pipe backend tmpdir %s\n", tmpdir);
362
static void backend_exit(void)
366
struct backend pipe_backend = {
367
.init = backend_init,
368
.exit = backend_exit,
369
.handle_mail = backend_handle_mail,
370
.start = backend_start,
371
.rollback = backend_rollback,
372
.commit = backend_commit,