Coverage Report

Created: 2026-08-13 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-storage/mail-storage.c
Line
Count
Source
1
/* Copyright (c) Dovecot authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "ioloop.h"
5
#include "array.h"
6
#include "llist.h"
7
#include "mail-storage.h"
8
#include "str.h"
9
#include "str-parse.h"
10
#include "sha1.h"
11
#include "unicode-data.h"
12
#include "unichar.h"
13
#include "hex-binary.h"
14
#include "fs-api.h"
15
#include "file-dotlock.h"
16
#include "file-create-locked.h"
17
#include "istream.h"
18
#include "eacces-error.h"
19
#include "mkdir-parents.h"
20
#include "time-util.h"
21
#include "wildcard-match.h"
22
#include "settings.h"
23
#include "dsasl-client.h"
24
#include "imap-date.h"
25
#include "mail-index-private.h"
26
#include "mail-index-alloc-cache.h"
27
#include "mailbox-tree.h"
28
#include "mailbox-list-private.h"
29
#include "mail-storage-private.h"
30
#include "mail-storage-service.h"
31
#include "mail-storage-settings.h"
32
#include "mail-namespace.h"
33
#include "mail-search.h"
34
#include "mail-search-register.h"
35
#include "mail-search-mime-register.h"
36
#include "mailbox-search-result-private.h"
37
#include "mailbox-guid-cache.h"
38
#include "mail-cache.h"
39
#include "utc-mktime.h"
40
41
#include <ctype.h>
42
43
0
#define MAILBOX_DELETE_RETRY_SECS 30
44
0
#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 255
45
46
extern struct mail_search_register *mail_search_register_imap4rev2;
47
extern struct mail_search_register *mail_search_register_imap4rev1;
48
extern struct mail_search_register *mail_search_register_human;
49
50
struct event_category event_category_storage = {
51
  .name = "storage",
52
};
53
struct event_category event_category_mailbox = {
54
  .parent = &event_category_storage,
55
  .name = "mailbox",
56
};
57
struct event_category event_category_mail = {
58
  .parent = &event_category_mailbox,
59
  .name = "mail",
60
};
61
62
struct mail_storage_module_register mail_storage_module_register = { 0 };
63
struct mail_module_register mail_module_register = { 0 };
64
65
struct mail_storage_mail_index_module mail_storage_mail_index_module =
66
  MODULE_CONTEXT_INIT(&mail_index_module_register);
67
ARRAY_TYPE(mail_storage) mail_storage_classes;
68
69
static int mail_storage_init_refcount = 0;
70
71
static const char *
72
mailbox_get_name_without_prefix(struct mail_namespace *ns,
73
        const char *vname)
74
0
{
75
0
  if (ns->prefix_len > 0 &&
76
0
      strncmp(ns->prefix, vname, ns->prefix_len-1) == 0) {
77
0
    if (vname[ns->prefix_len-1] == mail_namespace_get_sep(ns))
78
0
      vname += ns->prefix_len;
79
0
    else if (vname[ns->prefix_len-1] == '\0') {
80
      /* namespace prefix itself */
81
0
      vname = "";
82
0
    }
83
0
  }
84
0
  return vname;
85
0
}
86
87
void mail_storage_init(void)
88
0
{
89
0
  if (mail_storage_init_refcount++ > 0)
90
0
    return;
91
0
  dsasl_clients_init();
92
0
  mailbox_attributes_init();
93
0
  mailbox_lists_init();
94
0
  mail_storage_hooks_init();
95
0
  i_array_init(&mail_storage_classes, 8);
96
0
  mail_storage_register_all();
97
0
  mailbox_list_register_all();
98
0
  settings_info_register(&mail_storage_setting_parser_info);
99
0
}
100
101
void mail_storage_deinit(void)
102
0
{
103
0
  i_assert(mail_storage_init_refcount > 0);
104
0
  if (--mail_storage_init_refcount > 0)
105
0
    return;
106
0
  if (mail_search_register_human != NULL)
107
0
    mail_search_register_deinit(&mail_search_register_human);
108
0
  if (mail_search_register_imap4rev1 != NULL)
109
0
    mail_search_register_deinit(&mail_search_register_imap4rev1);
110
0
  if (mail_search_register_imap4rev2 != NULL)
111
0
    mail_search_register_deinit(&mail_search_register_imap4rev2);
112
0
  mail_search_mime_register_deinit();
113
0
  if (array_is_created(&mail_storage_classes))
114
0
    array_free(&mail_storage_classes);
115
0
  mail_storage_hooks_deinit();
116
0
  mailbox_lists_deinit();
117
0
  mailbox_attributes_deinit();
118
0
  dsasl_clients_deinit();
119
0
}
120
121
void mail_storage_class_register(struct mail_storage *storage_class)
122
0
{
123
0
  i_assert(mail_storage_find_class(storage_class->name) == NULL);
124
125
0
  if (storage_class->set_info != NULL)
126
0
    settings_info_register(storage_class->set_info);
127
128
  /* append it after the list, so the autodetection order is correct */
129
0
  array_push_back(&mail_storage_classes, &storage_class);
130
0
}
131
132
void mail_storage_class_unregister(struct mail_storage *storage_class)
133
0
{
134
0
  unsigned int i;
135
136
0
  if (!array_lsearch_ptr_idx(&mail_storage_classes, storage_class, &i))
137
0
    i_unreached();
138
0
  array_delete(&mail_storage_classes, i, 1);
139
0
}
140
141
struct mail_storage *mail_storage_find_class(const char *name)
142
0
{
143
0
  struct mail_storage *const *classes;
144
0
  unsigned int i, count;
145
146
0
  i_assert(name != NULL);
147
148
0
  classes = array_get(&mail_storage_classes, &count);
149
0
  for (i = 0; i < count; i++) {
150
0
    if (strcasecmp(classes[i]->name, name) == 0)
151
0
      return classes[i];
152
0
  }
153
0
  return NULL;
154
0
}
155
156
static struct mail_storage *
157
mail_storage_autodetect(const struct mail_namespace *ns,
158
      const struct mail_storage_settings *mail_set,
159
      const char **root_path_override,
160
      const char **inbox_path_override)
161
0
{
162
0
  struct mail_storage *const *classes;
163
0
  const char *root_path, *inbox_path = NULL;
164
0
  unsigned int i, count;
165
166
0
  classes = array_get(&mail_storage_classes, &count);
167
0
  for (i = 0; i < count; i++) {
168
0
    if (classes[i]->v.autodetect != NULL) {
169
0
      if (classes[i]->v.autodetect(ns, mail_set,
170
0
                 &root_path, &inbox_path)) {
171
0
        *root_path_override = root_path;
172
0
        *inbox_path_override = inbox_path;
173
0
        return classes[i];
174
0
      }
175
0
    }
176
0
  }
177
0
  return NULL;
178
0
}
179
180
static struct mail_storage *
181
mail_storage_get_class(struct mail_namespace *ns, const char *driver,
182
           struct event *set_event,
183
           const char **root_path_override,
184
           const char **inbox_path_override, const char **error_r)
185
0
{
186
0
  struct mail_storage *storage_class = NULL;
187
0
  const char *home;
188
189
0
  if (driver[0] == '\0') {
190
    /* empty mail_driver setting, autodetect */
191
0
  } else if (strcmp(driver, "auto") == 0) {
192
    /* explicit autodetection with "auto" driver. */
193
0
  } else {
194
0
    storage_class = mail_user_get_storage_class(ns->user, driver);
195
0
    if (storage_class == NULL) {
196
0
      *error_r = t_strdup_printf(
197
0
        "Unknown mail storage driver %s", driver);
198
0
      return NULL;
199
0
    }
200
0
  }
201
202
0
  if (storage_class != NULL)
203
0
    return storage_class;
204
205
0
  const struct mail_storage_settings *mail_set;
206
0
  if (settings_get(set_event, &mail_storage_setting_parser_info, 0,
207
0
       &mail_set, error_r) < 0)
208
0
    return NULL;
209
210
0
  storage_class = mail_storage_autodetect(ns, mail_set, root_path_override,
211
0
            inbox_path_override);
212
0
  if (storage_class != NULL) {
213
0
    settings_free(mail_set);
214
0
    return storage_class;
215
0
  }
216
217
0
  (void)mail_user_get_home(ns->user, &home);
218
0
  if (home == NULL || *home == '\0') home = "(not set)";
219
220
0
  *error_r = t_strdup_printf(
221
0
    "Mail storage autodetection failed (home=%s, mail_path=%s) - "
222
0
    "Set mail_driver explicitly",
223
0
    home, mail_set->mail_path);
224
0
  settings_free(mail_set);
225
0
  return NULL;
226
0
}
227
228
static int
229
mail_storage_verify_root(const char *root_dir, const char *dir_type,
230
       const char **error_r)
231
0
{
232
0
  struct stat st;
233
234
0
  if (stat(root_dir, &st) == 0) {
235
    /* exists */
236
0
    if (S_ISDIR(st.st_mode))
237
0
      return 0;
238
0
    *error_r = t_strdup_printf(
239
0
      "Root mail directory is a file: %s", root_dir);
240
0
    return -1;
241
0
  } else if (ENOACCESS(errno)) {
242
0
    *error_r = mail_error_eacces_msg("stat", root_dir);
243
0
    return -1;
244
0
  } else if (errno != ENOENT) {
245
0
    *error_r = t_strdup_printf("stat(%s) failed: %m", root_dir);
246
0
    return -1;
247
0
  } else {
248
0
    *error_r = t_strdup_printf(
249
0
      "Root %s directory doesn't exist: %s", dir_type, root_dir);
250
0
    return -1;
251
0
  }
252
0
}
253
254
static int
255
mail_storage_create_root(struct mailbox_list *list,
256
       enum mail_storage_flags flags, const char **error_r)
257
0
{
258
0
  const char *root_dir, *type_name, *error;
259
0
  enum mailbox_list_path_type type;
260
261
0
  if (list->mail_set->mailbox_list_iter_from_index_dir) {
262
0
    type = MAILBOX_LIST_PATH_TYPE_INDEX;
263
0
    type_name = "index";
264
0
  } else {
265
0
    type = MAILBOX_LIST_PATH_TYPE_MAILBOX;
266
0
    type_name = "mail";
267
0
  }
268
0
  if (!mailbox_list_get_root_path(list, type, &root_dir)) {
269
    /* storage doesn't use directories (e.g. shared root) */
270
0
    return 0;
271
0
  }
272
273
0
  if ((flags & MAIL_STORAGE_FLAG_NO_AUTOVERIFY) != 0) {
274
0
    if (!event_want_debug_log(list->event))
275
0
      return 0;
276
277
    /* we don't need to verify, but since debugging is
278
       enabled, check and log if the root doesn't exist */
279
0
    if (mail_storage_verify_root(root_dir, type_name, &error) < 0) {
280
0
      e_debug(list->event,
281
0
        "Namespace %s: Creating storage despite: %s",
282
0
        list->ns->set->name, error);
283
0
    }
284
0
    return 0;
285
0
  }
286
287
0
  if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) == 0) {
288
    /* If the directories don't exist, we'll just autocreate them
289
       later. */
290
0
    return 0;
291
0
  }
292
0
  return mail_storage_verify_root(root_dir, type_name, error_r);
293
0
}
294
295
static bool
296
mail_storage_match_class(struct mail_storage *storage,
297
       const struct mail_storage *storage_class,
298
       const struct mail_storage_settings *mail_set)
299
0
{
300
0
  if (strcmp(storage->name, storage_class->name) != 0)
301
0
    return FALSE;
302
303
0
  if ((storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0 &&
304
0
      strcmp(storage->unique_root_dir, mail_set->mail_path) != 0)
305
0
    return FALSE;
306
307
0
  if (strcmp(storage->name, "shared") == 0) {
308
    /* allow multiple independent shared namespaces */
309
0
    return FALSE;
310
0
  }
311
0
  return TRUE;
312
0
}
313
314
static struct mail_storage *
315
mail_storage_find(struct mail_user *user,
316
      const struct mail_storage *storage_class,
317
      const struct mail_storage_settings *mail_set)
318
0
{
319
0
  struct mail_storage *storage = user->storages;
320
321
0
  for (; storage != NULL; storage = storage->next) {
322
0
    if (mail_storage_match_class(storage, storage_class, mail_set))
323
0
      return storage;
324
0
  }
325
0
  return NULL;
326
0
}
327
328
static void
329
mail_storage_create_ns_instance(struct mail_namespace *ns,
330
        struct event *set_event)
331
0
{
332
0
  if (ns->_set_instance != NULL)
333
0
    return;
334
335
0
  struct settings_instance *set_instance =
336
0
    mail_storage_service_user_get_settings_instance(
337
0
      ns->user->service_user);
338
0
  ns->_set_instance = settings_instance_dup(set_instance);
339
0
  event_set_ptr(set_event, SETTINGS_EVENT_INSTANCE, ns->_set_instance);
340
0
}
341
342
static int
343
mail_storage_create_list(struct mail_namespace *ns,
344
       struct mail_storage *storage_class,
345
       struct event *parent_set_event,
346
       enum mail_storage_flags flags,
347
       const char *root_path_override,
348
       const char *inbox_path_override,
349
       const char **error_r)
350
0
{
351
0
  enum mailbox_list_flags list_flags = 0;
352
0
  if (mail_storage_is_mailbox_file(storage_class))
353
0
    list_flags |= MAILBOX_LIST_FLAG_MAILBOX_FILES;
354
0
  if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0)
355
0
    list_flags |= MAILBOX_LIST_FLAG_NO_MAIL_FILES;
356
0
  if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_LIST_DELETES) != 0)
357
0
    list_flags |= MAILBOX_LIST_FLAG_NO_DELETES;
358
359
0
  struct mailbox_list *list;
360
0
  struct event *set_event = event_create(parent_set_event);
361
  /* Lookup storage-specific settings, especially to get
362
     storage-specific defaults for mailbox list settings. */
363
0
  settings_event_add_filter_name(set_event, storage_class->name);
364
  /* Set namespace, but don't overwrite if it already is set.
365
     Shared storage uses the same shared namespace here also for the
366
     user's root prefix="" namespace. */
367
0
  if (event_find_field_recursive(set_event, SETTINGS_EVENT_NAMESPACE_NAME) == NULL) {
368
0
    event_add_str(set_event, SETTINGS_EVENT_NAMESPACE_NAME, ns->set->name);
369
0
    settings_event_add_list_filter_name(set_event,
370
0
      SETTINGS_EVENT_NAMESPACE_NAME, ns->set->name);
371
0
  }
372
373
0
  if ((flags & MAIL_STORAGE_FLAG_SHARED_DYNAMIC) != 0) {
374
0
    mail_storage_create_ns_instance(ns, set_event);
375
0
    settings_override(ns->_set_instance,
376
0
          "*/mailbox_list_layout", "shared",
377
0
          SETTINGS_OVERRIDE_TYPE_CODE);
378
0
  }
379
380
0
  const struct mailbox_list_layout_settings *layout_set;
381
0
  if (settings_get(set_event, &mailbox_list_layout_setting_parser_info, 0,
382
0
       &layout_set, error_r) < 0) {
383
0
    event_unref(&set_event);
384
0
    return -1;
385
0
  }
386
387
  /* Lookup also layout-specific settings, especially defaults */
388
0
  struct event *set_event2 = event_create(set_event);
389
0
  event_unref(&set_event);
390
0
  set_event = set_event2;
391
0
  settings_event_add_filter_name(set_event, t_strdup_printf("layout_%s",
392
0
    t_str_lcase(layout_set->mailbox_list_layout)));
393
0
  settings_free(layout_set);
394
395
0
  if (root_path_override != NULL) {
396
0
    mail_storage_create_ns_instance(ns, set_event);
397
0
    settings_override(ns->_set_instance, "*/mail_path",
398
0
          root_path_override,
399
0
          SETTINGS_OVERRIDE_TYPE_CODE);
400
0
  }
401
0
  if (inbox_path_override != NULL) {
402
0
    mail_storage_create_ns_instance(ns, set_event);
403
0
    settings_override(ns->_set_instance, "*/mail_inbox_path",
404
0
          inbox_path_override,
405
0
          SETTINGS_OVERRIDE_TYPE_CODE);
406
0
  }
407
408
0
  const struct mail_storage_settings *mail_set;
409
0
  if (settings_get(set_event, &mail_storage_setting_parser_info, 0,
410
0
       &mail_set, error_r) < 0) {
411
0
    event_unref(&set_event);
412
0
    return -1;
413
0
  }
414
415
0
  if (mail_set->mail_path[0] == '\0') {
416
    /* no root directory given. is this allowed? */
417
0
    if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0) {
418
      /* autodetection should take care of this */
419
0
    } else if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
420
      /* root not required for this storage */
421
0
    } else {
422
0
      *error_r = "Root mail directory not given";
423
0
      settings_free(mail_set);
424
0
      event_unref(&set_event);
425
0
      return -1;
426
0
    }
427
0
  }
428
429
  /* Use parent_set_event instead of set_event mainly to avoid
430
     permanently having SETTINGS_EVENT_FILTER_NAME=storage_name in
431
     mailbox_list->event. This would be wrong, since mailbox_list can
432
     support multiple storages. */
433
0
  struct event *event = event_create(parent_set_event);
434
0
  event_add_str(event, SETTINGS_EVENT_NAMESPACE_NAME, ns->set->name);
435
0
  settings_event_add_list_filter_name(event,
436
0
    SETTINGS_EVENT_NAMESPACE_NAME, ns->set->name);
437
0
  int ret = mailbox_list_create(event, ns, mail_set, list_flags,
438
0
              &list, error_r);
439
0
  if (ret < 0) {
440
0
    *error_r = t_strdup_printf("mailbox_list_layout %s: %s",
441
0
      mail_set->mailbox_list_layout, *error_r);
442
0
  }
443
0
  settings_free(mail_set);
444
0
  event_unref(&event);
445
0
  event_unref(&set_event);
446
0
  return ret;
447
0
}
448
449
static bool ATTR_PURE pop3_uidl_format_has_md5(const char *fmt)
450
0
{
451
0
  struct var_expand_program *prog;
452
0
  const char *error;
453
0
  if (var_expand_program_create(fmt, &prog, &error) < 0)
454
0
    i_fatal("Invalid pop3_uidl_format: %s", error);
455
0
  const char *const *vars = var_expand_program_variables(prog);
456
0
  bool has_md5 = str_array_find(vars, "md5");
457
0
  var_expand_program_free(&prog);
458
0
  return has_md5;
459
0
}
460
461
static int
462
mail_storage_create_real(struct mail_namespace *ns, struct event *set_event,
463
       enum mail_storage_flags flags,
464
       struct mail_storage **storage_r, const char **error_r)
465
0
{
466
0
  struct mail_storage *storage_class, *storage = NULL;
467
0
  const struct mail_driver_settings *driver_set;
468
0
  const char *driver = NULL;
469
0
  const char *inbox_path_override = NULL;
470
0
  const char *root_path_override = NULL;
471
472
  /* Lookup initial mailbox list settings. Once they're found, another
473
     settings lookup is done with mailbox format as an additional
474
     filter. */
475
0
  if (settings_get(set_event, &mail_driver_setting_parser_info, 0,
476
0
       &driver_set, error_r) < 0)
477
0
    return -1;
478
0
  driver = driver_set->mail_driver;
479
480
0
  if ((flags & MAIL_STORAGE_FLAG_SHARED_DYNAMIC) != 0) {
481
    /* internal shared namespace */
482
0
    driver = MAIL_SHARED_STORAGE_NAME;
483
0
    root_path_override = ns->user->set->base_dir;
484
0
  }
485
486
0
  storage_class = mail_storage_get_class(ns, driver, set_event,
487
0
                 &root_path_override,
488
0
                 &inbox_path_override, error_r);
489
0
  settings_free(driver_set);
490
0
  if (storage_class == NULL)
491
0
    return -1;
492
493
0
  if (ns->list == NULL) {
494
    /* first storage for namespace */
495
0
    if (mail_storage_create_list(ns, storage_class, set_event,
496
0
               flags, root_path_override,
497
0
               inbox_path_override, error_r) < 0)
498
0
      return -1;
499
0
    if ((storage_class->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) == 0) {
500
0
      if (mail_storage_create_root(ns->list, flags, error_r) < 0)
501
0
        return -1;
502
0
    }
503
0
  }
504
505
0
  storage = mail_storage_find(ns->user, storage_class,
506
0
            ns->list->mail_set);
507
0
  if (storage != NULL) {
508
    /* using an existing storage */
509
0
    storage->refcount++;
510
0
    mail_namespace_add_storage(ns, storage);
511
0
    *storage_r = storage;
512
0
    return 0;
513
0
  }
514
515
0
  if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
516
0
      ns->list->mail_set->pop3_uidl_format != NULL) {
517
    /* if pop3_uidl_format contains %m, we want to keep the
518
       header MD5 sums stored even if we're not running POP3
519
       right now. */
520
0
    if (pop3_uidl_format_has_md5(ns->list->mail_set->pop3_uidl_format))
521
0
      flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
522
0
  }
523
524
0
  storage = storage_class->v.alloc();
525
0
  storage->refcount = 1;
526
0
  storage->storage_class = storage_class;
527
0
  storage->user = ns->user;
528
0
  storage->set = ns->list->mail_set;
529
0
  pool_ref(storage->set->pool);
