const char *storage_name;
struct mailbox *box;
struct mailbox_status status;
+ uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
struct local_dsync_mailbox_change *change;
struct local_dsync_dir_change *dir_change;
const char *const *fields;
}
box = mailbox_alloc(info->ns->list, storage_name, NULL, flags);
- if (mailbox_sync(box, 0) < 0) {
+ if (mailbox_sync(box, 0) < 0 ||
+ mailbox_get_guid(box, mailbox_guid) < 0) {
struct mail_storage *storage = mailbox_get_storage(box);
i_error("Failed to sync mailbox %s: %s", info->name,
}
mailbox_get_status(box, STATUS_UIDNEXT | STATUS_UIDVALIDITY |
- STATUS_HIGHESTMODSEQ | STATUS_GUID |
- STATUS_CACHE_FIELDS, &status);
+ STATUS_HIGHESTMODSEQ | STATUS_CACHE_FIELDS, &status);
- change = hash_table_lookup(worker->mailbox_changes_hash,
- status.mailbox_guid);
+ change = hash_table_lookup(worker->mailbox_changes_hash, mailbox_guid);
if (change != NULL) {
/* it shouldn't be marked as deleted, but drop it to be sure */
change->deleted_mailbox = FALSE;
}
- memcpy(dsync_box_r->mailbox_guid.guid, status.mailbox_guid,
+ memcpy(dsync_box_r->mailbox_guid.guid, mailbox_guid,
sizeof(dsync_box_r->mailbox_guid.guid));
dsync_box_r->uid_validity = status.uidvalidity;
dsync_box_r->uid_next = status.uidnext;
enum mailbox_flags flags = MAILBOX_FLAG_KEEP_RECENT;
struct local_dsync_mailbox *lbox;
struct mailbox *box;
- struct mailbox_status status;
+ uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
lbox = hash_table_lookup(worker->mailbox_hash, guid);
if (lbox == NULL) {
}
box = mailbox_alloc(lbox->ns->list, lbox->storage_name, NULL, flags);
- if (mailbox_sync(box, 0) < 0) {
+ if (mailbox_sync(box, 0) < 0 ||
+ mailbox_get_guid(box, mailbox_guid) < 0) {
struct mail_storage *storage = mailbox_get_storage(box);
i_error("Failed to sync mailbox %s: %s", lbox->storage_name,
return -1;
}
- mailbox_get_status(box, STATUS_GUID, &status);
- if (memcmp(status.mailbox_guid, guid->guid, sizeof(guid->guid)) != 0) {
+ if (memcmp(mailbox_guid, guid->guid, sizeof(guid->guid)) != 0) {
i_error("Mailbox %s changed its GUID (%s -> %s)",
lbox->storage_name, dsync_guid_to_str(guid),
- binary_to_hex(status.mailbox_guid,
- sizeof(status.mailbox_guid)));
+ binary_to_hex(mailbox_guid, sizeof(mailbox_guid)));
mailbox_free(&box);
return -1;
}
const char *ref;
const char *const *patterns;
enum mailbox_list_iter_flags list_flags;
- enum mailbox_status_items status_items;
+ struct imap_status_items status_items;
struct mail_namespace *ns;
struct mailbox_list_iterate_context *list_iter;
unsigned int cur_ns_send_prefix:1;
unsigned int cur_ns_skip_trailing_sep:1;
unsigned int used_listext:1;
+ unsigned int used_status:1;
};
static void
list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN;
else if (strcasecmp(atom, "STATUS") == 0 &&
args[1].type == IMAP_ARG_LIST) {
- /* FIXME: this should probably be a plugin.. */
if (imap_status_parse_items(ctx->cmd,
IMAP_ARG_LIST_ARGS(&args[1]),
&ctx->status_items) < 0)
return FALSE;
+ ctx->used_status = TRUE;
args++;
} else {
/* skip also optional list value */
static void list_send_status(struct cmd_list_context *ctx, const char *name)
{
- struct mailbox_status status;
+ struct imap_status_result result;
const char *storage_name, *error;
storage_name = mail_namespace_get_storage_name(ctx->ns, name);
if (imap_status_get(ctx->cmd, ctx->ns, storage_name,
- ctx->status_items, &status, &error) < 0) {
+ &ctx->status_items, &result, &error) < 0) {
client_send_line(ctx->cmd->client,
t_strconcat("* ", error, NULL));
return;
}
- imap_status_send(ctx->cmd->client, name, ctx->status_items, &status);
+ imap_status_send(ctx->cmd->client, name, &ctx->status_items, &result);
}
static int
mailbox_childinfo2str(ctx, str, flags);
ret = client_send_line(ctx->cmd->client, str_c(str));
- if (ctx->status_items != 0 &&
+ if (ctx->used_status &&
(flags & (MAILBOX_NONEXISTENT | MAILBOX_NOSELECT)) == 0) {
T_BEGIN {
list_send_status(ctx, name);
{
struct client *client = cmd->client;
const struct imap_arg *args;
- struct mailbox_status status;
- enum mailbox_status_items items;
+ struct imap_status_items items;
+ struct imap_status_result result;
struct mail_namespace *ns;
const char *mailbox, *real_mailbox, *error;
bool selected_mailbox;
selected_mailbox = client->mailbox != NULL &&
mailbox_equals(client->mailbox, ns, real_mailbox);
- if (imap_status_get(cmd, ns, real_mailbox, items,
- &status, &error) < 0) {
+ if (imap_status_get(cmd, ns, real_mailbox, &items,
+ &result, &error) < 0) {
client_send_tagline(cmd, error);
return TRUE;
}
- imap_status_send(client, mailbox, items, &status);
+ imap_status_send(client, mailbox, &items, &result);
if (!selected_mailbox)
client_send_tagline(cmd, "OK Status completed.");
else {
int imap_status_parse_items(struct client_command_context *cmd,
const struct imap_arg *args,
- enum mailbox_status_items *items_r)
+ struct imap_status_items *items_r)
{
const char *item;
enum mailbox_status_items items;
+ memset(items_r, 0, sizeof(*items_r));
items = 0;
for (; args->type != IMAP_ARG_EOL; args++) {
if (args->type != IMAP_ARG_ATOM) {
else if (strcmp(item, "HIGHESTMODSEQ") == 0)
items |= STATUS_HIGHESTMODSEQ;
else if (strcmp(item, "X-GUID") == 0)
- items |= STATUS_GUID;
+ items_r->guid = TRUE;
else {
client_send_tagline(cmd, t_strconcat(
"BAD Invalid status item ", item, NULL));
}
}
- *items_r = items;
+ items_r->mailbox_items = items;
return 0;
}
int imap_status_get(struct client_command_context *cmd,
struct mail_namespace *ns,
- const char *mailbox, enum mailbox_status_items items,
- struct mailbox_status *status_r, const char **error_r)
+ const char *mailbox, const struct imap_status_items *items,
+ struct imap_status_result *result_r, const char **error_r)
{
struct client *client = cmd->client;
struct mailbox *box;
if (client->mailbox != NULL &&
mailbox_equals(client->mailbox, ns, mailbox)) {
/* this mailbox is selected */
- mailbox_get_status(client->mailbox, items, status_r);
- return TRUE;
+ box = client->mailbox;
+ } else {
+ /* open the mailbox */
+ box = mailbox_alloc(ns->list, mailbox, NULL,
+ MAILBOX_FLAG_READONLY |
+ MAILBOX_FLAG_KEEP_RECENT);
+ if (client->enabled_features != 0)
+ mailbox_enable(box, client->enabled_features);
}
- /* open the mailbox */
- box = mailbox_alloc(ns->list, mailbox, NULL, MAILBOX_FLAG_READONLY |
- MAILBOX_FLAG_KEEP_RECENT);
-
- if ((items & STATUS_HIGHESTMODSEQ) != 0)
+ if ((items->mailbox_items & STATUS_HIGHESTMODSEQ) != 0)
client_enable(client, MAILBOX_FEATURE_CONDSTORE);
- if (client->enabled_features != 0)
- mailbox_enable(box, client->enabled_features);
- ret = mailbox_sync(box, 0);
- if (ret == 0)
- mailbox_get_status(box, items, status_r);
- else {
+ ret = box == client->mailbox ? 0 : mailbox_sync(box, 0);
+ if (ret == 0) {
+ mailbox_get_status(box, items->mailbox_items,
+ &result_r->status);
+ if (items->guid)
+ ret = mailbox_get_guid(box, result_r->mailbox_guid);
+ }
+
+ if (ret < 0) {
struct mail_storage *storage = mailbox_get_storage(box);
*error_r = mail_storage_get_last_error(storage, &error);
*error_r = imap_get_error_string(cmd, *error_r, error);
}
- mailbox_free(&box);
+ if (box != client->mailbox)
+ mailbox_free(&box);
return ret;
}
void imap_status_send(struct client *client, const char *mailbox,
- enum mailbox_status_items items,
- const struct mailbox_status *status)
+ const struct imap_status_items *items,
+ const struct imap_status_result *result)
{
+ const struct mailbox_status *status = &result->status;
string_t *str;
str = t_str_new(128);
imap_quote_append_string(str, mailbox, FALSE);
str_append(str, " (");
- if (items & STATUS_MESSAGES)
+ if ((items->mailbox_items & STATUS_MESSAGES) != 0)
str_printfa(str, "MESSAGES %u ", status->messages);
- if (items & STATUS_RECENT)
+ if ((items->mailbox_items & STATUS_RECENT) != 0)
str_printfa(str, "RECENT %u ", status->recent);
- if (items & STATUS_UIDNEXT)
+ if ((items->mailbox_items & STATUS_UIDNEXT) != 0)
str_printfa(str, "UIDNEXT %u ", status->uidnext);
- if (items & STATUS_UIDVALIDITY)
+ if ((items->mailbox_items & STATUS_UIDVALIDITY) != 0)
str_printfa(str, "UIDVALIDITY %u ", status->uidvalidity);
- if (items & STATUS_UNSEEN)
+ if ((items->mailbox_items & STATUS_UNSEEN) != 0)
str_printfa(str, "UNSEEN %u ", status->unseen);
- if (items & STATUS_HIGHESTMODSEQ) {
+ if ((items->mailbox_items & STATUS_HIGHESTMODSEQ) != 0) {
str_printfa(str, "HIGHESTMODSEQ %llu ",
(unsigned long long)status->highest_modseq);
}
- if (items & STATUS_GUID) {
+ if (items->guid) {
str_printfa(str, "X-GUID %s ",
- binary_to_hex(status->mailbox_guid,
- sizeof(status->mailbox_guid)));
+ binary_to_hex(result->mailbox_guid,
+ sizeof(result->mailbox_guid)));
}
if (items != 0)
#ifndef IMAP_STATUS_H
#define IMAP_STATUS_H
+struct imap_status_items {
+ enum mailbox_status_items mailbox_items;
+
+ unsigned int guid:1;
+};
+
+struct imap_status_result {
+ struct mailbox_status status;
+ uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
+};
+
int imap_status_parse_items(struct client_command_context *cmd,
const struct imap_arg *args,
- enum mailbox_status_items *items_r);
+ struct imap_status_items *items_r);
int imap_status_get(struct client_command_context *cmd,
struct mail_namespace *ns,
- const char *mailbox, enum mailbox_status_items items,
- struct mailbox_status *status_r, const char **error_r);
+ const char *mailbox, const struct imap_status_items *items,
+ struct imap_status_result *result_r, const char **error_r);
void imap_status_send(struct client *client, const char *mailbox,
- enum mailbox_status_items items,
- const struct mailbox_status *status);
+ const struct imap_status_items *items,
+ const struct imap_status_result *result);
#endif
index_storage_get_status,
NULL,
NULL,
+ NULL,
cydir_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
return ret;
}
-static void mdbox_storage_get_status_guid(struct mailbox *box,
- struct mailbox_status *status_r)
+static int
+mdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
{
struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)box;
struct mdbox_index_header hdr;
/* regenerate it */
if (mdbox_write_index_header(box, NULL) < 0 ||
mdbox_read_header(mbox, &hdr) < 0)
- return;
+ return -1;
}
- memcpy(status_r->mailbox_guid, hdr.mailbox_guid,
- sizeof(status_r->mailbox_guid));
-}
-
-static void
-mdbox_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
- struct mailbox_status *status_r)
-{
- index_storage_get_status(box, items, status_r);
-
- if ((items & STATUS_GUID) != 0)
- mdbox_storage_get_status_guid(box, status_r);
+ memcpy(guid, hdr.mailbox_guid, MAIL_GUID_128_SIZE);
+ return 0;
}
static int
dbox_mailbox_create,
mdbox_mailbox_update,
mdbox_mailbox_delete,
- mdbox_storage_get_status,
+ index_storage_get_status,
+ mdbox_mailbox_get_guid,
NULL,
NULL,
mdbox_storage_sync_init,
return ret;
}
-static void sdbox_storage_get_status_guid(struct mailbox *box,
- struct mailbox_status *status_r)
+static int
+sdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
{
struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box;
struct sdbox_index_header hdr;
/* regenerate it */
if (sdbox_write_index_header(box, NULL) < 0 ||
sdbox_read_header(mbox, &hdr) < 0)
- return;
+ return -1;
}
- memcpy(status_r->mailbox_guid, hdr.mailbox_guid,
- sizeof(status_r->mailbox_guid));
-}
-
-static void
-dbox_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
- struct mailbox_status *status_r)
-{
- index_storage_get_status(box, items, status_r);
-
- if ((items & STATUS_GUID) != 0)
- sdbox_storage_get_status_guid(box, status_r);
+ memcpy(guid, hdr.mailbox_guid, MAIL_GUID_128_SIZE);
+ return 0;
}
static int
dbox_mailbox_create,
dbox_mailbox_update,
index_storage_mailbox_delete,
- dbox_storage_get_status,
+ index_storage_get_status,
+ sdbox_mailbox_get_guid,
NULL,
NULL,
sdbox_storage_sync_init,
int index_storage_mailbox_delete(struct mailbox *box)
{
- struct mailbox_status status;
+ uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
if (!box->opened) {
/* \noselect mailbox, try deleting only the directory */
return index_storage_mailbox_delete_dir(box, FALSE);
}
- mailbox_get_status(box, STATUS_GUID, &status);
+ if (mailbox_get_guid(box, mailbox_guid) < 0)
+ return -1;
/* Make sure the indexes are closed before trying to delete the
directory that contains them. It can still fail with some NFS
}
mailbox_list_add_change(box->list, MAILBOX_LOG_RECORD_DELETE_MAILBOX,
- status.mailbox_guid);
+ mailbox_guid);
return index_storage_mailbox_delete_dir(box, TRUE);
}
return update == NULL ? 0 : maildir_mailbox_update(box, update);
}
-static void
-maildir_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
- struct mailbox_status *status_r)
+static int
+maildir_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
- index_storage_get_status(box, items, status_r);
- if ((items & STATUS_GUID) != 0) {
- (void)maildir_uidlist_get_mailbox_guid(mbox->uidlist,
- status_r->mailbox_guid);
- }
+ return maildir_uidlist_get_mailbox_guid(mbox->uidlist, guid);
}
static int
maildir_mailbox_create,
maildir_mailbox_update,
index_storage_mailbox_delete,
- maildir_storage_get_status,
+ index_storage_get_status,
+ maildir_mailbox_get_guid,
maildir_list_index_has_changed,
maildir_list_index_update_sync,
maildir_storage_sync_init,
index_storage_mailbox_close(box);
}
-static void
-mbox_storage_get_status(struct mailbox *box, enum mailbox_status_items items,
- struct mailbox_status *status_r)
+static int
+mbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
{
struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
- index_storage_get_status(box, items, status_r);
- if ((items & STATUS_GUID) != 0) {
- memcpy(status_r->mailbox_guid, mbox->mbox_hdr.mailbox_guid,
- sizeof(status_r->mailbox_guid));
- }
+ memcpy(guid, mbox->mbox_hdr.mailbox_guid, MAIL_GUID_128_SIZE);
+ return 0;
}
static void mbox_notify_changes(struct mailbox *box)
mbox_mailbox_create,
mbox_mailbox_update,
index_storage_mailbox_delete,
- mbox_storage_get_status,
+ index_storage_get_status,
+ mbox_mailbox_get_guid,
NULL,
NULL,
mbox_storage_sync_init,
index_storage_get_status,
NULL,
NULL,
+ NULL,
raw_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
void (*get_status)(struct mailbox *box, enum mailbox_status_items items,
struct mailbox_status *status_r);
+ int (*get_guid)(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]);
/* Lookup sync extension record and figure out if it mailbox has
changed since. Returns 1 = yes, 0 = no, -1 = error. */
box->v.get_status(box, items, status_r);
}
+int mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
+{
+ if (box->v.get_guid == NULL) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
+ "Storage doesn't support mailbox GUIDs");
+ }
+ if (!box->opened) {
+ if (mailbox_open(box) < 0)
+ return -1;
+ }
+ return box->v.get_guid(box, guid);
+}
+
struct mailbox_sync_context *
mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
STATUS_FIRST_UNSEEN_SEQ = 0x20,
STATUS_KEYWORDS = 0x40,
STATUS_HIGHESTMODSEQ = 0x80,
- STATUS_GUID = 0x100,
- STATUS_CACHE_FIELDS = 0x200
+ STATUS_CACHE_FIELDS = 0x100
};
enum mailbox_search_result_flags {
uint32_t first_unseen_seq;
uint64_t highest_modseq;
- uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
const ARRAY_TYPE(keywords) *keywords;
/* Fields that have "temp" or "yes" caching decision. */
/* Gets the mailbox status information. */
void mailbox_get_status(struct mailbox *box, enum mailbox_status_items items,
struct mailbox_status *status_r);
+/* Get mailbox GUID, creating it if necessary. */
+int mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE]);
/* Synchronize the mailbox. */
struct mailbox_sync_context *
test_mailbox_get_status,
NULL,
NULL,
+ NULL,
test_mailbox_sync_init,
test_mailbox_sync_next,
test_mailbox_sync_deinit,
index_storage_get_status,
NULL,
NULL,
+ NULL,
virtual_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,