/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2021 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
. */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#define SIEVE_RT_ARG(m,n,t) ((m)->prog[(m)->pc+(n)].t)
#define SIEVE_RT_ADJUST(m,n) (m)->pc+=(n)
#define INSTR_DISASS(m) ((m)->state == mu_sieve_state_disass)
#define INSTR_DEBUG(m) \
(INSTR_DISASS(m) || mu_debug_level_p (mu_sieve_debug_handle, MU_DEBUG_TRACE9))
void
_mu_i_sv_instr_locus (mu_sieve_machine_t mach)
{
mu_locus_point_set_file (&mach->locus.beg,
mu_i_sv_id_str (mach, SIEVE_RT_ARG (mach, 0, pc)));
mach->locus.beg.mu_line = SIEVE_RT_ARG (mach, 1, unum);
mach->locus.beg.mu_col = SIEVE_RT_ARG (mach, 2, unum);
mu_locus_point_set_file (&mach->locus.end,
mu_i_sv_id_str (mach, SIEVE_RT_ARG (mach, 3, pc)));
mach->locus.end.mu_line = SIEVE_RT_ARG (mach, 4, unum);
mach->locus.end.mu_col = SIEVE_RT_ARG (mach, 5, unum);
mu_stream_ioctl (mach->errstream, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_LOCUS_RANGE, &mach->locus);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 1, "LOCUS");
SIEVE_RT_ADJUST (mach, 6);
}
static int
instr_run (mu_sieve_machine_t mach, char const *what)
{
int rc = 0;
mu_sieve_handler_t han = SIEVE_RT_ARG (mach, 0, handler);
mach->argstart = SIEVE_RT_ARG (mach, 1, pc);
mach->argcount = SIEVE_RT_ARG (mach, 2, pc);
mach->tagcount = SIEVE_RT_ARG (mach, 3, pc);
mach->identifier = SIEVE_RT_ARG (mach, 4, string);
mach->comparator = SIEVE_RT_ARG (mach, 5, comp);
SIEVE_RT_ADJUST (mach, 6);
if (INSTR_DEBUG (mach))
mu_i_sv_debug_command (mach, mach->pc - 7, what);
else
mu_i_sv_trace (mach, what);
if (!INSTR_DISASS (mach))
rc = han (mach);
mach->argstart = 0;
mach->argcount = 0;
mach->tagcount = 0;
mach->identifier = NULL;
mach->comparator = NULL;
return rc;
}
void
_mu_i_sv_instr_action (mu_sieve_machine_t mach)
{
mach->action_count++;
instr_run (mach, "ACTION");
}
void
_mu_i_sv_instr_test (mu_sieve_machine_t mach)
{
mach->reg = instr_run (mach, "TEST");
}
void
_mu_i_sv_instr_not (mu_sieve_machine_t mach)
{
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 1, "NOT");
if (INSTR_DISASS (mach))
return;
mach->reg = !mach->reg;
}
void
_mu_i_sv_instr_branch (mu_sieve_machine_t mach)
{
long num = SIEVE_RT_ARG (mach, 0, number);
SIEVE_RT_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 2, "BRANCH %lu",
(unsigned long)(mach->pc + num));
if (INSTR_DISASS (mach))
return;
mach->pc += num;
}
void
_mu_i_sv_instr_brz (mu_sieve_machine_t mach)
{
long num = SIEVE_RT_ARG (mach, 0, number);
SIEVE_RT_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 2, "BRZ %lu",
(unsigned long)(mach->pc + num));
if (INSTR_DISASS (mach))
return;
if (!mach->reg)
mach->pc += num;
}
void
_mu_i_sv_instr_brnz (mu_sieve_machine_t mach)
{
long num = SIEVE_RT_ARG (mach, 0, number);
SIEVE_RT_ADJUST (mach, 1);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc - 2, "BRNZ %lu",
(unsigned long)(mach->pc + num));
if (INSTR_DISASS (mach))
return;
if (mach->reg)
mach->pc += num;
}
void
mu_sieve_abort (mu_sieve_machine_t mach)
{
longjmp (mach->errbuf, MU_ERR_FAILURE);
}
void
mu_sieve_set_data (mu_sieve_machine_t mach, void *data)
{
mach->data = data;
}
void *
mu_sieve_get_data (mu_sieve_machine_t mach)
{
return mach->data;
}
int
mu_sieve_get_locus (mu_sieve_machine_t mach, struct mu_locus_range *loc)
{
return mu_locus_range_copy (loc, &mach->locus);
}
mu_mailbox_t
mu_sieve_get_mailbox (mu_sieve_machine_t mach)
{
return mach->mailbox;
}
mu_message_t
mu_sieve_get_message (mu_sieve_machine_t mach)
{
if (!mach->msg)
mu_mailbox_get_message (mach->mailbox, mach->msgno, &mach->msg);
return mach->msg;
}
size_t
mu_sieve_get_message_num (mu_sieve_machine_t mach)
{
return mach->msgno;
}
const char *
mu_sieve_get_identifier (mu_sieve_machine_t mach)
{
return mach->identifier;
}
void
mu_sieve_get_argc (mu_sieve_machine_t mach, size_t *args, size_t *tags)
{
if (args)
*args = mach->argcount;
if (tags)
*tags = mach->tagcount;
}
int
mu_sieve_is_dry_run (mu_sieve_machine_t mach)
{
return mach->dry_run;
}
int
mu_sieve_set_dry_run (mu_sieve_machine_t mach, int val)
{
if (mach->state != mu_sieve_state_compiled)
return EINVAL; /* FIXME: another error code */
return mach->dry_run = val;
}
int
sieve_run (mu_sieve_machine_t mach)
{
int rc;
mu_sieve_stream_save (mach);
rc = setjmp (mach->errbuf);
if (rc == 0)
{
mach->action_count = 0;
mu_i_sv_init_variables (mach);
for (mach->pc = 1; mach->prog[mach->pc].handler; )
(*mach->prog[mach->pc++].instr) (mach);
if (mach->action_count == 0)
mu_sieve_log_action (mach, "IMPLICIT KEEP", NULL);
if (INSTR_DEBUG (mach))
mu_i_sv_debug (mach, mach->pc, "STOP");
}
mu_sieve_stream_restore (mach);
return rc;
}
int
mu_sieve_disass (mu_sieve_machine_t mach)
{
int rc;
if (mach->state != mu_sieve_state_compiled)
return EINVAL; /* FIXME: Error code */
mach->state = mu_sieve_state_disass;
rc = sieve_run (mach);
mach->state = mu_sieve_state_compiled;
return rc;
}
static int
_sieve_action (mu_observer_t obs, size_t type, void *data, void *action_data)
{
mu_sieve_machine_t mach;
if (type != MU_EVT_MESSAGE_ADD)
return 0;
mach = mu_observer_get_owner (obs);
mach->msgno++;
mu_mailbox_get_message (mach->mailbox, mach->msgno, &mach->msg);
sieve_run (mach);
return 0;
}
int
mu_sieve_mailbox (mu_sieve_machine_t mach, mu_mailbox_t mbox)
{
int rc;
size_t total;
mu_observer_t observer;
mu_observable_t observable;
if (!mach || !mbox)
return EINVAL;
if (mach->state != mu_sieve_state_compiled)
return EINVAL; /* FIXME: Error code */
mach->state = mu_sieve_state_running;
mu_observer_create (&observer, mach);
mu_observer_set_action (observer, _sieve_action, mach);
mu_mailbox_get_observable (mbox, &observable);
mu_observable_attach (observable, MU_EVT_MESSAGE_ADD, observer);
mach->mailbox = mbox;
mach->msgno = 0;
rc = mu_mailbox_scan (mbox, 1, &total);
if (rc)
mu_sieve_error (mach, _("mu_mailbox_scan: %s"), mu_strerror (errno));
mu_observable_detach (observable, observer);
mu_observer_destroy (&observer, mach);
mach->state = mu_sieve_state_compiled;
mach->mailbox = NULL;
return rc;
}
int
mu_sieve_message (mu_sieve_machine_t mach, mu_message_t msg)
{
int rc;
if (!mach || !msg)
return EINVAL;
if (mach->state != mu_sieve_state_compiled)
return EINVAL; /* FIXME: Error code */
mach->state = mu_sieve_state_running;
mach->msgno = 1;
mach->msg = msg;
mach->mailbox = NULL;
rc = sieve_run (mach);
mach->state = mu_sieve_state_compiled;
mach->msg = NULL;
return rc;
}