530
0
  storage->flags = flags;
531
  /* Set to UINT32_MAX manually to denote 'unset', as the default 0 is
532
     used for mails currently being saved. */
533
0
  storage->last_internal_error_mail_uid = UINT32_MAX;
534
535
0
  storage->event = event_create(ns->user->event);
536
0
  if (storage_class->event_category != NULL)
537
0
    event_add_category(storage->event, storage_class->event_category);
538
0
  event_set_append_log_prefix(
539
0
    storage->event, t_strdup_printf("%s: ", storage_class->name));
540
0
  p_array_init(&storage->module_contexts, storage->pool, 5);
541
542
0
  if (storage->v.create != NULL &&
543
0
      storage->v.create(storage, ns, error_r) < 0) {
544
0
    *error_r = t_strdup_printf("%s: %s", storage->name, *error_r);
545
0
    storage->v.destroy(storage);
546
0
    settings_free(storage->set);
547
0
    event_unref(&storage->event);
548
0
    pool_unref(&storage->pool);
549
0
    return -1;
550
0
  }
551
552
  /* If storage supports list index rebuild,
553
     provide default mailboxes_fs unless storage
554
     wants to use its own. */
555
0
  if (storage->v.list_index_rebuild != NULL &&
556
0
      storage->mailboxes_fs == NULL) {
557
0
    struct fs_parameters fs_params;
558
0
    const char *error;
559
0
    i_zero(&fs_params);
560
0
    mail_user_init_fs_parameters(storage->user, &fs_params);
561
562
0
    struct settings_instance *set_instance =
563
0
      mail_storage_service_user_get_settings_instance(
564
0
        storage->user->service_user);
565
0
    storage->mailboxes_fs_set_instance =
566
0
      settings_instance_dup(set_instance);
567
0
    settings_override(storage->mailboxes_fs_set_instance,
568
0
          "*/fs", "__posix",
569
0
          SETTINGS_OVERRIDE_TYPE_CODE);
570
0
    settings_override(storage->mailboxes_fs_set_instance,
571
0
          "fs/__posix/fs_driver", "posix",
572
0
          SETTINGS_OVERRIDE_TYPE_CODE);
573
574
0
    struct event *event = event_create(storage->event);
575
0
    event_set_ptr(event, SETTINGS_EVENT_INSTANCE,
576
0
            storage->mailboxes_fs_set_instance);
577
0
    if (fs_init_auto(event, &fs_params, &storage->mailboxes_fs,
578
0
         &error) <= 0) {
579
0
      *error_r = t_strdup_printf("fs_init(posix) failed: %s", error);
580
0
      event_unref(&event);
581
0
      storage->v.destroy(storage);
582
0
      settings_free(storage->set);
583
0
      event_unref(&storage->event);
584
0
      pool_unref(&storage->pool);
585
0
      return -1;
586
0
    }
587
0
    event_unref(&event);
588
0
  }
589
590
0
  T_BEGIN {
591
0
    hook_mail_storage_created(storage);
592
0
  } T_END;
593
594
0
  i_assert(storage->unique_root_dir != NULL ||
595
0
     (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) == 0);
596
0
  DLLIST_PREPEND(&ns->user->storages, storage);
597
0
  mail_namespace_add_storage(ns, storage);
598
0
  *storage_r = storage;
599
0
  return 0;
600
0
}
601
602
int mail_storage_create(struct mail_namespace *ns, struct event *set_event,
603
      enum mail_storage_flags flags,
604
      struct mail_storage **storage_r, const char **error_r)
605
0
{
606
0
  int ret;
607
0
  T_BEGIN {
608
0
    ret = mail_storage_create_real(ns, set_event, flags,
609
0
                 storage_r, error_r);
610
0
  } T_END_PASS_STR_IF(ret < 0, error_r);
611
0
  return ret;
612
0
}
613
614
void mail_storage_unref(struct mail_storage **_storage)
615
0
{
616
0
  struct mail_storage *storage = *_storage;
617
618
0
  i_assert(storage->refcount > 0);
619
620
  /* set *_storage=NULL only after calling destroy() callback.
621
     for example mdbox wants to access ns->storage */
622
0
  if (--storage->refcount > 0) {
623
0
    *_storage = NULL;
624
0
    return;
625
0
  }
626
627
0
  if (storage->mailboxes != NULL) {
628
0
    i_panic("Trying to deinit storage without freeing mailbox %s",
629
0
      storage->mailboxes->vname);
630
0
  }
631
0
  if (storage->obj_refcount != 0)
632
0
    i_panic("Trying to deinit storage before freeing its objects");
633
634
0
  DLLIST_REMOVE(&storage->user->storages, storage);
635
636
0
  storage->v.destroy(storage);
637
0
  mail_storage_clear_error(storage);
638
0
  if (array_is_created(&storage->error_stack)) {
639
0
    i_assert(array_count(&storage->error_stack) == 0);
640
0
    array_free(&storage->error_stack);
641
0
  }
642
0
  fs_unref(&storage->mailboxes_fs);
643
0
  settings_instance_free(&storage->mailboxes_fs_set_instance);
644
0
  settings_free(storage->set);
645
0
  event_unref(&storage->event);
646
647
0
  *_storage = NULL;
648
0
  pool_unref(&storage->pool);
649
650
0
  mail_index_alloc_cache_destroy_unrefed();
651
0
}
652
653
void mail_storage_obj_ref(struct mail_storage *storage)
654
0
{
655
0
  i_assert(storage->refcount > 0);
656
657
0
  if (storage->obj_refcount++ == 0)
658
0
    mail_user_ref(storage->user);
659
0
}
660
661
void mail_storage_obj_unref(struct mail_storage *storage)
662
0
{
663
0
  i_assert(storage->refcount > 0);
664
0
  i_assert(storage->obj_refcount > 0);
665
666
0
  if (--storage->obj_refcount == 0) {
667
0
    struct mail_user *user = storage->user;
668
0
    mail_user_unref(&user);
669
0
  }
670
0
}
671
672
void mail_storage_clear_error(struct mail_storage *storage)
673
0
{
674
0
  i_free_and_null(storage->error_string);
675
676
0
  i_free(storage->last_internal_error);
677
0
  i_free(storage->last_internal_error_mailbox);
678
0
  storage->last_error_is_internal = FALSE;
679
0
  storage->error = MAIL_ERROR_NONE;
680
0
  storage->last_internal_error_mail_uid = UINT32_MAX;
681
0
}
682
683
void mail_storage_set_error(struct mail_storage *storage,
684
          enum mail_error error, const char *string)
685
0
{
686
0
  if (storage->error_string != string) {
687
0
    i_free(storage->error_string);
688
0
    storage->error_string = i_strdup(string);
689
0
  }
690
0
  storage->last_error_is_internal = FALSE;
691
0
  storage->error = error;
692
0
  storage->last_internal_error_mail_uid = UINT32_MAX;
693
0
}
694
695
void mail_storage_set_internal_error(struct mail_storage *storage)
696
0
{
697
0
  const char *str;
698
699
0
  str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
700
701
0
  i_free(storage->error_string);
702
0
  storage->error_string = i_strdup(str);
703
0
  storage->error = MAIL_ERROR_TEMP;
704
705
  /* this function doesn't set last_internal_error, so
706
     last_error_is_internal can't be TRUE. */
707
0
  storage->last_error_is_internal = FALSE;
708
0
  i_free(storage->last_internal_error);
709
0
  i_free(storage->last_internal_error_mailbox);
710
0
  storage->last_internal_error_mail_uid = UINT32_MAX;
711
0
}
712
713
static void
714
mail_storage_set_critical_error(struct mail_storage *storage, const char *str,
715
        const char *mailbox_vname, uint32_t mail_uid)
716
0
{
717
0
  char *old_error = storage->error_string;
718
0
  char *old_internal_error = storage->last_internal_error;
719
0
  char *old_internal_error_mailbox = storage->last_internal_error_mailbox;
720
721
0
  storage->error_string = NULL;
722
0
  storage->last_internal_error = NULL;
723
0
  storage->last_internal_error_mailbox = NULL;
724
  /* critical errors may contain sensitive data, so let user
725
     see only "Internal error" with a timestamp to make it
726
     easier to look from log files the actual error message. */
727
0
  mail_storage_set_internal_error(storage);
728
729
0
  storage->last_internal_error = i_strdup(str);
730
0
  storage->last_internal_error_mailbox = i_strdup(mailbox_vname);
731
0
  storage->last_internal_error_mail_uid = mail_uid;
732
0
  storage->last_error_is_internal = TRUE;
733
734
  /* free the old_error and old_internal_error only after the new error
735
     is generated, because they may be one of the parameters. */
736
0
  i_free(old_error);
737
0
  i_free(old_internal_error);
738
0
  i_free(old_internal_error_mailbox);
739
0
}
740
741
void mail_storage_set_critical(struct mail_storage *storage,
742
             const char *fmt, ...)
743
0
{
744
0
  va_list va;
745
746
0
  va_start(va, fmt);
747
0
  T_BEGIN {
748
0
    const char *str = t_strdup_vprintf(fmt, va);
749
0
    mail_storage_set_critical_error(storage, str, NULL, UINT32_MAX);
750
0
    e_error(storage->event, "%s", str);
751
0
  } T_END;
752
0
  va_end(va);
753
0
}
754
755
void mailbox_set_critical(struct mailbox *box, const char *fmt, ...)
756
0
{
757
0
  va_list va;
758
759
0
  va_start(va, fmt);
760
0
  T_BEGIN {
761
0
    const char *str = t_strdup_vprintf(fmt, va);
762
0
    mail_storage_set_critical_error(box->storage, str, box->vname,
763
0
            UINT32_MAX);
764
0
    e_error(box->event, "%s", str);
765
0
  } T_END;
766
0
  va_end(va);
767
0
}
768
769
void mail_set_critical(struct mail *mail, const char *fmt, ...)
770
0
{
771
0
  va_list va;
772
773
0
  va_start(va, fmt);
774
0
  T_BEGIN {
775
0
    const char *formatted_msg = t_strdup_vprintf(fmt, va);
776
0
    mail_storage_set_critical_error(mail->box->storage, formatted_msg,
777
0
            mail->box->vname, mail->uid);
778
0
    e_error(mail_event(mail), "%s", formatted_msg);
779
0
  } T_END;
780
0
  va_end(va);
781
0
}
782
783
/* Note: mail_storage_get_last_internal_error() will always include
784
   the mailbox prefix, while mailbox_get_last_internal_error() and
785
   mail_get_last_internal_error() usually will not. */
786
const char *mail_storage_get_last_internal_error(struct mail_storage *storage,
787
             enum mail_error *error_r)
788
0
{
789
0
  if (error_r != NULL)
790
0
    *error_r = storage->error;
791
0
  if (storage->last_error_is_internal) {
792
0
    i_assert(storage->last_internal_error != NULL);
793
794
0
    bool is_mailbox_error_set = storage->last_internal_error_mailbox != NULL;
795
0
    bool is_mail_error_set =
796
0
      storage->last_internal_error_mail_uid != UINT32_MAX;
797
798
0
    if (is_mail_error_set) {
799
0
      i_assert(is_mailbox_error_set);
800
0
      return t_strdup_printf(
801
0
        "Mailbox %s: UID %u: %s",
802
0
        mailbox_name_sanitize(storage->last_internal_error_mailbox),
803
0
        storage->last_internal_error_mail_uid,
804
0
        storage->last_internal_error);
805
0
    }
806
0
    if (is_mailbox_error_set)
807
0
      return t_strdup_printf(
808
0
        "Mailbox %s: %s",
809
0
        mailbox_name_sanitize(storage->last_internal_error_mailbox),
810
0
        storage->last_internal_error);
811
812
0
    return storage->last_internal_error;
813
0
  }
814
0
  return mail_storage_get_last_error(storage, error_r);
815
0
}
816
817
/* Note: mailbox_get_last_internal_error() will include the mailbox prefix only
818
   when mailbox->vname does not match last_internal_error_mailbox, which
819
   might happen with e.g. virtual mailboxes logging about physical
820
   mailboxes, while mail_storage_get_last_internal_error() always does. */
821
const char *mailbox_get_last_internal_error(struct mailbox *box,
822
              enum mail_error *error_r)
823
0
{
824
0
  struct mail_storage *storage = mailbox_get_storage(box);
825
0
  const char *last_mailbox = storage->last_internal_error_mailbox;
826
0
  if (last_mailbox != NULL &&
827
0
      strcmp(last_mailbox, box->vname) != 0)
828
0
    return mail_storage_get_last_internal_error(storage, error_r);
829
830
0
  if (error_r != NULL)
831
0
    *error_r = storage->error;
832
0
  if (storage->last_error_is_internal) {
833
0
    i_assert(storage->last_internal_error != NULL);
834
0
    if (storage->last_internal_error_mail_uid != UINT32_MAX)
835
0
      return t_strdup_printf("UID %u: %s",
836
0
                 storage->last_internal_error_mail_uid,
837
0
                 storage->last_internal_error);
838
0
    return storage->last_internal_error;
839
0
  }
840
0
  return mail_storage_get_last_error(storage, error_r);
841
0
}
842
843
/* Note: mail_get_last_internal_error() will include the mail prefix only when
844
   mail->uid does not match last_internal_error_mail_uid, while
845
   mail_storage_get_last_internal_error() always does. */
846
const char *
847
mail_get_last_internal_error(struct mail *mail, enum mail_error *error_r)
848
0
{
849
0
  struct mail_storage *storage = mailbox_get_storage(mail->box);
850
0
  const char *last_mailbox = storage->last_internal_error_mailbox;
851
0
  if (last_mailbox != NULL &&
852
0
      strcmp(last_mailbox, mail->box->vname) != 0)
853
0
    return mail_storage_get_last_internal_error(storage, error_r);
854
855
0
  uint32_t last_mail_uid = storage->last_internal_error_mail_uid;
856
0
  if (last_mail_uid == UINT32_MAX || last_mail_uid != mail->uid)
857
0
    return mailbox_get_last_internal_error(mail->box, error_r);
858
859
0
  if (error_r != NULL)
860
0
    *error_r = storage->error;
861
0
  if (storage->last_error_is_internal) {
862
0
    i_assert(storage->last_internal_error != NULL);
863
0
    return storage->last_internal_error;
864
0
  }
865
0
  return mail_storage_get_last_error(storage, error_r);
866
0
}
867
868
void mail_storage_copy_error(struct mail_storage *dest,
869
           struct mail_storage *src)
870
0
{
871
0
  const char *str;
872
0
  enum mail_error error;
873
874
0
  if (src == dest)
875
0
    return;
876
877
0
  str = mail_storage_get_last_error(src, &error);
878
0
  mail_storage_set_error(dest, error, str);
879
0
}
880
881
void mail_storage_copy_list_error(struct mail_storage *storage,
882
          struct mailbox_list *list)
883
0
{
884
0
  const char *str;
885
0
  enum mail_error error;
886
887
0
  str = mailbox_list_get_last_error(list, &error);
888
0
  mail_storage_set_error(storage, error, str);
889
0
}
890
891
void mailbox_set_index_error(struct mailbox *box)
892
0
{
893
0
  if (mail_index_is_deleted(box->index)) {
894
0
    mailbox_set_deleted(box);
895
0
    mail_index_reset_error(box->index);
896
0
  } else {
897
0
    i_free(box->storage->last_internal_error_mailbox);
898
0
    box->storage->last_internal_error_mailbox = i_strdup(box->vname);
899
0
    mail_storage_set_index_error(box->storage, box->index);
900
0
  }
901
0
}
902
903
void mail_storage_set_index_error(struct mail_storage *storage,
904
          struct mail_index *index)
905
0
{
906
0
  const char *index_error;
907
908
0
  mail_storage_set_internal_error(storage);
909
  /* use the lib-index's error as our internal error string */
910
0
  index_error = mail_index_get_last_error(index, NULL);
911
0
  if (index_error == NULL)
912
0
    index_error = "BUG: Unknown internal index error";
913
0
  storage->last_internal_error = i_strdup(index_error);
914
0
  storage->last_error_is_internal = TRUE;
915
0
  mail_index_reset_error(index);
916
0
}
917
918
const struct mail_storage_settings *
919
mail_storage_get_settings(struct mail_storage *storage)
920
0
{
921
0
  return storage->set;
922
0
}
923
924
struct mail_user *mail_storage_get_user(struct mail_storage *storage)
925
0
{
926
0
  return storage->user;
927
0
}
928
929
void mail_storage_set_callbacks(struct mail_storage *storage,
930
        struct mail_storage_callbacks *callbacks,
931
        void *context)
932
0
{
933
0
  storage->callbacks = *callbacks;
934
0
  storage->callback_context = context;
935
0
}
936
937
int mail_storage_purge(struct mail_storage *storage)
938
0
{
939
0
  if (storage->v.purge == NULL)
940
0
    return 0;
941
942
0
  int ret;
943
0
  T_BEGIN {
944
0
    ret = storage->v.purge(storage);
945
0
  } T_END;
946
0
  return ret;
947
0
}
948
949
const char *mail_storage_get_last_error(struct mail_storage *storage,
950
          enum mail_error *error_r)
951
0
{
952
  /* We get here only in error situations, so we have to return some
953
     error. If storage->error is NONE, it means we forgot to set it at
954
     some point.. */
955
0
  if (storage->error == MAIL_ERROR_NONE) {
956
0
    if (error_r != NULL)
957
0
      *error_r = MAIL_ERROR_TEMP;
958
0
    return storage->error_string != NULL ? storage->error_string :
959
0
      "BUG: Unknown internal error";
960
0
  }
961
962
0
  if (storage->error_string == NULL) {
963
    /* This shouldn't happen.. */
964
0
    storage->error_string =
965
0
      i_strdup_printf("BUG: Unknown 0x%x error",
966
0
          storage->error);
967
0
  }
968
969
0
  if (error_r != NULL)
970
0
    *error_r = storage->error;
971
0
  return storage->error_string;
972
0
}
973
974
const char *mailbox_get_last_error(struct mailbox *box,
975
           enum mail_error *error_r)
976
0
{
977
0
  return mail_storage_get_last_error(box->storage, error_r);
978
0
}
979
980
enum mail_error mailbox_get_last_mail_error(struct mailbox *box)
981
0
{
982
0
  enum mail_error error;
983
984
0
  mail_storage_get_last_error(box->storage, &error);
985
0
  return error;
986
0
}
987
988
void mail_storage_last_error_push(struct mail_storage *storage)
989
0
{
990
0
  struct mail_storage_error *err;
991
992
0
  if (!array_is_created(&storage->error_stack))
993
0
    i_array_init(&storage->error_stack, 2);
994
0
  err = array_append_space(&storage->error_stack);
995
0
  err->error_string = i_strdup(storage->error_string);
996
0
  err->error = storage->error;
997
0
  err->last_error_is_internal = storage->last_error_is_internal;
998
  /* Initially set to UINT32_MAX manually to denote 'unset', as the
999
     default 0 is used for mails currently being saved. If there is no
1000
     internal error, the attribute would not be set otherwise. */
1001
0
  err->last_internal_error_mail_uid = UINT32_MAX;
1002
0
  if (err->last_error_is_internal) {
1003
0
    err->last_internal_error = i_strdup(storage->last_internal_error);
1004
0
    err->last_internal_error_mailbox =
1005
0
      i_strdup(storage->last_internal_error_mailbox);
1006
0
    err->last_internal_error_mail_uid =
1007
0
      storage->last_internal_error_mail_uid;
1008
0
  }
1009
0
}
1010
1011
void mail_storage_last_error_pop(struct mail_storage *storage)
1012
0
{
1013
0
  unsigned int count = array_count(&storage->error_stack);
1014
0
  const struct mail_storage_error *err =
1015
0
    array_idx(&storage->error_stack, count-1);
1016
1017
0
  i_free(storage->error_string);
1018
0
  i_free(storage->last_internal_error);
1019
0
  i_free(storage->last_internal_error_mailbox);
1020
0
  storage->error_string = err->error_string;
1021
0
  storage->error = err->error;
1022
0
  storage->last_error_is_internal = err->last_error_is_internal;
1023
0
  storage->last_internal_error = err->last_internal_error;
1024
0
  storage->last_internal_error_mailbox = err->last_internal_error_mailbox;
1025
0
  storage->last_internal_error_mail_uid = err->last_internal_error_mail_uid;
1026
0
  array_delete(&storage->error_stack, count-1, 1);
1027
0
}
1028
1029
bool mail_storage_is_mailbox_file(struct mail_storage *storage)
1030
0
{
1031
0
  return (storage->class_flags &
1032
0
    MAIL_STORAGE_CLASS_FLAG_MAILBOX_IS_FILE) != 0;
1033
0
}
1034
1035
bool mail_storage_set_error_from_errno(struct mail_storage *storage)
1036
0
{
1037
0
  const char *error_string;
1038
0
  enum mail_error error;
1039
1040
0
  if (!mail_error_from_errno(&error, &error_string))
1041
0
    return FALSE;
1042
0
  if (event_want_debug_log(storage->event) && error != MAIL_ERROR_NOTFOUND) {
1043
    /* debugging is enabled - admin may be debugging a
1044
       (permission) problem, so return FALSE to get the caller to
1045
       log the full error message. */
1046
0
    return FALSE;
1047
0
  }
1048
1049
0
  mail_storage_set_error(storage, error, error_string);
1050
0
  return TRUE;
1051
0
}
1052
1053
static int
1054
mailbox_list_get_default_box_settings(struct mailbox_list *list,
1055
              const struct mailbox_settings **set_r,
1056
              const char **error_r)
