~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/lib-storage/mailbox-list.c

  • Committer: Bazaar Package Importer
  • Author(s): CHuck Short, Chuck Short
  • Date: 2009-11-06 00:47:29 UTC
  • mfrom: (4.1.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091106004729-i39n7v9e7d4h51f6
Tags: 1:1.2.6-1ubuntu1
* Merge from debian testing, remaining changes:
  Add new binary pkg dovecot-postfix that integrates postfix and dovecot
  automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restrictions
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
   + debian/dovecot-postfix.dirs: create backup directory for postfix's configuration
   + restart postfix and dovecot.
   + debian/dovecot-postfix.postrm:
     - remove all dovecot related configuration from postfix.
     - restart postfix and dovecot.
   + debian/dovecot-common.init:
     - check if /etc/dovecot/dovecot-postfix.conf exists and use it
       as the configuration file if so.
   + debian/patches/warning-ubuntu-postfix.dpatch
     - add warning about dovecot-postfix.conf in dovecot default 
       configuration file
   + debian/patches/dovecot-postfix.conf.diff:
     - Ubuntu server custom changes to the default dovecot configuration for
       better interfation with postfix
     - enable sieve plugin
   + debian/patches/dovecot-postfix.conf.diff:
     + Ubuntu server custom changes to the default dovecot configuration for
       better integration with postfix:
       - enable imap, pop3, imaps, pop3s and managesieve by default.
       - enable dovecot LDA (deliver).
       - enable SASL auth socket in postfix private directory.
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules:
       + install profile
     - debian/control:
       + Suggest ufw
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). LP: #254721
   + debian/control:
     - Update Vcs-* headers.
   + debian/rules:
     - Create emtpy stamp.h.in files in dovecot-sieve/ and dovecot-managesieve/
       if they're not there since empty files are not included in the diff.gz 
       file.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
   + Dropped:
     - debian/patches/security-CVE-2009-3235: Applied upstream.
     - debian/patches/fix-pop3-assertion.dpatch: Applied upstream.
     - dovecot-sieve and dovecot-managesieve: Use the debian patches instead.

  [Chuck Short]
  - Updated dovecot-sieve to 0.1.13.
  - Updated dovecot-managesieve to 0.11.9.

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
#include "lib.h"
4
4
#include "array.h"
5
5
#include "ioloop.h"
 
6
#include "mkdir-parents.h"
 
7
#include "str.h"
6
8
#include "home-expand.h"
7
9
#include "unlink-directory.h"
8
10
#include "imap-match.h"
 
11
#include "imap-utf7.h"
9
12
#include "mailbox-tree.h"
10
13
#include "mailbox-list-private.h"
11
14
 
22
25
#define MAILBOX_MAX_HIERARCHY_LEVELS 20
23
26
#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 200
24
27
 
25
 
/* Message to show to users when critical error occurs */
26
 
#define CRITICAL_MSG \
27
 
        "Internal error occurred. Refer to server log for more information."
28
 
#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
 
28
struct ns_list_iterate_context {
 
29
        struct mailbox_list_iterate_context ctx;
 
30
        struct mailbox_list_iterate_context *backend_ctx;
 
31
        struct mail_namespace *namespaces;
 
32
        pool_t pool;
 
33
        const char **patterns;
 
34
};
29
35
 
30
36
struct mailbox_list_module_register mailbox_list_module_register = { 0 };
31
37
 
100
106
        return 0;
101
107
}
102
108
 
103
 
static const char *fix_path(const char *path)
 
109
static int fix_path(struct mail_namespace *ns, const char *path,
 
110
                    const char **path_r, const char **error_r)
