mailbox-list-maildir.c revision 738cb8e908b144d6dd6f6d7484a40ad67054aac5
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2006-2007 Dovecot authors, see the included COPYING file */
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainenextern struct mailbox_list maildir_mailbox_list;
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainenextern struct mailbox_list imapdir_mailbox_list;
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenstatic struct mailbox_list *maildir_list_alloc(void)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pool = pool_alloconly_create("maildir++ list", 1024);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen list = p_new(pool, struct maildir_mailbox_list, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen p_strconcat(pool, "temp.", my_hostname, ".", my_pid, ".", NULL);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic struct mailbox_list *imapdir_list_alloc(void)
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen pool = pool_alloconly_create("imapdir list", 1024);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen list = p_new(pool, struct maildir_mailbox_list, 1);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen list->temp_prefix = p_strconcat(pool, ".temp.", my_hostname, ".",
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainenstatic void maildir_list_deinit(struct mailbox_list *_list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic const char *
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainenmaildir_list_get_dirname_path(struct mailbox_list *list, const char *dir,
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen if (strcmp(list->name, MAILBOX_LIST_NAME_IMAPDIR) == 0)
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen return t_strdup_printf("%s/%c%s", dir, list->hierarchy_sep, name);
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenstatic const char *
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenmaildir_list_get_absolute_path(struct mailbox_list *list, const char *name)
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainen const char *p;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* fallback to using as ~name */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return maildir_list_get_dirname_path(list, t_strdup_until(name, p),
63ca9cacc5d2d1b1cebfc430bb89637f8c138e4cTimo Sirainenmaildir_list_is_valid_common(struct mailbox_list *list, const char *name,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* check that there are no adjacent hierarchy separators */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool maildir_list_is_valid_common_nonfs(const char *name)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (*name == '~' || strchr(name, '/') != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* "." and ".." aren't allowed. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmaildir_is_valid_pattern(struct mailbox_list *list ATTR_UNUSED,
65b7beb7cefce89e175920ef6c16118b1b0dbfb3Timo Sirainenmaildir_is_valid_existing_name(struct mailbox_list *list, const char *name)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!maildir_list_is_valid_common(list, name, &len))
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return maildir_list_is_valid_common_nonfs(name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmaildir_is_valid_create_name(struct mailbox_list *list, const char *name)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!maildir_list_is_valid_common(list, name, &len))
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (len > MAILDIR_MAX_CREATE_MAILBOX_NAME_LENGTH)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!maildir_list_is_valid_common_nonfs(name))
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (mailbox_list_name_is_too_large(name, list->hierarchy_sep))
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic const char *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmaildir_list_get_path(struct mailbox_list *_list, const char *name,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* return root directories */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(mailbox_list_is_valid_existing_name(_list, name));
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((list->list.flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0 &&
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return maildir_list_get_absolute_path(_list, name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return maildir_list_get_dirname_path(_list, _list->set.root_dir, name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmaildir_list_get_mailbox_name_status(struct mailbox_list *_list,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strcmp(name, "INBOX") == 0 || stat(path, &st) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!mailbox_list_is_valid_create_name(_list, name)) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen mailbox_list_set_critical(_list, "stat(%s) failed: %m", path);
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainenstatic const char *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenmaildir_list_get_temp_prefix(struct mailbox_list *_list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic int maildir_list_set_subscribed(struct mailbox_list *_list,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen path = t_strconcat(_list->set.control_dir != NULL ?
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return subsfile_set_subscribed(_list, path, list->temp_prefix,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic int rename_dir(struct mailbox_list *list,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen oldpath = mailbox_list_get_path(list, oldname, type);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen newpath = mailbox_list_get_path(list, newname, type);
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_set_critical(list, "rename(%s, %s) failed: %m",
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainenstatic int rename_children(struct mailbox_list *list,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen const char *pattern, *oldpath, *newpath, *old_listname, *new_listname;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen const char *const *names;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen unsigned int i, count;
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* first get the list of the children and save them to memory, because
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen we can't rely on readdir() not skipping files while the directory
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen is being modified. this doesn't protect against modifications by
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen other processes though. */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen pool = pool_alloconly_create("Maildir++ children list", 1024);
2fb976923a6d6e45a7c2da90484944b2fac50c06Timo Sirainen while ((info = mailbox_list_iter_next(iter)) != NULL) {
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* verify that the prefix matches, otherwise we could have
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen problems with mailbox names containing '%' and '*' chars */
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen if (strncmp(info->name, oldname, oldnamelen) == 0 &&
33f002135617b5b34577433b30c32560bd4b5e3cTimo Sirainen name = p_strdup(pool, info->name + oldnamelen);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen for (i = 0; i < count; i++) {
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen old_listname = t_strconcat(oldname, names[i], NULL);
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen /* When doing RENAME "a" "a.b" we see "a.b" here.
738cb8e908b144d6dd6f6d7484a40ad67054aac5Timo Sirainen We don't want to rename it anymore to "a.b.b". */
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen new_listname = t_strconcat(newname, names[i], NULL);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen oldpath = mailbox_list_get_path(list, old_listname,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen newpath = mailbox_list_get_path(list, new_listname,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* FIXME: it's possible to merge two mailboxes if either one of
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen them doesn't have existing root mailbox. We could check this
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen but I'm not sure if it's worth it. It could be even
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen considered as a feature.
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen Anyway, the bug with merging is that if both mailboxes have
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen identically named child mailbox they conflict. Just ignore
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen those and leave them under the old mailbox. */
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen if (rename(oldpath, newpath) == 0 || EDESTDIREXISTS(errno))
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen "rename(%s, %s) failed: %m", oldpath, newpath);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen (void)rename_dir(list, MAILBOX_LIST_PATH_TYPE_CONTROL,
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen (void)rename_dir(list, MAILBOX_LIST_PATH_TYPE_INDEX,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenmaildir_list_delete_mailbox(struct mailbox_list *list, const char *name)
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen /* let the backend handle the rest */
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen return mailbox_list_delete_index_control(list, name);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainenstatic int maildir_list_rename_mailbox(struct mailbox_list *list,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen /* NOTE: it's possible to rename a nonexisting mailbox which has
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen children. In that case we should ignore the rename() error. */
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen oldpath = mailbox_list_get_path(list, oldname,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen newpath = mailbox_list_get_path(list, newname,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen (void)rename_dir(list, MAILBOX_LIST_PATH_TYPE_CONTROL,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen (void)rename_dir(list, MAILBOX_LIST_PATH_TYPE_INDEX,
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen ret = rename_children(list, oldname, newname);
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen "Target mailbox already exists");
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen mailbox_list_set_critical(list, "rename(%s, %s) failed: %m",