1057
0
{
1058
0
  if (list->default_box_set == NULL) {
1059
0
    if (settings_get(list->event,
1060
0
         &mailbox_setting_parser_info, 0,
1061
0
         &list->default_box_set, error_r) < 0)
1062
0
      return -1;
1063
0
  }
1064
0
  pool_ref(list->default_box_set->pool);
1065
0
  *set_r = list->default_box_set;
1066
0
  return 1;
1067
0
}
1068
1069
int mailbox_name_try_get_settings(struct mailbox_list *list, const char *vname,
1070
          const struct mailbox_settings **set_r,
1071
          const char **error_r)
1072
0
{
1073
0
  if (array_is_empty(&list->ns->set->mailboxes))
1074
0
    return mailbox_list_get_default_box_settings(list, set_r, error_r);
1075
1076
0
  const char *vname_without_prefix =
1077
0
    mailbox_get_name_without_prefix(list->ns, vname);
1078
0
  unsigned int i, count;
1079
0
  const struct mailbox_settings *set = NULL, *const *mailboxes =
1080
0
    array_get(&list->ns->set->parsed_mailboxes, &count);
1081
1082
0
  for (i = 0; i < count; i++) {
1083
0
    if (!wildcard_match(vname_without_prefix, mailboxes[i]->name))
1084
0
      continue;
1085
1086
0
    if (set == NULL)
1087
0
      set = mailboxes[i];
1088
0
    else {
1089
      /* multiple mailbox named list filters match - need to
1090
         lookup settings to get them merged. */
1091
0
      return 0;
1092
0
    }
1093
0
  }
1094
0
  if (set == NULL)
1095
0
    return mailbox_list_get_default_box_settings(list, set_r, error_r);
1096
1097
0
  pool_ref(set->pool);
1098
0
  *set_r = set;
1099
0
  return 1;
1100
0
}
1101
1102
struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
1103
            enum mailbox_flags flags)
1104
0
{
1105
0
  const struct mail_storage_settings *mail_set = list->mail_set;
1106
0
  bool nfc = mail_set->mailbox_list_normalize_names_to_nfc;
1107
0
  struct mailbox_list *new_list = list;
1108
0
  struct mail_storage *storage;
1109
0
  struct mailbox *box;
1110
0
  enum mail_error open_error = 0;
1111
0
  const char *suffix, *errstr = NULL;
1112
0
  int ret;
1113
1114
0
  if (str_begins_icase(vname, "INBOX", &suffix) &&
1115
0
      !str_begins_with(vname, "INBOX")) {
1116
    /* make sure INBOX shows up in uppercase everywhere. do this
1117
       regardless of whether we're in inbox=yes namespace, because
1118
       clients expect INBOX to be case-insensitive regardless of
1119
       server's internal configuration. */
1120
0
    if (suffix[0] == '\0')
1121
0
      vname = "INBOX";
1122
0
    else if (suffix[0] != mail_namespace_get_sep(list->ns))
1123
0
      /* not INBOX prefix */ ;
1124
0
    else if (strncasecmp(list->ns->prefix, vname, 6) == 0 &&
1125
0
       !str_begins_with(list->ns->prefix, "INBOX")) {
1126
0
      mailbox_list_set_critical(list,
1127
0
        "Invalid server configuration: "
1128
0
        "Namespace %s: prefix=%s must be uppercase INBOX",
1129
0
        list->ns->set->name, list->ns->prefix);
1130
0
      open_error = MAIL_ERROR_TEMP;
1131
0
    } else {
1132
0
      vname = t_strconcat("INBOX", suffix, NULL);
1133
0
    }
1134
0
  }
1135
1136
0
  T_BEGIN {
1137
0
    const char *vname_raw = vname;
1138
0
    bool mailbox_name_changed_by_nfc = FALSE;
1139
1140
0
    if (nfc && HAS_NO_BITS(flags, MAILBOX_FLAG_RAW_NAME)) {
1141
0
      ret = uni_utf8_to_nfc(vname, strlen(vname), &vname);
1142
0
      i_assert(ret >= 0);
1143
0
      mailbox_name_changed_by_nfc =
1144
0
        (strcmp(vname_raw, vname) != 0);
1145
0
    }
1146
1147
0
    const char *error, *orig_vname = vname;
1148
0
    enum mailbox_list_get_storage_flags storage_flags = 0;
1149
0
    bool mailbox_not_original = FALSE;
1150
0
    int ret;
1151
1152
0
    if ((flags & MAILBOX_FLAG_SAVEONLY) != 0)
1153
0
      storage_flags |= MAILBOX_LIST_GET_STORAGE_FLAG_SAVEONLY;
1154
0
    if (mailbox_list_get_storage(&new_list, &vname,
1155
0
               storage_flags, &storage) < 0) {
1156
      /* do a delayed failure at mailbox_open() */
1157
0
      storage = mail_namespace_get_default_storage(list->ns);
1158
0
      errstr = mailbox_list_get_last_error(new_list, &open_error);
1159
0
      errstr = t_strdup(errstr);
1160
0
    } else if (strcmp(orig_vname, vname) != 0) {
1161
0
      mailbox_not_original = TRUE;
1162
1163
0
      vname_raw = orig_vname;
1164
0
      if (nfc && HAS_NO_BITS(flags, MAILBOX_FLAG_RAW_NAME)) {
1165
0
        ret = uni_utf8_to_nfc(vname, strlen(vname), &vname);
1166
0
        i_assert(ret >= 0);
1167
0
        mailbox_name_changed_by_nfc =
1168
0
          (strcmp(vname_raw, vname) != 0);
1169
0
      }
1170
0
    }
1171
1172
0
    if ((new_list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0 &&
1173
0
        new_list->ns->type == MAIL_NAMESPACE_TYPE_SHARED &&
1174
0
        str_begins(vname, new_list->ns->prefix, &suffix) &&
1175
0
        strcasecmp(suffix, "INBOX") == 0 &&
1176
0
        strcmp(suffix, "INBOX") != 0) {
1177
      /* Accessing INBOX explicitly in a shared namespace -
1178
         convert to uppercase. This is done regardless of the
1179
         mail_shared_explicit_inbox setting, since even with
1180
         "no" adding INBOX to the namespace prefix accesses
1181
         the same INBOX. When accessing the shared INBOX
1182
         as the namespace prefix, the uppercase INBOX is
1183
         appended when getting the storage_name in mailbox
1184
         list code. */
1185
0
      vname = t_strconcat(new_list->ns->prefix, "INBOX", NULL);
1186
0
    }
1187
1188
0
    box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
1189
0
    if (open_error != 0) {
1190
0
      box->open_error = open_error;
1191
0
      mail_storage_set_error(storage, open_error, errstr);
1192
0
    } else if ((ret = mailbox_name_try_get_settings(box->list,
1193
0
          vname, &box->set, &error)) < 0) {
1194
0
      mailbox_set_critical(box, "%s", error);
1195
0
      box->open_error = box->storage->error;
1196
0
    } else if (ret == 0) {
1197
0
      if (settings_get(box->event,
1198
0
           &mailbox_setting_parser_info, 0,
1199
0
           &box->set, &error) < 0) {
1200
0
        mailbox_set_critical(box, "%s", error);
1201
0
        box->open_error = box->storage->error;
1202
0
      }
1203
0
    }
1204
0
    if (vname_raw == vname || strcmp(vname_raw, vname) == 0)
1205
0
      box->vname_raw = box->vname;
1206
0
    else
1207
0
      box->vname_raw = p_strdup(box->pool, vname_raw);
1208
0
    box->mailbox_not_original = mailbox_not_original;
1209
0
    box->mailbox_name_changed_by_nfc = mailbox_name_changed_by_nfc;
1210
0
    hook_mailbox_allocated(box);
1211
0
  } T_END;
1212
1213
0
  DLLIST_PREPEND(&box->storage->mailboxes, box);
1214
0
  mail_storage_obj_ref(box->storage);
1215
0
  return box;
1216
0
}
1217
1218
struct mailbox *mailbox_alloc_guid(struct mailbox_list *list,
1219
           const guid_128_t guid,
1220
           enum mailbox_flags flags)
1221
0
{
1222
0
  struct mailbox *box = NULL;
1223
0
  struct mailbox_metadata metadata;
1224
0
  enum mail_error open_error = MAIL_ERROR_TEMP;
1225
0
  const char *vname;
1226
1227
0
  if (mailbox_guid_cache_find(list, guid, &vname) < 0) {
1228
0
    vname = NULL;
1229
0
  } else if (vname != NULL) {
1230
0
    box = mailbox_alloc(list, vname, flags);
1231
0
    if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID,
1232
0
           &metadata) < 0) {
1233
0
    } else if (memcmp(metadata.guid, guid,
1234
0
          sizeof(metadata.guid)) != 0) {
1235
      /* GUID mismatch, refresh cache and try again */
1236
0
      mailbox_free(&box);
1237
0
      mailbox_guid_cache_refresh(list);
1238
0
      return mailbox_alloc_guid(list, guid, flags);
1239
0
    } else {
1240
      /* successfully opened the correct mailbox */
1241
0
      return box;
1242
0
    }
1243
0
    e_error(list->event, "mailbox_alloc_guid(%s): "
1244
0
      "Couldn't verify mailbox GUID: %s",
1245
0
      guid_128_to_string(guid),
1246
0
      mailbox_get_last_internal_error(box, NULL));
1247
0
    vname = NULL;
1248
0
    mailbox_free(&box);
1249
0
  } else {
1250
0
    vname = t_strdup_printf("(nonexistent mailbox with GUID=%s)",
1251
0
          guid_128_to_string(guid));
1252
0
    open_error = MAIL_ERROR_NOTFOUND;
1253
0
  }
1254
1255
0
  if (vname == NULL) {
1256
0
    vname = t_strdup_printf("(error in mailbox with GUID=%s)",
1257
0
          guid_128_to_string(guid));
1258
0
  }
1259
0
  box = mailbox_alloc(list, vname, flags);
1260
0
  box->open_error = open_error;
1261
0
  return box;
1262
0
}
1263
1264
static bool
1265
str_contains_special_use(const char *str, const char *special_use)
1266
0
{
1267
0
  const char *const *uses;
1268
1269
0
  i_assert(special_use != NULL);
1270
0
  if (*special_use != '\\')
1271
0
    return FALSE;
1272
1273
0
  bool ret;
1274
0
  T_BEGIN {
1275
0
    uses = t_strsplit_spaces(str, " ");
1276
0
    ret = str_array_icase_find(uses, special_use);
1277
0
  } T_END;
1278
0
  return ret;
1279
0
}
1280
1281
static int
1282
namespace_find_special_use(struct mail_namespace *ns, const char *special_use,
1283
         const char **vname_r, enum mail_error *error_code_r)
1284
0
{
1285
0
  struct mailbox_list *list = ns->list;
1286
0
  struct mailbox_list_iterate_context *ctx;
1287
0
  const struct mailbox_info *info;
1288
0
  int ret = 0;
1289
1290
0
  *vname_r = NULL;
1291
0
  *error_code_r = MAIL_ERROR_NONE;
1292
1293
0
  if (!ns->set->parsed_have_special_use_mailboxes)
1294
0
    return 0;
1295
0
  if (!HAS_ALL_BITS(ns->type, MAIL_NAMESPACE_TYPE_PRIVATE))
1296
0
    return 0;
1297
1298
0
  ctx = mailbox_list_iter_init(list, "*",
1299
0
    MAILBOX_LIST_ITER_SELECT_SPECIALUSE |
1300
0
    MAILBOX_LIST_ITER_RETURN_SPECIALUSE);
1301
0
  while ((info = mailbox_list_iter_next(ctx)) != NULL) {
1302
0
    if ((info->flags &
1303
0
         (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) != 0)
1304
0
      continue;
1305
    /* iter can only return mailboxes that have non-empty
1306
       special-use */
1307
0
    i_assert(info->special_use != NULL &&
1308
0
       *info->special_use != '\0');
1309
1310
0
    if (str_contains_special_use(info->special_use, special_use)) {
1311
0
      *vname_r = t_strdup(info->vname);
1312
0
      ret = 1;
1313
0
      break;
1314
0
    }
1315
0
  }
1316
0
  if (mailbox_list_iter_deinit(&ctx) < 0) {
1317
0
    const char *error;
1318
1319
0
    error = mailbox_list_get_last_error(ns->list, error_code_r);
1320
0
    e_error(ns->list->event,
1321
0
      "Namespace %s: Failed to find mailbox with SPECIAL-USE flag '%s': %s",
1322
0
      ns->set->name, special_use, error);
1323
0
    return -1;
1324
0
  }
1325
0
  return ret;
1326
0
}
1327
1328
static int
1329
namespaces_find_special_use(struct mail_namespace *namespaces,
1330
          const char *special_use,
1331
          struct mail_namespace **ns_r,
1332
          const char **vname_r, enum mail_error *error_code_r)
1333
0
{
1334
0
  struct mail_namespace *ns_inbox;
1335
0
  int ret;
1336
1337
0
  *error_code_r = MAIL_ERROR_NONE;
1338
0
  *vname_r = NULL;
1339
1340
  /* check user's INBOX namespace first */
1341
0
  *ns_r = ns_inbox = mail_namespace_find_inbox(namespaces);
1342
0
  ret = namespace_find_special_use(*ns_r, special_use,
1343
0
           vname_r, error_code_r);
1344
0
  if (ret != 0)
1345
0
    return ret;
1346
1347
  /* check other namespaces */
1348
0
  for (*ns_r = namespaces; *ns_r != NULL; *ns_r = (*ns_r)->next) {
1349
0
    if (*ns_r == ns_inbox) {
1350
      /* already checked */
1351
0
      continue;
1352
0
    }
1353
0
    ret = namespace_find_special_use(*ns_r, special_use,
1354
0
             vname_r, error_code_r);
1355
0
    if (ret != 0)
1356
0
      return ret;
1357
0
  }
1358
1359
0
  *ns_r = ns_inbox;
1360
0
  return 0;
1361
0
}
1362
1363
struct mailbox *
1364
mailbox_alloc_for_user(struct mail_user *user, const char *mname,
1365
           enum mailbox_flags flags)
1366
0
{
1367
0
  struct mail_namespace *ns;
1368
0
  struct mailbox *box;
1369
0
  const char *vname;
1370
0
  enum mail_error open_error = MAIL_ERROR_NONE;
1371
0
  int ret;
1372
1373
0
  if (HAS_ALL_BITS(flags, MAILBOX_FLAG_SPECIAL_USE)) {
1374
0
    ret = namespaces_find_special_use(user->namespaces, mname,
1375
0
              &ns, &vname, &open_error);
1376
0
    if (ret < 0) {
1377
0
      i_assert(open_error != MAIL_ERROR_NONE);
1378
0
      vname = t_strdup_printf(
1379
0
        "(error finding mailbox with SPECIAL-USE=%s)",
1380
0
        mname);
1381
0
    } else if (ret == 0) {
1382
0
      i_assert(open_error == MAIL_ERROR_NONE);
1383
0
      vname = t_strdup_printf(
1384
0
        "(nonexistent mailbox with SPECIAL-USE=%s)",
1385
0
        mname);
1386
0
      open_error = MAIL_ERROR_NOTFOUND;
1387
0
    }
1388
0
  } else {
1389
0
    vname = mname;
1390
0
    ns = mail_namespace_find(user->namespaces, mname);
1391
0
  }
1392
1393
0
  if (HAS_ALL_BITS(flags, MAILBOX_FLAG_POST_SESSION)) {
1394
0
    flags |= MAILBOX_FLAG_SAVEONLY;
1395
1396
0
    if (strcmp(vname, ns->prefix) == 0 &&
1397
0
        (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
1398
      /* delivering to a namespace prefix means we actually
1399
         want to deliver to the INBOX instead */
1400
0
      vname = "INBOX";
1401
0
      ns = mail_namespace_find_inbox(user->namespaces);
1402
0
    }
1403
1404
0
    if (strcasecmp(vname, "INBOX") == 0) {
1405
      /* deliveries to INBOX must always succeed,
1406
         regardless of ACLs */
1407
0
      flags |= MAILBOX_FLAG_IGNORE_ACLS;
1408
0
    }
1409
0
  }
1410
1411
0
  i_assert(ns != NULL);
1412
0
  box = mailbox_alloc(ns->list, vname, flags);
1413
0
  if (open_error != MAIL_ERROR_NONE)
1414
0
    box->open_error = open_error;
1415
0
  return box;
1416
0
}
1417
1418
bool mailbox_is_autocreated(struct mailbox *box)
1419
0
{
1420
0
  if (box->inbox_user)
1421
0
    return TRUE;
1422
0
  if ((box->flags & MAILBOX_FLAG_AUTO_CREATE) != 0)
1423
0
    return TRUE;
1424
0
  return box->set != NULL &&
1425
0
    strcmp(box->set->autocreate, MAILBOX_SET_AUTO_NO) != 0;
1426
0
}
1427
1428
bool mailbox_is_autosubscribed(struct mailbox *box)
1429
0
{
1430
0
  if ((box->flags & MAILBOX_FLAG_AUTO_SUBSCRIBE) != 0)
1431
0
    return TRUE;
1432
0
  return box->set != NULL &&
1433
0
    strcmp(box->set->autocreate, MAILBOX_SET_AUTO_SUBSCRIBE) == 0;
1434
0
}
1435
1436
static int mailbox_autocreate(struct mailbox *box)
1437
0
{
1438
0
  const char *errstr;
1439
0
  enum mail_error error;
1440
1441
0
  if (mailbox_create(box, NULL, FALSE) < 0) {
1442
0
    errstr = mailbox_get_last_internal_error(box, &error);
1443
0
    if (error == MAIL_ERROR_NOTFOUND && box->acl_no_lookup_right) {
1444
      /* ACL prevents creating this mailbox */
1445
0
      return -1;
1446
0
    }
1447
0
    if (error != MAIL_ERROR_EXISTS) {
1448
0
      mailbox_set_critical(box,
1449
0
        "Failed to autocreate mailbox: %s",
1450
0
        errstr);
1451
0
      return -1;
1452
0
    }
1453
0
  } else if (mailbox_is_autosubscribed(box)) {
1454
0
    if (mailbox_set_subscribed(box, TRUE) < 0) {
1455
0
      mailbox_set_critical(box,
1456
0
        "Failed to autosubscribe to mailbox: %s",
1457
0
        mailbox_get_last_internal_error(box, NULL));
1458
0
      return -1;
1459
0
    }
1460
0
  }
1461
0
  return 0;
1462
0
}
1463
1464
static int mailbox_autocreate_and_reopen(struct mailbox *box)
1465
0
{
1466
0
  int ret;
1467
1468
0
  if (mailbox_autocreate(box) < 0)
1469
0
    return -1;
1470
0
  mailbox_close(box);
1471
1472
0
  ret = box->v.open(box);
1473
0
  if (ret < 0 && box->inbox_user && !box->acl_no_lookup_right &&
1474
0
      !box->storage->user->inbox_open_error_logged) {
1475
0
    box->storage->user->inbox_open_error_logged = TRUE;
1476
0
    mailbox_set_critical(box,
1477
0
      "Opening INBOX failed: %s",
1478
0
      mailbox_get_last_internal_error(box, NULL));
1479
0
  }
1480
0
  return ret;
1481
0
}
1482
1483
static void
1484
mailbox_vname_normalize_ns_prefix_nfc(struct mailbox_list *list,
1485
              const char **vname)
1486
0
{
1487
0
  struct mail_namespace *ns = list->ns;
1488
1489
0
  if (*ns->prefix == '\0')
1490
0
    return;
1491
1492
  /* Find the prefix in the raw name by splitting it at the expected
1493
     separator. */
1494
1495
0
  char sep = mail_namespace_get_sep(ns);
1496
0
  int seps_in_ns_prefix = 0;
1497
0
  const char *p = ns->prefix, *p_sep;
1498
1499
0
  while ((p = strchr(p, sep)) != NULL) {
1500
0
    seps_in_ns_prefix++;
1501
0
    p++;
1502
0
  }
1503
1504
0
  p = *vname;
1505
0
  while ((p_sep = strchr(p, sep)) != NULL && seps_in_ns_prefix > 0) {
1506
0
    seps_in_ns_prefix--;
1507
0
    p = p_sep + 1;
1508
0
  }
1509
0
  i_assert(seps_in_ns_prefix == 0);
1510
1511
  /* Normalize the prefix */
1512
1513
0
  string_t *str = t_str_new(128);
1514
0
  int ret;
1515
1516
0
  ret = uni_utf8_write_nfc(*vname, p - *vname, str);
1517
0
  i_assert(ret >= 0);
1518
0
  str_append(str, p);
1519
1520
0
  *vname = str_c(str);
1521
0
}
1522
1523
bool mailbox_was_vname_changed_by_nfc(struct mailbox *box,
1524
              const char **orig_vname_r)
1525
0
{
1526
0
  if (!box->mailbox_name_changed_by_nfc)
1527
0
    return FALSE;
1528
0
  if (orig_vname_r != NULL)
1529
0
    *orig_vname_r = box->vname_raw;
1530
0
  return TRUE;
1531
0
}
1532
1533
void mailbox_suppress_nfc_name_change_notification(struct mailbox *box)
1534
0
{
1535
0
  box->notifying_nfc_name_change = TRUE;
1536
0
}
1537
1538
int mailbox_rename_nfc_forced(struct mailbox_list *list, const char *vname_raw,
1539
            const char *vname_nfc, const char **vname_new_r,
1540
            const char **error_r)
1541
0
{
1542
0
  struct mailbox *box_old, *box_new;
1543
0
  int ret;
1544
1545
0
  mailbox_vname_normalize_ns_prefix_nfc(list, &vname_raw);
1546
0
  *vname_new_r = vname_nfc;
1547
0
  if (strcmp(vname_raw, vname_nfc) == 0) {
1548
    /* Only namespace prefix was not NFC */
1549
0
    return 0;
1550
0
  }
1551
0
  box_old = mailbox_alloc(list, vname_raw, (MAILBOX_FLAG_RAW_NAME |
1552
0
              MAILBOX_FLAG_IGNORE_ACLS));
1553
0
  box_old->notifying_nfc_name_change = TRUE;
1554
0
  box_new = mailbox_alloc(list, vname_nfc, MAILBOX_FLAG_RAW_NAME);
1555
0
  box_new->skip_create_name_restrictions = TRUE;
1556
0
  box_new->notifying_nfc_name_change = TRUE;
1557
1558
0
  ret = mailbox_rename(box_old, box_new);
1559
0
  if (ret < 0 &&
1560
0
      mailbox_get_last_mail_error(box_old) == MAIL_ERROR_NOTFOUND) {
1561
    /* ignore */
1562
0
    ret = 0;
1563
0
  } else if (ret < 0 &&
1564
0
       mailbox_get_last_mail_error(box_old) == MAIL_ERROR_EXISTS) {
1565
    /* generate a new unique name */
1566
0
    guid_128_t guid;
1567
0
    guid_128_generate(guid);
1568
1569
0
    *vname_new_r = t_strdup_printf("%s-%s", vname_nfc,
1570
0
                 guid_128_to_string(guid));
1571
0
    mailbox_free(&box_new);
1572
0
    box_new = mailbox_alloc(list, *vname_new_r, 0);
1573
0
    ret = mailbox_rename(box_old, box_new);
1574
0
  }
1575
0
  if (ret < 0)
1576
0
    *error_r = mailbox_get_last_error(box_old, NULL);
1577
0
  mailbox_free(&box_old);
1578
0
  mailbox_free(&box_new);
1579
1580
0
  return (ret == 0 ? 1 : ret);
1581
0
}
1582
1583
static int mailbox_nfc_normalize(struct mailbox *box)
1584
0
{
1585
0
  const char *vname, *error;
1586
0
  int ret;
1587
1588
0
  ret = mailbox_rename_nfc_forced(box->list, box->vname_raw, box->vname,
1589
0
          &vname, &error);
1590
0
  if (ret < 0) {
1591
0
    mailbox_set_critical(box,
1592
0
      "Failed to rename mailbox for NFC normalization: %s",
1593
0
      error);
1594
0
    return -1;
1595
0
  }
1596
0
  if (ret == 0)
1597
0
    return 0;
1598
0
  if (strcmp(box->vname, vname) == 0) {
1599
0
    e_debug(box->event, "Mailbox renamed for NFC normalization");
1600
0
  } else {
1601
0
    box->vname = p_strdup(box->pool, vname);
1602
0
    e_debug(box->event,
1603
0
      "Mailbox renamed to %s for NFC normalization "
1604
0
      "(mailbox with NFC normalized name existed already)",
1605
0
      box->vname);
1606
0
  }
1607
0
  return 1;
1608
0
}
1609
1610
static bool
1611
mailbox_name_verify_extra_separators(const char *vname, char sep,
1612
             const char **error_r)
1613
0
{
1614
0
  unsigned int i;
1615
0
  bool prev_sep = FALSE;
1616
1617
  /* Make sure the vname doesn't have extra separators:
1618
1619
     1) Must not have adjacent separators. If we allow these, these could
1620
     end up pointing to existing mailboxes due to kernel ignoring
1621
     duplicate '/' in paths. However, this might cause us to handle some
1622
     of our own checks wrong, such as skipping ACLs.
1623
1624
     2) Must not end with separator. Similar reasoning as above.
1625
  */
1626
0
  for (i = 0; vname[i] != '\0'; i++) {
1627
0
    if (vname[i] == sep) {
1628
0
      if (prev_sep) {
1629
0
        *error_r = "Has adjacent hierarchy separators";
1630
0
        return FALSE;
1631
0
      }
1632
0
      prev_sep = TRUE;
1633
0
    } else {
1634
0
      prev_sep = FALSE;
1635
0
    }
1636
0
  }
1637
0
  if (prev_sep && i > 0) {
1638
0
    *error_r = "Ends with hierarchy separator";
1639
0
    return FALSE;
1640
0
  }
1641
0
  return TRUE;
1642
0
}
1643
1644
static bool
1645
mailbox_verify_name_prefix(struct mail_namespace *ns, const char **vnamep,
1646
         const char **error_r)
1647
0
{
1648
0
  const char *vname = *vnamep;
1649
1650
0
  if (ns->prefix_len == 0)
1651
0
    return TRUE;
1652
1653
  /* vname is either "namespace/box" or "namespace" */
1654
0
  if (strncmp(vname, ns->prefix, ns->prefix_len-1) != 0 ||
1655
0
      (vname[ns->prefix_len-1] != '\0' &&
1656
0
       vname[ns->prefix_len-1] != ns->prefix[ns->prefix_len-1])) {
1657
    /* User input shouldn't normally be able to get us in
1658
       here. The main reason this isn't an assert is to
1659
       allow any input at all to mailbox_verify_*_name()
1660
       without crashing. */
1661
0
    *error_r = t_strdup_printf("Missing namespace prefix '%s'",
1662
0
             ns->prefix);
1663
0
    return FALSE;
1664
0
  }
1665
0
  vname += ns->prefix_len - 1;
1666
0
  if (vname[0] != '\0') {
1667
0
    i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
1668
0
    vname++;
1669
1670
0
    if (vname[0] == '\0') {
1671
      /* "namespace/" isn't a valid mailbox name. */
1672
0
      *error_r = "Ends with hierarchy separator";
1673
0
      return FALSE;
1674
0
    }
1675
0
  }
1676
0
  *vnamep = vname;
1677
0
  return TRUE;
1678
0
}
1679
1680
static int mailbox_verify_name_int(struct mailbox *box)
1681
0
{
1682
0
  struct mail_namespace *ns = box->list->ns;
1683
0
  const char *error, *vname = box->vname;
1684
0
  char list_sep, ns_sep;
1685
1686
0
  if (box->inbox_user) {
1687
    /* this is INBOX - don't bother with further checks */
1688
0
    return 0;
1689
0
  }
1690
1691
  /* Verify the namespace prefix here. Change vname to skip the prefix
1692
     for the following checks. */
1693
0
  if (!mailbox_verify_name_prefix(box->list->ns, &vname, &error)) {
1694
0
    mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
1695
0
      t_strdup_printf("Invalid mailbox name '%s': %s",
1696
0
          mailbox_name_sanitize(vname), error));
1697
0
    return -1;
1698
0
  }
1699
1700
0
  list_sep = mailbox_list_get_hierarchy_sep(box->list);
1701
0
  ns_sep = mail_namespace_get_sep(ns);
1702
1703
  /* If namespace { separator } differs from the mailbox_list separator,
1704
     the list separator can't actually be used in the mailbox name
1705
     unless it's escaped with storage_name_escape_char. For example if
1706
     namespace separator is '/' and mailbox_list_layout=Maildir++ has '.'
1707
     as the separator, there's no way to use '.' in the mailbox name
1708
     (without escaping) because it would end up becoming a hierarchy
1709
     separator. */
1710
0
  if (ns_sep != list_sep &&
1711
0
      box->list->mail_set->mailbox_list_storage_escape_char[0] == '\0' &&
1712
0
      strchr(vname, list_sep) != NULL) {
1713
0
    mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, t_strdup_printf(
1714
0
      "Character not allowed in mailbox name: '%c'", list_sep));
1715
0
    return -1;
1716
0
  }
1717
  /* vname must not begin with the hierarchy separator normally.
1718
     For example we don't want to allow accessing /etc/passwd. However,
1719
     if mail_full_filesystem_access=yes, we do actually want to allow
1720
     that. */
1721
0
  if (vname[0] == ns_sep &&
1722
0
      !box->storage->set->mail_full_filesystem_access) {
1723
0
    mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
1724
0
      "Invalid mailbox name: Begins with hierarchy separator");
1725
0
    return -1;
1726
0
  }
