mailbox-list-index-notify.c revision 2912eac52610bf9463e48f320a966d0b0c51bed0
/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "str.h"
#include "mail-index-private.h"
#include "mail-transaction-log-private.h"
#include "mail-storage-private.h"
#include "mailbox-list-notify.h"
#include "mailbox-list-notify-tree.h"
#include "mailbox-list-index.h"
#define NOTIFY_DELAY_MSECS 500
enum ilist_ext_type {
};
struct mailbox_list_notify_rename {
};
struct mailbox_list_inotify_entry {
bool expunge;
};
struct mailbox_list_notify_index {
struct mailbox_list_notify notify;
struct mailbox_tree_context *subscriptions;
struct mailbox_list_notify_tree *tree;
struct mail_index_view_sync_ctx *sync_ctx;
enum ilist_ext_type cur_ext;
void (*wait_callback)(void *context);
void *wait_context;
struct seq_range_iter changed_uids_iter;
struct mailbox_list_notify_rec notify_rec;
char *list_log_path, *inbox_log_path;
bool initialized:1;
bool read_failed:1;
bool inbox_event_pending:1;
};
static const enum mailbox_status_items notify_status_items =
static enum mailbox_list_notify_event
const struct mailbox_status *status)
{
enum mailbox_list_notify_event events = 0;
/* NOTE: not entirely reliable, since there could be both
expunges and appends.. but it shouldn't make any difference
in practise, since anybody interested in expunges is most
likely also interested in appends. */
}
return events;
}
static void
struct mailbox_status *status)
{
}
static void
{
}
struct mailbox_list_notify **notify_r)
{
struct mailbox_list_notify_index *inotify;
const char *index_dir;
/* can't do this without mailbox list indexes */
return -1;
}
(void)mailbox_list_index_refresh(list);
if ((mask & (MAILBOX_LIST_NOTIFY_SUBSCRIBE |
MAILBOX_LIST_NOTIFY_UNSUBSCRIBE)) != 0) {
}
/* INBOX can be handled also using mailbox list index */
/* no INBOX in this namespace */
} else if ((mask & MAILBOX_LIST_NOTIFY_STATUS) == 0) {
/* not interested in mailbox changes */
&index_dir) <= 0) {
/* no indexes for INBOX? can't handle it */
} else {
}
return 1;
}
{
struct mailbox_list_notify_index *inotify =
(struct mailbox_list_notify_index *)notify;
bool b;
}
static struct mailbox_list_index_node *
struct mail_index_view *view,
{
struct mailbox_list_index *ilist =
struct mailbox_list_index_node *index_node;
return NULL;
if (index_node == NULL) {
/* re-parse the index list using the given view. we could be
jumping here between old and new view. */
if (index_node == NULL)
return NULL;
}
/* get GUID */
return index_node;
}
bool stat_list, bool stat_inbox)
{
if (stat_list &&
}
}
}
if (call)
}
static void
{
struct mail_index_view_sync_rec sync_rec;
/* sync the view so that map extensions gets updated */
}
{
case ILIST_EXT_NONE:
i_unreached();
case ILIST_EXT_BASE:
/* UIDVALIDITY changed */
return FALSE;
break;
case ILIST_EXT_MSGS:
/* APPEND, EXPUNGE, \Seen or \Recent flag change */
return FALSE;
break;
case ILIST_EXT_HIGHESTMODSEQ:
/* when this doesn't come with EXT_MSGS update,
it can only be a flag change or an explicit
modseq change */
return FALSE;
break;
case ILIST_EXT_UNKNOWN:
return FALSE;
}
return TRUE;
}
static int
{
const struct mail_transaction_header *hdr;
const void *data;
int ret;
if (ret <= 0)
return ret;
/* all mailbox index updates are external */
return 1;
}
case MAIL_TRANSACTION_APPEND: {
/* mailbox added or renamed */
MAILBOX_LIST_NOTIFY_RENAME)) == 0)
break;
break;
}
case MAIL_TRANSACTION_EXPUNGE_GUID: {
/* mailbox deleted or renamed */
MAILBOX_LIST_NOTIFY_RENAME)) == 0)
break;
break;
}
case MAIL_TRANSACTION_EXT_INTRO: {
const char *name;
break;
/* we want to know what extension the future
ext-rec-updates are changing. we're assuming here that
there is only one ext-intro record before those,
which is true at least for now. */
/* get extension by id */
/* by name */
}
else
}
break;
}
case MAIL_TRANSACTION_EXT_REC_UPDATE: {
const struct mail_index_registered_ext *ext;
const struct mail_transaction_ext_rec_update *rec;
unsigned int i, record_size;
i_error("%s: Missing ext-intro for ext-rec-update",
break;
}
/* the record is padded to 32bits in the transaction log */
break;
break;
}
break;
}
}
return 1;
}
static int
const struct mailbox_list_inotify_entry *r2)
{
int ret;
if (ret != 0)
return ret;
/* this really shouldn't happen */
return 0;
}
}
static void
{
struct mailbox_status status;
struct mailbox_list_notify_rename *rename;
struct mailbox_list_inotify_entry *entry;
const struct mailbox_list_inotify_entry *e;
unsigned int i, count;
/* first get all of the added and expunged GUIDs */
!guid_128_is_empty(guid)) {
}
}
!guid_128_is_empty(guid)) {
}
}
/* now sort the entries by GUID and find those that have been both
added and expunged */
for (i = 1; i < count; i++) {
}
}
}
static void
{
int ret;
return;
for (;;) {
}
}
break;
ret = 1;
ret = -1;
else {
}
if (ret == 0) {
} else if (ret > 0) {
} else {
}
}
}
static void
{
&inotify->expunged_uids);
&inotify->changed_uids);
inotify->changed_uids_n = 0;
inotify->new_uids_n = 0;
inotify->expunged_uids_n = 0;
inotify->rename_idx = 0;
inotify->subscription_idx = 0;
inotify->unsubscription_idx = 0;
}
static void
{
bool b;
int ret;
/* read all changes from .log file */
/* remove changes for already deleted mailboxes */
&inotify->expunged_uids);
&inotify->expunged_uids);
}
}
static void
{
/* save the old view so we can look up expunged records */
}
static bool
struct mail_index_view *view,
struct mailbox_status *status_r,
struct mailbox_list_notify_rec **rec_r)
{
struct mailbox_list_index_node *index_node;
const char *storage_name;
if (index_node == NULL)
return FALSE;
/* get storage_name */
rec->storage_name);
return TRUE;
}
static bool
unsigned int idx)
{
const struct mailbox_list_notify_rename *rename;
struct mailbox_list_notify_rec *rec;
struct mailbox_status status;
const char *old_vname;
/* lookup the old name */
return FALSE;
/* return using the new name */
return FALSE;
return TRUE;
}
static bool
unsigned int idx)
{
const char *const *vnamep;
return TRUE;
}
static bool
unsigned int idx)
{
const char *const *vnamep;
return TRUE;
}
static bool
{
struct mailbox_list_notify_rec *rec;
struct mailbox_status status;
return FALSE;
return TRUE;
}
static bool
{
struct mailbox_list_notify_rec *rec;
struct mailbox_status status;
i_unreached();
return TRUE;
}
static bool
{
struct mailbox_list_notify_rec *rec;
struct mailbox_status status;
/* Mailbox is already deleted. We won't get here if we're
tracking MAILBOX_LIST_NOTIFY_DELETE or _RENAME
(which update expunged_uids). */
return FALSE;
}
/* get the old status */
rec->storage_name);
/* mailbox didn't exist earlier - report all events as new */
i_zero(&empty_node);
nnode = &empty_node;
}
/* update internal state */
}
static bool
{
/* first show mailbox deletes */
/* mailbox renames */
inotify->rename_idx++);
}
/* next mailbox creates */
/* subscribes */
inotify->subscription_idx++);
}
}
/* STATUS updates */
return TRUE;
}
return FALSE;
}
static enum mailbox_list_notify_event
{
struct mailbox_notify_node old_nnode;
i_error("Mailbox list index notify: Failed to sync INBOX: %s",
return 0;
}
}
const struct mailbox_list_notify_rec **rec_r)
{
struct mailbox_list_notify_index *inotify =
(struct mailbox_list_notify_index *)notify;
if (!inotify->initialized)
return -1;
while (mailbox_list_index_notify_try_next(inotify)) {
return 1;
} else {
/* caller doesn't care about this change */
}
}
if (inotify->inbox_event_pending) {
return 1;
}
}
{
}
{
/* there's a pending notification already -
no need to stat() again */
return;
}
/* log has changed. call the callback with a small delay
to allow bundling multiple changes together */
}
}
{
/* there's a pending INBOX notification already -
no need to stat() again */
return;
}
/* log has changed. call the callback with a small delay
to allow bundling multiple changes together */
}
}
{
}
void *context)
{
struct mailbox_list_notify_index *inotify =
(struct mailbox_list_notify_index *)notify;
unsigned int check_interval;
/* we need to check for INBOX explicitly, because INBOX changes
don't get added to mailbox.list.index.log */
&inotify->io_wait_inbox);
}
/* check with timeout as well, in case io_add_notify()
doesn't work (e.g. NFS) */
i_assert(check_interval > 0);
}
}
{
struct mailbox_list_notify_index *inotify =
(struct mailbox_list_notify_index *)notify;
/* no pending notification - check if anything had changed */
}
}