dovecot-2.1-pigeonhole: ManageSieve: added support for reading q...
pigeonhole at rename-it.nl
pigeonhole at rename-it.nl
Sun Jan 22 22:57:54 EET 2012
details: http://hg.rename-it.nl/dovecot-2.1-pigeonhole/rev/ae857042882b
changeset: 1596:ae857042882b
user: Stephan Bosch <stephan at rename-it.nl>
date: Sun Jan 22 21:57:45 2012 +0100
description:
ManageSieve: added support for reading quoted and literal strings as a stream. Fixes support for handing large SASL responses.
Also resolves long-standing FIXME regarding the second parameter of PUTSCRIPT: it can now be a quoted string.
Includes a few small changes in the login daemon that were done in the dovecot equivalents before.
diffstat:
src/lib-managesieve/managesieve-parser.c | 226 ++++++++++++++++++++++++++++----
src/lib-managesieve/managesieve-parser.h | 54 ++++---
src/lib-sievestorage/sieve-storage-quota.c | 6 +
src/lib-sievestorage/sieve-storage-quota.h | 3 +
src/managesieve-login/client-authenticate.c | 203 ++++++++++++++++++++++------
src/managesieve-login/client.c | 153 +++++++++++++--------
src/managesieve-login/client.h | 7 +
src/managesieve-login/managesieve-proxy.c | 2 +-
src/managesieve/cmd-putscript.c | 164 +++++++++++++----------
src/managesieve/managesieve-client.c | 2 +-
src/managesieve/managesieve-quota.c | 5 +
src/managesieve/managesieve-quota.h | 2 +
12 files changed, 596 insertions(+), 231 deletions(-)
diffs (truncated from 1385 to 300 lines):
diff -r 66c9a4a82428 -r ae857042882b src/lib-managesieve/managesieve-parser.c
--- a/src/lib-managesieve/managesieve-parser.c Fri Jan 20 22:26:53 2012 +0100
+++ b/src/lib-managesieve/managesieve-parser.c Sun Jan 22 21:57:45 2012 +0100
@@ -3,7 +3,7 @@
#include "lib.h"
#include "unichar.h"
-#include "istream.h"
+#include "istream-private.h"
#include "ostream.h"
#include "strescape.h"
#include "managesieve-parser.h"
@@ -25,7 +25,6 @@
/* permanent */
pool_t pool;
struct istream *input;
- struct ostream *output;
size_t max_line_size;
enum managesieve_parser_flags flags;
@@ -40,6 +39,8 @@
int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */
uoff_t literal_size; /* ARG_PARSE_LITERAL: string size */
+ struct istream *str_stream;
+
const char *error;
unsigned int literal_skip_crlf:1;
@@ -48,6 +49,9 @@
unsigned int fatal_error:1;
};
+static struct istream *quoted_string_istream_create
+ (struct managesieve_parser *parser);
+
/* @UNSAFE */
#define LIST_REALLOC(parser, old_list, new_size) \
p_realloc((parser)->pool, old_list, \
@@ -65,15 +69,13 @@
}
struct managesieve_parser *
-managesieve_parser_create(struct istream *input, struct ostream *output,
- size_t max_line_size)
+managesieve_parser_create(struct istream *input, size_t max_line_size)
{
struct managesieve_parser *parser;
parser = i_new(struct managesieve_parser, 1);
parser->pool = pool_alloconly_create("MANAGESIEVE parser", 8192);
parser->input = input;
- parser->output = output;
parser->max_line_size = max_line_size;
managesieve_args_realloc(parser, LIST_ALLOC_SIZE);
@@ -82,6 +84,9 @@
void managesieve_parser_destroy(struct managesieve_parser **parser)
{
+ if ((*parser)->str_stream != NULL)
+ i_stream_unref(&(*parser)->str_stream);
+
pool_unref(&(*parser)->pool);
i_free(*parser);
*parser = NULL;
@@ -107,10 +112,14 @@
parser->literal_skip_crlf = FALSE;
parser->eol = FALSE;
+ if ( parser->str_stream != NULL )
+ i_stream_unref(&parser->str_stream);
+
managesieve_args_realloc(parser, LIST_ALLOC_SIZE);
}
-const char *managesieve_parser_get_error(struct managesieve_parser *parser, bool *fatal)
+const char *managesieve_parser_get_error
+(struct managesieve_parser *parser, bool *fatal)
{
*fatal = parser->fatal_error;
return parser->error;
@@ -168,26 +177,29 @@
break;
case ARG_PARSE_STRING:
/* data is quoted and may contain escapes. */
- i_assert(size > 0);
+ if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) {
+ arg->type = MANAGESIEVE_ARG_STRING_STREAM;
+ arg->_data.str_stream = parser->str_stream;
+ } else {
+ i_assert(size > 0);
- arg->type = MANAGESIEVE_ARG_STRING;
- arg->_data.str = p_strndup(parser->pool, data+1, size-1);
+ arg->type = MANAGESIEVE_ARG_STRING;
+ arg->_data.str = p_strndup(parser->pool, data+1, size-1);
- /* remove the escapes */
- if (parser->str_first_escape >= 0 &&
- (parser->flags & MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE) == 0) {
- /* -1 because we skipped the '"' prefix */
- str_unescape(arg->_data.str +
- parser->str_first_escape-1);
+ /* remove the escapes */
+ if (parser->str_first_escape >= 0 &&
+ (parser->flags & MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE) == 0) {
+ /* -1 because we skipped the '"' prefix */
+ str_unescape(arg->_data.str +
+ parser->str_first_escape-1);
+ }
}
break;
case ARG_PARSE_LITERAL_DATA:
- if ((parser->flags & MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE) != 0) {
- /* save literal size */
- arg->type = MANAGESIEVE_ARG_LITERAL_SIZE;
- arg->_data.literal_size = parser->literal_size;
- } else if ((parser->flags &
- MANAGESIEVE_PARSE_FLAG_LITERAL_TYPE) != 0) {
+ if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) {
+ arg->type = MANAGESIEVE_ARG_STRING_STREAM;
+ arg->_data.str_stream = parser->str_stream;
+ } else if ((parser->flags & MANAGESIEVE_PARSE_FLAG_LITERAL_TYPE) != 0) {
arg->type = MANAGESIEVE_ARG_LITERAL;
arg->_data.str = p_strndup(parser->pool, data, size);
} else {
@@ -273,7 +285,8 @@
i++;
if ( !IS_QUOTED_SPECIAL(data[i]) ) {
- parser->error = "Escaped quoted-string character is not a QUOTED-SPECIAL.";
+ parser->error =
+ "Escaped quoted-string character is not a QUOTED-SPECIAL.";
return FALSE;
}
@@ -292,7 +305,7 @@
static int managesieve_parser_literal_end(struct managesieve_parser *parser)
{
- if ((parser->flags & MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE) == 0) {
+ if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) == 0) {
if (parser->line_size >= parser->max_line_size ||
parser->literal_size >
parser->max_line_size - parser->line_size) {
@@ -387,7 +400,7 @@
i_assert(parser->cur_pos == 0);
}
- if ((parser->flags & MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE) == 0) {
+ if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) == 0) {
/* now we just wait until we've read enough data */
if (data_size < parser->literal_size) {
return FALSE;
@@ -404,8 +417,10 @@
return TRUE;
}
} else {
- /* we want to save only literal size, not the literal itself. */
+ /* we don't read the data; we just create a stream for the literal */
parser->eol = TRUE;
+ parser->str_stream = i_stream_create_limit
+ (parser->input, parser->literal_size);
managesieve_parser_save_arg(parser, NULL, 0);
return TRUE;
}
@@ -461,8 +476,17 @@
return FALSE;
break;
case ARG_PARSE_STRING:
- if (!managesieve_parser_read_string(parser, data, data_size))
+ if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) {
+ parser->eol = TRUE;
+ parser->line_size += parser->cur_pos;
+ i_stream_skip(parser->input, parser->cur_pos);
+ parser->cur_pos = 0;
+ parser->str_stream = quoted_string_istream_create(parser);
+ managesieve_parser_save_arg(parser, NULL, 0);
+
+ } else if (!managesieve_parser_read_string(parser, data, data_size)) {
return FALSE;
+ }
break;
case ARG_PARSE_LITERAL:
if (!managesieve_parser_read_literal(parser, data, data_size))
@@ -623,10 +647,10 @@
return NULL;
}
-uoff_t _managesieve_arg_literal_size_error(const struct managesieve_arg *arg)
+struct istream *_managesieve_arg_str_stream_error(const struct managesieve_arg *arg)
{
- i_panic("Tried to access managesieve_arg type %d as literal size", arg->type);
- return 0;
+ i_panic("Tried to access managesieve_arg type %d as string stream", arg->type);
+ return NULL;
}
struct managesieve_arg_list *_managesieve_arg_list_error(const struct managesieve_arg *arg)
@@ -634,3 +658,147 @@
i_panic("Tried to access managesieve_arg type %d as list", arg->type);
return NULL;
}
+
+/*
+ * Quoted string stream
+ */
+
+struct quoted_string_istream {
+ struct istream_private istream;
+
+ struct stat statbuf;
+
+ struct managesieve_parser *parser;
+
+ unsigned int pending_slash:1;
+ unsigned int last_slash:1;
+ unsigned int finished:1;
+};
+
+static ssize_t quoted_string_istream_read(struct istream_private *stream)
+{
+ struct quoted_string_istream *qsstream =
+ (struct quoted_string_istream *)stream;
+ const unsigned char *data;
+ size_t i, dest, size;
+ ssize_t ret = 0;
+ bool slash;
+
+ if ( qsstream->finished ) {
+ stream->istream.eof = TRUE;
+ return -1;
+ }
+
+ /* Read from parent */
+ data = i_stream_get_data(stream->parent, &size);
+ if (size == 0) {
+ ret = i_stream_read(stream->parent);
+ if (ret <= 0 && (ret != -2 || stream->skip == 0)) {
+ if ( stream->istream.eof && stream->istream.stream_errno == 0 ) {
+ stream->istream.eof = 0;
+ stream->istream.stream_errno = EPROTO;
+ } else {
+ stream->istream.stream_errno = stream->parent->stream_errno;
+ stream->istream.eof = stream->parent->eof;
+ }
+ return ret;
+ }
+ data = i_stream_get_data(stream->parent, &size);
+ i_assert(size != 0);
+ }
+
+ /* Allocate buffer space */
+ if (!i_stream_get_buffer_space(stream, size, NULL))
+ return -2;
+
+ /* Parse quoted string content */
+ dest = stream->pos;
+ slash = qsstream->pending_slash;
+ ret = 0;
+ for (i = 0; i < size && dest < stream->buffer_size; i++) {
+ if ( data[i] == '"' ) {
+ if ( !slash ) {
+ qsstream->finished = TRUE;
+ i++;
+ break;
+ }
+ slash = FALSE;
+ } else if ( data[i] == '\\' ) {
+ if ( !slash ) {
+ slash = TRUE;
+ continue;
+ }
+ slash = FALSE;
+ } else if ( slash ) {
+ if ( !IS_QUOTED_SPECIAL(data[i]) ) {
+ qsstream->parser->error =
+ "Escaped quoted-string character is not a QUOTED-SPECIAL.";
+ stream->istream.stream_errno = EPROTO;
+ ret = -1;
+ break;
+ }
+ slash = FALSE;
+ }
+
+ if ( (data[i] & 0x80) == 0 && ( data[i] == '\r' || data[i] == '\n' ) ) {
+ qsstream->parser->error = "String contains invalid character.";
+ stream->istream.stream_errno = EPROTO;
+ ret = -1;
+ break;
+ }
+
+ stream->w_buffer[dest++] = data[i];
+ }
+
+ i_stream_skip(stream->parent, i);
+ qsstream->pending_slash = slash;
+
+ if ( ret < 0 ) {
More information about the dovecot-cvs
mailing list