104
111
{
105
112
        size_t len = strlen(path);
106
113
 
107
114
        if (len > 1 && path[len-1] == '/')
108
115
                path = t_strndup(path, len-1);
109
 
        return home_expand(path);
 
116
        if (path[0] == '~' && path[1] != '/') {
 
117
                /* ~otheruser/dir */
 
118
                if (home_try_expand(&path) < 0) {
 
119
                        *error_r = t_strconcat(
 
120
                                "No home directory for system user. "
 
121
                                "Can't expand ", t_strcut(path, '/'),
 
122
                                " for ", NULL);
 
123
                        return -1;
 
124
                }
 
125
        } else {
 
126
                if (mail_user_try_home_expand(ns->user, &path) < 0) {
 
127
                        *error_r = "Home directory not set for user. "
 
128
                                "Can't expand ~/ for ";
 
129
                        return -1;
 
130
                }
 
131
        }
 
132
        *path_r = path;
 
133
        return 0;
 
134
}
 
135
 
 
136
static const char *split_next_arg(const char *const **_args)
 
137
{
 
138
        const char *const *args = *_args;
 
139
        const char *str = args[0];
 
140
 
 
141
        args++;
 
142
        while (*args != NULL && **args == '\0') {
 
143
                args++;
 
144
                if (*args == NULL) {
 
145
                        /* string ends with ":", just ignore it. */
 
146
                        break;
 
147
                }
 
148
                str = t_strconcat(str, ":", *args, NULL);
 
149
                args++;
 
150
        }
 
151
        *_args = args;
 
152
        return str;
110
153
}
111
154
 
112
155
int mailbox_list_settings_parse(const char *data,
113
156
                                struct mailbox_list_settings *set,
 
157
                                struct mail_namespace *ns,
114
158
                                const char **layout, const char **alt_dir_r,
115
159
                                const char **error_r)
