imap-state.c revision 7bc3126bb62589fe373f40aa40132e671e4a363d
/* Copyright (c) 2014-2016 Dovecot authors, see the included COPYING file */
#include "imap-common.h"
#include "crc32.h"
#include "numpack.h"
#include "net.h"
#include "ostream.h"
#include "str.h"
#include "str-sanitize.h"
#include "imap-util.h"
#include "mail-search-build.h"
#include "mail-storage.h"
#include "mailbox-recent-flags.h"
#include "imap-client.h"
#include "imap-fetch.h"
#include "imap-search-args.h"
#include "imap-state.h"
enum imap_state_type_public {
IMAP_STATE_TYPE_MAILBOX = 'B',
IMAP_STATE_TYPE_SEARCHRES = '1',
};
enum imap_state_type_internal {
IMAP_STATE_TYPE_ID_LOGGED = 'I',
};
enum imap_state_feature {
IMAP_STATE_FEATURE_CONDSTORE = 'C',
};
struct mailbox_import_state {
const char *vname;
bool examined;
};
static void
{
unsigned int i, count;
next_uid = 1;
for (i = 0; i < count; i++) {
} else {
}
}
}
static int
{
return -1;
next_uid = 1;
for (i = 0; i < count; i++) {
return -1;
if ((num & 1) == 0) {
} else {
return -1;
}
}
return 0;
}
const char **error_r)
{
/* the only IMAP command we allow running is IDLE or X-STATE */
*error_r = "Multiple commands in progress";
return 0;
}
/* this would require saving the seq <-> uid mapping
and restore it on import. quite a lot of trouble if
messages have been expunged in the mean time. */
*error_r = "Non-IDLE connections not supported currently";
return 0;
}
}
const char **error_r)
{
*error_r = "Multiple commands in progress";
return 0;
}
}
static int
{
while (size > 0) {
if (ret <= 0) {
return ret < 0 ? -1 : 0;
}
}
return 1;
}
const char **error_r)
{
}
const char **error_r)
{
}
static int
const char **error_r)
{
struct mailbox_transaction_context *trans;
struct mail_search_args *search_args;
struct mail_search_context *search_ctx;
int ret = 1;
}
if (mailbox_search_deinit(&search_ctx) < 0) {
ret = -1;
}
(void)mailbox_transaction_commit(&trans);
return ret;
}
static uint32_t
{
const char *const *strp;
return crc;
}
static int
{
struct mailbox_status status;
struct mailbox_metadata metadata;
enum mail_error mail_error;
&status);
if (status.nonpermanent_modseqs) {
*error_r = "Nonpermanent modseqs";
return 0;
}
/* if the selected mailbox can't have a GUID, fail silently */
}
else
/* keywords count + CRC32 should be enough to figure out if it
needs to be resent */
/* we're now basically done, but just in case there's a bug add a
checksum of the currently existing UIDs and verify it when
importing. this also writes the list of recent UIDs. */
}
{
int ret;
/* these could be tricky */
*error_r = "CONTEXT=SEARCH updates not supported currently";
return 0;
}
/* FIXME: this really should be supported. also IDLE wouldn't
be needed if NOTIFY allows sending EXPUNGEs to selected
mailbox. */
*error_r = "NOTIFY not supported currently";
return 0;
}
if (ret <= 0)
return ret;
}
/* IMAP features */
if (client->enabled_features != 0) {
MAILBOX_FEATURE_QRESYNC)) == 0);
}
if (internal) {
if (client->tls_compression)
}
/* IMAP SEARCHRES extension */
}
return 1;
}
static int
const char **str_r)
{
const unsigned char *p;
if (p == NULL)
return -1;
*data = p + 1;
return 0;
}
static int
const struct mailbox_import_state *state,
unsigned int *expunge_count_r,
const char **error_r)
{
struct mailbox_transaction_context *trans;
struct mail_search_args *search_args;
struct mail_search_context *search_ctx;
struct seq_range_iter iter;
unsigned int i, expunge_count, n = 0;
int ret = 0;
*expunge_count_r = 0;
/* the mailbox was empty originally - there couldn't be any
pending expunges. */
return 0;
}
*error_r = "Invalid UIDNEXT";
return -1;
}
/* get all the message UIDs expunged since the last known modseq */
&uids_filter, &expunged_uids)) {
"Couldn't get recently expunged UIDs "
(unsigned long long)state->highest_modseq);
return -1;
}
/* find sequence numbers for the expunged UIDs */
seq++; n++;
sizeof(expunged_uid));
}
break;
break;
}
seq++; n++;
sizeof(expunged_uid));
}
if (mailbox_search_deinit(&search_ctx) < 0) {
ret = -1;
*error_r = "Message count mismatch after handling expunges";
ret = -1;
}
(void)mailbox_transaction_commit(&trans);
if (ret < 0)
return -1;
*error_r = "Message count too low after handling expunges";
return -1;
}
*error_r = "Message UIDs CRC32 mismatch";
return -1;
}
for (i = expunge_count; i > 0; i--) {
str_truncate(str, 0);
}
} else {
}
return 0;
}
static int
const struct mailbox_import_state *state)
{
struct imap_fetch_context *fetch_ctx;
struct mail_search_args *search_args;
int ret;
return 0;
pool_unref(&pool);
}
/* FIXME: ideally do this asynchronously.. */
while (imap_fetch_more_no_lock_update(fetch_ctx) == 0) ;
return ret;
}
static ssize_t
struct mailbox_import_state *state_r,
const char **error_r)
{
/* vname */
*error_r = "Mailbox state truncated at name";
return 0;
}
/* GUID */
*error_r = "Mailbox state truncated at GUID";
return 0;
}
p += sizeof(state_r->mailbox_guid);
*error_r = "Empty GUID";
return 0;
}
/* EXAMINEd vs SELECTed */
if (p == end) {
*error_r = "Mailbox state truncated at examined-flag";
return 0;
}
p++;
/* mailbox state */
*error_r = "Mailbox state truncated";
return 0;
}
if (state_r->uidvalidity == 0) {
*error_r = "Empty UIDVALIDITY";
return 0;
}
*error_r = "Empty UIDNEXT";
return 0;
}
return p - data;
}
static int
const struct mailbox_import_state *state,
const char **error_r)
{
struct mail_namespace *ns;
struct mailbox_metadata metadata;
struct mailbox_status status;
enum mailbox_flags flags = 0;
unsigned int expunge_count;
int ret = 0;
*error_r = "Namespace not found for mailbox";
return -1;
}
else
if (mailbox_open(box) < 0) {
mailbox_free(&box);
return -1;
}
if (client->enabled_features != 0)
mailbox_free(&box);
return -1;
}
/* verify that this still looks like the same mailbox */
mailbox_free(&box);
return -1;
}
*error_r = "Mailbox GUID has changed";
mailbox_free(&box);
return -1;
}
*error_r = "Mailbox UIDVALIDITY has changed";
mailbox_free(&box);
return -1;
}
*error_r = "Mailbox UIDNEXT shrank";
mailbox_free(&box);
return -1;
}
*error_r = "Mailbox HIGHESTMODSEQ shrank";
mailbox_free(&box);
return -1;
}
return -1;
*error_r = "Mailbox message count shrank";
return -1;
}
/* new messages arrived */
}
}
/* no changes to keywords */
} else {
}
*error_r = "Couldn't send flag changes";
return -1;
}
"* OK [HIGHESTMODSEQ %llu] Highest",
(unsigned long long)status.highest_modseq));
}
return 0;
}
static ssize_t
{
struct mailbox_import_state state;
*error_r = "Duplicate mailbox state";
return 0;
}
if (ret <= 0) {
return ret;
}
return -1;
return ret;
}
static ssize_t
{
enum imap_state_feature feature;
size_t i = 0;
for (i = 0; i < size; i++) {
if (data[i] == '\0')
return i+1;
switch (feature) {
break;
break;
default:
"Unknown feature '%c'", feature);
return 0;
}
}
*error_r = "Non-terminated features list";
return 0;
}
static ssize_t
{
const unsigned char *p = data;
*error_r = "Invalid SEARCHRES seq-range";
return 0;
}
return p - data;
}
static ssize_t
const unsigned char *data ATTR_UNUSED,
const char **error_r ATTR_UNUSED)
{
return 0;
}
static ssize_t
const unsigned char *data ATTR_UNUSED,
const char **error_r ATTR_UNUSED)
{
return 0;
}
{
if (client->state_import_idle_continue) {
/* IDLE command continues */
struct client_command_context *cmd;
if (command_exec(cmd)) {
/* IDLE terminated because of an external change, but
DONE was already buffered */
} else {
}
} else {
/* we're finishing IDLE command */
"%s %s Idle completed.", tag,
}
}
static struct {
enum imap_state_type_public type;
} imap_states_public[] = {
};
static struct {
enum imap_state_type_internal type;
} imap_states_internal[] = {
};
static ssize_t
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(imap_states_public); i++) {
ret = imap_states_public[i].
}
}
return -2;
}
static ssize_t
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(imap_states_internal); i++) {
ret = imap_states_internal[i].
}
}
return -2;
}
const char **error_r)
{
const unsigned char *p;
if (p == NULL)
return 0;
}
pos = 5;
}
if (ret == -2) {
}
return ret < 0 ? -1 : 0;
}
}
return pos;
}