1727
1728
0
  if (!mailbox_name_verify_extra_separators(vname, ns_sep, &error) ||
1729
0
      !mailbox_list_is_valid_name(box->list, box->name, &error)) {
1730
0
    mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
1731
0
      t_strdup_printf("Invalid mailbox name: %s", error));
1732
0
    return -1;
1733
0
  }
1734
0
  return 0;
1735
0
}
1736
1737
int mailbox_verify_name(struct mailbox *box)
1738
0
{
1739
0
  int ret;
1740
0
  T_BEGIN {
1741
0
    ret = mailbox_verify_name_int(box);
1742
0
  } T_END;
1743
0
  return ret;
1744
0
}
1745
1746
static int mailbox_verify_existing_name_int(struct mailbox *box)
1747
0
{
1748
0
  const char *path;
1749
1750
0
  if (box->opened)
1751
0
    return 0;
1752
1753
0
  if (mailbox_verify_name(box) < 0)
1754
0
    return -1;
1755
1756
  /* Make sure box->_path is set, so mailbox_get_path() works from
1757
     now on. Note that this may also fail with some backends if the
1758
     mailbox doesn't exist. */
1759
0
  int ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path);
1760
0
  if (ret < 0 && box->storage->error == MAIL_ERROR_NOTFOUND &&
1761
0
      box->mailbox_name_changed_by_nfc) {
1762
0
    ret = mailbox_nfc_normalize(box);
1763
0
    if (ret == 0) {
1764
0
      i_assert(box->storage->error == MAIL_ERROR_NOTFOUND);
1765
0
      ret = -1;
1766
0
    } else {
1767
0
      ret = mailbox_get_path_to(box,
1768
0
        MAILBOX_LIST_PATH_TYPE_MAILBOX, &path);
1769
0
    }
1770
0
  }
1771
1772
0
  if (ret < 0) {
1773
0
    if (box->storage->error != MAIL_ERROR_NOTFOUND ||
1774
0
        !mailbox_is_autocreated(box))
1775
0
      return -1;
1776
    /* if this is an autocreated mailbox, create it now */
1777
0
    if (mailbox_autocreate(box) < 0)
1778
0
      return -1;
1779
0
    mailbox_close(box);
1780
0
    if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
1781
0
          &path) < 0)
1782
0
      return -1;
1783
0
  }
1784
0
  return 0;
1785
0
}
1786
1787
static int mailbox_verify_existing_name(struct mailbox *box)
1788
0
{
1789
0
  int ret;
1790
0
  T_BEGIN {
1791
0
    ret = mailbox_verify_existing_name_int(box);
1792
0
  } T_END;
1793
0
  return ret;
1794
0
}
1795
1796
static int
1797
mailbox_name_check_forbidden_chars(const char *name, const char **error_r)
1798
0
{
1799
0
  const unsigned char *input = (const unsigned char *)name;
1800
0
  size_t size = strlen(name);
1801
1802
  /* RFC 9755, Section 3:
1803
1804
     Mailbox names MUST comply with the Net-Unicode Definition ([RFC5198],
1805
     Section 2) with the specific exception that they MUST NOT contain
1806
     control characters (U+0000 - U+001F and U+0080 - U+009F), a delete
1807
     character (U+007F), a line separator (U+2028), or a paragraph
1808
     separator (U+2029).
1809
1810
     RFC 5198, Section 2:
1811
1812
     5.  As suggested in Section 6 of RFC 3629, the Byte Order Mark
1813
         ("BOM") signature MUST NOT appear at the beginning of these text
1814
         strings.
1815
1816
     6.  Systems conforming to this specification MUST NOT transmit any
1817
         string containing any code point that is unassigned in the
1818
         version of Unicode on which they are dependent.  The version of
1819
         NFC and the version of Unicode used by that system MUST be
1820
         consistent.
1821
   */
1822
1823
0
  while (size > 0) {
1824
0
    unichar_t chr;
1825
0
    int bytes;
1826
1827
0
    bytes = uni_utf8_get_char_n(input, size, &chr);
1828
0
    i_assert(bytes > 0); /* UTF8 already checked */
1829
0
    input += bytes;
1830
0
    size -= bytes;
1831
1832
0
    if (chr <= 0x1f || chr == 0x7f ||
1833
0
        (chr >= 0x0080 && chr <= 0x009f) ||
1834
0
        chr == 0x2028 || chr == 0x2029 || chr == 0xFEFF ||
1835
0
        !unicode_code_point_is_assigned(chr)) {
1836
0
      *error_r = t_strdup_printf(
1837
0
        "New mailbox name contains forbidden character "
1838
0
        "(U+%04X)", chr);
1839
0
      return -1;
1840
0
    }
1841
0
  }
1842
0
  return 0;
1843
0
}
1844
1845
void mailbox_skip_create_name_restrictions(struct mailbox *box, bool set)
1846
0
{
1847
0
  box->skip_create_name_restrictions = set;
1848
0
}
1849
1850
int mailbox_verify_create_name(struct mailbox *box)
1851
0
{
1852
0
  const char *error;
1853
1854
  /* mailbox_alloc() already checks that vname is valid UTF8,
1855
     so we don't need to verify that.
1856
1857
     check vname instead of storage name, because vname is what is
1858
     visible to users, while storage name may be a fixed length GUID. */
1859
0
  if (mailbox_verify_name(box) < 0)
1860
0
    return -1;
1861
0
  if (box->skip_create_name_restrictions)
1862
0
    return 0;
1863
0
  if (mailbox_name_check_forbidden_chars(box->vname, &error) < 0) {
1864
0
    mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS, error);
1865
0
    return -1;
1866
0
  }
1867
0
  if (strlen(box->vname) > MAILBOX_LIST_NAME_MAX_LENGTH) {
1868
0
    mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
1869
0
               "Mailbox name too long");
1870
0
    return -1;
1871
0
  }
1872
  /* check individual component names, too */
1873
0
  const char *old_name = box->name;
1874
0
  const char *name;
1875
0
  const char sep = mailbox_list_get_hierarchy_sep(box->list);
1876
0
  while((name = strchr(old_name, sep)) != NULL) {
1877
0
    if (name - old_name > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
1878
0
      mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
1879
0
        "Mailbox name too long");
1880
0
      return -1;
1881
0
    }
1882
0
    name++;
1883
0
    old_name = name;
1884
0
  }
1885
0
  if (strlen(old_name) > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
1886
0
    mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
1887
0
               "Mailbox name too long");
1888
0
    return -1;
1889
0
  }
1890
0
  return 0;
1891
0
}
1892
1893
static bool have_listable_namespace_prefix(struct mail_namespace *ns,
1894
             const char *name)
1895
0
{
1896
0
  size_t name_len = strlen(name);
1897
1898
0
  for (; ns != NULL; ns = ns->next) {
1899
0
    if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
1900
0
          NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
1901
0
      continue;
1902
1903
0
    if (ns->prefix_len <= name_len)
1904
0
      continue;
1905
1906
    /* if prefix has multiple hierarchies, match
1907
       any of the hierarchies */
1908
0
    if (strncmp(ns->prefix, name, name_len) == 0 &&
1909
0
        ns->prefix[name_len] == mail_namespace_get_sep(ns))
1910
0
      return TRUE;
1911
0
  }
1912
0
  return FALSE;
1913
0
}
1914
1915
int mailbox_exists(struct mailbox *box, bool auto_boxes,
1916
       enum mailbox_existence *existence_r)
1917
0
{
1918
0
  switch (box->open_error) {
1919
0
  case 0:
1920
0
    break;
1921
0
  case MAIL_ERROR_NOTFOUND:
1922
0
    *existence_r = MAILBOX_EXISTENCE_NONE;
1923
0
    return 0;
1924
0
  default:
1925
    /* unsure if this exists or not */
1926
0
    return -1;
1927
0
  }
1928
0
  if (mailbox_verify_name(box) < 0) {
1929
    /* the mailbox name is invalid. we don't know if it currently
1930
       exists or not, but since it can never be accessed in any way
1931
       report it as if it didn't exist. */
1932
0
    *existence_r = MAILBOX_EXISTENCE_NONE;
1933
0
    return 0;
1934
0
  }
1935
1936
0
  int ret;
1937
0
  T_BEGIN {
1938
0
    ret = box->v.exists(box, auto_boxes, existence_r);
1939
0
  } T_END;
1940
0
  if (ret == 0 && *existence_r == MAILBOX_EXISTENCE_NONE &&
1941
0
      box->mailbox_name_changed_by_nfc) {
1942
0
    const char *nfc_vname = box->vname;
1943
0
    box->vname = box->vname_raw;
1944
0
    T_BEGIN {
1945
0
      ret = box->v.exists(box, auto_boxes, existence_r);
1946
0
    } T_END;
1947
0
    box->vname = nfc_vname;
1948
0
  }
1949
0
  if (ret < 0)
1950
0
    return -1;
1951
1952
0
  if (!box->inbox_user && *existence_r == MAILBOX_EXISTENCE_NOSELECT &&
1953
0
      have_listable_namespace_prefix(box->storage->user->namespaces,
1954
0
             box->vname)) {
1955
         /* listable namespace prefix always exists. */
1956
0
    *existence_r = MAILBOX_EXISTENCE_NOSELECT;
1957
0
    return 0;
1958
0
  }
1959
1960
  /* if this is a shared namespace with only INBOX and
1961
     mail_shared_explicit_inbox=no, we'll need to mark the namespace as
1962
     usable here since nothing else will. */
1963
0
  box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
1964
0
  return 0;
1965
0
}
1966
1967
static int ATTR_NULL(2)
1968
mailbox_open_full(struct mailbox *box, struct istream *input)
1969
0
{
1970
0
  struct mail_storage *storage = box->storage;
1971
0
  bool notifying_nfc_name_change = box->notifying_nfc_name_change;
1972
0
  int ret;
1973
1974
0
  if (box->opened)
1975
0
    return 0;
1976
1977
0
  switch (box->open_error) {
1978
0
  case 0:
1979
0
    e_debug(box->event, "Mailbox opened");
1980
0
    break;
1981
0
  case MAIL_ERROR_NOTFOUND:
1982
0
    mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
1983
0
      T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
1984
0
    return -1;
1985
0
  default:
1986
0
    mail_storage_set_internal_error(storage);
1987
0
    storage->error = box->open_error;
1988
0
    return -1;
1989
0
  }
1990
1991
0
  ret = mailbox_verify_existing_name(box);
1992
0
  if (ret < 0 && storage->error == MAIL_ERROR_NOTFOUND &&
1993
0
      box->mailbox_name_changed_by_nfc) {
1994
0
    ret = mailbox_nfc_normalize(box);
1995
0
    if (ret == 0) {
1996
0
      i_assert(storage->error == MAIL_ERROR_NOTFOUND);
1997
0
      ret = -1;
1998
0
    }
1999
0
  }
2000
0
  if (ret < 0)
2001
0
    return -1;
2002
2003
0
  if (input != NULL) {
2004
0
    if ((storage->class_flags &
2005
0
         MAIL_STORAGE_CLASS_FLAG_OPEN_STREAMS) == 0) {
2006
0
      mailbox_set_critical(box,
2007
0
        "Storage doesn't support streamed mailboxes");
2008
0
      return -1;
2009
0
    }
2010
0
    box->input = input;
2011
0
    box->flags |= MAILBOX_FLAG_READONLY;
2012
0
    i_stream_ref(box->input);
2013
0
  }
2014
2015
0
  box->notifying_nfc_name_change = TRUE;
2016
0
  ret = box->v.open(box);
2017
0
  if (ret < 0 && storage->error == MAIL_ERROR_NOTFOUND &&
2018
0
      box->mailbox_name_changed_by_nfc) {
2019
0
    ret = mailbox_nfc_normalize(box);
2020
0
    if (ret == 0) {
2021
0
      i_assert(storage->error == MAIL_ERROR_NOTFOUND);
2022
0
      ret = -1;
2023
0
    }
2024
0
    if (ret > 0) {
2025
0
      mailbox_close(box);
2026
0
      ret = box->v.open(box);
2027
0
    }
2028
0
  }
2029
0
  if (ret < 0 && storage->error == MAIL_ERROR_NOTFOUND &&
2030
0
      !box->deleting && !box->creating &&
2031
0
      box->input == NULL && mailbox_is_autocreated(box)) T_BEGIN {
2032
0
    ret = mailbox_autocreate_and_reopen(box);
2033
0
  } T_END;
2034
2035
0
  if (ret < 0) {
2036
0
    if (box->input != NULL)
2037
0
      i_stream_unref(&box->input);
2038
0
    box->notifying_nfc_name_change = notifying_nfc_name_change;
2039
0
    return -1;
2040
0
  }
2041
2042
  /* Always notify an NFC normalization rename, even when the physical
2043
     rename happened in the past. */
2044
0
  if (!notifying_nfc_name_change && box->mailbox_name_changed_by_nfc &&
2045
0
      storage->callbacks.notify_mailbox_implicit_rename != NULL) {
2046
0
    storage->callbacks.notify_mailbox_implicit_rename(
2047
0
      box, box->vname_raw, storage->callback_context);
2048
0
  }
2049
2050
0
  box->notifying_nfc_name_change = notifying_nfc_name_change;
2051
0
  box->list->ns->flags |= NAMESPACE_FLAG_USABLE;
2052
0
  return 0;
2053
0
}
2054
2055
static bool mailbox_try_undelete(struct mailbox *box)
2056
0
{
2057
0
  time_t mtime;
2058
2059
0
  i_assert(!box->mailbox_undeleting);
2060
2061
0
  if ((box->flags & MAILBOX_FLAG_READONLY) != 0) {
2062
    /* most importantly we don't do this because we want to avoid
2063
       a loop: mdbox storage rebuild -> mailbox_open() ->
2064
       mailbox_mark_index_deleted() -> mailbox_sync() ->
2065
       mdbox storage rebuild. */
2066
0
    return FALSE;
2067
0
  }
2068
0
  if (box->index == NULL) {
2069
    /* mailbox_open() failed before the index was opened (e.g. the
2070
       backend's delete failed and we're reverting the deletion).
2071
       There's nothing to undelete. */
2072
0
    return FALSE;
2073
0
  }
2074
0
  if (mail_index_get_modification_time(box->index, &mtime) < 0)
2075
0
    return FALSE;
2076
0
  if (mtime + MAILBOX_DELETE_RETRY_SECS > time(NULL))
2077
0
    return FALSE;
2078
2079
0
  box->mailbox_undeleting = TRUE;
2080
0
  int ret = mailbox_mark_index_deleted(box, FALSE);
2081
0
  box->mailbox_undeleting = FALSE;
2082
0
  if (ret < 0)
2083
0
    return FALSE;
2084
0
  box->mailbox_deleted = FALSE;
2085
0
  return TRUE;
2086
0
}
2087
2088
int mailbox_open(struct mailbox *box)
2089
0
{
2090
0
  int ret;
2091
2092
0
  T_BEGIN {
2093
0
    ret = mailbox_open_full(box, NULL);
2094
0
  } T_END;
2095
0
  if (ret < 0) {
2096
0
    if (!box->mailbox_deleted || box->mailbox_undeleting)
2097
0
      return -1;
2098
2099
    /* mailbox has been marked as deleted. if this deletion
2100
       started (and crashed) a long time ago, it can be confusing
2101
       to user that the mailbox can't be opened. so we'll just
2102
       undelete it and reopen. */
2103
0
    if(!mailbox_try_undelete(box))
2104
0
      return -1;
2105
2106
    /* make sure we close the mailbox in the middle. some backends
2107
       may not have fully opened the mailbox while it was being
2108
       undeleted. */
2109
0
    mailbox_close(box);
2110
0
    T_BEGIN {
2111
0
      ret = mailbox_open_full(box, NULL);
2112
0
    } T_END;
2113
0
    if (ret < 0)
2114
0
      return -1;
2115
0
  }
2116
0
  return 0;
2117
0
}
2118
2119
static int mailbox_alloc_index_pvt(struct mailbox *box)
2120
0
{
2121
0
  const char *index_dir;
2122
0
  int ret;
2123
2124
0
  if (box->index_pvt != NULL)
2125
0
    return 1;
2126
2127
0
  ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE,
2128
0
          &index_dir);