116
160
{
117
 
        const char *const *tmp, *key, *value;
 
161
        const char *const *tmp, *key, *value, **dest, *str, *error;
118
162
 
119
163
        i_assert(*data != '\0');
120
164
 
124
168
 
125
169
        /* <root dir> */
126
170
        tmp = t_strsplit(data, ":");
127
 
        set->root_dir = fix_path(*tmp);
128
 
        tmp++;
 
171
        str = split_next_arg(&tmp);
 
172
        if (fix_path(ns, str, &set->root_dir, &error) < 0) {
 
173
                *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
 
174
                return -1;
 
175
        }
129
176
 
130
 
        for (; *tmp != NULL; tmp++) {
131
 
                value = strchr(*tmp, '=');
 
177
        while (*tmp != NULL) {
 
178
                str = split_next_arg(&tmp);
 
179
                value = strchr(str, '=');
132
180
                if (value == NULL) {
133
 
                        key = *tmp;
 
181
                        key = str;
134
182
                        value = "";
135
183
                } else {
136
 
                        key = t_strdup_until(*tmp, value);
 
184
                        key = t_strdup_until(str, value);
137
185
                        value++;
138
186
                }
139
187
 
140
188
                if (strcmp(key, "INBOX") == 0)
141
 
                        set->inbox_path = fix_path(value);
 
189
                        dest = &set->inbox_path;
142
190
                else if (strcmp(key, "INDEX") == 0)
143
 
                        set->index_dir = fix_path(value);
 
191
                        dest = &set->index_dir;
144
192
                else if (strcmp(key, "CONTROL") == 0)
145
 
                        set->control_dir = fix_path(value);
 
193
                        dest = &set->control_dir;
146
194
                else if (strcmp(key, "ALT") == 0 && alt_dir_r != NULL)
147
 
                        *alt_dir_r = fix_path(value);
 
195
                        dest = alt_dir_r;
148
196
                else if (strcmp(key, "LAYOUT") == 0)
149
 
                        *layout = value;
 
197
                        dest = layout;
150
198
                else if (strcmp(key, "SUBSCRIPTIONS") == 0)
151
 
                        set->subscription_fname = fix_path(value);
 
199
                        dest = &set->subscription_fname;
152
200
                else if (strcmp(key, "DIRNAME") == 0)
153
 
                        set->maildir_name = value;
 
201
                        dest = &set->maildir_name;
 
202
                else if (strcmp(key, "MAILBOXDIR") == 0)
 
203
                        dest = &set->mailbox_dir_name;
154
204
                else {
155
205
                        *error_r = t_strdup_printf("Unknown setting: %s", key);
156
206
                        return -1;
157
207
                }
 
208
                if (fix_path(ns, value, dest, &error) < 0) {
 
209
                        *error_r = t_strconcat(error, key, " in: ", data, NULL);
 
210
                        return -1;
 
211
                }
158
212
        }
159
213
 
160
214
        if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
173
227
        list->ns = ns;
174
228
        list->flags = flags;
175
229
        list->file_create_mode = (mode_t)-1;
 
230
        list->dir_create_mode = (mode_t)-1;
176
231
        list->file_create_gid = (gid_t)-1;
177
232
 
178
233
        /* copy settings */
187
242
        list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
188
243
        list->set.subscription_fname =
189
244
                p_strdup(list->pool, set->subscription_fname);
190
 
        list->set.maildir_name = p_strdup(list->pool, set->maildir_name);
 
245
        list->set.maildir_name =
 
246
                (list->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 ? "" :
 
247
                p_strdup(list->pool, set->maildir_name);
 
248
 
 
249
        if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
 
250
                list->set.mailbox_dir_name = "";
 
251
        else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
 
252
                list->set.mailbox_dir_name =
 
253
                        p_strdup(list->pool, set->mailbox_dir_name);
 
254
        } else {
 
255
                list->set.mailbox_dir_name =
 
256
                        p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
 
257
        }
191
258
 
192
259
        list->set.mail_storage_flags = set->mail_storage_flags;
193
260
        list->set.lock_method = set->lock_method;
194
261
 
195
262
        if ((flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
196
263
                i_info("%s: root=%s, index=%s, control=%s, inbox=%s",
197
 
                       list->name, list->set.root_dir,
 
264
                       list->name,
 
265
                       list->set.root_dir == NULL ? "" : list->set.root_dir,
198
266
                       list->set.index_dir == NULL ? "" : list->set.index_dir,
199
267
                       list->set.control_dir == NULL ?
200
268
                       "" : list->set.control_dir,
216
284
        list->v.deinit(list);
217
285
}
218
286
 
219
 
const char *mailbox_list_get_driver_name(struct mailbox_list *list)
 
287
const char *mailbox_list_get_driver_name(const struct mailbox_list *list)
220
288
{
221
289
        return list->name;
222
290
}
223
291
 
224
 
char mailbox_list_get_hierarchy_sep(struct mailbox_list *list)
 
292
char mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
225
293
{
226
294
        return list->hierarchy_sep;
227
295
}
228
296
 
229
 
enum mailbox_list_flags mailbox_list_get_flags(struct mailbox_list *list)
 
297
enum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
230
298
{
231
299
        return list->flags;
232
300
}
233
301
 
234
 
struct mail_namespace *mailbox_list_get_namespace(struct mailbox_list *list)
 
302
struct mail_namespace *
 
303
mailbox_list_get_namespace(const struct mailbox_list *list)
235
304
{
236
305
        return list->ns;
237
306
}
238
307
 
239
 
void mailbox_list_get_permissions(struct mailbox_list *list,
240
 
                                  mode_t *mode_r, gid_t *gid_r)
 
308
static mode_t get_dir_mode(mode_t mode)
 
309
{
 
310
        /* add the execute bit if either read or write bit is set */
 
311
        if ((mode & 0600) != 0) mode |= 0100;
 
312
        if ((mode & 0060) != 0) mode |= 0010;
 
313
        if ((mode & 0006) != 0) mode |= 0001;
 
314
        return mode;
 
315
}
 
316
 
 
317
static void
 
318
mailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
 
319
                                  mode_t *file_mode_r, mode_t *dir_mode_r,
 
320
                                  gid_t *gid_r, const char **gid_origin_r)
241
321
{
242
322
        const char *path;
243
323
        struct stat st;
244
324
 
245
 
        if (list->file_create_mode != (mode_t)-1) {
246
 
                *mode_r = list->file_create_mode;
247
 
                *gid_r = list->file_create_gid;
248
 
                return;
249
 
        }
250
 
 
251
 
        path = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_DIR);
 
325
        path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
252
326
        if (stat(path, &st) < 0) {
253
327
                if (!ENOTFOUND(errno)) {
254
328
                        mailbox_list_set_critical(list, "stat(%s) failed: %m",
257
331
                        i_info("Namespace %s: Permission lookup failed from %s",
258
332
                               list->ns->prefix, path);
259
333
                }
 
334
                if (name != NULL) {
 
335
                        /* return defaults */
 
336
                        mailbox_list_get_permissions_full(list, NULL,
 
337
                                                          file_mode_r,
 
338
                                                          dir_mode_r, gid_r,
 
339
                                                          gid_origin_r);
 
340
                        return;
 
341
                }
260
342
                /* return safe defaults */
261
 
                *mode_r = 0600;
 
343
                *file_mode_r = 0600;
 
344
                *dir_mode_r = 0700;
262
345
                *gid_r = (gid_t)-1;
263
 
                return;
264
 
        }
265
 
 
266
 
        list->file_create_mode = st.st_mode & 0666;
267
 
        if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
268
 
                /* directory's GID is used automatically for new files */
269
 
                list->file_create_gid = (gid_t)-1;
270
 
        } else if ((st.st_mode & 0060) == 0) {
271
 
                /* group doesn't have any permissions, so don't bother
272
 
                   changing it */
273
 
                list->file_create_gid = (gid_t)-1;
274
 
        } else if (getegid() == st.st_gid) {
275
 
                /* using our own gid, no need to change it */
276
 
                list->file_create_gid = (gid_t)-1;
 
346
                *gid_origin_r = "defaults";
277
347
        } else {
278
 
                list->file_create_gid = st.st_gid;
279
 
        }
280
 
 
281
 
        if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
 
348
                *file_mode_r = st.st_mode & 0666;
 
349
                *dir_mode_r = st.st_mode & 0777;
 
350
                *gid_origin_r = path;
 
351
 
 
352
                if (!S_ISDIR(st.st_mode)) {
 
353
                        /* we're getting permissions from a file.
 
354
                           apply +x modes as necessary. */
 
355
                        *dir_mode_r = get_dir_mode(*dir_mode_r);
 
356
                }
 
357
 
 
358
                if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
 
359
                        /* directory's GID is used automatically for new
 
360
                           files */
 
361
                        *gid_r = (gid_t)-1;
 
362
                } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
 
363
                        /* group has same permissions as world, so don't bother
 
364
                           changing it */
 
365
                        *gid_r = (gid_t)-1;
 
366
                } else if (getegid() == st.st_gid) {
 
367
                        /* using our own gid, no need to change it */
 
368
                        *gid_r = (gid_t)-1;
 
369
                } else {
 
370
                        *gid_r = st.st_gid;
 
371
                }
 
372
        }
 
