|
|
2c808a |
From b9a2f18466a0d3377bab3e7a57691bdd75d8507c Mon Sep 17 00:00:00 2001
|
|
|
2c808a |
From: Timo Sirainen <timo.sirainen@open-xchange.com>
|
|
|
2c808a |
Date: Mon, 17 Aug 2020 17:32:11 +0300
|
|
|
2c808a |
Subject: [PATCH] lib-imap: Add imap_parser_read_tag() and _read_command_name()
|
|
|
2c808a |
|
|
|
2c808a |
---
|
|
|
2c808a |
src/lib-imap/imap-parser.c | 67 +++++++++++++++++++++++++++++++++
|
|
|
2c808a |
src/lib-imap/imap-parser.h | 7 ++++
|
|
|
2c808a |
src/lib-imap/test-imap-parser.c | 67 +++++++++++++++++++++++++++++++++
|
|
|
2c808a |
3 files changed, 141 insertions(+)
|
|
|
2c808a |
|
|
|
2c808a |
diff --git a/src/lib-imap/imap-parser.c b/src/lib-imap/imap-parser.c
|
|
|
2c808a |
index b6c6e63fb1..52d79282fa 100644
|
|
|
2c808a |
--- a/src/lib-imap/imap-parser.c
|
|
|
2c808a |
+++ b/src/lib-imap/imap-parser.c
|
|
|
2c808a |
@@ -947,3 +947,70 @@ const char *imap_parser_read_word(struct imap_parser *parser)
|
|
|
2c808a |
return NULL;
|
|
|
2c808a |
}
|
|
|
2c808a |
}
|
|
|
2c808a |
+
|
|
|
2c808a |
+static int
|
|
|
2c808a |
+imap_parser_read_next_atom(struct imap_parser *parser, bool parsing_tag,
|
|
|
2c808a |
+ const char **atom_r)
|
|
|
2c808a |
+{
|
|
|
2c808a |
+ const unsigned char *data;
|
|
|
2c808a |
+ size_t i, data_size;
|
|
|
2c808a |
+
|
|
|
2c808a |
+ data = i_stream_get_data(parser->input, &data_size);
|
|
|
2c808a |
+
|
|
|
2c808a |
+ /*
|
|
|
2c808a |
+ tag = 1*<any ASTRING-CHAR except "+">
|
|
|
2c808a |
+ ASTRING-CHAR = ATOM-CHAR / resp-specials
|
|
|
2c808a |
+ ATOM-CHAR = <any CHAR except atom-specials>
|
|
|
2c808a |
+
|
|
|
2c808a |
+ x-command = "X" atom <experimental command arguments>
|
|
|
2c808a |
+ atom = 1*ATOM-CHAR
|
|
|
2c808a |
+ */
|
|
|
2c808a |
+ for (i = 0; i < data_size; i++) {
|
|
|
2c808a |
+ /* explicitly check for atom-specials, because
|
|
|
2c808a |
+ IS_ATOM_PARSER_INPUT() allows some atom-specials */
|
|
|
2c808a |
+ switch (data[i]) {
|
|
|
2c808a |
+ case ' ':
|
|
|
2c808a |
+ case '\r':
|
|
|
2c808a |
+ case '\n':
|
|
|
2c808a |
+ data_size = i + (data[i] == ' ' ? 1 : 0);
|
|
|
2c808a |
+ parser->line_size += data_size;
|
|
|
2c808a |
+ i_stream_skip(parser->input, data_size);
|
|
|
2c808a |
+ *atom_r = p_strndup(parser->pool, data, i);
|
|
|
2c808a |
+ /* don't allow empty string */
|
|
|
2c808a |
+ return i == 0 ? -1 : 1;
|
|
|
2c808a |
+ /* atom-specials: */
|
|
|
2c808a |
+ case '(':
|
|
|
2c808a |
+ case ')':
|
|
|
2c808a |
+ case '{':
|
|
|
2c808a |
+ /* list-wildcards: */
|
|
|
2c808a |
+ case '%':
|
|
|
2c808a |
+ case '*':
|
|
|
2c808a |
+ /* quoted-specials: */
|
|
|
2c808a |
+ case '"':
|
|
|
2c808a |
+ case '\\':
|
|
|
2c808a |
+ /* resp-specials: */
|
|
|
2c808a |
+ case ']':
|
|
|
2c808a |
+ return -1;
|
|
|
2c808a |
+ case '+':
|
|
|
2c808a |
+ if (parsing_tag)
|
|
|
2c808a |
+ return -1;
|
|
|
2c808a |
+ break;
|
|
|
2c808a |
+ default:
|
|
|
2c808a |
+ if ((unsigned char)data[i] < ' ' ||
|
|
|
2c808a |
+ (unsigned char)data[i] >= 0x80)
|
|
|
2c808a |
+ return -1;
|
|
|
2c808a |
+ }
|
|
|
2c808a |
+ }
|
|
|
2c808a |
+ return 0;
|
|
|
2c808a |
+}
|
|
|
2c808a |
+
|
|
|
2c808a |
+int imap_parser_read_tag(struct imap_parser *parser, const char **tag_r)
|
|
|
2c808a |
+{
|
|
|
2c808a |
+ return imap_parser_read_next_atom(parser, TRUE, tag_r);
|
|
|
2c808a |
+}
|
|
|
2c808a |
+
|
|
|
2c808a |
+int imap_parser_read_command_name(struct imap_parser *parser,
|
|
|
2c808a |
+ const char **name_r)
|
|
|
2c808a |
+{
|
|
|
2c808a |
+ return imap_parser_read_next_atom(parser, FALSE, name_r);
|
|
|
2c808a |
+}
|
|
|
2c808a |
diff --git a/src/lib-imap/imap-parser.h b/src/lib-imap/imap-parser.h
|
|
|
2c808a |
index e5d01c17f2..5e09d61d2b 100644
|
|
|
2c808a |
--- a/src/lib-imap/imap-parser.h
|
|
|
2c808a |
+++ b/src/lib-imap/imap-parser.h
|
|
|
2c808a |
@@ -101,5 +101,12 @@ int imap_parser_finish_line(struct imap_parser *parser, unsigned int count,
|
|
|
2c808a |
/* Read one word - used for reading tag and command name.
|
|
|
2c808a |
Returns NULL if more data is needed. */
|
|
|
2c808a |
const char *imap_parser_read_word(struct imap_parser *parser);
|
|
|
2c808a |
+/* Read command tag. Returns 1 if tag was returned, 0 if more data is needed,
|
|
|
2c808a |
+ -1 if input isn't a valid tag. */
|
|
|
2c808a |
+int imap_parser_read_tag(struct imap_parser *parser, const char **tag_r);
|
|
|
2c808a |
+/* Read command name. Returns 1 if command name was returned, 0 if more data is
|
|
|
2c808a |
+ needed, -1 if input isn't a valid command name string. */
|
|
|
2c808a |
+int imap_parser_read_command_name(struct imap_parser *parser,
|
|
|
2c808a |
+ const char **name_r);
|
|
|
2c808a |
|
|
|
2c808a |
#endif
|
|
|
2c808a |
diff --git a/src/lib-imap/test-imap-parser.c b/src/lib-imap/test-imap-parser.c
|
|
|
2c808a |
index 93ef8fd59b..3ca4e34858 100644
|
|
|
2c808a |
--- a/src/lib-imap/test-imap-parser.c
|
|
|
2c808a |
+++ b/src/lib-imap/test-imap-parser.c
|
|
|
2c808a |
@@ -79,10 +79,77 @@ static void test_imap_parser_partial_list(void)
|
|
|
2c808a |
test_end();
|
|
|
2c808a |
}
|
|
|
2c808a |
|
|
|
2c808a |
+static void test_imap_parser_read_tag_cmd(void)
|
|
|
2c808a |
+{
|
|
|
2c808a |
+ enum read_type {
|
|
|
2c808a |
+ BOTH,
|
|
|
2c808a |
+ TAG,
|
|
|
2c808a |
+ COMMAND
|
|
|
2c808a |
+ };
|
|
|
2c808a |
+ struct {
|
|
|
2c808a |
+ const char *input;
|
|
|
2c808a |
+ const char *tag;
|
|
|
2c808a |
+ int ret;
|
|
|
2c808a |
+ enum read_type type;
|
|
|
2c808a |
+ } tests[] = {
|
|
|
2c808a |
+ { "tag foo", "tag", 1, BOTH },
|
|
|
2c808a |
+ { "tag\r", "tag", 1, BOTH },
|
|
|
2c808a |
+ { "tag\rfoo", "tag", 1, BOTH },
|
|
|
2c808a |
+ { "tag\nfoo", "tag", 1, BOTH },
|
|
|
2c808a |
+ { "tag\r\nfoo", "tag", 1, BOTH },
|
|
|
2c808a |
+ { "\n", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag", NULL, 0, BOTH },
|
|
|
2c808a |
+ { "tag\t", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag\001", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag\x80", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag(", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag)", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag{", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag/ ", "tag/", 1, BOTH },
|
|
|
2c808a |
+ { "tag%", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag*", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag\"", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag\\", NULL, -1, BOTH },
|
|
|
2c808a |
+ { "tag+", NULL, -1, TAG },
|
|
|
2c808a |
+ { "tag+ ", "tag+", 1, COMMAND },
|
|
|
2c808a |
+ };
|
|
|
2c808a |
+ struct istream *input;
|
|
|
2c808a |
+ struct imap_parser *parser;
|
|
|
2c808a |
+ const char *atom;
|
|
|
2c808a |
+ int ret;
|
|
|
2c808a |
+
|
|
|
2c808a |
+ test_begin("imap_parser_read_tag and imap_parser_read_command_name");
|
|
|
2c808a |
+ for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
|
|
|
2c808a |
+ if (tests[i].type != COMMAND) {
|
|
|
2c808a |
+ input = test_istream_create(tests[i].input);
|
|
|
2c808a |
+ test_assert(i_stream_read(input) > 0);
|
|
|
2c808a |
+ parser = imap_parser_create(input, NULL, 1024);
|
|
|
2c808a |
+ ret = imap_parser_read_tag(parser, &atom);
|
|
|
2c808a |
+ test_assert_idx(ret == tests[i].ret, i);
|
|
|
2c808a |
+ test_assert_idx(ret <= 0 || strcmp(tests[i].tag, atom) == 0, i);
|
|
|
2c808a |
+ imap_parser_unref(&parser);
|
|
|
2c808a |
+ i_stream_destroy(&input);
|
|
|
2c808a |
+ }
|
|
|
2c808a |
+
|
|
|
2c808a |
+ if (tests[i].type != TAG) {
|
|
|
2c808a |
+ input = test_istream_create(tests[i].input);
|
|
|
2c808a |
+ test_assert(i_stream_read(input) > 0);
|
|
|
2c808a |
+ parser = imap_parser_create(input, NULL, 1024);
|
|
|
2c808a |
+ ret = imap_parser_read_command_name(parser, &atom);
|
|
|
2c808a |
+ test_assert_idx(ret == tests[i].ret, i);
|
|
|
2c808a |
+ test_assert_idx(ret <= 0 || strcmp(tests[i].tag, atom) == 0, i);
|
|
|
2c808a |
+ imap_parser_unref(&parser);
|
|
|
2c808a |
+ i_stream_destroy(&input);
|
|
|
2c808a |
+ }
|
|
|
2c808a |
+ }
|
|
|
2c808a |
+ test_end();
|
|
|
2c808a |
+}
|
|
|
2c808a |
+
|
|
|
2c808a |
int main(void)
|
|
|
2c808a |
{
|
|
|
2c808a |
static void (*const test_functions[])(void) = {
|
|
|
2c808a |
test_imap_parser_crlf,
|
|
|
2c808a |
+ test_imap_parser_read_tag_cmd,
|
|
|
2c808a |
NULL
|
|
|
2c808a |
};
|
|
|
2c808a |
return test_run(test_functions);
|