]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: Implemented support for the LITERAL- capability.
authorStephan Bosch <stephan@dovecot.fi>
Sun, 29 May 2016 17:14:58 +0000 (19:14 +0200)
committerStephan Bosch <stephan@dovecot.fi>
Sun, 29 May 2016 18:30:31 +0000 (20:30 +0200)
This replaces the LITERAL+ capability when the imap_literal_minus setting is enabled.

12 files changed:
configure.ac
doc/example-config/conf.d/20-imap.conf
src/imap-login/imap-login-client.c
src/imap-login/imap-login-settings.c
src/imap-login/imap-login-settings.h
src/imap/cmd-append.c
src/imap/cmd-setmetadata.c
src/imap/imap-client.c
src/imap/imap-settings.c
src/imap/imap-settings.h
src/lib-imap/imap-parser.c
src/lib-imap/imap-parser.h

index 7e8d56fa9aaa3df831128f2bc93631e0d2dcbc98..da03a919cf02979633878c5eeb4a5e967b1781bb 100644 (file)
@@ -778,7 +778,7 @@ dnl **
 
 dnl IDLE doesn't really belong to banner. It's there just to make Blackberries
 dnl happy, because otherwise BIS server disables push email.
-capability_banner="IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE"
+capability_banner="IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE"
 capability="$capability_banner SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE"
 AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", [IMAP capabilities])
 AC_DEFINE_UNQUOTED(CAPABILITY_BANNER_STRING, "$capability_banner", [IMAP capabilities advertised in banner])
index f10ae87f4abd7d16ad2ef14202d77626d2c75f76..dfae29d19c588af82356ea52f6e346ce1565355d 100644 (file)
@@ -68,6 +68,9 @@
 # Host allowed in URLAUTH URLs sent by client. "*" allows all.
 #imap_urlauth_host =
 
