Skip to content

Commit

Permalink
Implemented the imapsieve extension for Sieve and IMAP as a plugin.
Browse files Browse the repository at this point in the history
  • Loading branch information
stephanbosch committed Mar 27, 2016
1 parent b190d77 commit dbe03ae
Show file tree
Hide file tree
Showing 15 changed files with 2,455 additions and 5 deletions.
8 changes: 3 additions & 5 deletions TODO
Expand Up @@ -88,11 +88,9 @@ Low priority items:
within Dovecot)
* Warn during compile if using non-existent folders.

* Implement IMAP plugin for IMAPSieve support:
- Requires some sort of Sieve transaction support.
- This may include support for manually running a script on a set of messages
through IMAP (no specification for something like this is available; we will
have to provide our own)
* Implement support for manually running a script on a set of messages through
IMAP (no specification for something like this is available; we will have to
provide our own)
* Variables extension: implement compile time evaluation of constant values
- Detect assignment of too large constant values to variables at compile
time.
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Expand Up @@ -223,6 +223,7 @@ src/plugins/Makefile
src/plugins/doveadm-sieve/Makefile
src/plugins/lda-sieve/Makefile
src/plugins/sieve-extprograms/Makefile
src/plugins/imapsieve/Makefile
src/plugins/settings/Makefile
src/sieve-tools/Makefile
src/managesieve/Makefile
Expand Down
1 change: 1 addition & 0 deletions src/plugins/Makefile.am
Expand Up @@ -2,4 +2,5 @@ SUBDIRS = \
doveadm-sieve \
lda-sieve \
sieve-extprograms \
imapsieve \
settings
40 changes: 40 additions & 0 deletions src/plugins/imapsieve/Makefile.am
@@ -0,0 +1,40 @@
imap_moduledir = $(dovecot_moduledir)
sieve_plugindir = $(dovecot_moduledir)/sieve

imap_module_LTLIBRARIES = lib95_imap_sieve_plugin.la
sieve_plugin_LTLIBRARIES = lib90_sieve_imapsieve_plugin.la

lib95_imap_sieve_plugin_la_LDFLAGS = -module -avoid-version
lib90_sieve_imapsieve_plugin_la_LDFLAGS = -module -avoid-version

AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib-sieve \
-I$(top_srcdir)/src/lib-sieve/util \
-I$(top_srcdir)/src/lib-sieve/plugins/environment \
$(LIBDOVECOT_IMAP_INCLUDE) \
$(LIBDOVECOT_LDA_INCLUDE) \
$(LIBDOVECOT_INCLUDE) \
-DPKG_RUNDIR=\""$(rundir)"\"

lib95_imap_sieve_plugin_la_SOURCES = \
ext-imapsieve.c \
ext-imapsieve-environment.c \
imap-sieve.c \
imap-sieve-storage.c \
imap-sieve-plugin.c
lib95_imap_sieve_plugin_la_LIBADD = \
$(top_builddir)/src/lib-sieve/libdovecot-sieve.la

lib90_sieve_imapsieve_plugin_la_SOURCES = \
ext-imapsieve.c \
sieve-imapsieve-plugin.c
lib90_sieve_imapsieve_plugin_la_CPPFLAGS = \
${AM_CPPFLAGS} \
-D__IMAPSIEVE_DUMMY

noinst_HEADERS = \
ext-imapsieve-common.h \
imap-sieve.h \
imap-sieve-storage.h \
imap-sieve-plugin.h \
sieve-imapsieve-plugin.h
26 changes: 26 additions & 0 deletions src/plugins/imapsieve/ext-imapsieve-common.h
@@ -0,0 +1,26 @@
/* Copyright (c) 2016 Pigeonhole authors, see the included COPYING file
*/

#ifndef __EXT_IMAPSIEVE_COMMON_H
#define __EXT_IMAPSIEVE_COMMON_H

#include "sieve-extensions.h"

#include "imap-sieve.h"

/*
* Extensions
*/

extern const struct sieve_extension_def imapsieve_extension;
extern const struct sieve_extension_def imapsieve_extension_dummy;

/*
* Environment items
*/

void ext_imapsieve_environment_items_register
(const struct sieve_extension *ext,
const struct sieve_runtime_env *renv);

#endif /* __EXT_IMAPSIEVE_COMMON_H */
131 changes: 131 additions & 0 deletions src/plugins/imapsieve/ext-imapsieve-environment.c
@@ -0,0 +1,131 @@
/* Copyright (c) 2016 Pigeonhole authors, see the included COPYING file
*/

#include "lib.h"
#include "array.h"
#include "mail-storage.h"

#include "sieve-extensions.h"
#include "sieve-commands.h"
#include "sieve-validator.h"
#include "sieve-generator.h"
#include "sieve-runtime.h"

#include "sieve-ext-environment.h"

#include "ext-imapsieve-common.h"

/*
* Environment items
*/

/* imap.user */

static const char *envit_imap_user_get_value
(const struct sieve_runtime_env *renv)
{
const struct sieve_script_env *senv = renv->scriptenv;

return senv->user->username;
}

const struct sieve_environment_item imap_user_env_item = {
.name = "imap.user",
.get_value = envit_imap_user_get_value
};

/* imap.email */

static const char *envit_imap_email_get_value
(const struct sieve_runtime_env *renv)
{
struct sieve_instance *svinst = renv->svinst;
const struct sieve_script_env *senv = renv->scriptenv;
const char *username = senv->user->username;

// FIXME: explicit configuration
if ( strchr(username, '@') != 0 )
return username;
if ( svinst->domainname != NULL )
return t_strconcat(username, "@", svinst->domainname, NULL);
return NULL;
}