2129
0
  if (ret <= 0)
2130
0
    return ret; /* error / no private indexes */
2131
2132
0
  if (mailbox_create_missing_dir(box, MAILBOX_LIST_PATH_TYPE_INDEX_PRIVATE) < 0)
2133
0
    return -1;
2134
2135
  /* Note that this may cause box->event to live longer than box */
2136
0
  box->index_pvt = mail_index_alloc_cache_get(box->event,
2137
0
    NULL, index_dir, t_strconcat(box->index_prefix, ".pvt", NULL));
2138
0
  mail_index_set_fsync_mode(box->index_pvt,
2139
0
          box->storage->set->parsed_fsync_mode, 0);
2140
0
  mail_index_set_lock_method(box->index_pvt,
2141
0
    box->storage->set->parsed_lock_method,
2142
0
    mail_storage_get_lock_timeout(box->storage, UINT_MAX));
2143
0
  return 1;
2144
0
}
2145
2146
int mailbox_open_index_pvt(struct mailbox *box)
2147
0
{
2148
0
  enum mail_index_open_flags index_flags;
2149
0
  int ret;
2150
2151
0
  if (box->view_pvt != NULL)
2152
0
    return 1;
2153
0
  if (mailbox_get_private_flags_mask(box) == 0)
2154
0
    return 0;
2155
2156
0
  if ((ret = mailbox_alloc_index_pvt(box)) <= 0)
2157
0
    return ret;
2158
0
  index_flags = MAIL_INDEX_OPEN_FLAG_CREATE |
2159
0
    mail_storage_settings_to_index_flags(box->storage->set);
2160
0
  if ((box->flags & MAILBOX_FLAG_SAVEONLY) != 0)
2161
0
    index_flags |= MAIL_INDEX_OPEN_FLAG_SAVEONLY;
2162
0
  if (mail_index_open(box->index_pvt, index_flags) < 0)
2163
0
    return -1;
2164
0
  box->view_pvt = mail_index_view_open(box->index_pvt);
2165
0
  return 1;
2166
0
}
2167
2168
int mailbox_open_stream(struct mailbox *box, struct istream *input)
2169
0
{
2170
0
  return mailbox_open_full(box, input);
2171
0
}
2172
2173
int mailbox_enable(struct mailbox *box, enum mailbox_feature features)
2174
0
{
2175
0
  if (mailbox_verify_name(box) < 0)
2176
0
    return -1;
2177
2178
0
  int ret;
2179
0
  T_BEGIN {
2180
0
    ret = box->v.enable(box, features);
2181
0
  } T_END;
2182
0
  return ret;
2183
0
}
2184
2185
enum mailbox_feature mailbox_get_enabled_features(struct mailbox *box)
2186
0
{
2187
0
  return box->enabled_features;
2188
0
}
2189
2190
void mail_storage_free_binary_cache(struct mail_storage *storage)
2191
0
{
2192
0
  if (storage->binary_cache.box == NULL)
2193
0
    return;
2194
2195
0
  timeout_remove(&storage->binary_cache.to);
2196
0
  i_stream_destroy(&storage->binary_cache.input);
2197
0
  i_zero(&storage->binary_cache);
2198
0
}
2199
2200
void mailbox_close(struct mailbox *box)
2201
0
{
2202
0
  if (!box->opened)
2203
0
    return;
2204
2205
0
  if (box->transaction_count != 0) {
2206
0
    i_panic("Trying to close mailbox %s with open transactions",
2207
0
      box->name);
2208
0
  }
2209
0
  T_BEGIN {
2210
0
    box->v.close(box);
2211
0
  } T_END;
2212
2213
0
  if (box->storage->binary_cache.box == box)
2214
0
    mail_storage_free_binary_cache(box->storage);
2215
0
  box->opened = FALSE;
2216
0
  box->mailbox_deleted = FALSE;
2217
0
  array_clear(&box->search_results);
2218
2219
0
  if (array_is_created(&box->recent_flags))
2220
0
    array_free(&box->recent_flags);
2221
0
  box->recent_flags_prev_uid = 0;
2222
0
  box->recent_flags_count = 0;
2223
0
}
2224
2225
void mailbox_free(struct mailbox **_box)
2226
0
{
2227
0
  struct mailbox *box = *_box;
2228
2229
0
  *_box = NULL;
2230
2231
0
  mailbox_close(box);
2232
0
  box->v.free(box);
2233
2234
0
  if (box->attribute_iter_count != 0) {
2235
0
    i_panic("Trying to free mailbox %s with %u open attribute iterators",
2236
0
      box->name, box->attribute_iter_count);
2237
0
  }
2238
2239
0
  DLLIST_REMOVE(&box->storage->mailboxes, box);
2240
0
  mail_storage_obj_unref(box->storage);
2241
0
  settings_free(box->set);
2242
0
  pool_unref(&box->pool);
2243
0
}
2244
2245
bool mailbox_equals(const struct mailbox *box1,
2246
        const struct mail_namespace *ns2, const char *vname2)
2247
0
{
2248
0
  struct mail_namespace *ns1 = mailbox_get_namespace(box1);
2249
0
  const char *name1;
2250
2251
0
  if (ns1 != ns2)
2252
0
    return FALSE;
2253
2254
0
  name1 = mailbox_get_vname(box1);
2255
0
  if (strcmp(name1, vname2) == 0)
2256
0
    return TRUE;
2257
2258
0
  return strcasecmp(name1, "INBOX") == 0 &&
2259
0
    strcasecmp(vname2, "INBOX") == 0;
2260
0
}
2261
2262
bool mailbox_is_any_inbox(struct mailbox *box)
2263
0
{
2264
0
  return box->inbox_any;
2265
0
}
2266
2267
bool mailbox_has_special_use(struct mailbox *box, const char *special_use)
2268
0
{
2269
0
  if (box->set == NULL)
2270
0
    return FALSE;
2271
0
  return str_contains_special_use(t_array_const_string_join(&box->set->special_use, " "),
2272
0
          special_use);
2273
0
}
2274
2275
static void mailbox_copy_cache_decisions_from_inbox(struct mailbox *box)
2276
0
{
2277
0
  struct mail_namespace *ns =
2278
0
    mail_namespace_find_inbox(box->storage->user->namespaces);
2279
0
  struct mailbox *inbox =
2280
0
    mailbox_alloc(ns->list, "INBOX", MAILBOX_FLAG_READONLY);
2281
0
  enum mailbox_existence existence;
2282
2283
  /* this should be NoSelect but since inbox can never be
2284
     NoSelect we use EXISTENCE_NONE to avoid creating inbox by accident */
2285
0
  if (mailbox_exists(inbox, FALSE, &existence) == 0 &&
2286
0
      existence != MAILBOX_EXISTENCE_NONE &&
2287
0
      mailbox_open(inbox) == 0 &&
2288
0
      mailbox_open(box) == 0) {
2289
    /* we can't do much about errors here */
2290
0
    (void)mail_cache_decisions_copy(inbox->cache, box->cache);
2291
0
  }
2292
2293
0
  mailbox_free(&inbox);
2294
0
}
2295
2296
int mailbox_create(struct mailbox *box, const struct mailbox_update *update,
2297
       bool directory)
2298
0
{
2299
0
  struct mail_storage *storage = box->storage;
2300
0
  bool notifying_nfc_name_change = box->notifying_nfc_name_change;
2301
0
  int ret;
2302
2303
0
  if (mailbox_verify_create_name(box) < 0)
2304
0
    return -1;
2305
2306
0
  struct event_reason *reason = event_reason_begin("mailbox:create");
2307
2308
  /* Avoid race conditions by keeping mailbox list locked during changes.
2309
     This especially fixes a race during INBOX creation with
2310
     mailbox_list_layout=index
2311
     because it scans for missing mailboxes if INBOX doesn't exist. The
2312
     second process's scan can find a half-created INBOX and add it,
2313
     causing the first process to become confused. */
2314
0
  if (mailbox_list_lock(box->list) < 0) {
2315
0
    mail_storage_copy_list_error(box->storage, box->list);
2316
0
    event_reason_end(&reason);
2317
0
    return -1;
2318
0
  }
2319
0
  box->creating = TRUE;
2320
0
  box->notifying_nfc_name_change = TRUE;
2321
0
  if ((box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) != 0) {
2322
    /* Layout doesn't support creating \NoSelect mailboxes.
2323
       Switch to creating a selectable mailbox */
2324
0
    directory = FALSE;
2325
0
  }
2326
0
  T_BEGIN {
2327
0
    ret = box->v.create_box(box, update, directory);
2328
0
  } T_END;
2329
0
  box->creating = FALSE;
2330
0
  mailbox_list_unlock(box->list);
2331
2332
0
  if (ret == 0) {
2333
0
    box->list->guid_cache_updated = TRUE;
2334
0
    if (!box->inbox_any) T_BEGIN {
2335
0
      mailbox_copy_cache_decisions_from_inbox(box);
2336
0
    } T_END;
2337
    /* Notify NFC normalization */
2338
0
    if (!notifying_nfc_name_change && box->mailbox_name_changed_by_nfc &&
2339
0
        storage->callbacks.notify_mailbox_implicit_rename != NULL) {
2340
0
      storage->callbacks.notify_mailbox_implicit_rename(
2341
0
        box, box->vname_raw, storage->callback_context);
2342
0
    }
2343
0
  } else if (box->opened) {
2344
    /* Creation failed after (partially) opening the mailbox.
2345
       It may not be in a valid state, so close it. */
2346
0
    mail_storage_last_error_push(box->storage);
2347
0
    mailbox_close(box);
2348
0
    mail_storage_last_error_pop(box->storage);
2349
0
  }
2350
0
  box->notifying_nfc_name_change = notifying_nfc_name_change;
2351
0
  event_reason_end(&reason);
2352
0
  return ret;
2353
0
}
2354
2355
int mailbox_update(struct mailbox *box, const struct mailbox_update *update)
2356
0
{
2357
0
  int ret;
2358
2359
0
  i_assert(update->min_next_uid == 0 ||
2360
0
     update->min_first_recent_uid == 0 ||
2361
0
     update->min_first_recent_uid <= update->min_next_uid);
2362
2363
0
  if (mailbox_verify_existing_name(box) < 0)
2364
0
    return -1;
2365
2366
0
  struct event_reason *reason = event_reason_begin("mailbox:update");
2367
0
  T_BEGIN {
2368
0
    ret = box->v.update_box(box, update);
2369
0
  } T_END;
2370
0
  if (!guid_128_is_empty(update->mailbox_guid))
2371
0
    box->list->guid_cache_invalidated = TRUE;
2372
0
  event_reason_end(&reason);
2373
0
  return ret;
2374
0
}
2375
2376
int mailbox_mark_index_deleted(struct mailbox *box, bool del)
2377
0
{
2378
0
  struct mail_index_transaction *trans;
2379
0
  enum mail_index_transaction_flags trans_flags = 0;
2380
0
  enum mailbox_flags old_flag;
2381
0
  int ret;
2382
2383
0
  e_debug(box->event, "Attempting to %s mailbox", del ?
2384
0
    "delete" : "undelete");
2385
2386
0
  if (box->marked_deleted && del) {
2387
    /* we already marked it deleted. this allows plugins to
2388
       "lock" the deletion earlier. */
2389
0
    return 0;
2390
0
  }
2391
2392
0
  old_flag = box->flags & MAILBOX_FLAG_OPEN_DELETED;
2393
0
  box->flags |= MAILBOX_FLAG_OPEN_DELETED;
2394
0
  ret = mailbox_open(box);
2395
0
  box->flags = (box->flags & ENUM_NEGATE(MAILBOX_FLAG_OPEN_DELETED)) | old_flag;
2396
0
  if (ret < 0)
2397
0
    return -1;
2398
2399
0
  trans_flags = del ? 0 : MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL;
2400
0
  trans = mail_index_transaction_begin(box->view, trans_flags);
2401
0
  if (del)
2402
0
    mail_index_set_deleted(trans);
2403
0
  else
2404
0
    mail_index_set_undeleted(trans);
2405
0
  if (mail_index_transaction_commit(&trans) < 0) {
2406
0
    mailbox_set_index_error(box);
2407
0
    return -1;
2408
0
  }
2409
2410
0
  if (del) {
2411
    /* sync the mailbox. this finishes the index deletion and it
2412
       can succeed only for a single session. we do it here, so the
2413
       rest of the deletion code doesn't have to worry about race
2414
       conditions. */
2415
0
    box->delete_sync_check = TRUE;
2416
0
    ret = mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ);
2417
0
    box->delete_sync_check = FALSE;
2418
0
    if (ret < 0)
2419
0
      return -1;
2420
0
  }
2421
2422
0
  box->marked_deleted = del;
2423
0
  return 0;
2424
0
}
2425
2426
static void mailbox_close_reset_path(struct mailbox *box)
2427
0
{
2428
0
  i_zero(&box->_perm);
2429
0
  box->_path = NULL;
2430
0
  box->_index_path = NULL;
2431
0
}
2432
2433
static int mailbox_delete_real(struct mailbox *box)
2434
0
{
2435
0
  bool list_locked;
2436
0
  int ret;
2437
2438
0
  if (*box->name == '\0') {
2439
0
    mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
2440
0
               "Storage root can't be deleted");
2441
0
    return -1;
2442
0
  }
2443
2444
0
  struct event_reason *reason = event_reason_begin("mailbox:delete");
2445
2446
0
  box->deleting = TRUE;
2447
0
  if (mailbox_open(box) < 0) {
2448
0
    if (mailbox_get_last_mail_error(box) != MAIL_ERROR_NOTFOUND &&
2449
0
        !box->mailbox_deleted) {
2450
0
      event_reason_end(&reason);
2451
0
      return -1;
2452
0
    }
2453
    /* might be a \noselect mailbox, so continue deletion */
2454
0
  }
2455
2456
0
  if (mailbox_list_lock(box->list) < 0) {
2457
0
    mail_storage_copy_list_error(box->storage, box->list);
2458
0
    list_locked = FALSE;
2459
0
    ret = -1;
2460
0
  } else {
2461
0
    list_locked = TRUE;
2462
0
    ret = box->v.delete_box(box);
2463
0
  }
2464
0
  if (ret < 0 && box->marked_deleted) {
2465
    /* deletion failed. revert the mark so it can maybe be
2466
       tried again later. */
2467
0
    if (mailbox_mark_index_deleted(box, FALSE) < 0)
2468
0
      ret = -1;
2469
0
  }
2470
0
  if (list_locked)
2471
0
    mailbox_list_unlock(box->list);
2472
2473
0
  box->deleting = FALSE;
2474
0
  mailbox_close(box);
2475
2476
  /* if mailbox is reopened, its path may be different with
2477
     mailbox_list_layout=index */
2478
0
  mailbox_close_reset_path(box);
2479
0
  event_reason_end(&reason);
2480
0
  return ret;
2481
0
}
2482
2483
int mailbox_delete(struct mailbox *box)
2484
0
{
2485
0
  int ret;
2486
0
  T_BEGIN {
2487
0
    ret = mailbox_delete_real(box);
2488
0
  } T_END;
2489
0
  return ret;
2490
0
}
2491
2492
int mailbox_delete_empty(struct mailbox *box)
2493
0
{
2494
0
  int ret;
2495
2496
  /* FIXME: should be a parameter to delete(), but since it changes API
2497
     don't do it for now */
2498
0
  box->deleting_must_be_empty = TRUE;
2499
0
  ret = mailbox_delete(box);
2500
0
  box->deleting_must_be_empty = FALSE;
2501
0
  return ret;
2502
0
}
2503
2504
static bool
2505
mail_storages_rename_compatible(struct mail_storage *storage1,
2506
        struct mail_storage *storage2,
2507
        const char **error_r)
2508
0
{
2509
0
  if (storage1 == storage2)
2510
0
    return TRUE;
2511
2512
0
  if (strcmp(storage1->name, storage2->name) != 0) {
2513
0
    *error_r = t_strdup_printf("storage %s != %s",
2514
0
             storage1->name, storage2->name);
2515
0
    return FALSE;
2516
0
  }
2517
0
  if ((storage1->class_flags & MAIL_STORAGE_CLASS_FLAG_UNIQUE_ROOT) != 0) {
2518
    /* e.g. mdbox where all mails are in storage/ directory and
2519
       they can't be easily moved from there. */
2520
0
    *error_r = t_strdup_printf("storage %s uses unique root",
2521
0
             storage1->name);
2522
0
    return FALSE;
2523
0
  }
2524
0
  return TRUE;
2525
0
}
2526
2527
static bool nullequals(const void *p1, const void *p2)
2528
0
{
2529
0
  return (p1 == NULL && p2 == NULL) || (p1 != NULL && p2 != NULL);
2530
0
}
2531
2532
static bool
2533
mailbox_lists_rename_compatible(struct mailbox_list *list1,
2534
        struct mailbox_list *list2,
2535
        const char **error_r)
