lazy-expunge-plugin.c revision e5bc823952a118eeeab4e9f4e98f7f4ee72fc323
/* Copyright (c) 2006-2016 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "str.h"
#include "hash.h"
#include "seq-range-array.h"
#include "mkdir-parents.h"
#include "mail-storage-private.h"
#include "mail-search-build.h"
#include "mailbox-list-private.h"
#include "mail-namespace.h"
#include "lazy-expunge-plugin.h"
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#define LAZY_EXPUNGE_CONTEXT(obj) \
#define LAZY_EXPUNGE_LIST_CONTEXT(obj) \
#define LAZY_EXPUNGE_USER_CONTEXT(obj) \
#define LAZY_EXPUNGE_MAIL_CONTEXT(obj) \
struct lazy_expunge_mail_user {
struct mail_namespace *lazy_ns;
const char *lazy_mailbox_vname;
const char *env;
bool copy_only_last_instance;
};
struct lazy_expunge_mailbox_list {
unsigned int allow_rename:1;
unsigned int internal_namespace:1;
};
struct lazy_expunge_transaction {
struct mailbox_transaction_context *dest_trans;
HASH_TABLE(const char *, void *) guids;
bool failed;
bool copy_only_last_instance;
};
const char *lazy_expunge_plugin_version = DOVECOT_ABI_VERSION;
static const char *
{
struct lazy_expunge_mail_user *luser =
const char *name;
return luser->lazy_mailbox_vname;
/* use the (canonical / unaliased) storage name */
/* replace hierarchy separators with destination virtual separator */
unsigned int i;
for (i = 0; name[i] != '\0'; i++) {
else
}
}
/* add expunge namespace prefix. the name is now a proper vname */
}
static struct mailbox *
const char **error_r)
{
enum mail_error error;
const char *name;
if (mailbox_open(box) == 0) {
return box;
}
if (error != MAIL_ERROR_NOTFOUND) {
mailbox_free(&box);
return NULL;
}
/* try creating and re-opening it. */
mailbox_free(&box);
return NULL;
}
if (mailbox_open(box) < 0) {
mailbox_free(&box);
return NULL;
}
return box;
}
static unsigned int
const char *guid)
{
void *refcountp;
unsigned int refcount;
1024);
}
if (refcount == 1) {
} else {
}
return refcount-1;
}
{
struct lazy_expunge_transaction *lt =
unsigned long refcount;
enum mail_error error;
if (error == MAIL_ERROR_EXPUNGED) {
/* already expunged - just ignore it */
return 0;
}
"lazy_expunge: Couldn't lookup message's refcount: %s",
errstr);
return -1;
}
if (*value == '\0') {
/* refcounts not supported by backend. assume all mails are
the last instance. */
return 1;
}
if (refcount > 1) {
/* this probably isn't the last instance of the mail, but
it's possible that the same mail was copied to this mailbox
multiple times and we're deleting more than one instance
within this transaction. in those cases each expunge will
see the same refcount, so we need to adjust the refcount
by tracking the expunged message GUIDs. */
"lazy_expunge: Couldn't lookup message's GUID");
return -1;
}
if (*value == '\0') {
/* GUIDs not supported by backend, but refcounts are?
not with our current backends. */
"lazy_expunge: Message unexpectedly has no GUID");
return -1;
}
}
}
{
struct lazy_expunge_mail_user *luser =
struct lazy_expunge_mailbox_list *llist =
/* lazy_expunge not enabled at all */
return FALSE;
}
if (llist->internal_namespace) {
/* lazy-expunge namespace */
return TRUE;
}
/* lazy-expunge mailbox */
return TRUE;
}
return FALSE;
}
{
struct lazy_expunge_mail_user *luser =
struct lazy_expunge_transaction *lt =
struct mail_save_context *save_ctx;
const char *error;
int ret;
/* don't copy the mail if we're expunging from lazy_expunge
namespace (even if it's via a virtual mailbox) */
return;
}
return;
}
if (lt->copy_only_last_instance) {
/* we want to copy only the last instance of the mail to
lazy_expunge namespace. other instances will be expunged
immediately. */
return;
}
if (ret == 0) {
return;
}
}
"lazy_expunge: Couldn't open expunge mailbox: "
"%s", error);
return;
}
"lazy_expunge: Couldn't sync expunge mailbox");
return;
}
}
}
static struct mailbox_transaction_context *
{
struct lazy_expunge_mail_user *luser =
struct mailbox_transaction_context *t;
struct lazy_expunge_transaction *lt;
return t;
}
{
}
static int
struct mail_transaction_commit_changes *changes_r)
{
int ret;
}
ret = -1;
} else {
}
return ret;
}
static void
{
}
{
struct lazy_expunge_transaction *lt =
union mail_module_context *mmail;
return;
}
static int
{
struct lazy_expunge_mailbox_list *src_llist =
struct lazy_expunge_mailbox_list *dest_llist =
if (!src_llist->allow_rename &&
return -1;
}
}
{
struct lazy_expunge_mailbox_list *llist =
union mailbox_module_context *mbox;
return;
if (!lazy_expunge_is_internal_mailbox(box)) {
} else if (llist->internal_namespace) {
} else {
/* internal mailbox in a non-internal namespace -
don't add any unnecessary restrictions to it. if it's not
wanted, just use the ACL plugin. */
}
}
{
struct lazy_expunge_mail_user *luser =
struct lazy_expunge_mailbox_list *llist;
return;
/* if this is one of our internal namespaces, mark it as such before
quota plugin sees it */
llist);
}
}
static void
{
struct lazy_expunge_mail_user *luser =
struct lazy_expunge_mailbox_list *llist;
return;
/* we don't want to override this namespace's expunge operation. */
} else {
/* store the the expunged mails to the specified mailbox. */
}
}
{
/* mail_namespaces_created hook isn't necessarily ever called */
}
{
struct lazy_expunge_mail_user *luser;
const char *env;
} else if (user->mail_debug) {
i_debug("lazy_expunge: No lazy_expunge setting - "
"plugin disabled");
}
}
static struct mail_storage_hooks lazy_expunge_mail_storage_hooks = {
};
{
}
void lazy_expunge_plugin_deinit(void)
{
}