373
 
 
374
        if (name == NULL) {
 
375
                list->file_create_mode = *file_mode_r;
 
376
                list->dir_create_mode = *dir_mode_r;
 
377
                list->file_create_gid = *gid_r;
 
378
                list->file_create_gid_origin =
 
379
                        p_strdup(list->pool, *gid_origin_r);
 
380
        }
 
381
 
 
382
        if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0 && name == NULL) {
282
383
                i_info("Namespace %s: Using permissions from %s: "
283
384
                       "mode=0%o gid=%ld", list->ns->prefix, path,
284
 
                       (int)list->file_create_mode,
 
385
                       (int)list->dir_create_mode,
285
386
                       list->file_create_gid == (gid_t)-1 ? -1L :
286
387
                       (long)list->file_create_gid);
287
388
        }
288
 
 
289
 
        *mode_r = list->file_create_mode;
290
 
        *gid_r = list->file_create_gid;
 
389
}
 
390
 
 
391
void mailbox_list_get_permissions(struct mailbox_list *list,
 
392
                                  const char *name,
 
393
                                  mode_t *mode_r, gid_t *gid_r,
 
394
                                  const char **gid_origin_r)
 
395
{
 
396
        mode_t dir_mode;
 
397
 
 
398
        if (list->file_create_mode != (mode_t)-1 && name == NULL) {
 
399
                *mode_r = list->file_create_mode;
 
400
                *gid_r = list->file_create_gid;
 
401
                *gid_origin_r = list->file_create_gid_origin;
 
402
                return;
 
403
        }
 
404
 
 
405
        mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
 
406
                                          gid_origin_r);
 