2536
0
{
2537
0
  if (!nullequals(list1->mail_set->mail_alt_path,
2538
0
      list2->mail_set->mail_alt_path)) {
2539
0
    *error_r = t_strdup_printf(
2540
0
      "Namespace %s has mail_alt_path, %s doesn't",
2541
0
      list1->ns->set->name, list2->ns->set->name);
2542
0
    return FALSE;
2543
0
  }
2544
0
  if (!nullequals(list1->mail_set->mail_index_path,
2545
0
      list2->mail_set->mail_index_path)) {
2546
0
    *error_r = t_strdup_printf(
2547
0
      "Namespace %s has mail_index_path, %s doesn't",
2548
0
      list1->ns->set->name, list2->ns->set->name);
2549
0
    return FALSE;
2550
0
  }
2551
0
  if (!nullequals(list1->mail_set->mail_cache_path,
2552
0
      list2->mail_set->mail_cache_path)) {
2553
0
    *error_r = t_strdup_printf(
2554
0
      "Namespace %s has mail_cache_path, %s doesn't",
2555
0
      list1->ns->set->name, list2->ns->set->name);
2556
0
    return FALSE;
2557
0
  }
2558
0
  if (!nullequals(list1->mail_set->mail_control_path,
2559
0
      list2->mail_set->mail_control_path)) {
2560
0
    *error_r = t_strdup_printf(
2561
0
      "Namespace %s has mail_control_path, %s doesn't",
2562
0
      list1->ns->set->name, list2->ns->set->name);
2563
0
    return FALSE;
2564
0
  }
2565
0
  return TRUE;
2566
0
}
2567
2568
static
2569
int mailbox_rename_check_children(struct mailbox *src, struct mailbox *dest)
2570
0
{
2571
0
  int ret = 0;
2572
0
  size_t src_prefix_len = strlen(src->vname)+1; /* include separator */
2573
0
  size_t dest_prefix_len = strlen(dest->vname)+1;
2574
  /* this can return folders with * in their name, that are not
2575
     actually our children */
2576
0
  char ns_sep = mail_namespace_get_sep(src->list->ns);
2577
0
  const char *pattern = t_strdup_printf("%s%c*", src->vname, ns_sep);
2578
2579
0
  struct mailbox_list_iterate_context *iter = mailbox_list_iter_init(src->list, pattern,
2580
0
              MAILBOX_LIST_ITER_RETURN_NO_FLAGS);
2581
2582
0
  const struct mailbox_info *child;
2583
0
  while((child = mailbox_list_iter_next(iter)) != NULL) {
2584
0
    if (strncmp(child->vname, src->vname, src_prefix_len-1) != 0 ||
2585
0
        child->vname[src_prefix_len-1] != ns_sep)
2586
0
      continue; /* not our child */
2587
    /* if total length of new name exceeds the limit, fail */
2588
0
    if (strlen(child->vname + src_prefix_len)+dest_prefix_len > MAILBOX_LIST_NAME_MAX_LENGTH) {
2589
0
      mail_storage_set_error(src->storage, MAIL_ERROR_PARAMS,
2590
0
        "Mailbox or child name too long");
2591
0
      ret = -1;
2592
0
      break;
2593
0
    }
2594
0
  }
2595
2596
  /* something went bad */
2597
0
  if (mailbox_list_iter_deinit(&iter) < 0) {
2598
0
    mail_storage_copy_list_error(src->storage, src->list);
2599
0
    ret = -1;
2600
0
  }
2601
0
  return ret;
2602
0
}
2603
2604
static int mailbox_rename_real(struct mailbox *src, struct mailbox *dest)
2605
0
{
2606
0
  const char *error = NULL;
2607
0
  bool src_notifying_nfc_name_change = src->notifying_nfc_name_change;
2608
0
  bool dest_notifying_nfc_name_change = dest->notifying_nfc_name_change;
2609
2610
  /* Check only name validity, \Noselect don't necessarily exist. */
2611
0
  if (mailbox_verify_name(src) < 0)
2612
0
    return -1;
2613
0
  if (*src->name == '\0') {
2614
0
    mail_storage_set_error(src->storage, MAIL_ERROR_PARAMS,
2615
0
               "Can't rename mailbox root");
2616
0
    return -1;
2617
0
  }
2618
0
  if (mailbox_verify_create_name(dest) < 0) {
2619
0
    mail_storage_copy_error(src->storage, dest->storage);
2620
0
    return -1;
2621
0
  }
2622
0
  if (mailbox_rename_check_children(src, dest) != 0) {
2623
0
    return -1;
2624
0
  }
2625
2626
0
  if (!mail_storages_rename_compatible(src->storage,
2627
0
               dest->storage, &error) ||
2628
0
      !mailbox_lists_rename_compatible(src->list,
2629
0
               dest->list, &error)) {
2630
0
    e_debug(src->event,
2631
0
      "Can't rename '%s' to '%s': %s",
2632
0
      src->vname, dest->vname, error);
2633
0
    mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
2634
0
      "Can't rename mailboxes across specified storages.");
2635
0
    return -1;
2636
0
  }
2637
0
  if (src->list != dest->list &&
2638
0
      (src->list->ns->type != MAIL_NAMESPACE_TYPE_PRIVATE ||
2639
0
       dest->list->ns->type != MAIL_NAMESPACE_TYPE_PRIVATE)) {
2640
0
    mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
2641
0
      "Renaming not supported across non-private namespaces.");
2642
0
    return -1;
2643
0
  }
2644
0
  if (src->list == dest->list && strcmp(src->name, dest->name) == 0) {
2645
0
    mail_storage_set_error(src->storage, MAIL_ERROR_EXISTS,
2646
0
               "Can't rename mailbox to itself.");
2647
0
    return -1;
2648
0
  }
2649
2650
  /* It would be safer to lock both source and destination, but that
2651
     could lead to deadlocks. So at least for now lets just lock only the
2652
     destination list. */
2653
0
  if (mailbox_list_lock(dest->list) < 0) {
2654
0
    mail_storage_copy_list_error(src->storage, dest->list);
2655
0
    return -1;
2656
0
  }
2657
2658
  /* Make sure nested calls don't repeat notification of NFC
2659
     normalization. */
2660
0
  src->notifying_nfc_name_change = TRUE;
2661
0
  dest->notifying_nfc_name_change = TRUE;
2662
2663
0
  int ret = src->v.rename_box(src, dest);
2664
0
  if (ret < 0 && src->storage->error == MAIL_ERROR_NOTFOUND &&
2665
0
      src->mailbox_name_changed_by_nfc) {
2666
0
    ret = mailbox_nfc_normalize(src);
2667
0
    if (ret >= 0)
2668
0
      ret = src->v.rename_box(src, dest);
2669
0
  }
2670
0
  mailbox_list_unlock(dest->list);
2671
0
  if (ret < 0) {
2672
0
    src->notifying_nfc_name_change = src_notifying_nfc_name_change;
2673
0
    dest->notifying_nfc_name_change = dest_notifying_nfc_name_change;
2674
0
    return -1;
2675
0
  }
2676
2677
  /* Always notify an NFC normalization rename, even when the physical
2678
     rename happened in the past. However, don't send the notification
2679
     here when this is a nested call. */
2680
0
  if (!src_notifying_nfc_name_change &&
2681
0
      src->mailbox_name_changed_by_nfc &&
2682
0
      src->storage->callbacks.notify_mailbox_implicit_rename != NULL) {
2683
0
    src->storage->callbacks.notify_mailbox_implicit_rename(
2684
0
      src, src->vname_raw, src->storage->callback_context);
2685
0
  }
2686
0
  if (!dest_notifying_nfc_name_change &&
2687
0
      dest->mailbox_name_changed_by_nfc &&
2688
0
      dest->storage->callbacks.notify_mailbox_implicit_rename != NULL) {
2689
0
    dest->storage->callbacks.notify_mailbox_implicit_rename(
2690
0
      dest, dest->vname_raw, dest->storage->callback_context);
2691
0
  }
2692
2693
0
  src->notifying_nfc_name_change = src_notifying_nfc_name_change;
2694
0
  dest->notifying_nfc_name_change = dest_notifying_nfc_name_change;
2695
2696
0
  src->list->guid_cache_invalidated = TRUE;
2697
0
  dest->list->guid_cache_invalidated = TRUE;
2698
0
  return 0;
2699
0
}
2700
2701
int mailbox_rename(struct mailbox *src, struct mailbox *dest)
2702
0
{
2703
0
   int ret;
2704
0
   T_BEGIN {
2705
0
     struct event_reason *reason =
2706
0
       event_reason_begin("mailbox:rename");
2707
0
     ret = mailbox_rename_real(src, dest);
2708
0
     event_reason_end(&reason);
2709
0
   } T_END;
2710
0
   return ret;
2711
0
}
2712
2713
int mailbox_set_subscribed(struct mailbox *box, bool set)
2714
0
{
2715
0
  int ret;
2716
2717
0
  if (mailbox_verify_name(box) < 0)
2718
0
    return -1;
2719
2720
0
  struct event_reason *reason =
2721
0
    event_reason_begin(set ? "mailbox:subscribe" :
2722
0
           "mailbox:unsubscribe");
2723
0
  if (mailbox_list_iter_subscriptions_refresh(box->list) < 0) {
2724
0
    mail_storage_copy_list_error(box->storage, box->list);
2725
0
    ret = -1;
2726
0
  } else if (mailbox_is_subscribed(box) == set)
2727
0
    ret = 0;
2728
0
  else T_BEGIN {
2729
0
    ret = box->v.set_subscribed(box, set);
2730
0
  } T_END;
2731
0
  event_reason_end(&reason);
2732
0
  return ret;
2733
0
}
2734
2735
bool mailbox_is_subscribed(struct mailbox *box)
2736
0
{
2737
0
  struct mailbox_node *node;
2738
2739
0
  i_assert(box->list->subscriptions != NULL);
2740
2741
0
  node = mailbox_tree_lookup(box->list->subscriptions, box->vname);
2742
0
  return node != NULL && (node->flags & MAILBOX_SUBSCRIBED) != 0;
2743
0
}
2744
2745
struct mail_storage *mailbox_get_storage(const struct mailbox *box)
2746
0
{
2747
0
  return box->storage;
2748
0
}
2749
2750
struct mail_namespace *
2751
mailbox_get_namespace(const struct mailbox *box)
2752
0
{
2753
0
  return box->list->ns;
2754
0
}
2755
2756
const struct mailbox_settings *mailbox_get_settings(struct mailbox *box)
2757
0
{
2758
0
  return box->set;
2759
0
}
2760
2761
const char *mailbox_get_name(const struct mailbox *box)
2762
0
{
2763
0
  return box->name;
2764
0
}
2765
2766
const char *mailbox_get_vname(const struct mailbox *box)
2767
0
{
2768
0
  return box->vname;
2769
0
}
2770
2771
bool mailbox_is_readonly(struct mailbox *box)
2772
0
{
2773
0
  i_assert(box->opened);
2774
2775
0
  return box->v.is_readonly(box);
2776
0
}
2777
2778
bool mailbox_backends_equal(const struct mailbox *box1,
2779
          const struct mailbox *box2)
2780
0
{
2781
0
  struct mail_namespace *ns1 = box1->list->ns, *ns2 = box2->list->ns;
2782
2783
0
  if (strcmp(box1->name, box2->name) != 0)
2784
0
    return FALSE;
2785
2786
0
  while (ns1->alias_for != NULL)
2787
0
    ns1 = ns1->alias_for;
2788
0
  while (ns2->alias_for != NULL)
2789
0
    ns2 = ns2->alias_for;
2790
0
  return ns1 == ns2;
2791
0
}
2792
2793
static void
2794
mailbox_get_status_set_defaults(struct mailbox *box,
2795
        struct mailbox_status *status_r)
2796
0
{
2797
0
  i_zero(status_r);
2798
0
  if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUIDS) != 0)
2799
0
    status_r->have_guids = TRUE;
2800
0
  if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_SAVE_GUIDS) != 0)
2801
0
    status_r->have_save_guids = TRUE;
2802
0
  if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUID128) != 0)
2803
0
    status_r->have_only_guid128 = TRUE;
2804
0
}
2805
2806
int mailbox_get_status(struct mailbox *box,
2807
           enum mailbox_status_items items,
2808
           struct mailbox_status *status_r)
2809
0
{
2810
0
  mailbox_get_status_set_defaults(box, status_r);
2811
0
  if (mailbox_verify_existing_name(box) < 0)
2812
0
    return -1;
2813
2814
0
  int ret;
2815
0
  T_BEGIN {
2816
0
    ret = box->v.get_status(box, items, status_r);
2817
0
  } T_END;
2818
0
  if (ret < 0)
2819
0
    return -1;
2820
0
  i_assert(status_r->have_guids || !status_r->have_save_guids);
2821
0
  return 0;
2822
0
}
2823
2824
void mailbox_get_open_status(struct mailbox *box,
2825
           enum mailbox_status_items items,
2826
           struct mailbox_status *status_r)
2827
0
{
2828
0
  i_assert(box->opened);
2829
0
  i_assert((items & MAILBOX_STATUS_FAILING_ITEMS) == 0);
2830
2831
0
  mailbox_get_status_set_defaults(box, status_r);
2832
0
  T_BEGIN {
2833
0
    if (box->v.get_status(box, items, status_r) < 0)
2834
0
      i_unreached();
2835
0
  } T_END;
2836
0
}
2837
2838
int mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items,
2839
       struct mailbox_metadata *metadata_r)
2840
0
{
2841
0
  i_zero(metadata_r);
2842
0
  if (mailbox_verify_existing_name(box) < 0)
2843
0
    return -1;
2844
2845
  /* NOTE: metadata_r->cache_fields is currently returned from
2846
     data stack, so can't use a data stack frame here. */
2847
0
  if (box->v.get_metadata(box, items, metadata_r) < 0)
2848
0
    return -1;
2849
2850
0
  i_assert((items & MAILBOX_METADATA_GUID) == 0 ||
2851
0
     !guid_128_is_empty(metadata_r->guid));
2852
0
  return 0;
2853
0
}
2854
2855
enum mail_flags mailbox_get_private_flags_mask(struct mailbox *box)
2856
0
{
2857
0
  if (box->v.get_private_flags_mask != NULL)
2858
0
    return box->v.get_private_flags_mask(box);
2859
0
  else if (box->list->mail_set->mail_index_private_path[0] != '\0')
2860
0
    return MAIL_SEEN; /* FIXME */
2861
0
  else
2862
0
    return 0;
2863
0
}
2864
2865
struct mailbox_sync_context *
2866
mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
2867
0
{
2868
0
  struct mailbox_sync_context *ctx;
2869
2870
0
  if (box->transaction_count != 0) {
2871
0
    i_panic("Trying to sync mailbox %s with open transactions",
2872
0
      box->name);
2873
0
  }
2874
0
  if (!box->opened) {
2875
0
    if (mailbox_open(box) < 0) {
2876
0
      ctx = i_new(struct mailbox_sync_context, 1);
2877
0
      ctx->box = box;
2878
0
      ctx->flags = flags;
2879
0
      ctx->open_failed = TRUE;
2880
0
      return ctx;
2881
0
    }
2882
0
  }
2883
0
  T_BEGIN {
2884
0
    ctx = box->v.sync_init(box, flags);
2885
0
  } T_END;
2886
0
  return ctx;
2887
0
}
2888
2889
bool mailbox_sync_next(struct mailbox_sync_context *ctx,
2890
           struct mailbox_sync_rec *sync_rec_r)
2891
0
{
2892
0
  if (ctx->open_failed)
2893
0
    return FALSE;
2894
2895
0
  bool ret;
2896
0
  T_BEGIN {
2897
0
    ret = ctx->box->v.sync_next(ctx, sync_rec_r);
2898
0
  } T_END;
2899
0
  return ret;
2900
0
}
2901
2902
int mailbox_sync_deinit(struct mailbox_sync_context **_ctx,
2903
      struct mailbox_sync_status *status_r)
2904
0
{
2905
0
  struct mailbox_sync_context *ctx = *_ctx;
2906
0
  struct mailbox *box = ctx->box;
2907
0
  const char *errormsg;
2908
0
  enum mail_error error;
2909
0
  int ret;
2910
2911
0
  *_ctx = NULL;
2912
2913
0
  i_zero(status_r);
2914
2915
0
  if (!ctx->open_failed) {
2916
0
    T_BEGIN {
2917
0
      ret = box->v.sync_deinit(ctx, status_r);
2918
0
    } T_END;
2919
0
  } else {
2920
0
    i_free(ctx);
2921
0
    ret = -1;
2922
0
  }
2923
0
  if (ret < 0 && box->inbox_user &&
2924
0
      !box->storage->user->inbox_open_error_logged) {
2925
0
    errormsg = mailbox_get_last_internal_error(box, &error);
2926
0
    if (error == MAIL_ERROR_NOTPOSSIBLE) {
2927
0
      box->storage->user->inbox_open_error_logged = TRUE;
2928
0
      e_error(box->event, "Syncing INBOX failed: %s", errormsg);
2929
0
    }
2930
0
  }
2931
0
  if (ret == 0)
2932
0
    box->synced = TRUE;
2933
0
  return ret;
2934
0
}
2935
2936
int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags)
2937
0
{
2938
0
  struct mailbox_sync_context *ctx;
2939
0
  struct mailbox_sync_status status;
2940
2941
0
  if (array_count(&box->search_results) == 0) {
2942
    /* we don't care about mailbox's current state, so we might
2943
       as well fix inconsistency state */
2944
0
    flags |= MAILBOX_SYNC_FLAG_FIX_INCONSISTENT;
2945
0
  }
2946
2947
0
  ctx = mailbox_sync_init(box, flags);
2948
0
  return mailbox_sync_deinit(&ctx, &status);
2949
0
}
2950
2951
#undef mailbox_notify_changes
2952
void mailbox_notify_changes(struct mailbox *box,
2953
          mailbox_notify_callback_t *callback, void *context)
2954
0
{
2955
0
  i_assert(box->opened);
2956
2957
0
  box->notify_callback = callback;
2958
0
  box->notify_context = context;
2959
2960
0
  T_BEGIN {
2961
0
    box->v.notify_changes(box);
2962
0
  } T_END;
2963
0
}
2964
2965
void mailbox_notify_changes_stop(struct mailbox *box)
2966
0
{
2967
0
  i_assert(box->opened);
2968
2969
0
  box->notify_callback = NULL;
2970
0
  box->notify_context = NULL;
2971
2972
0
  T_BEGIN {
2973
0
    box->v.notify_changes(box);
2974
0
  } T_END;
2975
0
}
2976
2977
struct mail_search_context *
2978
mailbox_search_init(struct mailbox_transaction_context *t,
2979
        struct mail_search_args *args,
2980
        const enum mail_sort_type *sort_program,
2981
        enum mail_fetch_field wanted_fields,
2982
        struct mailbox_header_lookup_ctx *wanted_headers)
2983
0
{
2984
0
  i_assert(wanted_headers == NULL || wanted_headers->box == t->box);
2985
2986
0
  mail_search_args_ref(args);
2987
0
  if (!args->simplified)
2988
0
    mail_search_args_simplify(args);
2989
2990
0
  struct mail_search_context *ctx;
2991
0
  T_BEGIN {
2992
0
    ctx = t->box->v.search_init(t, args, sort_program,
2993
0
              wanted_fields, wanted_headers);
2994
0
  } T_END;
2995
0
  return ctx;
2996
0
}
2997
2998
int mailbox_search_deinit(struct mail_search_context **_ctx)
2999
0
{
3000
0
  struct mail_search_context *ctx = *_ctx;
3001
0
  struct mail_search_args *args = ctx->args;
3002
0
  int ret;
3003
3004
0
  *_ctx = NULL;
3005
0
  mailbox_search_results_initial_done(ctx);
3006
0
  T_BEGIN {
3007
0
    ret = ctx->transaction->box->v.search_deinit(ctx);
3008
0
  } T_END;
3009
0
  mail_search_args_unref(&args);
3010
0
  return ret;
3011
0
}
3012
3013
void mailbox_search_reset_progress_start(struct mail_search_context *ctx)
3014
0
{
3015
0
  i_zero(&ctx->search_start_time);
3016
0
  i_zero(&ctx->last_notify);
3017
0
}
3018
3019
void
3020
mailbox_search_set_progress_hidden(struct mail_search_context *ctx, bool hidden)
3021
0
{
3022
0
  ctx->progress_hidden = hidden;
3023
0
}
3024
3025
void mailbox_search_notify(struct mailbox *box, struct mail_search_context *ctx)
3026
0
{
3027
0
  if (ctx->search_start_time.tv_sec == 0) {
3028
0
    ctx->search_start_time = ioloop_timeval;
3029
0
    return;
3030
0
  }
3031
3032
0
  if (ctx->last_notify.tv_sec == 0)
3033
0
    ctx->last_notify = ctx->search_start_time;
3034
3035
0
  if (box->storage->callbacks.notify_progress == NULL ||
3036
0
      ctx->progress_hidden)
3037
0
        return;
3038
3039
0
  if (++ctx->search_notify_passes % 1024 == 0)
3040
0
    io_loop_time_refresh();
3041
3042
0
  if (ioloop_time - ctx->last_notify.tv_sec < MAIL_STORAGE_NOTIFY_INTERVAL_SECS)
3043
0
        return;
3044
3045
0
  struct mail_storage_progress_details dtl = {
3046
0
    .total = ctx->progress_max,
3047
0
    .processed = ctx->progress_cur,
3048
0
    .start_time = ctx->search_start_time,
3049
0
    .now = ioloop_timeval,
3050
0
  };
3051
3052
0
  box->storage->callbacks.notify_progress(box, &dtl,
3053
0
            box->storage->callback_context);
3054
3055
0
  ctx->last_notify = ioloop_timeval;
3056
0
}
3057
3058
bool mailbox_search_next(struct mail_search_context *ctx, struct mail **mail_r)
3059
0
{
3060
0
  bool tryagain;
3061
3062
0
  while (!mailbox_search_next_nonblock(ctx, mail_r, &tryagain)) {
3063
0
    if (!tryagain)
3064
0
      return FALSE;
3065
0
  }
3066
0
  return TRUE;
3067
0
}
3068
3069
bool mailbox_search_next_nonblock(struct mail_search_context *ctx,
3070
          struct mail **mail_r, bool *tryagain_r)
