imap-messageset.c \
imap-search.c \
imap-sort.c \
+ imap-sync.c \
imap-thread.c \
mail-storage-callbacks.c \
main.c \
imap-messageset.h \
imap-search.h \
imap-sort.h \
+ imap-sync.h \
imap-thread.h \
namespace.h
struct mailbox *mailbox;
struct mailbox_keywords keywords;
unsigned int select_counter; /* increased when mailbox is changed */
+ uint32_t messages_count, recent_count;
time_t last_input;
unsigned int bad_counter;
#include "istream.h"
#include "ostream.h"
#include "commands.h"
+#include "imap-sync.h"
#include <stdlib.h>
o_stream_cork(client->output);
- if (client->idle_expunge) {
+ if (client->idle_expunge != 0) {
client_send_line(client,
t_strdup_printf("* %u EXPUNGE", client->idle_expunge));
}
client->io = io_add(i_stream_get_fd(client->input),
IO_READ, _client_input, client);
- if (client->mailbox != NULL) {
- mailbox_auto_sync(client->mailbox, mailbox_check_interval != 0 ?
- MAILBOX_SYNC_FLAG_NO_EXPUNGES :
- MAILBOX_SYNC_AUTO_STOP,
- mailbox_check_interval);
- }
+ if (client->mailbox != NULL)
+ mailbox_notify_changes(client->mailbox, 0, NULL, NULL);
client_sync_full(client);
if (done_ok)
static void idle_timeout(void *context)
{
struct client *client = context;
- struct mailbox_status status;
+
+ /* outlook workaround - it hasn't sent anything for a long time and
+ we're about to disconnect unless it does something. send a fake
+ EXISTS to see if it responds. it's expunged later. */
timeout_remove(client->idle_to);
client->idle_to = NULL;
- if (mailbox_get_status(client->mailbox, STATUS_MESSAGES, &status) < 0) {
+ client->idle_expunge = client->messages_count+1;
+ client_send_line(client,
+ t_strdup_printf("* %u EXISTS", client->idle_expunge));
+ mailbox_notify_changes(client->mailbox, 0, NULL, NULL);
+}
+
+static void idle_callback(struct mailbox *box, void *context)
+{
+ struct client *client = context;
+
+ if (imap_sync(client, box, 0) < 0) {
client_send_untagged_storage_error(client,
mailbox_get_storage(client->mailbox));
- idle_finish(client, TRUE);
- } else {
- client->idle_expunge = status.messages+1;
- client_send_line(client,
- t_strdup_printf("* %u EXISTS", client->idle_expunge));
-
- mailbox_auto_sync(client->mailbox, MAILBOX_SYNC_AUTO_STOP, 0);
+ mailbox_notify_changes(client->mailbox, 0, NULL, NULL);
}
}
if (interval == 0)
interval = DEFAULT_IDLE_CHECK_INTERVAL;
- if (client->mailbox != NULL)
- mailbox_auto_sync(client->mailbox, 0, interval);
-
+ if (client->mailbox != NULL) {
+ mailbox_notify_changes(client->mailbox, interval,
+ idle_callback, client);
+ }
client_send_line(client, "+ idling");
io_remove(client->io);
#include "common.h"
#include "commands.h"
+#include "imap-sync.h"
int _cmd_select_full(struct client *client, int readonly)
{
return TRUE;
}
+ if (imap_sync(client, box, 0) < 0) {
+ client_send_storage_error(client, storage);
+ mailbox_close(box);
+ return TRUE;
+ }
+
if (mailbox_get_status(box, STATUS_MESSAGES | STATUS_RECENT |
STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY |
STATUS_UIDNEXT | STATUS_KEYWORDS,
client_save_keywords(&client->keywords,
status.keywords, status.keywords_count);
+ client->messages_count = status.messages;
+ client->recent_count = status.recent;
/* set client's mailbox only after getting status to make sure
we're not sending any expunge/exists replies too early to client */
client_send_tagline(client, mailbox_is_readonly(box) ?
"OK [READ-ONLY] Select completed." :
"OK [READ-WRITE] Select completed.");
-
- if (mailbox_check_interval != 0) {
- mailbox_auto_sync(box, MAILBOX_SYNC_FLAG_NO_EXPUNGES,
- mailbox_check_interval);
- }
-
return TRUE;
}
#include "str.h"
#include "imap-quote.h"
#include "commands.h"
+#include "imap-sync.h"
/* Returns status items, or -1 if error */
static enum mailbox_status_items
return FALSE;
}
- failed = mailbox_get_status(box, items, status) < 0;
+ if (imap_sync(client, box, 0) < 0)
+ failed = TRUE;
+ else
+ failed = mailbox_get_status(box, items, status) < 0;
if (box != client->mailbox)
mailbox_close(box);
/* Copyright (C) 2002 Timo Sirainen */
#include "common.h"
+#include "str.h"
#include "commands.h"
#include "imap-search.h"
#include "imap-util.h"
static int mail_send_flags(struct client *client, struct mail *mail)
{
const struct mail_full_flags *flags;
- const char *str;
+ string_t *str;
flags = mail->get_flags(mail);
if (flags == NULL)
return FALSE;
t_push();
- str = imap_write_flags(flags);
- str = t_strdup_printf(client->cmd_uid ?
- "* %u FETCH (FLAGS (%s) UID %u)" :
- "* %u FETCH (FLAGS (%s))",
- mail->seq, str, mail->uid);
- client_send_line(client, str);
+ str = t_str_new(128);
+ str_printfa(str, "* %u FETCH (FLAGS (", mail->seq);
+ imap_write_flags(str, flags);
+ if (client->cmd_uid)
+ str_printfa(str, ") UID %u)", mail->uid);
+ else
+ str_append(str, "))");
+ client_send_line(client, str_c(str));
t_pop();
return TRUE;
#include "imap-util.h"
#include "mail-storage.h"
#include "imap-parser.h"
+#include "imap-sync.h"
#include "namespace.h"
/* Maximum length for mailbox name, including it's path. This isn't fully
if (client->mailbox == NULL)
return;
- if (mailbox_sync(client->mailbox, 0) < 0) {
+ if (imap_sync(client, client->mailbox, 0) < 0) {
client_send_untagged_storage_error(client,
mailbox_get_storage(client->mailbox));
}
if (client->mailbox == NULL)
return;
- if (mailbox_sync(client->mailbox, MAILBOX_SYNC_FLAG_FAST) < 0) {
+ if (imap_sync(client, client->mailbox, MAILBOX_SYNC_FLAG_FAST) < 0) {
client_send_untagged_storage_error(client,
mailbox_get_storage(client->mailbox));
}
if (client->mailbox == NULL)
return;
- if (mailbox_sync(client->mailbox, MAILBOX_SYNC_FLAG_FAST |
- MAILBOX_SYNC_FLAG_NO_EXPUNGES) < 0) {
+ if (imap_sync(client, client->mailbox, MAILBOX_SYNC_FLAG_FAST |
+ MAILBOX_SYNC_FLAG_NO_EXPUNGES) < 0) {
client_send_untagged_storage_error(client,
mailbox_get_storage(client->mailbox));
}
flags = &full_flags;
}
- str_printfa(ctx->str, "FLAGS (%s) ", imap_write_flags(flags));
+ str_append(ctx->str, "FLAGS (");
+ imap_write_flags(ctx->str, flags);
+ str_append(ctx->str, ") ");
return TRUE;
}
--- /dev/null
+/* Copyright (C) 2002 Timo Sirainen */
+
+#include "common.h"
+#include "str.h"
+#include "imap-util.h"
+#include "mail-storage.h"
+#include "imap-sync.h"
+
+int imap_sync(struct client *client, struct mailbox *box,
+ enum mailbox_sync_flags flags)
+{
+ struct mailbox_transaction_context *t;
+ struct mailbox_sync_context *ctx;
+ struct mailbox_sync_rec sync_rec;
+ struct mailbox_status status;
+ struct mail *mail;
+ const struct mail_full_flags *mail_flags;
+ string_t *str;
+ uint32_t seq;
+
+ if (client->mailbox != box) {
+ /* mailbox isn't selected - we only wish to sync the mailbox
+ without sending anything to client */
+ ctx = mailbox_sync_init(box, flags);
+ while (mailbox_sync_next(ctx, &sync_rec) > 0)
+ ;
+ return mailbox_sync_deinit(ctx, &status);
+ }
+
+ t_push();
+ str = t_str_new(256);
+
+ t = mailbox_transaction_begin(box, FALSE);
+ ctx = mailbox_sync_init(box, flags);
+ while (mailbox_sync_next(ctx, &sync_rec) > 0) {
+ switch (sync_rec.type) {
+ case MAILBOX_SYNC_TYPE_FLAGS:
+ for (seq = sync_rec.seq1; seq <= sync_rec.seq2; seq++) {
+ mail = mailbox_fetch(t, seq, MAIL_FETCH_FLAGS);
+
+ mail_flags = mail->get_flags(mail);
+ if (mail_flags == NULL)
+ continue;
+
+ str_truncate(str, 0);
+ str_printfa(str, "* %u FETCH (FLAGS (", seq);
+ imap_write_flags(str, mail_flags);
+ str_append(str, "))");
+ client_send_line(client, str_c(str));
+ }
+ break;
+ case MAILBOX_SYNC_TYPE_EXPUNGE:
+ for (seq = sync_rec.seq2; seq >= sync_rec.seq1; seq--) {
+ str_truncate(str, 0);
+ str_printfa(str, "* %u EXPUNGE", seq);
+ client_send_line(client, str_c(str));
+ }
+ break;
+ }
+ }
+
+ if (mailbox_sync_deinit(ctx, &status) < 0) {
+ mailbox_transaction_rollback(t);
+ t_pop();
+ return -1;
+ }
+
+ mailbox_transaction_commit(t);
+
+ if (status.messages != client->messages_count) {
+ client->messages_count = status.messages;
+ str_truncate(str, 0);
+ str_printfa(str, "* %u EXISTS", status.messages);
+ client_send_line(client, str_c(str));
+ }
+ if (status.recent != client->recent_count) {
+ client->recent_count = status.recent;
+ str_truncate(str, 0);
+ str_printfa(str, "* %u RECENT", status.recent);
+ client_send_line(client, str_c(str));
+ }
+
+ /*FIXME:client_save_keywords(&client->keywords, keywords, keywords_count);
+ client_send_mailbox_flags(client, mailbox, keywords, keywords_count);*/
+
+ t_pop();
+ return 0;
+}
--- /dev/null
+#ifndef __IMAP_SYNC_H
+#define __IMAP_SYNC_H
+
+int imap_sync(struct client *client, struct mailbox *box,
+ enum mailbox_sync_flags flags);
+
+#endif
o_stream_flush(client->output);
}
-static void expunge(struct mailbox *mailbox, unsigned int seq, void *context)
-{
- struct client *client = context;
- char str[MAX_INT_STRLEN+20];
-
- if (client->mailbox != mailbox)
- return;
-
- i_snprintf(str, sizeof(str), "* %u EXPUNGE", seq);
- client_send_line(client, str);
-}
-
-static void update_flags(struct mailbox *mailbox, unsigned int seq,
- const struct mail_full_flags *flags, void *context)
-{
- struct client *client = context;
- const char *str;
-
- if (client->mailbox != mailbox)
- return;
-
- t_push();
- str = imap_write_flags(flags);
- str = t_strdup_printf("* %u FETCH (FLAGS (%s))", seq, str);
- client_send_line(client, str);
- t_pop();
-}
-
-static void message_count_changed(struct mailbox *mailbox, unsigned int count,
- void *context)
-{
- struct client *client = context;
- char str[MAX_INT_STRLEN+20];
-
- if (client->mailbox != mailbox)
- return;
-
- i_snprintf(str, sizeof(str), "* %u EXISTS", count);
- client_send_line(client, str);
-}
-
-static void recent_count_changed(struct mailbox *mailbox, unsigned int count,
- void *context)
-{
- struct client *client = context;
- char str[MAX_INT_STRLEN+20];
-
- if (client->mailbox != mailbox)
- return;
-
- i_snprintf(str, sizeof(str), "* %u RECENT", count);
- client_send_line(client, str);
-}
-
-static void new_keywords(struct mailbox *mailbox, const char *keywords[],
- unsigned int keywords_count, void *context)
-{
- struct client *client = context;
-
- if (client->mailbox != mailbox)
- return;
-
- client_save_keywords(&client->keywords, keywords, keywords_count);
- client_send_mailbox_flags(client, mailbox, keywords, keywords_count);
-}
-
struct mail_storage_callbacks mail_storage_callbacks = {
alert_no_diskspace,
notify_ok,
- notify_no,
- expunge,
- update_flags,
- message_count_changed,
- recent_count_changed,
- new_keywords
+ notify_no
};
#include "mail-types.h"
#include "imap-util.h"
-const char *imap_write_flags(const struct mail_full_flags *flags)
+void imap_write_flags(string_t *dest, const struct mail_full_flags *flags)
{
- string_t *str;
- const char *sysflags;
unsigned int i;
-
- if (flags == 0)
- return "";
-
- sysflags = t_strconcat(
- (flags->flags & MAIL_ANSWERED) ? " \\Answered" : "",
- (flags->flags & MAIL_FLAGGED) ? " \\Flagged" : "",
- (flags->flags & MAIL_DELETED) ? " \\Deleted" : "",
- (flags->flags & MAIL_SEEN) ? " \\Seen" : "",
- (flags->flags & MAIL_DRAFT) ? " \\Draft" : "",
- (flags->flags & MAIL_RECENT) ? " \\Recent" : "",
- NULL);
-
- if (*sysflags != '\0')
- sysflags++;
-
- if (flags->keywords_count == 0)
- return sysflags;
-
- /* we have keywords too */
- str = t_str_new(256);
- str_append(str, sysflags);
-
- for (i = 0; i < flags->keywords_count; i++) {
- if (str_len(str) > 0)
- str_append_c(str, ' ');
- str_append(str, flags->keywords[i]);
+ size_t size;
+
+ size = str_len(dest);
+ if ((flags->flags & MAIL_ANSWERED) != 0)
+ str_append(dest, "\\Answered ");
+ if ((flags->flags & MAIL_FLAGGED) != 0)
+ str_append(dest, "\\Flagged ");
+ if ((flags->flags & MAIL_DELETED) != 0)
+ str_append(dest, "\\Deleted ");
+ if ((flags->flags & MAIL_SEEN) != 0)
+ str_append(dest, "\\Seen ");
+ if ((flags->flags & MAIL_DRAFT) != 0)
+ str_append(dest, "\\Draft ");
+ if ((flags->flags & MAIL_RECENT) != 0)
+ str_append(dest, "\\Recent ");
+
+ if (flags->keywords_count > 0) {
+ /* we have keywords too */
+ for (i = 0; i < flags->keywords_count; i++) {
+ str_append(dest, flags->keywords[i]);
+ str_append_c(dest, ' ');
+ }
}
- return str_c(str);
+
+ if (str_len(dest) != size)
+ str_truncate(dest, str_len(dest)-1);
}
struct mail_full_flags;
/* Return flags as a space separated string. */
-const char *imap_write_flags(const struct mail_full_flags *flags);
+void imap_write_flags(string_t *dest, const struct mail_full_flags *flags);
#endif
#include <fcntl.h>
#include <sys/stat.h>
+struct index_notify_file {
+ struct index_notify_file *next;
+
+ char *path;
+ time_t last_stamp;
+};
+
+struct index_notify_io {
+ struct index_notify_io *next;
+ struct io *io;
+ int fd;
+};
+
static void check_timeout(void *context)
{
struct index_mailbox *ibox = context;
- struct index_autosync_file *file;
+ struct index_notify_file *file;
struct stat st;
- int sync;
+ time_t last_check;
+ int notify;
/* check changes only when we can also notify of new mail */
- if ((unsigned int) (ioloop_time - ibox->sync_last_check) <
- ibox->min_newmail_notify_interval)
+ last_check = I_MAX(ibox->sync_last_check, ibox->notify_last_check);
+ if ((unsigned int)(ioloop_time - last_check) <
+ ibox->min_notify_interval)
return;
- ibox->sync_last_check = ioloop_time;
+ ibox->notify_last_check = ioloop_time;
- sync = ibox->autosync_pending;
- for (file = ibox->autosync_files; file != NULL; file = file->next) {
+ notify = ibox->notify_pending;
+ for (file = ibox->notify_files; file != NULL; file = file->next) {
if (stat(file->path, &st) == 0 &&
file->last_stamp != st.st_mtime)
file->last_stamp = st.st_mtime;
}
- if (sync) {
- ibox->box.sync(&ibox->box, ibox->autosync_flags);
- ibox->sync_last_notify = ioloop_time;
- ibox->autosync_pending = FALSE;
+ if (notify) {
+ ibox->notify_last_sent = ioloop_time;
+ ibox->notify_pending = FALSE;
+ ibox->notify_callback(&ibox->box, ibox->notify_context);
}
}
{
struct index_mailbox *ibox = context;
- ibox->sync_last_check = ioloop_time;
- if ((unsigned int) (ioloop_time - ibox->sync_last_notify) >=
- ibox->min_newmail_notify_interval) {
- ibox->box.sync(&ibox->box, ibox->autosync_flags);
- ibox->sync_last_notify = ioloop_time;
- ibox->autosync_pending = FALSE;
+ ibox->notify_last_check = ioloop_time;
+ if ((unsigned int)(ioloop_time - ibox->notify_last_sent) >=
+ ibox->min_notify_interval) {
+ ibox->notify_last_sent = ioloop_time;
+ ibox->notify_pending = FALSE;
+ ibox->notify_callback(&ibox->box, ibox->notify_context);
} else {
- ibox->autosync_pending = TRUE;
+ ibox->notify_pending = TRUE;
}
}
void index_mailbox_check_add(struct index_mailbox *ibox,
const char *path, int dir)
{
- struct index_autosync_file *file;
+ struct index_notify_file *file;
struct stat st;
struct io *io;
- struct index_autosync_io *aio;
+ struct index_notify_io *aio;
int fd;
fd = open(path, O_RDONLY);
io = io_add(fd, dir ? IO_DIR_NOTIFY : IO_FILE_NOTIFY,
notify_callback, ibox);
if (io != NULL) {
- aio = i_new(struct index_autosync_io, 1);
+ aio = i_new(struct index_notify_io, 1);
aio->io = io;
aio->fd = fd;
- aio->next = ibox->autosync_ios;
- ibox->autosync_ios = aio;
+ aio->next = ibox->notify_ios;
+ ibox->notify_ios = aio;
}
}
- file = i_new(struct index_autosync_file, 1);
+ file = i_new(struct index_notify_file, 1);
file->path = i_strdup(path);
if (fd < 0)
file->last_stamp = stat(path, &st) < 0 ? 0 : st.st_mtime;
else
file->last_stamp = fstat(fd, &st) < 0 ? 0 : st.st_mtime;
- file->next = ibox->autosync_files;
- ibox->autosync_files = file;
+ file->next = ibox->notify_files;
+ ibox->notify_files = file;
- if (ibox->autosync_to == NULL)
- ibox->autosync_to = timeout_add(1000, check_timeout, ibox);
+ if (ibox->notify_to == NULL)
+ ibox->notify_to = timeout_add(1000, check_timeout, ibox);
}
void index_mailbox_check_remove_all(struct index_mailbox *ibox)
{
- struct index_autosync_file *file;
- struct index_autosync_io *aio;
+ struct index_notify_file *file;
+ struct index_notify_io *aio;
/* reset notify stamp */
- ibox->sync_last_notify = 0;
+ ibox->notify_last_sent = 0;
- while (ibox->autosync_files != NULL) {
- file = ibox->autosync_files;
- ibox->autosync_files = file->next;
+ while (ibox->notify_files != NULL) {
+ file = ibox->notify_files;
+ ibox->notify_files = file->next;
i_free(file->path);
i_free(file);
}
- while (ibox->autosync_ios != NULL) {
- aio = ibox->autosync_ios;
- ibox->autosync_ios = aio->next;
+ while (ibox->notify_ios != NULL) {
+ aio = ibox->notify_ios;
+ ibox->notify_ios = aio->next;
io_remove(aio->io);
if (close(aio->fd) < 0)
- i_error("close(autosync_io) failed: %m");
+ i_error("close(notify_io) failed: %m");
i_free(aio);
}
- if (ibox->autosync_to != NULL) {
- timeout_remove(ibox->autosync_to);
- ibox->autosync_to = NULL;
+ if (ibox->notify_to != NULL) {
+ timeout_remove(ibox->notify_to);
+ ibox->notify_to = NULL;
}
}
#include "lib.h"
#include "index-storage.h"
-#define STATUS_MESSAGE_COUNTS \
- (STATUS_MESSAGES | STATUS_RECENT | STATUS_UIDNEXT | \
- STATUS_UIDVALIDITY | STATUS_UNSEEN | STATUS_FIRST_UNSEEN_SEQ)
-
/*static void
get_keywords(struct mail_keywords *mcf, struct mailbox_status *status)
{
status->keywords[i] = t_strdup(flags[i]);
}*/
-int index_storage_get_status(struct mailbox *box,
- enum mailbox_status_items items,
- struct mailbox_status *status)
+int index_storage_get_status_locked(struct index_mailbox *ibox,
+ enum mailbox_status_items items,
+ struct mailbox_status *status_r)
{
- struct index_mailbox *ibox = (struct index_mailbox *) box;
const struct mail_index_header *hdr;
- memset(status, 0, sizeof(struct mailbox_status));
-
- if ((items & STATUS_MESSAGE_COUNTS) != 0) {
- /* sync mailbox to update message counts */
- if (mailbox_sync(box, 0) < 0)
- return -1;
- }
+ memset(status_r, 0, sizeof(struct mailbox_status));
/* we can get most of the status items without any trouble */
if (mail_index_get_header(ibox->view, &hdr) < 0)
return -1;
- if ((items & STATUS_MESSAGE_COUNTS) != 0) {
- status->messages = hdr->messages_count;
- status->recent = ibox->synced_recent_count;
- status->unseen = hdr->messages_count - hdr->seen_messages_count;
- status->uidvalidity = hdr->uid_validity;
- status->uidnext = hdr->next_uid;
- }
- //FIXME:status->diskspace_full = ibox->nodiskspace;
+
+ status_r->messages = hdr->messages_count;
+ status_r->recent = ibox->synced_recent_count;
+ status_r->unseen =
+ hdr->messages_count - hdr->seen_messages_count;
+ status_r->uidvalidity = hdr->uid_validity;
+ status_r->uidnext = hdr->next_uid;
+ //FIXME:status_r->diskspace_full = ibox->nodiskspace;
if (items & STATUS_FIRST_UNSEEN_SEQ) {
if (mail_index_lookup_first(ibox->view, 0, MAIL_SEEN,
- &status->first_unseen_seq) < 0) {
+ &status_r->first_unseen_seq) < 0) {
mail_storage_set_index_error(ibox);
return -1;
}
}
/*FIXME:if (items & STATUS_KEYWORDS)
- get_keywords(ibox, status);*/
+ get_keywords(ibox, status_r);*/
+ return 0;
+}
+
+int index_storage_get_status(struct mailbox *box,
+ enum mailbox_status_items items,
+ struct mailbox_status *status)
+{
+ struct index_mailbox *ibox = (struct index_mailbox *)box;
+ int ret;
+ ret = index_storage_get_status_locked(ibox, items, status);
mail_index_view_unlock(ibox->view);
- return 0;
+ return ret;
}
MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE
};
-struct index_autosync_file {
- struct index_autosync_file *next;
-
- char *path;
- time_t last_stamp;
-};
-
-struct index_autosync_io {
- struct index_autosync_io *next;
- struct io *io;
- int fd;
-};
-
struct index_storage {
struct mail_storage storage;
void (*mail_deinit)(struct index_mail *mail);
int (*is_recent)(struct index_mailbox *ibox, uint32_t uid);
- struct timeout *autosync_to;
- struct index_autosync_file *autosync_files;
- struct index_autosync_io *autosync_ios;
- enum mailbox_sync_flags autosync_flags;
- time_t sync_last_check, sync_last_notify;
- unsigned int min_newmail_notify_interval;
+ struct timeout *notify_to;
+ struct index_notify_file *notify_files;
+ struct index_notify_io *notify_ios;
+ time_t notify_last_check, notify_last_sent;
+ unsigned int min_notify_interval;
+ mailbox_notify_callback_t *notify_callback;
+ void *notify_context;
time_t next_lock_notify; /* temporary */
enum mailbox_lock_notify_type last_notify_type;
buffer_t *recent_flags;
uint32_t recent_flags_start_seq, recent_flags_count;
- unsigned int synced_recent_count;
+ uint32_t synced_recent_count;
+ time_t sync_last_check;
/* mbox: */
int mbox_fd;
unsigned int recent_flags_synced:1;
unsigned int sent_diskspace_warning:1;
unsigned int sent_readonly_flags_warning:1;
- unsigned int autosync_pending:1;
+ unsigned int notify_pending:1;
unsigned int mail_read_mmaped:1;
unsigned int syncing_commit:1;
};
const char *path, int dir);
void index_mailbox_check_remove_all(struct index_mailbox *ibox);
+struct mailbox_sync_context *
+index_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags,
+ int failed);
+int index_mailbox_sync_next(struct mailbox_sync_context *ctx,
+ struct mailbox_sync_rec *sync_rec_r);
+int index_mailbox_sync_deinit(struct mailbox_sync_context *ctx,
+ struct mailbox_status *status_r);
+
int index_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
void index_storage_set_callbacks(struct mail_storage *storage,
int index_storage_get_status(struct mailbox *box,
enum mailbox_status_items items,
struct mailbox_status *status);
+int index_storage_get_status_locked(struct index_mailbox *ibox,
+ enum mailbox_status_items items,
+ struct mailbox_status *status_r);
struct mail *
index_storage_fetch(struct mailbox_transaction_context *t, uint32_t seq,
#include "buffer.h"
#include "index-storage.h"
+struct index_mailbox_sync_context {
+ struct mailbox_sync_context ctx;
+ struct index_mailbox *ibox;
+ struct mail_index_view_sync_ctx *sync_ctx;
+ uint32_t messages_count;
+
+ const uint32_t *expunges;
+ size_t expunges_count;
+ int failed;
+};
+
void index_mailbox_set_recent(struct index_mailbox *ibox, uint32_t seq)
{
unsigned char *p;
return 0;
}
-int index_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+struct mailbox_sync_context *
+index_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags,
+ int failed)
{
struct index_mailbox *ibox = (struct index_mailbox *)box;
- struct mail_index_view_sync_ctx *ctx;
- struct mail_full_flags full_flags;
- const struct mail_index_record *rec;
- struct mail_index_sync_rec sync;
- struct mail_storage_callbacks *sc;
- const uint32_t *expunges;
- size_t i, expunges_count;
- void *sc_context;
+ struct index_mailbox_sync_context *ctx;
enum mail_index_sync_type sync_mask;
- uint32_t seq, seq1, seq2;
- uint32_t messages_count, last_messages_count;
- int ret;
+
+ ctx = i_new(struct index_mailbox_sync_context, 1);
+ ctx->ctx.box = box;
+ ctx->ibox = ibox;
+
+ if (failed) {
+ ctx->failed = TRUE;
+ return &ctx->ctx;
+ }
+
+ ctx->messages_count = mail_index_view_get_message_count(ibox->view);
sync_mask = MAIL_INDEX_SYNC_MASK_ALL;
if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0)
sync_mask &= ~MAIL_INDEX_SYNC_TYPE_EXPUNGE;
- if (mail_index_view_sync_begin(ibox->view, sync_mask, &ctx) < 0) {
- mail_storage_set_index_error(ibox);
- return -1;
+ if (mail_index_view_sync_begin(ibox->view, sync_mask,
+ &ctx->sync_ctx) < 0) {
+ mail_storage_set_index_error(ibox);
+ ctx->failed = TRUE;
+ return &ctx->ctx;
}
- last_messages_count = mail_index_view_get_message_count(ibox->view);
-
if (!ibox->recent_flags_synced) {
ibox->recent_flags_synced = TRUE;
- index_mailbox_update_recent(ibox, 1, last_messages_count);
+ index_mailbox_update_recent(ibox, 1, ctx->messages_count);
}
- if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0) {
- expunges_count = 0;
- expunges = NULL;
- } else {
- expunges =
- mail_index_view_sync_get_expunges(ctx, &expunges_count);
+ if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) == 0) {
+ ctx->expunges =
+ mail_index_view_sync_get_expunges(ctx->sync_ctx,
+ &ctx->expunges_count);
}
+ return &ctx->ctx;
+}
- sc = ibox->storage->callbacks;
- sc_context = ibox->storage->callback_context;
+int index_mailbox_sync_next(struct mailbox_sync_context *_ctx,
+ struct mailbox_sync_rec *sync_rec_r)
+{
+ struct index_mailbox_sync_context *ctx =
+ (struct index_mailbox_sync_context *)_ctx;
+ struct mail_index_sync_rec sync;
+ int ret;
- memset(&full_flags, 0, sizeof(full_flags));
- while ((ret = mail_index_view_sync_next(ctx, &sync)) > 0) {
+ if (ctx->failed)
+ return -1;
+
+ while ((ret = mail_index_view_sync_next(ctx->sync_ctx, &sync)) > 0) {
switch (sync.type) {
case MAIL_INDEX_SYNC_TYPE_APPEND:
+ /* not interested */
break;
case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
/* later */
break;
case MAIL_INDEX_SYNC_TYPE_FLAGS:
- if (sc->update_flags == NULL)
- break;
-
/* FIXME: hide the flag updates for expunged messages */
-
- if (mail_index_lookup_uid_range(ibox->view,
- sync.uid1, sync.uid2,
- &seq1, &seq2) < 0) {
- ret = -1;
- break;
+ if (mail_index_lookup_uid_range(ctx->ibox->view,
+ sync.uid1, sync.uid2,
+ &sync_rec_r->seq1,
+ &sync_rec_r->seq2) < 0) {
+ ctx->failed = TRUE;
+ return -1;
}
- if (seq1 == 0)
+ if (sync_rec_r->seq1 == 0)
break;
- for (seq = seq1; seq <= seq2; seq++) {
- if (mail_index_lookup(ibox->view,
- seq, &rec) < 0) {
- ret = -1;
- break;
- }
- full_flags.flags = rec->flags; // FIXME
- if (index_mailbox_is_recent(ibox, seq))
- full_flags.flags |= MAIL_RECENT;
- sc->update_flags(&ibox->box, seq,
- &full_flags, sc_context);
- }
- break;
+ sync_rec_r->type = MAILBOX_SYNC_TYPE_FLAGS;
+ return 1;
}
}
- if (ret < 0)
- mail_storage_set_index_error(ibox);
-
- if (sc->expunge != NULL) {
+ if (ret == 0 && ctx->expunges_count > 0) {
/* expunges[] is a sorted array of sequences. it's easiest for
us to print them from end to beginning. */
- messages_count = mail_index_view_get_message_count(ibox->view);
- for (i = expunges_count*2; i > 0; i -= 2) {
- seq = expunges[i-1];
- index_mailbox_expunge_recent(ibox, expunges[i-2], seq);
- if (seq > messages_count)
- seq = messages_count;
- for (; seq >= expunges[i-2]; seq--) {
- sc->expunge(&ibox->box, seq, sc_context);
- last_messages_count--;
- }
- }
- }
+ sync_rec_r->seq1 = ctx->expunges[ctx->expunges_count*2-2];
+ sync_rec_r->seq2 = ctx->expunges[ctx->expunges_count*2-1];
+ index_mailbox_expunge_recent(ctx->ibox, sync_rec_r->seq1,
+ sync_rec_r->seq2);
+
+ if (sync_rec_r->seq2 > ctx->messages_count)
+ sync_rec_r->seq2 = ctx->messages_count;
- mail_index_view_sync_end(ctx);
+ ctx->messages_count -= sync_rec_r->seq2 - sync_rec_r->seq1 + 1;
+ ctx->expunges_count--;
- messages_count = mail_index_view_get_message_count(ibox->view);
- if (messages_count != last_messages_count) {
- index_mailbox_update_recent(ibox, last_messages_count+1,
- messages_count);
- sc->message_count_changed(&ibox->box, messages_count,
- sc_context);
+ sync_rec_r->type = MAILBOX_SYNC_TYPE_EXPUNGE;
+ return 1;
}
- if (ibox->recent_flags_count != ibox->synced_recent_count) {
- ibox->synced_recent_count = ibox->recent_flags_count;
- sc->recent_count_changed(&ibox->box, ibox->synced_recent_count,
- sc_context);
+ if (ret < 0)
+ mail_storage_set_index_error(ctx->ibox);
+ return ret;
+}
+
+#define SYNC_STATUS_FLAGS \
+ (STATUS_MESSAGES | STATUS_RECENT | STATUS_UIDNEXT | \
+ STATUS_UIDVALIDITY | STATUS_UNSEEN | STATUS_KEYWORDS)
+
+int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx,
+ struct mailbox_status *status_r)
+{
+ struct index_mailbox_sync_context *ctx =
+ (struct index_mailbox_sync_context *)_ctx;
+ struct index_mailbox *ibox = ctx->ibox;
+ uint32_t messages_count;
+ int ret = ctx->failed ? -1 : 0;
+
+ if (ctx->sync_ctx != NULL)
+ mail_index_view_sync_end(ctx->sync_ctx);
+
+ if (ret == 0) {
+ messages_count = mail_index_view_get_message_count(ibox->view);
+ if (messages_count != ctx->messages_count) {
+ index_mailbox_update_recent(ibox,
+ ctx->messages_count+1,
+ messages_count);
+ }
+
+ if (ibox->recent_flags_count != ibox->synced_recent_count)
+ ibox->synced_recent_count = ibox->recent_flags_count;
+
+ ret = index_storage_get_status_locked(ctx->ibox,
+ SYNC_STATUS_FLAGS,
+ status_r);
}
- mail_index_view_unlock(ibox->view);
+ mail_index_view_unlock(ctx->ibox->view);
+ i_free(ctx);
return ret;
}
return ret;
}
-static void maildir_storage_auto_sync(struct mailbox *box,
- enum mailbox_sync_flags flags,
- unsigned int min_newmail_notify_interval)
+static void
+maildir_notify_changes(struct mailbox *box, unsigned int min_interval,
+ mailbox_notify_callback_t *callback, void *context)
{
struct index_mailbox *ibox = (struct index_mailbox *)box;
- ibox->min_newmail_notify_interval = min_newmail_notify_interval;
+ ibox->min_notify_interval = min_interval;
+ ibox->notify_callback = callback;
+ ibox->notify_context = context;
- if ((ibox->autosync_flags == 0 && flags == 0) ||
- (ibox->autosync_flags != 0 && flags != 0)) {
- /* flags or interval just changed. or nothing. */
- ibox->autosync_flags = flags;
- }
- ibox->autosync_flags = flags;
-
- if (flags == 0) {
+ if (callback == NULL) {
index_mailbox_check_remove_all(ibox);
return;
}
index_storage_allow_new_keywords,
maildir_storage_close,
index_storage_get_status,
- maildir_storage_sync,
- maildir_storage_auto_sync,
+ maildir_storage_sync_init,
+ index_mailbox_sync_next,
+ index_mailbox_sync_deinit,
+ maildir_notify_changes,
maildir_transaction_begin,
maildir_transaction_commit,
maildir_transaction_rollback,
struct mailbox_list *
maildir_mailbox_list_next(struct mailbox_list_context *ctx);
-int maildir_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
+struct mailbox_sync_context *
+maildir_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);
int maildir_storage_sync_force(struct index_mailbox *ibox);
struct mailbox_transaction_context *
return ret;
}
-int maildir_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+struct mailbox_sync_context *
+maildir_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct index_mailbox *ibox = (struct index_mailbox *)box;
struct maildir_sync_context *ctx;
- int ret;
+ int ret = 0;
if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
ibox->sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <= ioloop_time) {
ctx = maildir_sync_context_new(ibox);
ret = maildir_sync_context(ctx, FALSE);
maildir_sync_deinit(ctx);
-
- if (ret < 0)
- return -1;
}
- return index_storage_sync(box, flags);
+ return index_mailbox_sync_init(box, flags, ret < 0);
}
return 0;
}
-static void mbox_storage_auto_sync(struct mailbox *box,
- enum mailbox_sync_flags flags,
- unsigned int min_newmail_notify_interval)
+static void
+mbox_notify_changes(struct mailbox *box, unsigned int min_interval,
+ mailbox_notify_callback_t *callback, void *context)
{
struct index_mailbox *ibox = (struct index_mailbox *)box;
- ibox->min_newmail_notify_interval = min_newmail_notify_interval;
+ ibox->min_notify_interval = min_interval;
+ ibox->notify_callback = callback;
+ ibox->notify_context = context;
- if ((ibox->autosync_flags == 0 && flags == 0) ||
- (ibox->autosync_flags != 0 && flags != 0)) {
- /* flags or interval just changed. or nothing. */
- ibox->autosync_flags = flags;
- }
- ibox->autosync_flags = flags;
-
- if (flags == 0)
+ if (callback == NULL)
index_mailbox_check_remove_all(ibox);
else
index_mailbox_check_add(ibox, ibox->path, FALSE);
index_storage_allow_new_keywords,
mbox_storage_close,
index_storage_get_status,
- mbox_storage_sync,
- mbox_storage_auto_sync,
+ mbox_storage_sync_init,
+ index_mailbox_sync_next,
+ index_mailbox_sync_deinit,
+ mbox_notify_changes,
mbox_transaction_begin,
mbox_transaction_commit,
mbox_transaction_rollback,
int mbox_transaction_commit(struct mailbox_transaction_context *t);
void mbox_transaction_rollback(struct mailbox_transaction_context *t);
-int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
+struct mailbox_sync_context *
+mbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);
int mbox_save(struct mailbox_transaction_context *t,
const struct mail_full_flags *flags,
return ret;
}
-int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+struct mailbox_sync_context *
+mbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct index_mailbox *ibox = (struct index_mailbox *)box;
+ int ret = 0;
if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
ibox->sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <= ioloop_time) {
ibox->sync_last_check = ioloop_time;
- if (mbox_sync(ibox, FALSE, FALSE, FALSE) < 0)
- return -1;
+ ret = mbox_sync(ibox, FALSE, FALSE, FALSE);
}
- return index_storage_sync(box, flags);
+ return index_mailbox_sync_init(box, flags, ret < 0);
}
int (*get_status)(struct mailbox *box, enum mailbox_status_items items,
struct mailbox_status *status);
- int (*sync)(struct mailbox *box, enum mailbox_sync_flags flags);
- void (*auto_sync)(struct mailbox *box, enum mailbox_sync_flags flags,
- unsigned int min_newmail_notify_interval);
+ struct mailbox_sync_context *
+ (*sync_init)(struct mailbox *box,
+ enum mailbox_sync_flags flags);
+ int (*sync_next)(struct mailbox_sync_context *ctx,
+ struct mailbox_sync_rec *sync_rec_r);
+ int (*sync_deinit)(struct mailbox_sync_context *ctx,
+ struct mailbox_status *status_r);
+
+ void (*notify_changes)(struct mailbox *box, unsigned int min_interval,
+ mailbox_notify_callback_t *callback,
+ void *context);
struct mailbox_transaction_context *
(*transaction_begin)(struct mailbox *box, int hide);
struct mailbox *box;
};
+struct mailbox_sync_context {
+ struct mailbox *box;
+};
+
/* Set error message in storage. Critical errors are logged with i_error(),
but user sees only "internal error" message. */
void mail_storage_clear_error(struct mail_storage *storage);
return box->get_status(box, items, status);
}
-int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+struct mailbox_sync_context *
+mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
- return box->sync(box, flags);
+ return box->sync_init(box, flags);
}
-void mailbox_auto_sync(struct mailbox *box, enum mailbox_sync_flags flags,
- unsigned int min_newmail_notify_interval)
+int mailbox_sync_next(struct mailbox_sync_context *ctx,
+ struct mailbox_sync_rec *sync_rec_r)
{
- box->auto_sync(box, flags, min_newmail_notify_interval);
+ return ctx->box->sync_next(ctx, sync_rec_r);
+}
+
+int mailbox_sync_deinit(struct mailbox_sync_context *ctx,
+ struct mailbox_status *status_r)
+{
+ return ctx->box->sync_deinit(ctx, status_r);
+}
+
+void mailbox_notify_changes(struct mailbox *box, unsigned int min_interval,
+ mailbox_notify_callback_t *callback, void *context)
+{
+ box->notify_changes(box, min_interval, callback, context);
}
struct mail *mailbox_fetch(struct mailbox_transaction_context *t, uint32_t seq,
MAILBOX_SYNC_AUTO_STOP = 0x04
};
+enum mailbox_sync_type {
+ MAILBOX_SYNC_TYPE_EXPUNGE = 0x01,
+ MAILBOX_SYNC_TYPE_FLAGS = 0x02
+};
+
struct mail_storage;
struct mail_storage_callbacks;
struct mailbox_list;
const char **keywords;
};
+struct mailbox_sync_rec {
+ uint32_t seq1, seq2;
+ enum mailbox_sync_type type;
+};
+
struct mail_storage_callbacks {
/* Alert: Not enough disk space */
void (*alert_no_diskspace)(struct mailbox *mailbox, void *context);
void (*notify_no)(struct mailbox *mailbox, const char *text,
void *context);
- /* EXPUNGE */
- void (*expunge)(struct mailbox *mailbox, unsigned int seq,
- void *context);
- /* FETCH FLAGS */
- void (*update_flags)(struct mailbox *mailbox, unsigned int seq,
- const struct mail_full_flags *flags,
- void *context);
-
- /* EXISTS */
- void (*message_count_changed)(struct mailbox *mailbox,
- unsigned int count, void *context);
- /* RECENT */
- void (*recent_count_changed)(struct mailbox *mailbox,
- unsigned int count, void *context);
- /* FLAGS, PERMANENTFLAGS */
- void (*new_keywords)(struct mailbox *mailbox,
- const char *keywords[],
- unsigned int keywords_count, void *context);
-
};
+typedef void mailbox_notify_callback_t(struct mailbox *box, void *context);
+
extern int full_filesystem_access;
void mail_storage_init(void);
struct mailbox_status *status);
/* Synchronize the mailbox. */
-int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags);
-
-/* Synchronize mailbox in background. It's done until this function is
- called with flags = MAILBOX_SYNC_AUTO_STOP. */
-void mailbox_auto_sync(struct mailbox *box, enum mailbox_sync_flags flags,
- unsigned int min_newmail_notify_interval);
+struct mailbox_sync_context *
+mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);
+int mailbox_sync_next(struct mailbox_sync_context *ctx,
+ struct mailbox_sync_rec *sync_rec_r);
+int mailbox_sync_deinit(struct mailbox_sync_context *ctx,
+ struct mailbox_status *status_r);
+
+/* Call given callback function when something changes in the mailbox.
+ It's done until this function is called with callback = NULL. */
+void mailbox_notify_changes(struct mailbox *box, unsigned int min_interval,
+ mailbox_notify_callback_t *callback, void *context);
struct mailbox_transaction_context *
mailbox_transaction_begin(struct mailbox *box, int hide);
return p->box->get_status(p->box, items, status);
}
-static int _sync(struct mailbox *box, enum mailbox_sync_flags flags)
+static struct mailbox_sync_context *
+_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct proxy_mailbox *p = (struct proxy_mailbox *) box;
- return p->box->sync(p->box, flags);
+ return p->box->sync_init(p->box, flags);
}
-static void _auto_sync(struct mailbox *box, enum mailbox_sync_flags flags,
- unsigned int min_newmail_notify_interval)
+static void _notify_changes(struct mailbox *box, unsigned int min_interval,
+ mailbox_notify_callback_t *callback, void *context)
{
struct proxy_mailbox *p = (struct proxy_mailbox *) box;
- p->box->auto_sync(p->box, flags, min_newmail_notify_interval);
+ return p->box->notify_changes(box, min_interval, callback, context);
}
static struct mail *_fetch(struct mailbox_transaction_context *t, uint32_t seq,
pb->allow_new_keywords = _allow_new_keywords;
pb->close = _close;
pb->get_status = _get_status;
- pb->sync = _sync;
- pb->auto_sync = _auto_sync;
+ pb->sync_init = _sync_init;
+ pb->sync_next = box->sync_next;
+ pb->sync_deinit = box->sync_deinit;
+ pb->notify_changes = _notify_changes;
pb->fetch = _fetch;
pb->get_uids = _get_uids;
o_stream_close(client->output);
}
+static int sync_mailbox(struct mailbox *box)
+{
+ struct mailbox_sync_context *ctx;
+ struct mailbox_sync_rec sync_rec;
+ struct mailbox_status status;
+
+ ctx = mailbox_sync_init(box, 0);
+ while (mailbox_sync_next(ctx, &sync_rec) > 0)
+ ;
+ return mailbox_sync_deinit(ctx, &status);
+}
+
static int init_mailbox(struct client *client)
{
struct mail_search_arg search_arg;
search_arg.type = SEARCH_ALL;
for (i = 0; i < 2; i++) {
+ if (sync_mailbox(client->mailbox) < 0) {
+ client_send_storage_error(client);
+ return FALSE;
+ }
if (mailbox_get_status(client->mailbox, STATUS_MESSAGES,
&status) < 0) {
client_send_storage_error(client);
/* well, sync and try again */
mailbox_transaction_rollback(t);
- if (mailbox_sync(client->mailbox, 0) < 0) {
- client_send_storage_error(client);
- return FALSE;
- }
}
client_send_line(client, "-ERR [IN-USE] Couldn't sync mailbox.");
{
}
-static void expunge(struct mailbox *mailbox __attr_unused__,
- unsigned int seq, void *context)
-{
- struct client *client = context;
- unsigned char *mask = client->deleted_bitmask;
- unsigned int max, i, j;
-
- /* external deletes - we have to fix our internal deleted array.
- this should happen only when we're doing the expunging at quit. */
- seq--;
- client->messages_count--;
-
- if (!client->deleted)
- return;
-
- max = client->messages_count / CHAR_BIT;
- i = seq / CHAR_BIT; j = seq % CHAR_BIT;
- mask[i] = (mask[i] & ((1 << j) - 1)) |
- ((mask[i] >> (j+1)) << j) |
- (i == max ? 0 : ((mask[i+1] & 1) << (CHAR_BIT-1)));
-
- if (i != max) {
- for (i++; i < max-1; i++) {
- mask[i] = (mask[i] >> 1) |
- ((mask[i+1] & 1) << (CHAR_BIT-1));
- }
-
- mask[i] >>= 1;
- }
-}
-
-static void update_flags(struct mailbox *mailbox __attr_unused__,
- unsigned int seq __attr_unused__,
- const struct mail_full_flags *flags __attr_unused__,
- void *context __attr_unused__)
-{
-}
-
-static void message_count_changed(struct mailbox *mailbox __attr_unused__,
- unsigned int count __attr_unused__,
- void *context __attr_unused__)
-{
-}
-
-static void recent_count_changed(struct mailbox *mailbox __attr_unused__,
- unsigned int count __attr_unused__,
- void *context __attr_unused__)
-{
-}
-
-
-static void new_keywords(struct mailbox *mailbox __attr_unused__,
- const char *keywords[] __attr_unused__,
- unsigned int keywords_count __attr_unused__,
- void *context __attr_unused__)
-{
-}
-
struct mail_storage_callbacks mail_storage_callbacks = {
alert_no_diskspace,
notify_ok,
- notify_no,
- expunge,
- update_flags,
- message_count_changed,
- recent_count_changed,
- new_keywords
+ notify_no
};