+# Enable IMAP LITERAL- extension (replaces LITERAL+)
+#imap_literal_minus = no
+
 protocol imap {
   # Space separated list of plugins to load (default is global mail_plugins).
   #mail_plugins = $mail_plugins
index 8e539e7126248510fb309e5e65161031579407a9..77258d50245748a5b58d686302d4fa47725691e9 100644 (file)
@@ -97,17 +97,26 @@ static const char *get_capability(struct client *client)
 {
        struct imap_client *imap_client = (struct imap_client *)client;
        string_t *cap_str = t_str_new(256);
+       bool explicit_capability = FALSE;
 
        if (*imap_client->set->imap_capability == '\0')
                str_append(cap_str, CAPABILITY_BANNER_STRING);
-       else if (*imap_client->set->imap_capability != '+')
+       else if (*imap_client->set->imap_capability != '+') {
+               explicit_capability = TRUE;
                str_append(cap_str, imap_client->set->imap_capability);
-       else {
+       else {
                str_append(cap_str, CAPABILITY_BANNER_STRING);
                str_append_c(cap_str, ' ');
                str_append(cap_str, imap_client->set->imap_capability + 1);
        }
 
+       if (!explicit_capability) {
+               if (imap_client->set->imap_literal_minus)
+                       str_append(cap_str, " LITERAL-");
+               else
+                       str_append(cap_str, " LITERAL+");
+       }
+
        if (client_is_tls_enabled(client) && !client->tls)
                str_append(cap_str, " STARTTLS");
        if (is_login_cmd_disabled(client))
@@ -277,6 +286,8 @@ static int cmd_id(struct imap_client *client)
                id->parser = imap_parser_create(client->common.input,
                                                client->common.output,
                                                MAX_IMAP_LINE);
+               if (client->set->imap_literal_minus)
+                       imap_parser_enable_literal_minus(id->parser);
                parser_flags = IMAP_PARSE_FLAG_STOP_AT_LIST;
        } else {
                id = client->cmd_id;
@@ -543,6 +554,8 @@ static void imap_client_create(struct client *client, void **other_sets)
        imap_client->parser =
                imap_parser_create(imap_client->common.input,
                                   imap_client->common.output, MAX_IMAP_LINE);
+       if (imap_client->set->imap_literal_minus)
+               imap_parser_enable_literal_minus(imap_client->parser);
        client->io = io_add(client->fd, IO_READ, client_input, client);
 }
 
index a6d1043bf2f2d9f06cb07d4921e369be5ca1695b..d0987163ae4f0c8a831643a6c78517e45bade15c 100644 (file)
@@ -57,6 +57,7 @@ static const struct setting_define imap_login_setting_defines[] = {
        DEF(SET_STR, imap_capability),
        DEF(SET_STR, imap_id_send),
        DEF(SET_STR, imap_id_log),
+       DEF(SET_BOOL, imap_literal_minus),
 
        SETTING_DEFINE_LIST_END
 };
@@ -64,7 +65,8 @@ static const struct setting_define imap_login_setting_defines[] = {
 static const struct imap_login_settings imap_login_default_settings = {
        .imap_capability = "",
        .imap_id_send = "name *",
-       .imap_id_log = ""
+       .imap_id_log = "",
+       .imap_literal_minus = FALSE
 };
 
 static const struct setting_parser_info *imap_login_setting_dependencies[] = {
index 08cc92561aaf8c27183e66e7b3c2a34dedd8e919..f1d250fb0e4c091c9cff80e56faa0600e7edeaf3 100644 (file)
@@ -5,6 +5,7 @@ struct imap_login_settings {
        const char *imap_capability;
        const char *imap_id_send;
        const char *imap_id_log;
+       bool imap_literal_minus;
 };
 
 extern const struct setting_parser_info *imap_login_setting_roots[];
index 6bfac49141b3b5f53809fb75244ff01b74b569df..2718734201d8de2ce96e476dda075cd5e57f2549 100644 (file)
@@ -418,7 +418,10 @@ static bool cmd_append_continue_catenate(struct client_command_context *cmd)
                case IMAP_PARSE_ERROR_NONE:
                        i_unreached();
                case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
-                       client_disconnect_with_error(client, msg);
+                       client_send_line(client, t_strconcat("* BYE ",
+                               (client->set->imap_literal_minus ? "[TOOBIG] " : ""),
+                               msg, NULL));
+                       client_disconnect(client, msg);
                        break;
                default:
                        if (!ctx->failed)
@@ -761,7 +764,10 @@ static bool cmd_append_parse_new_msg(struct client_command_context *cmd)
                        case IMAP_PARSE_ERROR_NONE:
                                i_unreached();
                        case IMAP_PARSE_ERROR_LITERAL_TOO_BIG:
-                               client_disconnect_with_error(client, msg);
+                               client_send_line(client, t_strconcat("* BYE ",
+                                       (client->set->imap_literal_minus ? "[TOOBIG] " : ""),
+                                       msg, NULL));
+                               client_disconnect(client, msg);
                                break;
                        default:
                                client_send_command_error(cmd, msg);
@@ -936,6 +942,8 @@ bool cmd_append(struct client_command_context *cmd)
 
        ctx->save_parser = imap_parser_create(client->input, client->output,
                                              client->set->imap_max_line_length);
+       if (client->set->imap_literal_minus)
+               imap_parser_enable_literal_minus(ctx->save_parser);
 
        cmd->func = cmd_append_parse_new_msg;
        cmd->context = ctx;
index 652e13491aa8132b728e470220b1a9406e71222f..98b9dc2307b704175e470ac84514d860a963c6f0 100644 (file)
@@ -278,6 +278,8 @@ cmd_setmetadata_start(struct imap_setmetadata_context *ctx)
        client->input_lock = cmd;
        ctx->parser = imap_parser_create(client->input, client->output,
                                         client->set->imap_max_line_length);
+       if (client->set->imap_literal_minus)
+               imap_parser_enable_literal_minus(ctx->parser);
        o_stream_unset_flush_callback(client->output);
 
        cmd->func = cmd_setmetadata_continue;
index 7f48d983a7f6ca96e8b7c9e03ecf7a9e4590a585..0bbd1d55f2615e68e1d740a051de77e9196dc319 100644 (file)
@@ -139,6 +139,12 @@ struct client *client_create(int fd_in, int fd_out, const char *session_id,
                str_append_c(client->capability_string, ' ');
                str_append(client->capability_string, set->imap_capability + 1);
        }
+       if (!explicit_capability) {
+               if (client->set->imap_literal_minus)
+                       str_append(client->capability_string, " LITERAL-");
+               else
+                       str_append(client->capability_string, " LITERAL+");
+       }
        if (user->fuzzy_search && !explicit_capability) {
                /* Enable FUZZY capability only when it actually has
                   a chance of working */
@@ -756,6 +762,8 @@ client_command_new(struct client *client)
                cmd->parser =
                        imap_parser_create(client->input, client->output,
                                           client->set->imap_max_line_length);
+               if (client->set->imap_literal_minus)
+                       imap_parser_enable_literal_minus(cmd->parser);
        }
        return cmd;
 }
index 5355e8fe4da3066000b7726ec89ebf66269374cc..58d348bd9f3b4c09f9233ea85bff645fc21bb4e7 100644 (file)
@@ -71,6 +71,7 @@ static const struct setting_define imap_setting_defines[] = {
        DEF(SET_STR, imap_id_send),
        DEF(SET_STR, imap_id_log),
        DEF(SET_BOOL, imap_metadata),
+       DEF(SET_BOOL, imap_literal_minus),
        DEF(SET_TIME, imap_hibernate_timeout),
 
        DEF(SET_STR, imap_urlauth_host),
@@ -96,6 +97,7 @@ static const struct imap_settings imap_default_settings = {
        .imap_id_send = "name *",
        .imap_id_log = "",
        .imap_metadata = FALSE,
+       .imap_literal_minus = FALSE,
        .imap_hibernate_timeout = 0,
 
        .imap_urlauth_host = "",
index e4e70506c3f6161824956e7ddf05075f5bdf06f1..69e60d89480c124db751dbe2d016fa60a5084ac8 100644 (file)
@@ -25,6 +25,7 @@ struct imap_settings {
        const char *imap_id_send;
        const char *imap_id_log;
        bool imap_metadata;
+       bool imap_literal_minus;
        unsigned int imap_hibernate_timeout;
 
        /* imap urlauth: */
index 63474c3790b344db812da91d59293ff8209a059f..e3cad19e08de2da346cfce5db169b1ddfada992e 100644 (file)
@@ -57,6 +57,7 @@ struct imap_parser {
        enum imap_parser_error error;
        const char *error_msg;
 
+       unsigned int literal_minus:1;
        unsigned int literal_skip_crlf:1;
        unsigned int literal_nonsync:1;
        unsigned int literal8:1;
@@ -104,6 +105,11 @@ void imap_parser_unref(struct imap_parser **parser)
        *parser = NULL;
 }
 
+void imap_parser_enable_literal_minus(struct imap_parser *parser)
+{
+       parser->literal_minus = TRUE;
+}
+
 void imap_parser_reset(struct imap_parser *parser)
 {
        p_clear(parser->pool);
@@ -387,6 +393,13 @@ static int imap_parser_read_string(struct imap_parser *parser,
 
 static int imap_parser_literal_end(struct imap_parser *parser)
 {
+       if (parser->literal_minus && parser->literal_nonsync &&
+               parser->literal_size > 4096) {
+               parser->error_msg = "Non-synchronizing literal size too large";
+               parser->error = IMAP_PARSE_ERROR_LITERAL_TOO_BIG;
+               return FALSE;
+       }
+
        if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) == 0) {
                if (parser->line_size >= parser->max_line_size ||
                    parser->literal_size >
index 25dfda0672b39a3053fe6bcca0554c4beda6b548..e5d01c17f2bbeb593c2c07bf209af4e8358b63f3 100644 (file)
@@ -57,6 +57,10 @@ imap_parser_create(struct istream *input, struct ostream *output,
 void imap_parser_ref(struct imap_parser *parser);
 void imap_parser_unref(struct imap_parser **parser);
 
+/* Enable LITERAL- parser semantics: non-synchronizing literals must not
+   exceed 4096 bytes */
+void imap_parser_enable_literal_minus(struct imap_parser *parser);
+
 /* Reset the parser to initial state. */
 void imap_parser_reset(struct imap_parser *parser);