3071
0
{
3072
0
  struct mailbox *box = ctx->transaction->box;
3073
0
  bool ret;
3074
3075
0
  *mail_r = NULL;
3076
0
  *tryagain_r = FALSE;
3077
3078
0
  T_BEGIN {
3079
0
    mailbox_search_notify(box, ctx);
3080
0
    ret = box->v.search_next_nonblock(ctx, mail_r, tryagain_r);
3081
0
  } T_END;
3082
0
  if (!ret)
3083
0
    return FALSE;
3084
0
  else {
3085
0
    mailbox_search_results_add(ctx, (*mail_r)->uid);
3086
0
    return TRUE;
3087
0
  }
3088
0
}
3089
3090
bool mailbox_search_seen_lost_data(struct mail_search_context *ctx)
3091
0
{
3092
0
  return ctx->seen_lost_data;
3093
0
}
3094
3095
void mailbox_search_mail_detach(struct mail_search_context *ctx,
3096
        struct mail *mail)
3097
0
{
3098
0
  struct mail_private *pmail =
3099
0
    container_of(mail, struct mail_private, mail);
3100
0
  unsigned int idx;
3101
3102
0
  if (!array_lsearch_ptr_idx(&ctx->mails, mail, &idx))
3103
0
    i_unreached();
3104
0
  pmail->search_mail = FALSE;
3105
0
  array_delete(&ctx->mails, idx, 1);
3106
0
}
3107
3108
int mailbox_search_result_build(struct mailbox_transaction_context *t,
3109
        struct mail_search_args *args,
3110
        enum mailbox_search_result_flags flags,
3111
        struct mail_search_result **result_r)
3112
0
{
3113
0
  struct mail_search_context *ctx;
3114
0
  struct mail *mail;
3115
0
  int ret;
3116
3117
0
  ctx = mailbox_search_init(t, args, NULL, 0, NULL);
3118
0
  *result_r = mailbox_search_result_save(ctx, flags);
3119
0
  while (mailbox_search_next(ctx, &mail)) ;
3120
3121
0
  ret = mailbox_search_deinit(&ctx);
3122
0
  if (ret < 0)
3123
0
    mailbox_search_result_free(result_r);
3124
0
  return ret;
3125
0
}
3126
3127
struct mailbox_transaction_context *
3128
mailbox_transaction_begin(struct mailbox *box,
3129
        enum mailbox_transaction_flags flags,
3130
        const char *reason)
3131
0
{
3132
0
  struct mailbox_transaction_context *trans;
3133
3134
0
  i_assert(box->opened);
3135
3136
0
  box->transaction_count++;
3137
0
  T_BEGIN {
3138
0
    trans = box->v.transaction_begin(box, flags, reason);
3139
0
  } T_END;
3140
0
  i_assert(trans->reason != NULL);
3141
0
  return trans;
3142
0
}
3143
3144
int mailbox_transaction_commit(struct mailbox_transaction_context **t)
3145
0
{
3146
0
  struct mail_transaction_commit_changes changes;
3147
0
  int ret;
3148
3149
  /* Store changes temporarily so that plugins overriding
3150
     transaction_commit() can look at them. */
3151
0
  ret = mailbox_transaction_commit_get_changes(t, &changes);
3152
0
  pool_unref(&changes.pool);
3153
0
  return ret;
3154
0
}
3155
3156
int mailbox_transaction_commit_get_changes(
3157
  struct mailbox_transaction_context **_t,
3158
  struct mail_transaction_commit_changes *changes_r)
3159
0
{
3160
0
  struct mailbox_transaction_context *t = *_t;
3161
0
  struct mailbox *box = t->box;
3162
0
  unsigned int save_count = t->save_count;
3163
0
  struct event_reason *reason = NULL;
3164
0
  int ret;
3165
3166
0
  changes_r->pool = NULL;
3167
3168
0
  *_t = NULL;
3169
3170
0
  if (t->itrans->attribute_updates != NULL &&
3171
0
      t->itrans->attribute_updates->used > 0) {
3172
    /* attribute changes are also done directly via lib-index
3173
       by ACL and Sieve */
3174
0
    reason = event_reason_begin("mailbox:attributes_changed");
3175
0
  }
3176
0
  T_BEGIN {
3177
0
    ret = box->v.transaction_commit(t, changes_r);
3178
0
  } T_END;
3179
  /* either all the saved messages get UIDs or none, because a) we
3180
     failed, b) MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS not set,
3181
     c) backend doesn't support it (e.g. virtual plugin) */
3182
0
  i_assert(ret < 0 ||
3183
0
     seq_range_count(&changes_r->saved_uids) == save_count ||
3184
0
     array_count(&changes_r->saved_uids) == 0);
3185
  /* decrease the transaction count only after transaction_commit().
3186
     that way if it creates and destroys transactions internally, we
3187
     don't see transaction_count=0 until the parent transaction is fully
3188
     finished */
3189
0
  box->transaction_count--;
3190
0
  event_reason_end(&reason);
3191
0
  if (ret == 0 && box->mailbox_not_original) {
3192
    /* The mailbox name changed while opening it. This is
3193
       intentional when virtual mailbox is opened for saving mails,
3194
       which causes the backend mailbox to be opened instead. In
3195
       this situation the UIDVALIDITY / UIDs are for the physical
3196
       mailbox, not the virtual mailbox. Use this flag to prevent
3197
       IMAP APPEND from returning any UIDs in the tagged reply,
3198
       since they would be wrong. */
3199
0
    changes_r->no_read_perm = TRUE;
3200
0
  }
3201
0
  if (ret < 0 && changes_r->pool != NULL)
3202
0
    pool_unref(&changes_r->pool);
3203
0
  return ret;
3204
0
}
3205
3206
void mailbox_transaction_rollback(struct mailbox_transaction_context **_t)
3207
0
{
3208
0
  struct mailbox_transaction_context *t = *_t;
3209
0
  struct mailbox *box = t->box;
3210
3211
0
  *_t = NULL;
3212
0
  T_BEGIN {
3213
0
    box->v.transaction_rollback(t);
3214
0
  } T_END;
3215
0
  box->transaction_count--;
3216
0
}
3217
3218
unsigned int mailbox_transaction_get_count(const struct mailbox *box)
3219
0
{
3220
0
  return box->transaction_count;
3221
0
}
3222
3223
void mailbox_transaction_set_max_modseq(struct mailbox_transaction_context *t,
3224
          uint64_t max_modseq,
3225
          ARRAY_TYPE(seq_range) *seqs)
3226
0
{
3227
0
  mail_index_transaction_set_max_modseq(t->itrans, max_modseq, seqs);
3228
0
}
3229
3230
struct mailbox *
3231
mailbox_transaction_get_mailbox(const struct mailbox_transaction_context *t)
3232
0
{
3233
0
  return t->box;
3234
0
}
3235
3236
static void mailbox_save_dest_mail_close(struct mail_save_context *ctx)
3237
0
{
3238
0
  struct mail_private *mail = (struct mail_private *)ctx->dest_mail;
3239
3240
0
  T_BEGIN {
3241
0
    mail->v.close(&mail->mail);
3242
0
  } T_END;
3243
0
}
3244
3245
struct mail_save_context *
3246
mailbox_save_alloc(struct mailbox_transaction_context *t)
3247
0
{
3248
0
  struct mail_save_context *ctx;
3249
0
  T_BEGIN {
3250
0
    ctx = t->box->v.save_alloc(t);
3251
0
  } T_END;
3252
0
  i_assert(!ctx->unfinished);
3253
0
  ctx->unfinished = TRUE;
3254
0
  ctx->data.received_date = (time_t)-1;
3255
0
  ctx->data.save_date = (time_t)-1;
3256
3257
  /* Always have a dest_mail available. A lot of plugins make use
3258
     of this. */
3259
0
  if (ctx->dest_mail == NULL)
3260
0
    ctx->dest_mail = mail_alloc(t, 0, NULL);
3261
0
  else {
3262
    /* make sure the mail isn't used before mail_set_seq_saving() */
3263
0
    mailbox_save_dest_mail_close(ctx);
3264
0
  }
3265
3266
0
  return ctx;
3267
0
}
3268
3269
void mailbox_save_context_deinit(struct mail_save_context *ctx)
3270
0
{
3271
0
  i_assert(ctx->dest_mail != NULL);
3272
3273
0
  mail_free(&ctx->dest_mail);
3274
0
}
3275
3276
void mailbox_save_set_flags(struct mail_save_context *ctx,
3277
          enum mail_flags flags,
3278
          struct mail_keywords *keywords)
3279
0
{
3280
0
  struct mailbox *box = ctx->transaction->box;
3281
3282
0
  if (ctx->data.keywords != NULL)
3283
0
    mailbox_keywords_unref(&ctx->data.keywords);
3284
3285
0
  ctx->data.flags = flags & ENUM_NEGATE(mailbox_get_private_flags_mask(box));
3286
0
  ctx->data.pvt_flags = flags & mailbox_get_private_flags_mask(box);
3287
0
  ctx->data.keywords = keywords;
3288
0
  if (keywords != NULL)
3289
0
    mailbox_keywords_ref(keywords);
3290
0
}
3291
3292
void mailbox_save_copy_flags(struct mail_save_context *ctx, struct mail *mail)
3293
0
{
3294
0
  const char *const *keywords_list;
3295
0
  struct mail_keywords *keywords;
3296
3297
0
  keywords_list = mail_get_keywords(mail);
3298
0
  keywords = str_array_length(keywords_list) == 0 ? NULL :
3299
0
    mailbox_keywords_create_valid(ctx->transaction->box,
3300
0
                keywords_list);
3301
0
  mailbox_save_set_flags(ctx, mail_get_flags(mail), keywords);
3302
0
  if (keywords != NULL)
3303
0
    mailbox_keywords_unref(&keywords);
3304
0
}
3305
3306
void mailbox_save_set_min_modseq(struct mail_save_context *ctx,
3307
         uint64_t min_modseq)
3308
0
{
3309
0
  ctx->data.min_modseq = min_modseq;
3310
0
}
3311
3312
void mailbox_save_set_received_date(struct mail_save_context *ctx,
3313
            time_t received_date, int timezone_offset)
3314
0
{
3315
0
  ctx->data.received_date = received_date;
3316
0
  ctx->data.received_tz_offset = timezone_offset;
3317
0
}
3318
3319
void mailbox_save_set_save_date(struct mail_save_context *ctx,
3320
        time_t save_date)
3321
0
{
3322
0
  ctx->data.save_date = save_date;
3323
0
}
3324
3325
void mailbox_save_set_from_envelope(struct mail_save_context *ctx,
3326
            const char *envelope)
3327
0
{
3328
0
  i_free(ctx->data.from_envelope);
3329
0
  ctx->data.from_envelope = i_strdup(envelope);
3330
0
}
3331
3332
void mailbox_save_set_uid(struct mail_save_context *ctx, uint32_t uid)
3333
0
{
3334
0
  ctx->data.uid = uid;
3335
0
}
3336
3337
void mailbox_save_set_guid(struct mail_save_context *ctx, const char *guid)
3338
0
{
3339
0
  i_assert(guid == NULL || *guid != '\0');
3340
3341
0
  i_free(ctx->data.guid);
3342
0
  ctx->data.guid = i_strdup(guid);
3343
0
}
3344
3345
void mailbox_save_set_pop3_uidl(struct mail_save_context *ctx, const char *uidl)
3346
0
{
3347
0
  i_assert(*uidl != '\0');
3348
0
  i_assert(strchr(uidl, '\n') == NULL);
3349
3350
0
  i_free(ctx->data.pop3_uidl);
3351
0
  ctx->data.pop3_uidl = i_strdup(uidl);
3352
0
}
3353
3354
void mailbox_save_set_pop3_order(struct mail_save_context *ctx,
3355
         unsigned int order)
3356
0
{
3357
0
  i_assert(order > 0);
3358
3359
0
  ctx->data.pop3_order = order;
3360
0
}
3361
3362
struct mail *mailbox_save_get_dest_mail(struct mail_save_context *ctx)
3363
0
{
3364
0
  return ctx->dest_mail;
3365
0
}
3366
3367
int mailbox_save_begin(struct mail_save_context **ctx, struct istream *input)
3368
0
{
3369
0
  struct mailbox *box = (*ctx)->transaction->box;
3370
0
  int ret;
3371
3372
0
  if (mail_index_is_deleted(box->index)) {
3373
0
    mailbox_set_deleted(box);
3374
0
    mailbox_save_cancel(ctx);
3375
0
    return -1;
3376
0
  }
3377
3378
  /* make sure parts get parsed early on */
3379
0
  if (box->storage->set->parsed_mail_attachment_detection_add_flags)
3380
0
    mail_add_temp_wanted_fields((*ctx)->dest_mail,
3381
0
              MAIL_FETCH_MESSAGE_PARTS, NULL);
3382
3383
0
  if (!(*ctx)->copying_or_moving) {
3384
    /* We're actually saving the mail. We're not being called by
3385
       mail_storage_copy() because backend didn't support fast
3386
       copying. */
3387
0
    i_assert(!(*ctx)->copying_via_save);
3388
0
    (*ctx)->saving = TRUE;
3389
0
  } else {
3390
0
    i_assert((*ctx)->copying_via_save);
3391
0
  }
3392
0
  if (box->v.save_begin == NULL) {
3393
0
    mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
3394
0
               "Saving messages not supported");
3395
0
    ret = -1;
3396
0
  } else T_BEGIN {
3397
0
    ret = box->v.save_begin(*ctx, input);
3398
0
  } T_END;
3399
3400
0
  if (ret < 0) {
3401
0
    mailbox_save_cancel(ctx);
3402
0
    return -1;
3403
0
  }
3404
0
  return 0;
3405
0
}
3406
3407
int mailbox_save_begin_replace(struct mail_save_context **ctx,
3408
             struct istream *input,
3409
             struct mail *replaced)
3410
0
{
3411
0
  (*ctx)->expunged_mail = replaced;
3412
0
  return mailbox_save_begin(ctx, input);
3413
0
}
3414
3415
int mailbox_save_continue(struct mail_save_context *ctx)
3416
0
{
3417
0
  int ret;
3418
3419
0
  T_BEGIN {
3420
0
    ret = ctx->transaction->box->v.save_continue(ctx);
3421
0
  } T_END;
3422
0
  return ret;
3423
0
}
3424
3425
static void
3426
mailbox_save_add_pvt_flags(struct mailbox_transaction_context *t,
3427
         enum mail_flags pvt_flags)
3428
0
{
3429
0
  struct mail_save_private_changes *save;
3430
3431
0
  if (!array_is_created(&t->pvt_saves))
3432
0
    i_array_init(&t->pvt_saves, 8);
3433
0
  save = array_append_space(&t->pvt_saves);
3434
0
  save->mailnum = t->save_count;
3435
0
  save->flags = pvt_flags;
3436
0
}
3437
3438
static void
3439
mailbox_save_context_reset(struct mail_save_context *ctx, bool success)
3440
0
{
3441
0
  i_assert(!ctx->unfinished);
3442
0
  if (!ctx->copying_or_moving) {
3443
    /* we're finishing a save (not copy/move). Note that we could
3444
       have come here also from mailbox_save_cancel(), in which
3445
       case ctx->saving may be FALSE. */
3446
0
    i_assert(!ctx->copying_via_save);
3447
0
    i_assert(ctx->saving || !success);
3448
0
    ctx->saving = FALSE;
3449
0
  } else {
3450
0
    i_assert(ctx->copying_via_save || !success);
3451
    /* We came from mailbox_copy(). saving==TRUE is possible here
3452
       if we also came from mailbox_save_using_mail(). Don't set
3453
       saving=FALSE yet in that case, because copy() is still
3454
       running. */
3455
0
  }
3456
0
}
3457
3458
int mailbox_save_finish(struct mail_save_context **_ctx)
3459
0
{
3460
0
  struct mail_save_context *ctx = *_ctx;
3461
0
  struct mailbox_transaction_context *t = ctx->transaction;
3462
  /* we need to keep a copy of this because save_finish implementations
3463
     will likely zero the data structure during cleanup */
3464
0
  enum mail_flags pvt_flags = ctx->data.pvt_flags;
3465
0
  bool copying_via_save = ctx->copying_via_save;
3466
0
  int ret;
3467
3468
  /* Do one final continue. The caller may not have done it if the
3469
     input stream's offset already matched the number of bytes that
3470
     were wanted to be saved. But due to nested istreams some of the
3471
     underlying ones may not have seen the EOF yet, and haven't flushed
3472
     out the pending data. */
3473
0
  if (mailbox_save_continue(ctx) < 0) {
3474
0
    mailbox_save_cancel(_ctx);
3475
0
    return -1;
3476
0
  }
3477
0
  *_ctx = NULL;
3478
3479
0
  ctx->finishing = TRUE;
3480
0
  T_BEGIN {
3481
0
    ret = t->box->v.save_finish(ctx);
3482
0
  } T_END;
3483
0
  ctx->finishing = FALSE;
3484
3485
0
  if (ret == 0 && !copying_via_save) {
3486
0
    if (pvt_flags != 0)
3487
0
      mailbox_save_add_pvt_flags(t, pvt_flags);
3488
0
    t->save_count++;
3489
0
    if (ctx->expunged_mail != NULL)
3490
0
      mail_expunge(ctx->expunged_mail);
3491
0
  }
3492
3493
0
  mailbox_save_context_reset(ctx, TRUE);
3494
0
  return ret;
3495
0
}
3496
3497
void mailbox_save_cancel(struct mail_save_context **_ctx)
3498
0
{
3499
0
  struct mail_save_context *ctx = *_ctx;
3500
3501
0
  *_ctx = NULL;
3502
0
  T_BEGIN {
3503
0
    ctx->transaction->box->v.save_cancel(ctx);
3504
0
  } T_END;
3505
3506
  /* the dest_mail is no longer valid. if we're still saving
3507
     more mails, the mail sequence may get reused. make sure
3508
     the mail gets reset in between */
3509
0
  mailbox_save_dest_mail_close(ctx);
3510
3511
0
  mailbox_save_context_reset(ctx, FALSE);
3512
0
}
3513
3514
struct mailbox_transaction_context *
3515
mailbox_save_get_transaction(struct mail_save_context *ctx)
3516
0
{
3517
0
  return ctx->transaction;
3518
0
}
3519
3520
static int mailbox_copy_int(struct mail_save_context **_ctx, struct mail *mail)
3521
0
{
3522
0
  struct mail_save_context *ctx = *_ctx;
3523
0
  struct mailbox_transaction_context *t = ctx->transaction;
3524
0
  enum mail_flags pvt_flags = ctx->data.pvt_flags;
3525
0
  struct mail *backend_mail;
3526
0
  int ret;
3527
3528
0
  *_ctx = NULL;
3529
3530
0
  if (mail_index_is_deleted(t->box->index)) {
3531
0
    mailbox_set_deleted(t->box);
3532
0
    mailbox_save_cancel(&ctx);
3533
0
    return -1;
3534
0
  }
3535
3536
  /* bypass virtual storage, so hard linking can be used whenever
3537
     possible */
3538
0
  if (mail_get_backend_mail(mail, &backend_mail) < 0) {
3539
0
    mailbox_save_cancel(&ctx);
3540
0
    return -1;
3541
0
  }
3542
3543
0
  i_assert(!ctx->copying_or_moving);
3544
0
  i_assert(ctx->copy_src_mail == NULL);
3545
0
  ctx->copying_or_moving = TRUE;
3546
0
  ctx->copy_src_mail = mail;
3547
0
  ctx->finishing = TRUE;
3548
0
  T_BEGIN {
3549
0
    ret = t->box->v.copy(ctx, backend_mail);
3550
0
  } T_END;
3551
0
  ctx->finishing = FALSE;
3552
0
  if (ret == 0) {
3553
0
    if (pvt_flags != 0)
3554
0
      mailbox_save_add_pvt_flags(t, pvt_flags);
3555
0
    t->save_count++;
3556
0
  }
3557
0
  i_assert(!ctx->unfinished);
3558
3559
0
  ctx->copy_src_mail = NULL;
3560
0
  ctx->copying_via_save = FALSE;
3561
0
  ctx->copying_or_moving = FALSE;
3562
0
  ctx->saving = FALSE; /* if we came from mailbox_save_using_mail() */
3563
0
  return ret;
3564
0
}
3565
3566
int mailbox_copy(struct mail_save_context **_ctx, struct mail *mail)
3567
0
{
3568
0
  struct mail_save_context *ctx = *_ctx;
3569
3570
0
  i_assert(!ctx->saving);
3571
0
  i_assert(!ctx->moving);
3572
3573
0
  int ret;
3574
0
  T_BEGIN {
3575
0
    ret = mailbox_copy_int(_ctx, mail);
3576
0
  } T_END;
3577
3578
0
  return ret;
3579
0
}
3580
3581
int mailbox_move(struct mail_save_context **_ctx, struct mail *mail)
3582
0
{
3583
0
  struct mail_save_context *ctx = *_ctx;
3584
0
  int ret;
3585
3586
0
  i_assert(!ctx->saving);
3587
0
  i_assert(!ctx->moving);
3588
3589
0
  ctx->moving = TRUE;
3590
0
  ctx->expunged_mail = mail;
3591
0
  T_BEGIN {
3592
0
    if ((ret = mailbox_copy_int(_ctx, mail)) == 0)
3593
0
      mail_expunge(mail);
3594
0
  } T_END;
3595
0
  ctx->moving = FALSE;
3596
0
  return ret;
3597
0
}
3598
3599
int mailbox_save_using_mail(struct mail_save_context **_ctx, struct mail *mail)
3600
0
{
3601
0
  struct mail_save_context *ctx = *_ctx;
3602
3603
0
  i_assert(!ctx->saving);
3604
0
  i_assert(!ctx->moving);
3605
3606
0
  ctx->saving = TRUE;
3607
0
  return mailbox_copy_int(_ctx, mail);
3608
0
}
3609
3610
bool mailbox_is_inconsistent(struct mailbox *box)
3611
0
{
3612
0
  return box->mailbox_deleted || box->v.is_inconsistent(box);
3613
0
}
3614
3615
void mailbox_set_deleted(struct mailbox *box)
3616
0
{
3617
0
  mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
3618
0
             "Mailbox was deleted under us");
