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