AC_SUBST(SETTING_FILES)
AC_SUBST(SETTING_LINKED_FILES)
-dnl **
-dnl ** capabilities
-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 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 SNIPPET=FUZZY PREVIEW=FUZZY PREVIEW STATUS=SIZE SAVEDATE COMPRESS=DEFLATE INPROGRESS${experimental_capabilities}"
-AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", [IMAP capabilities])
-AC_DEFINE_UNQUOTED(CAPABILITY_BANNER_STRING, "$capability_banner", [IMAP capabilities advertised in banner])
-
CFLAGS="$CFLAGS $EXTRA_CFLAGS"
CXXFLAGS="$CXXFLAGS $EXTRA_CFLAGS"
BINARY_LDFLAGS="$PIE_LDFLAGS $RELRO_LDFLAGS"
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-master \
-I$(top_srcdir)/src/lib-login \
+ -I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/login-common \
$(BINARY_CFLAGS)
#include "imap-quote.h"
#include "imap-login-commands.h"
#include "imap-login-settings.h"
+#include "imap-util.h"
#if LOGIN_MAX_INBUF_SIZE < 1024+2
# error LOGIN_MAX_INBUF_SIZE too short to fit all ID command parameters
return FALSE;
}
+static int imap_client_reload_config(struct client *client,
+ const char **error_r);
+
static const char *get_capability(struct client *client)
{
struct imap_client *imap_client =
container_of(client, struct imap_client, common);
string_t *cap_str = t_str_new(256);
- if (*imap_client->set->imap_capability == '\0')
- str_append(cap_str, CAPABILITY_BANNER_STRING);
- else {
- str_append(cap_str, CAPABILITY_BANNER_STRING);
- str_append_c(cap_str, ' ');
- str_append(cap_str, imap_client->set->imap_capability + 1);
- }
-
- if (imap_client->set->imap_literal_minus)
- str_append(cap_str, " LITERAL-");
- else
- str_append(cap_str, " LITERAL+");
+ imap_write_capability(cap_str, &imap_client->set->imap_capability);
if (client_is_tls_enabled(client) && !client->connection_tls_secured &&
!client->haproxy_terminated_tls)
imap_parser_create(imap_client->common.input,
imap_client->common.output,
IMAP_LOGIN_MAX_LINE_LENGTH);
- if (imap_client->set->imap_literal_minus)
+ struct settings_instance *set_instance = settings_instance_find(client->event);
+ if (set_instance == NULL) {
+ set_instance = settings_instance_new(
+ master_service_get_settings_root(master_service));
+ event_set_ptr(client->event, SETTINGS_EVENT_INSTANCE, set_instance);
+ }
+
+ if (imap_client->set->imap_literal_minus) {
+ settings_override(set_instance,
+ "imap_capability/LITERAL+",
+ "no", SETTINGS_OVERRIDE_TYPE_CODE);
imap_parser_enable_literal_minus(imap_client->parser);
+ } else
+ settings_override(set_instance,
+ "imap_capability/LITERAL-",
+ "no", SETTINGS_OVERRIDE_TYPE_CODE);
client->io = io_add_istream(client->input, client_input, client);
+ if (imap_client_reload_config(client, &error) < 0) {
+ e_error(client->event, "%s", error);
+ return -1;
+ }
return 0;
}
SETTING_DEFINE_STRUCT_##type(#name, name, struct imap_login_settings)
static const struct setting_define imap_login_setting_defines[] = {
- DEF(STR, imap_capability),
+ DEF(BOOLLIST, imap_capability),
DEF(BOOL, imap_literal_minus),
DEF(BOOL, imap_id_retain),
};
static const struct imap_login_settings imap_login_default_settings = {
- .imap_capability = "",
+ .imap_capability = ARRAY_INIT,
.imap_id_send = ARRAY_INIT,
.imap_literal_minus = FALSE,
.imap_id_retain = FALSE,
};
static const struct setting_keyvalue imap_login_default_settings_keyvalue[] = {
+ {"service/imap-login/imap_capability/IMAP4rev1", "yes"},
+ {"service/imap-login/imap_capability/LOGIN-REFERRALS", "yes"},
+ {"service/imap-login/imap_capability/ID", "yes"},
+ {"service/imap-login/imap_capability/ENABLE", "yes"},
+ /* IDLE doesn't really belong to banner. It's there just to make
+ Blackberries happy, because otherwise BIS server disables push email. */
+ { "service/imap-login/imap_capability/IDLE", "yes" },
+ { "service/imap-login/imap_capability/SASL-IR", "yes" },
+ { "service/imap-login/imap_capability/LITERAL+", "yes" },
+ { "service/imap-login/imap_capability/LITERAL-", "yes" },
{ "imap_id_send/name", DOVECOT_NAME },
{ NULL, NULL },
};
struct imap_login_settings {
pool_t pool;
- const char *imap_capability;
+ ARRAY_TYPE(const_string) imap_capability;
ARRAY_TYPE(const_string) imap_id_send;
bool imap_literal_minus;
bool imap_id_retain;
client->urlauth_ctx = imap_urlauth_init(client->user, &config);
}
+static void
+imap_unset_capability(struct settings_instance *set_instance, const char *capability)
+{
+ settings_override(set_instance,
+ t_strdup_printf("imap_capability/%s", capability),
+ "no", SETTINGS_OVERRIDE_TYPE_CODE);
+}
+
struct client *client_create(int fd_in, int fd_out,
enum client_create_flags flags,
struct event *event, struct mail_user *user,
client->notify_flag_changes = TRUE;
p_array_init(&client->enabled_features, client->pool, 8);
- client->capability_string =
- str_new(client->pool, sizeof(CAPABILITY_STRING)+64);
-
- if (*set->imap_capability == '\0')
- str_append(client->capability_string, CAPABILITY_STRING);
- else
- str_append(client->capability_string, set->imap_capability);
+ struct settings_instance *set_instance =
+ mail_storage_service_user_get_settings_instance(
+ client->user->service_user);
+ /* All capabilities are enabled by defaults.
+ Remove the capabilities here that can't work due current settings. */
if (client->set->imap_literal_minus)
- client_add_capability(client, "LITERAL-");
- else
- client_add_capability(client, "LITERAL+");
- if (user->fuzzy_search) {
- /* Enable FUZZY capability only when it actually has
- a chance of working */
- client_add_capability(client, "SEARCH=FUZZY");
- }
+ imap_unset_capability(set_instance, "LITERAL+");
+ else
+ imap_unset_capability(set_instance, "LITERAL-");
+ /* Enable FUZZY capability only when it actually has a chance of working */
+ if (!user->fuzzy_search)
+ imap_unset_capability(set_instance, "SEARCH=FUZZY");
mail_set = mail_user_set_get_storage_set(user);
- if (mail_set->mailbox_list_index) {
- /* NOTIFY is enabled only when mailbox list indexes are
- enabled, although even that doesn't necessarily guarantee
- it always */
- client_add_capability(client, "NOTIFY");
- }
+ /* NOTIFY is enabled only when mailbox list indexes are enabled,
+ althoaugh even that doesn't necessarily guarantee it always */
+ if (!mail_set->mailbox_list_index)
+ imap_unset_capability(set_instance, "NOTIFY");
const char *error;
int ret = mailbox_attribute_dict_is_enabled(user, &error);
client->init_error = p_strdup(user->pool, error);
bool have_mailbox_attribute_dict = ret > 0;
- if (*set->imap_urlauth_host != '\0' && have_mailbox_attribute_dict) {
- /* Enable URLAUTH capability only when dict is
- configured correctly */
+ /* Enable URLAUTH capability only when dict is configured correctly */
+ if (*set->imap_urlauth_host != '\0' && have_mailbox_attribute_dict)
client_init_urlauth(client);
- client_add_capability(client, "URLAUTH");
- client_add_capability(client, "URLAUTH=BINARY");
- }
- if (set->imap_metadata && have_mailbox_attribute_dict)
- client_add_capability(client, "METADATA");
- if (user->have_special_use_mailboxes) {
- /* Advertise SPECIAL-USE only if there are actually some
- SPECIAL-USE flags in mailbox configuration. */
- client_add_capability(client, "SPECIAL-USE");
+ else {
+ imap_unset_capability(set_instance, "URLAUTH");
+ imap_unset_capability(set_instance, "URLAUTH=BINARY");
+ }
+ if (!set->imap_metadata || !have_mailbox_attribute_dict)
+ imap_unset_capability(set_instance, "METADATA");
+ /* Advertise SPECIAL-USE only if there are actually some
+ SPECIAL-USE flags in mailbox configuration. */
+ if (!user->have_special_use_mailboxes)
+ imap_unset_capability(set_instance, "SPECIAL-USE");
+
+ const struct imap_settings *modified_set;
+ if (settings_get(client->user->event, &imap_setting_parser_info,
+ 0, &modified_set, &error) < 0) {
+ if (client->init_error == NULL)
+ client->init_error = p_strdup(user->pool, error);
+ } else {
+ client->capability_string = str_new(client->pool, 256);
+ imap_write_capability(client->capability_string,
+ &modified_set->imap_capability);
+ settings_free(modified_set);
}
struct master_service_anvil_session anvil_session;
{
/* require a single capability at a time (feels cleaner) */
i_assert(strchr(capability, ' ') == NULL);
-
- if (client->set->imap_capability[0] != '\0') {
+ if (settings_boollist_is_stopped(&client->set->imap_capability)) {
/* explicit capability - don't change it */
return;
}
DEF(SIZE_HIDDEN, imap_max_line_length),
DEF(TIME_HIDDEN, imap_idle_notify_interval),
- DEF(STR, imap_capability),
+ DEF(BOOLLIST, imap_capability),
DEF(BOOLLIST, imap_client_workarounds),
DEF(STR_NOVARS, imap_logout_format),
DEF(ENUM, imap_fetch_failure),
liberal by default. */
.imap_max_line_length = 64*1024,
.imap_idle_notify_interval = 2*60,
- .imap_capability = "",
+ .imap_capability = ARRAY_INIT,
.imap_client_workarounds = ARRAY_INIT,
.imap_logout_format = "in=%i out=%o deleted=%{deleted} "
"expunged=%{expunged} trashed=%{trashed} "
};
static const struct setting_keyvalue imap_default_settings_keyvalue[] = {
+ { "service/imap/imap_capability/IMAP4rev1", "yes" },
+ { "service/imap/imap_capability/SASL-IR", "yes" },
+ { "service/imap/imap_capability/LOGIN-REFERRALS", "yes" },
+ { "service/imap/imap_capability/ID", "yes" },
+ { "service/imap/imap_capability/ENABLE", "yes" },
+ { "service/imap/imap_capability/IDLE", "yes" },
+ { "service/imap/imap_capability/SORT", "yes" },
+ { "service/imap/imap_capability/SORT=DISPLAY", "yes" },
+ { "service/imap/imap_capability/THREAD=REFERENCES", "yes" },
+ { "service/imap/imap_capability/THREAD=REFS", "yes" },
+ { "service/imap/imap_capability/THREAD=ORDEREDSUBJECT", "yes" },
+ { "service/imap/imap_capability/MULTIAPPEND", "yes" },
+ { "service/imap/imap_capability/URL-PARTIAL", "yes" },
+ { "service/imap/imap_capability/CATENATE", "yes" },
+ { "service/imap/imap_capability/UNSELECT", "yes" },
+ { "service/imap/imap_capability/CHILDREN", "yes" },
+ { "service/imap/imap_capability/NAMESPACE", "yes" },
+ { "service/imap/imap_capability/UIDPLUS", "yes" },
+ { "service/imap/imap_capability/LIST-EXTENDED", "yes" },
+ { "service/imap/imap_capability/I18NLEVEL=1", "yes" },
+ { "service/imap/imap_capability/CONDSTORE", "yes" },
+ { "service/imap/imap_capability/QRESYNC", "yes" },
+ { "service/imap/imap_capability/ESEARCH", "yes" },
+ { "service/imap/imap_capability/ESORT", "yes" },
+ { "service/imap/imap_capability/SEARCHRES", "yes" },
+ { "service/imap/imap_capability/WITHIN", "yes" },
+ { "service/imap/imap_capability/CONTEXT=SEARCH", "yes" },
+ { "service/imap/imap_capability/LIST-STATUS", "yes" },
+ { "service/imap/imap_capability/BINARY", "yes" },
+ { "service/imap/imap_capability/MOVE", "yes" },
+ { "service/imap/imap_capability/SNIPPET=FUZZY", "yes" },
+ { "service/imap/imap_capability/PREVIEW=FUZZY", "yes" },
+ { "service/imap/imap_capability/PREVIEW", "yes" },
+ { "service/imap/imap_capability/STATUS=SIZE", "yes" },
+ { "service/imap/imap_capability/SAVEDATE", "yes" },
+ { "service/imap/imap_capability/COMPRESS=DEFLATE", "yes" },
+ { "service/imap/imap_capability/INPROGRESS", "yes" },
+ { "service/imap/imap_capability/NOTIFY", "yes" },
+ { "service/imap/imap_capability/METADATA", "yes" },
+ { "service/imap/imap_capability/SPECIAL-USE", "yes" },
+ { "service/imap/imap_capability/LITERAL+", "yes" },
+ { "service/imap/imap_capability/LITERAL-", "yes" },
{ "imap_id_send/name", DOVECOT_NAME },
{ NULL, NULL },
};
/* imap: */
uoff_t imap_max_line_length;
unsigned int imap_idle_notify_interval;
- const char *imap_capability;
+ ARRAY_TYPE(const_string) imap_capability;
ARRAY_TYPE(const_string) imap_client_workarounds;
const char *imap_logout_format;
const char *imap_fetch_failure;
/* The first element after the visible array is NULL. If the next element
after the NULL is set_array_stop, then the boollist is stopped. */
unsigned int count;
- const char *const *values =
- array_get(array, &count);
+ const char *const *values = array_get(array, &count);
i_assert(values[count] == NULL);
- if (values[count + 1] == set_array_stop)
- return TRUE;
- return FALSE;
+ return values[count + 1] == set_array_stop;
}
static int