mailbox-list-index-notify.c revision 3aff91a1941ea35265f1e80e70853693e8ec8e0b
/* 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;
};
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) {
}
&index_dir) > 0) {
/* FIXME: annoyingly hardcoded filename. */
}
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;
}
{
}
}
}
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
{
const enum mailbox_status_items status_items =
struct mailbox_list_notify_rec *rec;
struct mailbox_status status;
i_unreached();
/* get the old status */
rec->storage_name);
/* mailbox didn't exist earlier - report all events as new */
i_zero(&empty_node);
nnode = &empty_node;
}
/* 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. */
}
/* 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;
}
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) {
/* Don't bother trying to figure out which event exactly this
is. Just send them all and let the caller handle it. */
return 1;
}
}
{
}
{
if (inotify->inbox_event_pending ||
/* log has changed. call the callback with a small delay
to allow bundling multiple changes together */
/* already doing this */
return;
}
}
}
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;
}