Skip to content

Commit

Permalink
imap: Add support for ENABLE extensions
Browse files Browse the repository at this point in the history
Based on patch by Aki Tuomi
  • Loading branch information
sirainen committed Nov 29, 2018
1 parent 808c126 commit 4cec00e
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 37 deletions.
101 changes: 72 additions & 29 deletions src/imap/imap-client.c
Expand Up @@ -24,6 +24,7 @@
#include "imap-search.h"
#include "imap-notify.h"
#include "imap-commands.h"
#include "imap-feature.h"

#include <unistd.h>

Expand All @@ -39,8 +40,8 @@ struct imap_module_register imap_module_register = { 0 };
struct client *imap_clients = NULL;
unsigned int imap_client_count = 0;

unsigned int imap_feature_condstore = MAILBOX_FEATURE_CONDSTORE;
unsigned int imap_feature_qresync = MAILBOX_FEATURE_QRESYNC;
unsigned int imap_feature_condstore = UINT_MAX;
unsigned int imap_feature_qresync = UINT_MAX;

static const char *client_command_state_names[CLIENT_COMMAND_STATE_DONE+1] = {
"wait-input",
Expand Down Expand Up @@ -153,6 +154,7 @@ struct client *client_create(int fd_in, int fd_out, const char *session_id,
client->user = user;
client->notify_count_changes = TRUE;
client->notify_flag_changes = TRUE;
p_array_init(&client->enabled_features, client->pool, 8);

if (set->rawlog_dir[0] != '\0') {
(void)iostream_rawlog_create(set->rawlog_dir, &client->input,
Expand Down Expand Up @@ -1449,24 +1451,39 @@ bool client_handle_search_save_ambiguity(struct client_command_context *cmd)

void client_enable(struct client *client, unsigned int feature_idx)
{
enum mailbox_feature features = feature_idx;
if (client_has_enabled(client, feature_idx))
return;

const struct imap_feature *feat = imap_feature_idx(feature_idx);
feat->callback(client);
/* set after the callback, so the callback can see what features were
previously set */
bool value = TRUE;
array_idx_set(&client->enabled_features, feature_idx, &value);
}

bool client_has_enabled(struct client *client, unsigned int feature_idx)
{
if (feature_idx >= array_count(&client->enabled_features))
return FALSE;
const bool *featurep =
array_idx(&client->enabled_features, feature_idx);
return *featurep;
}

static void imap_client_enable_condstore(struct client *client)
{
struct mailbox_status status;
bool had_condstore = client_has_enabled(client, imap_feature_condstore);
int ret;

if ((features & imap_feature_qresync) != 0)
features |= imap_feature_condstore;

if ((client->enabled_features & features) == features)
if (client->mailbox == NULL)
return;

client->enabled_features |= features;
if (client->mailbox == NULL)
if ((client_enabled_mailbox_features(client) & MAILBOX_FEATURE_CONDSTORE) != 0)
return;

ret = mailbox_enable(client->mailbox, features);
if (ret == 0 && !had_condstore &&
client_has_enabled(client, imap_feature_condstore)) {
ret = mailbox_enable(client->mailbox, MAILBOX_FEATURE_CONDSTORE);
if (ret == 0) {
/* CONDSTORE being enabled while mailbox is selected.
Notify client of the latest HIGHESTMODSEQ. */
ret = mailbox_get_status(client->mailbox,
Expand All @@ -1483,31 +1500,46 @@ void client_enable(struct client *client, unsigned int feature_idx)
}
}

bool client_has_enabled(struct client *client, unsigned int feature_idx)
static void imap_client_enable_qresync(struct client *client)
{
enum mailbox_feature features = feature_idx;

return (client->enabled_features & features) != 0;
/* enable also CONDSTORE */
client_enable(client, imap_feature_condstore);
}

enum mailbox_feature client_enabled_mailbox_features(struct client *client)
{
return client->enabled_features;
enum mailbox_feature mailbox_features = 0;
const struct imap_feature *feature;
const bool *client_enabled;
unsigned int count;

client_enabled = array_get(&client->enabled_features, &count);
for (unsigned int idx = 0; idx < count; idx++) {
if (client_enabled[idx]) {
feature = imap_feature_idx(idx);
mailbox_features |= feature->mailbox_features;
}
}
return mailbox_features;
}

const char *const *client_enabled_features(struct client *client)
{
static const char *condstore_str = "CONDSTORE";
static const char *qresync_str = "QRESYNC";
ARRAY_TYPE(const_string) features;
t_array_init(&features, 8);

if ((client->enabled_features & imap_feature_condstore) != 0)
array_append(&features, &condstore_str, 1);
if ((client->enabled_features & imap_feature_qresync) != 0)
array_append(&features, &qresync_str, 1);
array_append_zero(&features);
return array_idx(&features, 0);
ARRAY_TYPE(const_string) feature_strings;
const struct imap_feature *feature;
const bool *client_enabled;
unsigned int count;

t_array_init(&feature_strings, 8);
client_enabled = array_get(&client->enabled_features, &count);
for (unsigned int idx = 0; idx < count; idx++) {
if (client_enabled[idx]) {
feature = imap_feature_idx(idx);
array_append(&feature_strings, &feature->feature, 1);
}
}
array_append_zero(&feature_strings);
return array_idx(&feature_strings, 0);
}

struct imap_search_update *
Expand Down Expand Up @@ -1542,6 +1574,17 @@ void client_search_updates_free(struct client *client)
array_clear(&client->search_updates);
}

void clients_init(void)
{
imap_feature_condstore =
imap_feature_register("CONDSTORE", MAILBOX_FEATURE_CONDSTORE,
imap_client_enable_condstore);
imap_feature_qresync =
imap_feature_register("QRESYNC", MAILBOX_FEATURE_QRESYNC |
MAILBOX_FEATURE_CONDSTORE,
imap_client_enable_qresync);
}

void clients_destroy_all(void)
{
while (imap_clients != NULL) {
Expand Down
3 changes: 2 additions & 1 deletion src/imap/imap-client.h
Expand Up @@ -166,7 +166,7 @@ struct client {
struct mailbox_keywords keywords;
unsigned int sync_counter;
uint32_t messages_count, recent_count, uidvalidity;
enum mailbox_feature enabled_features;
ARRAY(bool) enabled_features;

time_t last_input, last_output;
unsigned int bad_counter;
Expand Down Expand Up @@ -338,6 +338,7 @@ void client_input(struct client *client);
bool client_handle_input(struct client *client);
int client_output(struct client *client);

void clients_init(void);
void clients_destroy_all(void);

#endif
45 changes: 38 additions & 7 deletions src/imap/imap-feature.c
Expand Up @@ -3,13 +3,44 @@
#include "imap-common.h"
#include "imap-feature.h"

static ARRAY_TYPE(imap_feature) feature_register = ARRAY_INIT;

bool imap_feature_lookup(const char *name, unsigned int *feature_idx_r)
{
if (strcasecmp(name, "CONDSTORE") == 0)
*feature_idx_r = imap_feature_condstore;
else if (strcasecmp(name, "QRESYNC") == 0)
*feature_idx_r = imap_feature_qresync;
else
return FALSE;
return TRUE;
for (unsigned int idx = 0; idx < array_count(&feature_register); idx++) {
const struct imap_feature *feat =
array_idx(&feature_register, idx);
if (strcasecmp(name, feat->feature) == 0) {
*feature_idx_r = idx;
return TRUE;
}
}
return FALSE;
}

const struct imap_feature *imap_feature_idx(unsigned int feature_idx)
{
return array_idx(&feature_register, feature_idx);
}

unsigned int
imap_feature_register(const char *feature, enum mailbox_feature mailbox_features,
imap_client_enable_callback_t *callback)
{
struct imap_feature *feat = array_append_space(&feature_register);
feat->feature = feature;
feat->mailbox_features = mailbox_features;
feat->callback = callback;
return array_count(&feature_register)-1;
}

void imap_features_init(void)
{
i_assert(!array_is_created(&feature_register));
i_array_init(&feature_register, 8);
}

void imap_features_deinit(void)
{
array_free(&feature_register);
}
18 changes: 18 additions & 0 deletions src/imap/imap-feature.h
@@ -1,6 +1,24 @@
#ifndef IMAP_FEATURE_H
#define IMAP_FEATURE_H

typedef void imap_client_enable_callback_t(struct client *);

struct imap_feature {
const char *feature;
enum mailbox_feature mailbox_features;
imap_client_enable_callback_t *callback;
bool enabled;
};
ARRAY_DEFINE_TYPE(imap_feature, struct imap_feature);

bool imap_feature_lookup(const char *name, unsigned int *feature_idx_r);
const struct imap_feature *imap_feature_idx(unsigned int feature_idx);

unsigned int
imap_feature_register(const char *feature, enum mailbox_feature mailbox_features,
imap_client_enable_callback_t *callback);

void imap_features_init(void);
void imap_features_deinit(void);

#endif
5 changes: 5 additions & 0 deletions src/imap/main.c
Expand Up @@ -21,6 +21,7 @@
#include "imap-master-client.h"
#include "imap-resp-code.h"
#include "imap-commands.h"
#include "imap-feature.h"
#include "imap-fetch.h"

#include <stdio.h>
Expand Down Expand Up @@ -481,6 +482,8 @@ int main(int argc, char *argv[])
/* plugins may want to add commands, so this needs to be called early */
commands_init();
imap_fetch_handlers_init();
imap_features_init();
clients_init();
imap_master_clients_init();

const char *error;
Expand Down Expand Up @@ -525,6 +528,8 @@ int main(int argc, char *argv[])
mail_storage_service_deinit(&storage_service);

imap_fetch_handlers_deinit();
imap_features_deinit();

commands_deinit();
imap_master_clients_deinit();

Expand Down

0 comments on commit 4cec00e

Please sign in to comment.