28
28
LAZY_NAMESPACE_COUNT
31
struct lazy_expunge_mailbox_list {
32
union mailbox_list_module_context module_ctx;
34
struct mail_storage *storage;
31
37
struct lazy_expunge_mail_storage {
32
struct mail_storage_vfuncs super;
38
union mail_storage_module_context module_ctx;
33
40
bool internal_namespace;
36
struct lazy_expunge_mailbox {
37
struct mailbox_vfuncs super;
40
43
struct lazy_expunge_transaction {
41
array_t ARRAY_DEFINE(expunge_seqs, struct seq_range);
44
union mailbox_transaction_module_context module_ctx;
46
ARRAY_TYPE(seq_range) expunge_seqs;
42
47
struct mailbox *expunge_box;
45
struct lazy_expunge_mail {
46
struct mail_vfuncs super;
49
52
const char *lazy_expunge_plugin_version = PACKAGE_VERSION;
54
static void (*lazy_expunge_next_hook_mail_namespaces_created)
55
(struct mail_namespace *namespaces);
51
56
static void (*lazy_expunge_next_hook_mail_storage_created)
52
57
(struct mail_storage *storage);
53
static void (*lazy_expunge_next_hook_client_created)(struct client **client);
55
static unsigned int lazy_expunge_storage_module_id = 0;
56
static bool lazy_expunge_storage_module_id_set = FALSE;
58
static struct namespace *lazy_namespaces[LAZY_NAMESPACE_COUNT];
58
static void (*lazy_expunge_next_hook_mailbox_list_created)
59
(struct mailbox_list *list);
61
static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_storage_module,
62
&mail_storage_module_register);
63
static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_module,
64
&mail_module_register);
65
static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mailbox_list_module,
66
&mailbox_list_module_register);
68
static struct mail_namespace *lazy_namespaces[LAZY_NAMESPACE_COUNT];
60
70
static struct mailbox *
61
71
mailbox_open_or_create(struct mail_storage *storage, const char *name)
63
73
struct mailbox *box;
74
enum mail_error error;
66
76
box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
67
77
MAILBOX_OPEN_KEEP_RECENT |
353
mailbox_move(struct mail_storage *src_storage, const char *src_name,
354
struct mail_storage *dest_storage, const char **_dest_name)
367
mailbox_move(struct mailbox_list *src_list, const char *src_name,
368
struct mailbox_list *dest_list, const char **_dest_name)
356
struct index_storage *src_istorage =
357
(struct index_storage *)src_storage;
358
struct index_storage *dest_istorage =
359
(struct index_storage *)dest_storage;
360
370
const char *dest_name = *_dest_name;
361
371
const char *srcdir, *src2dir, *src3dir, *destdir;
364
srcdir = mail_storage_get_mailbox_path(src_storage, src_name, &is_file);
365
destdir = mail_storage_get_mailbox_path(dest_storage, dest_name,
373
srcdir = mailbox_list_get_path(src_list, src_name,
374
MAILBOX_LIST_PATH_TYPE_MAILBOX);
375
destdir = mailbox_list_get_path(dest_list, dest_name,
376
MAILBOX_LIST_PATH_TYPE_MAILBOX);
367
377
while (rename(srcdir, destdir) < 0) {
368
378
if (errno == ENOENT)
371
381
if (!EDESTDIREXISTS(errno)) {
372
mail_storage_set_critical(src_storage,
382
mailbox_list_set_critical(src_list,
373
383
"rename(%s, %s) failed: %m", srcdir, destdir);
378
388
update the filename. */
379
389
dest_name = t_strdup_printf("%s-%04u", *_dest_name,
380
390
(uint32_t)random());
381
destdir = mail_storage_get_mailbox_path(dest_storage, dest_name,
391
destdir = mailbox_list_get_path(dest_list, dest_name,
392
MAILBOX_LIST_PATH_TYPE_MAILBOX);
386
src2dir = mail_storage_get_mailbox_control_dir(src_storage, src_name);
395
src2dir = mailbox_list_get_path(src_list, src_name,
396
MAILBOX_LIST_PATH_TYPE_CONTROL);
387
397
if (strcmp(src2dir, srcdir) != 0) {
388
destdir = mail_storage_get_mailbox_control_dir(dest_storage,
390
(void)dir_move_or_merge(src_storage, src2dir, destdir);
398
destdir = mailbox_list_get_path(dest_list, dest_name,
399
MAILBOX_LIST_PATH_TYPE_CONTROL);
400
(void)dir_move_or_merge(src_list, src2dir, destdir);
392
src3dir = t_strconcat(src_istorage->index_dir, "/"MAILDIR_FS_SEP_S,
402
src3dir = mailbox_list_get_path(src_list, src_name,
403
MAILBOX_LIST_PATH_TYPE_INDEX);
394
404
if (strcmp(src3dir, srcdir) != 0 && strcmp(src3dir, src2dir) != 0) {
395
destdir = t_strconcat(dest_istorage->index_dir,
398
(void)dir_move_or_merge(src_storage, src3dir, destdir);
405
destdir = mailbox_list_get_path(dest_list, dest_name,
406
MAILBOX_LIST_PATH_TYPE_INDEX);
407
(void)dir_move_or_merge(src_list, src3dir, destdir);
402
410
*_dest_name = dest_name;
407
lazy_expunge_mailbox_delete(struct mail_storage *storage, const char *name)
415
lazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name)
409
struct lazy_expunge_mail_storage *lstorage =
410
LAZY_EXPUNGE_CONTEXT(storage);
411
struct mail_storage *dest_storage;
417
struct lazy_expunge_mailbox_list *llist =
418
LAZY_EXPUNGE_LIST_CONTEXT(list);
419
struct lazy_expunge_mail_storage *lstorage;
420
struct mailbox_list *dest_list;
412
421
enum mailbox_name_status status;
413
422
const char *destname;
415
424
char timestamp[256];
427
if (llist->storage == NULL) {
428
/* not a maildir storage */
429
return llist->module_ctx.super.delete_mailbox(list, name);
432
lstorage = LAZY_EXPUNGE_CONTEXT(llist->storage);
418
433
if (lstorage->internal_namespace)
419
return lstorage->super.mailbox_delete(storage, name);
421
mail_storage_clear_error(storage);
434
return llist->module_ctx.super.delete_mailbox(list, name);
423
436
/* first do the normal sanity checks */
424
437
if (strcmp(name, "INBOX") == 0) {
425
mail_storage_set_error(storage, "INBOX can't be deleted.");
438
mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
439
"INBOX can't be deleted.");
429
if (mail_storage_get_mailbox_name_status(storage, name, &status) < 0)
443
if (mailbox_list_get_mailbox_name_status(list, name, &status) < 0)
431
445
if (status == MAILBOX_NAME_INVALID) {
432
mail_storage_set_error(storage, "Invalid mailbox name");
446
mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
447
"Invalid mailbox name");
436
451
/* destination mailbox name needs to contain a timestamp */
437
452
tm = localtime(&ioloop_time);
438
453
if (strftime(timestamp, sizeof(timestamp), "%Y%m%d-%H%M%S", tm) == 0)
439
strocpy(timestamp, dec2str(ioloop_time), sizeof(timestamp));
454
i_strocpy(timestamp, dec2str(ioloop_time), sizeof(timestamp));
440
455
destname = t_strconcat(name, "-", timestamp, NULL);
442
457
/* first move the actual mailbox */
443
dest_storage = lazy_namespaces[LAZY_NAMESPACE_DELETE]->storage;
444
if ((ret = mailbox_move(storage, name, dest_storage, &destname)) < 0)
458
dest_list = lazy_namespaces[LAZY_NAMESPACE_DELETE]->storage->list;
459
if ((ret = mailbox_move(list, name, dest_list, &destname)) < 0)
447
mail_storage_set_error(storage,
448
MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND, name);
462
mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
463
T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
452
467
/* next move the expunged messages mailbox, if it exists */
453
storage = lazy_namespaces[LAZY_NAMESPACE_EXPUNGE]->storage;
454
dest_storage = lazy_namespaces[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage;
455
(void)mailbox_move(storage, name, dest_storage, &destname);
468
list = lazy_namespaces[LAZY_NAMESPACE_EXPUNGE]->storage->list;
470
lazy_namespaces[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list;
471
(void)mailbox_move(list, name, dest_list, &destname);
475
static void lazy_expunge_mail_storage_init(struct mail_storage *storage)
477
struct lazy_expunge_mailbox_list *llist =
478
LAZY_EXPUNGE_LIST_CONTEXT(storage->list);
479
struct lazy_expunge_mail_storage *lstorage;
480
const char *const *p;
483
/* if this is one of our internal storages, mark it as such before
484
quota plugin sees it */
485
p = t_strsplit_spaces(getenv("LAZY_EXPUNGE"), " ");
486
for (i = 0; i < LAZY_NAMESPACE_COUNT; i++, p++) {
487
if (strcmp(storage->ns->prefix, *p) == 0) {
488
storage->ns->flags |= NAMESPACE_FLAG_INTERNAL;
493
llist->storage = storage;
495
lstorage = p_new(storage->pool, struct lazy_expunge_mail_storage, 1);
496
lstorage->module_ctx.super = storage->v;
497
storage->v.mailbox_open = lazy_expunge_mailbox_open;
499
MODULE_CONTEXT_SET(storage, lazy_expunge_mail_storage_module, lstorage);
459
502
static void lazy_expunge_mail_storage_created(struct mail_storage *storage)
461
struct lazy_expunge_mail_storage *lstorage;
504
/* only maildir supported for now */
505
if (strcmp(storage->name, "maildir") == 0)
506
lazy_expunge_mail_storage_init(storage);
463
508
if (lazy_expunge_next_hook_mail_storage_created != NULL)
464
509
lazy_expunge_next_hook_mail_storage_created(storage);
466
/* only maildir supported for now */
467
if (strcmp(storage->name, "maildir") != 0)
470
lstorage = p_new(storage->pool, struct lazy_expunge_mail_storage, 1);
471
lstorage->super = storage->v;
472
storage->v.mailbox_open = lazy_expunge_mailbox_open;
473
storage->v.mailbox_delete = lazy_expunge_mailbox_delete;
475
if (!lazy_expunge_storage_module_id_set) {
476
lazy_expunge_storage_module_id = mail_storage_module_id++;
477
lazy_expunge_storage_module_id_set = TRUE;
480
array_idx_set(&storage->module_contexts,
481
lazy_expunge_storage_module_id, &lstorage);
484
static void lazy_expunge_hook_client_created(struct client **client)
512
static void lazy_expunge_mailbox_list_created(struct mailbox_list *list)
514
struct lazy_expunge_mailbox_list *llist;
516
if (lazy_expunge_next_hook_mailbox_list_created != NULL)
517
lazy_expunge_next_hook_mailbox_list_created(list);
519
llist = p_new(list->pool, struct lazy_expunge_mailbox_list, 1);
520
llist->module_ctx.super = list->v;
521
list->v.delete_mailbox = lazy_expunge_mailbox_list_delete;
523
MODULE_CONTEXT_SET(list, lazy_expunge_mailbox_list_module, llist);
527
lazy_expunge_hook_mail_namespaces_created(struct mail_namespace *namespaces)
486
529
struct lazy_expunge_mail_storage *lstorage;
487
530
const char *const *p;
490
if (lazy_expunge_next_hook_client_created != NULL)
491
lazy_expunge_next_hook_client_created(client);
533
if (lazy_expunge_next_hook_mail_namespaces_created != NULL)
534
lazy_expunge_next_hook_mail_namespaces_created(namespaces);
493
/* FIXME: this works only as long as there's only one client. */
495
p = t_strsplit(getenv("LAZY_EXPUNGE"), " ");
536
p = t_strsplit_spaces(getenv("LAZY_EXPUNGE"), " ");
496
537
for (i = 0; i < LAZY_NAMESPACE_COUNT; i++, p++) {
497
538
const char *name = *p;