1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
/* Copyright (c) 2002-2013 Pigeonhole authors, see the included COPYING file
*/
#include "lib.h"
#include "array.h"
#include "sieve-common.h"
#include "sieve-extensions.h"
#include "sieve-commands.h"
#include "sieve-validator.h"
#include "sieve-generator.h"
#include "ext-ihave-common.h"
/*
* Ihave test
*
* Syntax:
* ihave <capabilities: string-list>
*/
static bool tst_ihave_validate
(struct sieve_validator *valdtr, struct sieve_command *tst);
static bool tst_ihave_validate_const
(struct sieve_validator *valdtr, struct sieve_command *tst,
int *const_current, int const_next);
const struct sieve_command_def ihave_test = {
"ihave",
SCT_TEST,
1, 0, FALSE, FALSE,
NULL, NULL,
tst_ihave_validate,
tst_ihave_validate_const,
NULL, NULL
};
/*
* Code validation
*/
static bool tst_ihave_validate
(struct sieve_validator *valdtr, struct sieve_command *tst)
{
struct _capability {
const struct sieve_extension *ext;
struct sieve_ast_argument *arg;
};
struct sieve_ast_argument *arg = tst->first_positional;
struct sieve_ast_argument *stritem;
enum sieve_compile_flags cpflags = sieve_validator_compile_flags(valdtr);
bool no_global = ( (cpflags & SIEVE_COMPILE_FLAG_NOGLOBAL) != 0 );
ARRAY(struct _capability) capabilities;
struct _capability capability;
const struct _capability *caps;
unsigned int i, count;
bool all_known = TRUE;
t_array_init(&capabilities, 64);
tst->data = (void *) FALSE;
/* Check stringlist argument */
if ( !sieve_validate_positional_argument
(valdtr, tst, arg, "capabilities", 1, SAAT_STRING_LIST) ) {
return FALSE;
}
switch ( sieve_ast_argument_type(arg) ) {
case SAAT_STRING:
/* Single string */
capability.arg = arg;
capability.ext = sieve_extension_get_by_name
(tst->ext->svinst, sieve_ast_argument_strc(arg));
if ( capability.ext == NULL || (no_global && capability.ext->global)) {
all_known = FALSE;
ext_ihave_ast_add_missing_extension
(tst->ext, tst->ast_node->ast, sieve_ast_argument_strc(arg));
} else {
array_append(&capabilities, &capability, 1);
}
break;
case SAAT_STRING_LIST:
/* String list */
stritem = sieve_ast_strlist_first(arg);
while ( stritem != NULL ) {
capability.arg = stritem;
capability.ext = sieve_extension_get_by_name
(tst->ext->svinst, sieve_ast_argument_strc(stritem));
if ( capability.ext == NULL || (no_global && capability.ext->global)) {
all_known = FALSE;
ext_ihave_ast_add_missing_extension
(tst->ext, tst->ast_node->ast, sieve_ast_argument_strc(stritem));
} else {
array_append(&capabilities, &capability, 1);
}
stritem = sieve_ast_strlist_next(stritem);
}
break;
default:
i_unreached();
}
if ( !all_known )
return TRUE;
/* RFC 5463, Section 4, page 4:
*
* The "ihave" extension is designed to be used with other extensions
* that add tests, actions, comparators, or arguments. Implementations
* MUST NOT allow it to be used with extensions that change the
* underlying Sieve grammar, or extensions like encoded-character
* [RFC5228], or variables [RFC5229] that change how the content of
* Sieve scripts are interpreted. The test MUST fail and the extension
* MUST NOT be enabled if such usage is attempted.
*
* FIXME: current implementation of this restriction is hardcoded and
* therefore highly inflexible
*/
caps = array_get(&capabilities, &count);
for ( i = 0; i < count; i++ ) {
if ( sieve_extension_name_is(caps[i].ext, "variables") ||
sieve_extension_name_is(caps[i].ext, "encoded-character") )
return TRUE;
}
/* Load all extensions */
caps = array_get(&capabilities, &count);
for ( i = 0; i < count; i++ ) {
if ( !sieve_validator_extension_load
(valdtr, tst, caps[i].arg, caps[i].ext) )
return FALSE;
}
tst->data = (void *) TRUE;
return TRUE;
}
static bool tst_ihave_validate_const
(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *tst,
int *const_current, int const_next ATTR_UNUSED)
{
if ( (bool)tst->data == TRUE )
*const_current = 1;
else
*const_current = 0;
return TRUE;
}
|