407
}
 
408
 
 
409
void mailbox_list_get_dir_permissions(struct mailbox_list *list,
 
410
                                      const char *name,
 
411
                                      mode_t *mode_r, gid_t *gid_r,
 
412
                                      const char **gid_origin_r)
 
413
{
 
414
        mode_t file_mode;
 
415
 
 
416
        if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
 
417
                *mode_r = list->dir_create_mode;
 
418
                *gid_r = list->file_create_gid;
 
419
                *gid_origin_r = list->file_create_gid_origin;
 
420
                return;
 
421
        }
 
422
 
 
423
        mailbox_list_get_permissions_full(list, name, &file_mode,
 
424
                                          mode_r, gid_r, gid_origin_r);
291
425
}
292
426
 
293
427
bool mailbox_list_is_valid_pattern(struct mailbox_list *list,
299
433
bool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
300
434
                                         const char *name)
301
435
{
 
436
        if (*name == '\0' && *list->ns->prefix != '\0') {
 
437
                /* an ugly way to get to mailbox root (e.g. Maildir/ when
 
438
                   it's not the INBOX) */
 
439
                return TRUE;
 
440
        }
 
441
 
302
442
        return list->v.is_valid_existing_name(list, name);
303
443
}
304
444
 
305
445
bool mailbox_list_is_valid_create_name(struct mailbox_list *list,
306
446
                                       const char *name)
307
447
{
308
 
        return list->v.is_valid_create_name(list, name);
 
448
        const char *p;
 
449
        int ret;
 
450
 
 
451
        /* safer to just disallow all control characters */
 
452
        for (p = name; *p != '\0'; p++) {
 
453
                if (*p < ' ')
 
454
                        return FALSE;
 
455
        }
 
456
 
 
457
        T_BEGIN {
 
458
                string_t *str = t_str_new(256);
 
459
                ret = imap_utf7_to_utf8(name, str);
 
460
        } T_END;
 
461
        return ret < 0 ? FALSE :
 
462
                list->v.is_valid_create_name(list, name);
309
463
}
310
464
 
311
465
const char *mailbox_list_get_path(struct mailbox_list *list, const char *name,
350
504
                *status = MAILBOX_NAME_INVALID;
351
505
                return 0;
352
506
        }
353
 
 
354
507
        return list->v.get_mailbox_name_status(list, name, status);
355
508
}
356
509
 
376
529
        return list->v.iter_init(list, patterns, flags);
377
530
}
378
531
 
 
532
static const struct mailbox_info *
 
533
mailbox_list_ns_iter_next(struct mailbox_list_iterate_context *_ctx)
 
