Skip to content

Commit

Permalink
imap: Implemented support for the LITERAL- capability.
Browse files Browse the repository at this point in the history
This replaces the LITERAL+ capability when the imap_literal_minus setting is enabled.
  • Loading branch information
stephanbosch committed May 29, 2016
1 parent 0adc24c commit d8aa10d
Show file tree
Hide file tree
Showing 12 changed files with 63 additions and 6 deletions.
2 changes: 1 addition & 1 deletion configure.ac
Expand Up @@ -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])
Expand Down
3 changes: 3 additions & 0 deletions doc/example-config/conf.d/20-imap.conf
Expand Up @@ -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
Expand Down
17 changes: 15 additions & 2 deletions src/imap-login/imap-login-client.c
Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down
4 changes: 3 additions & 1 deletion src/imap-login/imap-login-settings.c
Expand Up @@ -57,14 +57,16 @@ 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
};

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[] = {
Expand Down
1 change: 1 addition & 0 deletions src/imap-login/imap-login-settings.h
Expand Up @@ -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[];
Expand Down
12 changes: 10 additions & 2 deletions src/imap/cmd-append.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/imap/cmd-setmetadata.c
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions src/imap/imap-client.c
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions src/imap/imap-settings.c
Expand Up @@ -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),
Expand All @@ -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 = "",
Expand Down
1 change: 1 addition & 0 deletions src/imap/imap-settings.h
Expand Up @@ -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: */
Expand Down
13 changes: 13 additions & 0 deletions src/lib-imap/imap-parser.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 >
Expand Down
4 changes: 4 additions & 0 deletions src/lib-imap/imap-parser.h
Expand Up @@ -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);

Expand Down

0 comments on commit d8aa10d

Please sign in to comment.