const struct sieve_environment_item imap_email_env_item = {
.name = "imap.email",
.get_value = envit_imap_email_get_value
};

/* imap.cause */

static const char *envit_imap_cause_get_value
(const struct sieve_runtime_env *renv)
{
const struct sieve_script_env *senv = renv->scriptenv;
struct imap_sieve_context *isctx =
(struct imap_sieve_context *)senv->script_context;

return isctx->event.cause;
}

const struct sieve_environment_item imap_cause_env_item = {
.name = "imap.cause",
.get_value = envit_imap_cause_get_value
};

/* imap.mailbox */

static const char *envit_imap_mailbox_get_value
(const struct sieve_runtime_env *renv)
{
const struct sieve_script_env *senv = renv->scriptenv;
struct imap_sieve_context *isctx =
(struct imap_sieve_context *)senv->script_context;

return mailbox_get_vname(isctx->event.mailbox);
}

const struct sieve_environment_item imap_mailbox_env_item = {
.name = "imap.mailbox",
.get_value = envit_imap_mailbox_get_value
};


/* imap.changedflags */

static const char *envit_imap_changedflags_get_value
(const struct sieve_runtime_env *renv)
{
const struct sieve_script_env *senv = renv->scriptenv;
struct imap_sieve_context *isctx =
(struct imap_sieve_context *)senv->script_context;

return isctx->event.changed_flags;
}

const struct sieve_environment_item imap_changedflags_env_item = {
.name = "imap.changedflags",
.get_value = envit_imap_changedflags_get_value
};

/*
* Register
*/

void ext_imapsieve_environment_items_register
(const struct sieve_extension *ext, const struct sieve_runtime_env *renv)
{
const struct sieve_extension *env_ext =
(const struct sieve_extension *) ext->context;

sieve_environment_item_register
(env_ext, renv->interp, &imap_user_env_item);
sieve_environment_item_register
(env_ext, renv->interp, &imap_email_env_item);
sieve_environment_item_register
(env_ext, renv->interp, &imap_cause_env_item);
sieve_environment_item_register
(env_ext, renv->interp, &imap_mailbox_env_item);
sieve_environment_item_register
(env_ext, renv->interp, &imap_changedflags_env_item);
}
110 changes: 110 additions & 0 deletions src/plugins/imapsieve/ext-imapsieve.c
@@ -0,0 +1,110 @@
/* Copyright (c) 2016 Pigeonhole authors, see the included COPYING file
*/

/* Extension imapsieve
* -------------------
*
* Authors: Stephan Bosch
* Specification: rfc6785
* Implementation: full
* Status: experimental
*
*/

#include "lib.h"

#include "sieve-extensions.h"
#include "sieve-commands.h"
#include "sieve-binary.h"

#include "sieve-validator.h"
#include "sieve-interpreter.h"

#include "sieve-ext-environment.h"

#include "ext-imapsieve-common.h"

/*
* Extension
*/

static bool ext_imapsieve_load
(const struct sieve_extension *ext, void **context);
static bool ext_imapsieve_interpreter_load
(const struct sieve_extension *ext,
const struct sieve_runtime_env *renv,
sieve_size_t *address ATTR_UNUSED);

#ifdef __IMAPSIEVE_DUMMY
const struct sieve_extension_def imapsieve_extension_dummy = {
#else
const struct sieve_extension_def imapsieve_extension = {
#endif
.name = "imapsieve",
.load = ext_imapsieve_load,
.interpreter_load = ext_imapsieve_interpreter_load
};

/*
* Context
*/

static bool ext_imapsieve_load
(const struct sieve_extension *ext, void **context)
{
*context = (void*)
sieve_ext_environment_require_extension(ext->svinst);
return TRUE;
}

/*
* Interpreter
*/

static int ext_imapsieve_interpreter_run
(const struct sieve_extension *this_ext,
const struct sieve_runtime_env *renv,
void *context, bool deferred);

const struct sieve_interpreter_extension
imapsieve_interpreter_extension = {
#ifdef __IMAPSIEVE_DUMMY
.ext_def = &imapsieve_extension_dummy,
#else
.ext_def = &imapsieve_extension,
#endif
.run = ext_imapsieve_interpreter_run
};

static bool ext_imapsieve_interpreter_load
(const struct sieve_extension *ext ATTR_UNUSED,
const struct sieve_runtime_env *renv,
sieve_size_t *address ATTR_UNUSED)
{
sieve_interpreter_extension_register(renv->interp,
ext, &imapsieve_interpreter_extension, NULL);
return TRUE;
}

#ifdef __IMAPSIEVE_DUMMY
static int ext_imapsieve_interpreter_run
(const struct sieve_extension *ext ATTR_UNUSED,
const struct sieve_runtime_env *renv,
void *context ATTR_UNUSED, bool deferred)
{
if ( !deferred ) {
sieve_runtime_error(renv, NULL,
"the imapsieve extension cannot be used outside IMAP");
}
return SIEVE_EXEC_FAILURE;
}
#else
static int ext_imapsieve_interpreter_run
(const struct sieve_extension *ext ATTR_UNUSED,
const struct sieve_runtime_env *renv,
void *context ATTR_UNUSED, bool deferred ATTR_UNUSED)
{
ext_imapsieve_environment_items_register(ext, renv);
return SIEVE_EXEC_OK;
}
#endif

0 comments on commit dbe03ae

Please sign in to comment.