534
{
 
535
        struct ns_list_iterate_context *ctx =
 
536
                (struct ns_list_iterate_context *)_ctx;
 
537
        const struct mailbox_info *info;
 
538
 
 
539
        info = mailbox_list_iter_next(ctx->backend_ctx);
 
540
        if (info == NULL && ctx->namespaces != NULL) {
 
541
                /* go to the next namespace */
 
542
                if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
 
543
                        _ctx->failed = TRUE;
 
544
                ctx->ctx.list->ns = ctx->namespaces;
 
545
                ctx->backend_ctx =
 
546
                        mailbox_list_iter_init_multiple(ctx->namespaces->list,
 
547
                                                        ctx->patterns,
 
548
                                                        _ctx->flags);
 
549
                ctx->namespaces = ctx->namespaces->next;
 
550
                return mailbox_list_ns_iter_next(_ctx);
 
551
        }
 
552
        return info;
 
553
}
 
554
 
 
555
static int
 
556
mailbox_list_ns_iter_deinit(struct mailbox_list_iterate_context *_ctx)
 
557
{
 
558
        struct ns_list_iterate_context *ctx =
 
559
                (struct ns_list_iterate_context *)_ctx;
 
560
        int ret;
 
561
 
 
562
        if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
 
563
                _ctx->failed = TRUE;
 
564
        ret = _ctx->failed ? -1 : 0;
 
565
        pool_unref(&ctx->pool);
 
566
        return ret;
 
567
}
 
568
 
 
569
struct mailbox_list_iterate_context *
 
570
mailbox_list_iter_init_namespaces(struct mail_namespace *namespaces,
 
571
                                  const char *const *patterns,
 
572
                                  enum mailbox_list_iter_flags flags)
 
573
{
 
574
        struct ns_list_iterate_context *ctx;
 
575
        unsigned int i, count;
 
576
        pool_t pool;
 
577
 
 
578
        i_assert(namespaces != NULL);
 
579
 
 
580
        pool = pool_alloconly_create("mailbox list namespaces", 512);
 
581
        ctx = p_new(pool, struct ns_list_iterate_context, 1);
 
582
        ctx->pool = pool;
 
583
        ctx->ctx.flags = flags;
 
584
        ctx->ctx.list = p_new(pool, struct mailbox_list, 1);
 
585
        ctx->ctx.list->v.iter_next = mailbox_list_ns_iter_next;
 
586
        ctx->ctx.list->v.iter_deinit = mailbox_list_ns_iter_deinit;
 
587
 
 
588
        count = str_array_length(patterns);
 
589
        ctx->patterns = p_new(pool, const char *, count + 1);
 
590
        for (i = 0; i < count; i++)
 
591
                ctx->patterns[i] = p_strdup(pool, patterns[i]);
 
592
 
 
593
        ctx->ctx.list->ns = namespaces;
 
594
        ctx->backend_ctx = mailbox_list_iter_init_multiple(namespaces->list,
 
595
                                                           patterns, flags);
 
596
        ctx->namespaces = namespaces->next;
 
597
        return &ctx->ctx;
 
598
}
 
599
 
379
600
const struct mailbox_info *
380
601
mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx)
381
602
{
382
 
        return ctx->list->v.iter_next(ctx);
 
603
        const struct mailbox_info *info;
 
604
 
 
605
        info = ctx->list->v.iter_next(ctx);
 
606
        if (info != NULL)
 
607
                ctx->list->ns->flags |= NAMESPACE_FLAG_USABLE;
 
608
        return info;
383
609
}
384
610
 
385
611
int mailbox_list_iter_deinit(struct mailbox_list_iterate_context **_ctx)
391
617
        return ctx->list->v.iter_deinit(ctx);
392
618
}
393
619
 
 
620
int mailbox_list_mailbox(struct mailbox_list *list, const char *name,
 
621
                         enum mailbox_info_flags *flags_r)
 
622
{
 
623
        struct mailbox_list_iterate_context ctx;
 
624
        const char *path;
 
625
 
 
626
        memset(&ctx, 0, sizeof(ctx));
 
627
        ctx.list = list;
 
628
 
 
629
        *flags_r = 0;
 
630
        path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
 
631
        return list->v.iter_is_mailbox == NULL ? 0 :
 
632
                list->v.iter_is_mailbox(&ctx, path, "", "",
 
633
                                        MAILBOX_LIST_FILE_TYPE_UNKNOWN,
 
634
                                        flags_r);
 
635
}
 