3619
0
  box->mailbox_deleted = TRUE;
3620
0
}
3621
3622
static int get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
3623
           const char **internal_path, const char **path_r)
3624
0
{
3625
0
  int ret;
3626
3627
0
  if (internal_path != NULL && *internal_path != NULL) {
3628
0
    if ((*internal_path)[0] == '\0') {
3629
0
      *path_r = NULL;
3630
0
      return 0;
3631
0
    }
3632
0
    *path_r = *internal_path;
3633
0
    return 1;
3634
0
  }
3635
0
  ret = mailbox_list_get_path(box->list, box->name, type, path_r);
3636
0
  if (ret < 0) {
3637
0
    mail_storage_copy_list_error(box->storage, box->list);
3638
0
    return -1;
3639
0
  }
3640
0
  if (internal_path != NULL && *internal_path == NULL)
3641
0
    *internal_path = ret == 0 ? "" : p_strdup(box->pool, *path_r);
3642
0
  return ret;
3643
0
}
3644
3645
int mailbox_get_path_to(struct mailbox *box, enum mailbox_list_path_type type,
3646
      const char **path_r)
3647
0
{
3648
0
  if (type == MAILBOX_LIST_PATH_TYPE_MAILBOX)
3649
0
    return get_path_to(box, type, &box->_path, path_r);
3650
0
  if (type == MAILBOX_LIST_PATH_TYPE_INDEX)
3651
0
    return get_path_to(box, type, &box->_index_path, path_r);
3652
0
  return get_path_to(box, type, NULL, path_r);
3653
0
}
3654
3655
const char *mailbox_get_path(struct mailbox *box)
3656
0
{
3657
0
  i_assert(box->_path != NULL);
3658
0
  i_assert(box->_path[0] != '\0');
3659
0
  return box->_path;
3660
0
}
3661
3662
const char *mailbox_get_index_path(struct mailbox *box)
3663
0
{
3664
0
  i_assert(box->_index_path != NULL);
3665
0
  i_assert(box->_index_path[0] != '\0');
3666
0
  return box->_index_path;
3667
0
}
3668
3669
static void mailbox_get_permissions_if_not_set(struct mailbox *box)
3670
0
{
3671
0
  if (box->_perm.file_create_mode != 0)
3672
0
    return;
3673
3674
0
  if (box->input != NULL) {
3675
0
    box->_perm.file_uid = geteuid();
3676
0
    box->_perm.file_create_mode = 0600;
3677
0
    box->_perm.dir_create_mode = 0700;
3678
0
    box->_perm.file_create_gid = (gid_t)-1;
3679
0
    box->_perm.file_create_gid_origin = "defaults";
3680
0
    return;
3681
0
  }
3682
3683
0
  struct mailbox_permissions perm;
3684
0
  mailbox_list_get_permissions(box->list, box->name, &perm);
3685
0
  mailbox_permissions_copy(&box->_perm, &perm, box->pool);
3686
0
}
3687
3688
const struct mailbox_permissions *mailbox_get_permissions(struct mailbox *box)
3689
0
{
3690
0
  mailbox_get_permissions_if_not_set(box);
3691
3692
0
  if (!box->_perm.mail_index_permissions_set && box->index != NULL) {
3693
0
    box->_perm.mail_index_permissions_set = TRUE;
3694
0
    mail_index_set_permissions(box->index,
3695
0
             box->_perm.file_create_mode,
3696
0
             box->_perm.file_create_gid,
3697
0
             box->_perm.file_create_gid_origin);
3698
0
  }
3699
0
  return &box->_perm;
3700
0
}
3701
3702
void mailbox_refresh_permissions(struct mailbox *box)
3703
0
{
3704
0
  i_zero(&box->_perm);
3705
0
  (void)mailbox_get_permissions(box);
3706
0
}
3707
3708
int mailbox_create_fd(struct mailbox *box, const char *path, int flags,
3709
          int *fd_r)
3710
0
{
3711
0
  const struct mailbox_permissions *perm = mailbox_get_permissions(box);
3712
0
  mode_t old_mask;
3713
0
  int fd;
3714
3715
0
  i_assert((flags & O_CREAT) != 0);
3716
3717
0
  *fd_r = -1;
3718
3719
0
  old_mask = umask(0);
3720
0
  fd = open(path, flags, perm->file_create_mode);
3721
0
  umask(old_mask);
3722
3723
0
  if (fd != -1) {
3724
    /* ok */
3725
0
  } else if (errno == EEXIST) {
3726
    /* O_EXCL used, caller will handle this error */
3727
0
    return 0;
3728
0
  } else if (errno == ENOENT) {
3729
0
    mailbox_set_deleted(box);
3730
0
    return -1;
3731
0
  } else if (errno == ENOTDIR) {
3732
0
    mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
3733
0
      "Mailbox doesn't allow inferior mailboxes");
3734
0
    return -1;
3735
0
  } else if (mail_storage_set_error_from_errno(box->storage)) {
3736
0
    return -1;
3737
0
  } else {
3738
0
    mailbox_set_critical(box, "open(%s, O_CREAT) failed: %m", path);
3739
0
    return -1;
3740
0
  }
3741
3742
0
  if (perm->file_create_gid != (gid_t)-1) {
3743
0
    if (fchown(fd, (uid_t)-1, perm->file_create_gid) == 0) {
3744
      /* ok */
3745
0
    } else if (errno == EPERM) {
3746
0
      mailbox_set_critical(box, "%s",
3747
0
        eperm_error_get_chgrp("fchown", path,
3748
0
          perm->file_create_gid,
3749
0
          perm->file_create_gid_origin));
3750
0
    } else {
3751
0
      mailbox_set_critical(box,
3752
0
        "fchown(%s) failed: %m", path);
3753
0
    }
3754
0
  }
3755
0
  *fd_r = fd;
3756
0
  return 1;
3757
0
}
3758
3759
int mailbox_mkdir(struct mailbox *box, const char *path,
3760
      enum mailbox_list_path_type type)
3761
0
{
3762
0
  const struct mailbox_permissions *perm = mailbox_get_permissions(box);
3763
0
  const char *root_dir;
3764
3765
0
  if (!perm->gid_origin_is_mailbox_path) {
3766
    /* mailbox root directory doesn't exist, create it */
3767
0
    root_dir = mailbox_list_get_root_forced(box->list, type);
3768
0
    if (mailbox_list_mkdir_root(box->list, root_dir, type) < 0) {
3769
0
      mail_storage_copy_list_error(box->storage, box->list);
3770
0
      return -1;
3771
0
    }
3772
0
  }
3773
3774
0
  if (mkdir_parents_chgrp(path, perm->dir_create_mode,
3775
0
        perm->file_create_gid,
3776
0
        perm->file_create_gid_origin) == 0)
3777
0
    return 1;
3778
0
  else if (errno == EEXIST)
3779
0
    return 0;
3780
0
  else if (errno == ENOTDIR) {
3781
0
    mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
3782
0
      "Mailbox doesn't allow inferior mailboxes");
3783
0
    return -1;
3784
0
  } else if (mail_storage_set_error_from_errno(box->storage)) {
3785
0
    return -1;
3786
0
  } else {
3787
0
    mailbox_set_critical(box, "mkdir_parents(%s) failed: %m", path);
3788
0
    return -1;
3789
0
  }
3790
0
}
3791
3792
int mailbox_create_missing_dir(struct mailbox *box,
3793
             enum mailbox_list_path_type type)
3794
0
{
3795
0
  const char *mail_dir, *dir;
3796
0
  struct stat st;
3797
0
  int ret;
3798
3799
0
  if ((ret = mailbox_get_path_to(box, type, &dir)) <= 0)
3800
0
    return ret;
3801
0
  if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
3802
0
        &mail_dir) < 0)
3803
0
    return -1;
3804
0
  if (null_strcmp(dir, mail_dir) != 0) {
3805
    /* Mailbox directory is different - create a missing dir */
3806
0
  } else if ((box->list->props & MAILBOX_LIST_PROP_AUTOCREATE_DIRS) != 0) {
3807
    /* This layout (e.g. imapc) wants to autocreate missing mailbox
3808
       directories as well. */
3809
0
  } else {
3810
    /* If the mailbox directory doesn't exist, the mailbox
3811
       shouldn't exist at all. So just assume that it's already
3812
       created and if there's a race condition just fail later. */
3813
0
    return 0;
3814
0
  }
3815
3816
  /* we call this function even when the directory exists, so first do a
3817
     quick check to see if we need to mkdir anything */
3818
0
  if (stat(dir, &st) == 0)
3819
0
    return 0;
3820
3821
0
  if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) == 0 &&
3822
0
      null_strcmp(dir, mail_dir) != 0 && mail_dir != NULL &&
3823
0
      stat(mail_dir, &st) < 0 && (errno == ENOENT || errno == ENOTDIR)) {
3824
    /* Race condition - mail root directory doesn't exist
3825
       anymore either. We shouldn't create this directory
3826
       anymore. */
3827
0
    mailbox_set_deleted(box);
3828
0
    return -1;
3829
0
  }
3830
3831
0
  return mailbox_mkdir(box, dir, type);
3832
0
}
3833
3834
unsigned int mail_storage_get_lock_timeout(struct mail_storage *storage,
3835
             unsigned int secs)
3836
0
{
3837
0
  return storage->set->mail_max_lock_timeout == 0 ? secs :
3838
0
    I_MIN(secs, storage->set->mail_max_lock_timeout);
3839
0
}
3840
3841
enum mail_index_open_flags
3842
mail_storage_settings_to_index_flags(const struct mail_storage_settings *set)
3843
0
{
3844
0
  enum mail_index_open_flags index_flags = 0;
3845
3846
0
#ifndef MMAP_CONFLICTS_WRITE
3847
0
  if (set->mmap_disable)
3848
0
#endif
3849
0
    index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
3850
0
  if (set->dotlock_use_excl)
3851
0
    index_flags |= MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL;
3852
0
  if (set->mail_nfs_index)
3853
0
    index_flags |= MAIL_INDEX_OPEN_FLAG_NFS_FLUSH;
3854
0
  return index_flags;
3855
0
}
3856
3857
static void mailbox_settings_filters_add(struct event *event,
3858
           struct mailbox_list *list,
3859
           const char *vname)
3860
0
{
3861
0
  if (array_is_empty(&list->ns->set->mailboxes))
3862
0
    return;
3863
3864
0
  const char *vname_without_prefix =
3865
0
    mailbox_get_name_without_prefix(list->ns, vname);
3866
0
  unsigned int i, count;
3867
0
  const struct mailbox_settings *const *mailboxes =
3868
0
    array_get(&list->ns->set->parsed_mailboxes, &count);
3869
3870
0
  for (i = 0; i < count; i++) {
3871
0
    if (!wildcard_match(vname_without_prefix, mailboxes[i]->name))
3872
0
      continue;
3873
3874
0
    const char *filter_name =
3875
0
      array_idx_elem(&list->ns->set->mailboxes, i);
3876
0
    settings_event_add_list_filter_name(event,
3877
0
                "mailbox", filter_name);
3878
0
  }
3879
0
}
3880
3881
struct event *
3882
mail_storage_mailbox_create_event(struct event *parent,
3883
          struct mailbox_list *list, const char *vname)
3884
0
{
3885
0
  struct event *event = event_create(parent);
3886
0
  event_add_category(event, &event_category_mailbox);
3887
3888
0
  mailbox_settings_filters_add(event, list, vname);
3889
0
  event_add_str(event, "mailbox", vname);
3890
0
  event_add_str(event, SETTINGS_EVENT_NAMESPACE_NAME, list->ns->set->name);
3891
0
  settings_event_add_list_filter_name(event,
3892
0
    SETTINGS_EVENT_NAMESPACE_NAME, list->ns->set->name);
3893
3894
0
  event_drop_parent_log_prefixes(event, 1);
3895
0
  event_set_append_log_prefix(event, t_strdup_printf(
3896
0
    "Mailbox %s: ", mailbox_name_sanitize(vname)));
3897
0
  return event;
3898
0
}
3899
3900
int mail_parse_human_timestamp(const char *str, time_t *timestamp_r,
3901
             bool *utc_r)
3902
0
{
3903
0
  struct tm tm;
3904
0
  unsigned int secs;
3905
0
  const char *error;
3906
0
  int tz;
3907
3908
0
  if (i_isdigit(str[0]) && i_isdigit(str[1]) &&
3909
0
      i_isdigit(str[2]) && i_isdigit(str[3]) && str[4] == '-' &&
3910
0
      i_isdigit(str[5]) && i_isdigit(str[6]) && str[7] == '-' &&
3911
0
      i_isdigit(str[8]) && i_isdigit(str[9]) && str[10] == '\0') {
3912
    /* yyyy-mm-dd */
3913
0
    i_zero(&tm);
3914
0
    tm.tm_year = (str[0]-'0') * 1000 + (str[1]-'0') * 100 +
3915
0
      (str[2]-'0') * 10 + (str[3]-'0') - 1900;
3916
0
    tm.tm_mon = (str[5]-'0') * 10 + (str[6]-'0') - 1;
3917
0
    tm.tm_mday = (str[8]-'0') * 10 + (str[9]-'0');
3918
0
    *timestamp_r = utc_mktime(&tm);
3919
0
    *utc_r = TRUE;
3920
0
    return 0;
3921
0
  } else if (imap_parse_date(str, timestamp_r)) {
3922
    /* imap datetime */
3923
0
    *utc_r = FALSE;
3924
0
    return 0;
3925
0
  } else if (imap_parse_datetime(str, timestamp_r, &tz)) {
3926
    /* imap datetime */
3927
0
    *utc_r = TRUE;
3928
0
    return 0;
3929
0
  } else if (str_to_time(str, timestamp_r) == 0) {
3930
    /* unix timestamp */
3931
0
    *utc_r = TRUE;
3932
0
    return 0;
3933
0
  } else if (str_parse_get_interval(str, &secs, &error) == 0) {
3934
0
    *timestamp_r = ioloop_time - secs;
3935
0
    *utc_r = TRUE;
3936
0
    return 0;
3937
0
  } else {
3938
0
    return -1;
3939
0
  }
3940
0
}
3941
3942
void mail_set_mail_cache_corrupted(struct mail *mail, const char *fmt, ...)
3943
0
{
3944
0
  struct mail_cache_view *cache_view =
3945
0
    mail->transaction->cache_view;
3946
3947
0
  i_assert(cache_view != NULL);
3948
3949
0
  va_list va;
3950
0
  va_start(va, fmt);
3951
3952
0
  T_BEGIN {
3953
0
    mail_cache_set_seq_corrupted_reason(cache_view, mail->seq,
3954
0
                t_strdup_vprintf(fmt, va));
3955
0
  } T_END;
3956
3957
  /* update also the storage's internal error */
3958
0
  mailbox_set_index_error(mail->box);
3959
3960
0
  va_end(va);
3961
0
}
3962
3963
static int
3964
mail_storage_dotlock_create(const char *lock_path,
3965
          const struct file_create_settings *lock_set,
3966
          const struct mail_storage_settings *mail_set,
3967
          struct file_lock **lock_r, const char **error_r)
3968
0
{
3969
0
  const struct dotlock_settings dotlock_set = {
3970
0
    .timeout = lock_set->lock_timeout_secs,
3971
0
    .stale_timeout = I_MAX(60*5, lock_set->lock_timeout_secs),
3972
0
    .lock_suffix = "",
3973
3974
0
    .use_excl_lock = mail_set->dotlock_use_excl,
3975
0
    .nfs_flush = mail_set->mail_nfs_storage,
3976
0
    .use_io_notify = TRUE,
3977
0
  };
3978
0
  struct dotlock *dotlock;
3979
0
  int ret = file_dotlock_create(&dotlock_set, lock_path, 0, &dotlock);
3980
0
  if (ret <= 0) {
3981
0
    *error_r = t_strdup_printf("file_dotlock_create(%s) failed: %m",
3982
0
             lock_path);
3983
0
    return ret;
3984
0
  }
3985
0
  *lock_r = file_lock_from_dotlock(&dotlock);
3986
0
  return 1;
3987
0
}
3988
3989
int mail_storage_lock_create(const char *lock_path,
3990
           const struct file_create_settings *lock_set,
3991
           const struct mail_storage_settings *mail_set,
3992
           struct file_lock **lock_r, const char **error_r)
3993
0
{
3994
0
  struct file_create_settings lock_set_new = *lock_set;
3995
0
  bool created;
3996
3997
0
  if (lock_set->lock_settings.lock_method == FILE_LOCK_METHOD_DOTLOCK)
3998
0
    return mail_storage_dotlock_create(lock_path, lock_set, mail_set, lock_r, error_r);
3999
4000
0
  lock_set_new.lock_settings.close_on_free = TRUE;
4001
0
  lock_set_new.lock_settings.unlink_on_free = TRUE;
4002
0
  if (file_create_locked(lock_path, &lock_set_new, lock_r,
4003
0
             &created, error_r) == -1) {
4004
0
    *error_r = t_strdup_printf("file_create_locked(%s) failed: %s",
4005
0
             lock_path, *error_r);
4006
0
    return errno == EAGAIN ? 0 : -1;
4007
0
  }
4008
0
  return 1;
4009
0
}
4010
4011
int mailbox_lock_file_create(struct mailbox *box, const char *lock_fname,
4012
           unsigned int lock_secs, struct file_lock **lock_r,
4013
           const char **error_r)
4014
0
{
4015
0
  const struct mailbox_permissions *perm;
4016
0
  struct file_create_settings set;
4017
0
  const char *lock_path;
4018
4019
0
  perm = mailbox_get_permissions(box);
4020
0
  i_zero(&set);
4021
0
  set.lock_timeout_secs =
4022
0
    mail_storage_get_lock_timeout(box->storage, lock_secs);
4023
0
  set.lock_settings.lock_method = box->storage->set->parsed_lock_method;
4024
0
  set.mode = perm->file_create_mode;
4025
0
  set.gid = perm->file_create_gid;
4026
0
  set.gid_origin = perm->file_create_gid_origin;
4027
4028
0
  if (box->list->mail_set->mail_volatile_path[0] == '\0')
4029
0
    lock_path = t_strdup_printf("%s/%s", box->index->dir, lock_fname);
4030
0
  else {
4031
0
    unsigned char box_name_sha1[SHA1_RESULTLEN];
4032
0
    string_t *str = t_str_new(128);
4033
4034
    /* Keep this simple: Use the lock_fname with a SHA1 of the
4035
       mailbox name as the suffix. The mailbox name itself could
4036
       be too large as a filename and creating the full directory
4037
       structure would be pretty troublesome. It would also make
4038
       it more difficult to perform the automated deletion of empty
4039
       lock directories.
4040
       The SHA1 is calculated from the namespace prefix concatenated
4041
       with the mailbox name (prefix first, then name) to avoid
4042
       collisions when multiple namespaces share the same
4043
       mail_volatile_path. */
4044
0
    str_printfa(str, "%s/%s.", box->list->mail_set->mail_volatile_path,
4045
0
          lock_fname);
4046
0
    struct sha1_ctxt ctx;
4047
0
    sha1_init(&ctx);
4048
0
    sha1_loop(&ctx, box->list->ns->prefix, box->list->ns->prefix_len);
4049
0
    sha1_loop(&ctx, box->name, strlen(box->name));
4050
0
    sha1_result(&ctx, box_name_sha1);
4051
0
    binary_to_hex_append(str, box_name_sha1, sizeof(box_name_sha1));
4052
0
    lock_path = str_c(str);
4053
0
    set.mkdir_mode = 0700;
4054
0
  }
4055
4056
0
  return mail_storage_lock_create(lock_path, &set,
4057
0
          box->storage->set, lock_r, error_r);
4058
0
}
4059
4060
void mailbox_sync_notify(struct mailbox *box, uint32_t uid,
4061
       enum mailbox_sync_type sync_type)
4062
0
{
4063
0
  if (box->v.sync_notify != NULL) T_BEGIN {
4064
0
    box->v.sync_notify(box, uid, sync_type);
4065
0
  } T_END;
4066
4067
  /* Send an event for expunged mail. */
4068
0
  if (sync_type == MAILBOX_SYNC_TYPE_EXPUNGE) {
4069
0
    e_debug(event_create_passthrough(box->event)->
4070
0
      set_name("mail_expunged")->
4071
0
      add_int("uid", uid)->event(),
4072
0
      "UID %u: Mail expunged", uid);
4073
0
  }
4074
0
}