636
 
394
637
int mailbox_list_set_subscribed(struct mailbox_list *list,
395
638
                                const char *name, bool set)
396
639
{
401
644
 
402
645
int mailbox_list_delete_mailbox(struct mailbox_list *list, const char *name)
403
646
{
404
 
        if (!mailbox_list_is_valid_existing_name(list, name)) {
 
647
        if (!mailbox_list_is_valid_existing_name(list, name) || *name == '\0') {
405
648
                mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
406
649
                                       "Invalid mailbox name");
407
650
                return -1;
419
662
                                const char *oldname, const char *newname)
420
663
{
421
664
        if (!mailbox_list_is_valid_existing_name(list, oldname) ||
 
665
            *oldname == '\0' ||
422
666
            !mailbox_list_is_valid_create_name(list, newname)) {
423
667
                mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
424
668
                                       "Invalid mailbox name");
436
680
        if (errno == ENOTEMPTY) {
437
681
                /* We're most likely using NFS and we can't delete
438
682
                   .nfs* files. */
439
 
                mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
 
683
                mailbox_list_set_error(list, MAIL_ERROR_INUSE,
440
684
                        "Mailbox is still open in another session, "
441
685
                        "can't delete it.");
442
686
        } else {
603
847
        return type;
604
848
}
605
849
 
 
850
bool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
 
851
                                        const char **name)
 
852
{
 
853
        if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) == 0)
 
854
                return FALSE;
 
855
 
 
856
        if (**name == '/')
 
857
                return TRUE;
 
858
        if (**name != '~')
 
859
                return FALSE;
 
860
 
 
861
        /* try to expand home directory */
 
862
        if ((*name)[1] == '/') {
 
863
                /* ~/dir - use the configured home directory */
 
864
                if (mail_user_try_home_expand(list->ns->user, name) == 0)
 
865
                        return TRUE;
 
866
        } else {
 
867
                /* ~otheruser/dir - assume we're using system users */
 
868
                if (home_try_expand(name) == 0)
 
869
                        return TRUE;
 
870
        }
 
871
        /* fallback to using ~dir */
 
872
        return FALSE;
 
873
}
 
874
 
 
875
int mailbox_list_create_parent_dir(struct mailbox_list *list,
 
876
                                   const char *mailbox, const char *path)
 
877
{
 
878
        const char *p, *dir, *origin;
 
879
        gid_t gid;
 
880
        mode_t mode;
 
881
 
 
882
        p = strrchr(path, '/');
 
883
        if (p == NULL)
 
884
                return 0;
 
885
 
 
886
        dir = t_strdup_until(path, p);
 
887
        mailbox_list_get_dir_permissions(list, mailbox, &mode, &gid, &origin);
 
888
        if (mkdir_parents_chgrp(dir, mode, gid, origin) < 0 &&
 
889
            errno != EEXIST) {
 
890
                mailbox_list_set_critical(list, "mkdir_parents(%s) failed: %m",
 
891
                                          dir);
 
892
                return -1;
 
893
        }
 
894
        return 0;
 
895
}
 
896
 
606
897
const char *mailbox_list_get_last_error(struct mailbox_list *list,
607
898
                                        enum mail_error *error_r)
608
899
{
637
928
 
638
929
        i_free(list->error_string);
639
930
        list->error_string =
640
 
                strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
641
 
                i_strdup(str) : i_strdup(CRITICAL_MSG);
 
931
                strftime(str, sizeof(str),
 
932
                         MAIL_ERRSTR_CRITICAL_MSG_STAMP, tm) > 0 ?
 
933
                i_strdup(str) : i_strdup(MAIL_ERRSTR_CRITICAL_MSG);
642
934
        list->error = MAIL_ERROR_TEMP;
643
935
}
644
936