Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/list/mailbox-list-maildir.c @ 4808:93bc9770f938 HEAD
Initial code for separation of mailbox accessing and directory layout
handling. It's not yet possible to change the default layouts though.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 16 Nov 2006 02:16:31 +0200 |
parents | |
children | 414c0c45040e |
line wrap: on
line source
/* Copyright (C) 2006 Timo Sirainen */ #include "lib.h" #include "hostpid.h" #include "home-expand.h" #include "subscription-file.h" #include "mailbox-list-maildir.h" #include <sys/stat.h> extern struct mailbox_list maildir_mailbox_list; static struct mailbox_list *maildir_list_alloc(void) { struct maildir_mailbox_list *list; pool_t pool; pool = pool_alloconly_create("maildir++ list", 512); list = p_new(pool, struct maildir_mailbox_list, 1); list->list = maildir_mailbox_list; list->list.pool = pool; list->temp_prefix = p_strconcat(pool, "temp.", my_hostname, ".", my_pid, ".", NULL); return &list->list; } static void maildir_list_deinit(struct mailbox_list *_list) { struct maildir_mailbox_list *list = (struct maildir_mailbox_list *)_list; pool_unref(list->list.pool); } static const char * maildir_list_get_absolute_path(struct mailbox_list *list, const char *name) { const char *p; name = home_expand(name); p = strrchr(name, '/'); if (p == NULL) return name; return t_strdup_printf("%s/%c%s", t_strdup_until(name, p), list->hierarchy_sep, p+1); } static bool maildir_list_is_valid_common(struct mailbox_list *list, const char *name, size_t *len_r) { size_t len; /* check that there are no adjacent hierarchy separators */ for (len = 0; name[len] != '\0'; len++) { if (name[len] == list->hierarchy_sep && name[len+1] == list->hierarchy_sep) return FALSE; } if (len == 0 || name[len-1] == '/') return FALSE; if (name[0] == list->hierarchy_sep || name[len-1] == list->hierarchy_sep) return FALSE; *len_r = len; return TRUE; } static bool maildir_list_is_valid_common_nonfs(const char *name) { if (*name == '~' || strchr(name, '/') != NULL) return FALSE; if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) { /* "." and ".." aren't allowed. */ return FALSE; } return TRUE; } static bool maildir_is_valid_mask(struct mailbox_list *list __attr_unused__, const char *mask __attr_unused__) { i_unreached(); return FALSE; } static bool maildir_is_valid_existing_name(struct mailbox_list *list, const char *name) { size_t len; if (!maildir_list_is_valid_common(list, name, &len)) return FALSE; if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0) return TRUE; return maildir_list_is_valid_common_nonfs(name); } static bool maildir_is_valid_create_name(struct mailbox_list *list, const char *name) { size_t len; if (!maildir_list_is_valid_common(list, name, &len)) return FALSE; if (len > MAILDIR_MAX_CREATE_MAILBOX_NAME_LENGTH) return FALSE; if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0) return TRUE; if (!maildir_list_is_valid_common_nonfs(name)) return FALSE; if (mailbox_list_name_is_too_large(name, list->hierarchy_sep)) return FALSE; return TRUE; } static const char * maildir_list_get_path(struct mailbox_list *_list, const char *name, enum mailbox_list_path_type type) { struct maildir_mailbox_list *list = (struct maildir_mailbox_list *)_list; mailbox_list_clear_error(&list->list); if (name == NULL) { /* return root directories */ switch (type) { case MAILBOX_LIST_PATH_TYPE_DIR: case MAILBOX_LIST_PATH_TYPE_MAILBOX: return _list->set.root_dir; case MAILBOX_LIST_PATH_TYPE_CONTROL: return _list->set.control_dir != NULL ? _list->set.control_dir : _list->set.root_dir; case MAILBOX_LIST_PATH_TYPE_INDEX: return _list->set.index_dir != NULL ? _list->set.index_dir : _list->set.root_dir; } i_unreached(); } i_assert(mailbox_list_is_valid_existing_name(_list, name)); if ((list->list.flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0 && (*name == '/' || *name == '~')) return maildir_list_get_absolute_path(_list, name); switch (type) { case MAILBOX_LIST_PATH_TYPE_DIR: case MAILBOX_LIST_PATH_TYPE_MAILBOX: break; case MAILBOX_LIST_PATH_TYPE_CONTROL: if (_list->set.control_dir != NULL) { return t_strdup_printf("%s/%c%s", _list->set.control_dir, _list->hierarchy_sep, name); } break; case MAILBOX_LIST_PATH_TYPE_INDEX: if (_list->set.index_dir != NULL) { if (*_list->set.index_dir == '\0') return ""; return t_strdup_printf("%s/%c%s", _list->set.index_dir, _list->hierarchy_sep, name); } break; } if (strcmp(name, "INBOX") == 0) { return _list->set.inbox_path != NULL ? _list->set.inbox_path : _list->set.root_dir; } return t_strdup_printf("%s/%c%s", _list->set.root_dir, _list->hierarchy_sep, name); } static int maildir_list_get_mailbox_name_status(struct mailbox_list *_list, const char *name, enum mailbox_name_status *status) { struct maildir_mailbox_list *list = (struct maildir_mailbox_list *)_list; struct stat st; const char *path; mailbox_list_clear_error(&list->list); if (!mailbox_list_is_valid_existing_name(_list, name)) { *status = MAILBOX_NAME_INVALID; return 0; } path = mailbox_list_get_path(_list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX); if (strcmp(name, "INBOX") == 0 || stat(path, &st) == 0) { *status = MAILBOX_NAME_EXISTS; return 0; } if (!mailbox_list_is_valid_create_name(_list, name)) { *status = MAILBOX_NAME_INVALID; return 0; } if (ENOTFOUND(errno) || errno == EACCES) { *status = MAILBOX_NAME_VALID; return 0; } else { mailbox_list_set_critical(_list, "stat(%s) failed: %m", path); return -1; } } static const char * maildir_list_get_temp_prefix(struct mailbox_list *_list) { struct maildir_mailbox_list *list = (struct maildir_mailbox_list *)_list; return list->temp_prefix; } static int maildir_list_set_subscribed(struct mailbox_list *_list, const char *name, bool set) { struct maildir_mailbox_list *list = (struct maildir_mailbox_list *)_list; const char *path; mailbox_list_clear_error(&list->list); path = t_strconcat(_list->set.control_dir != NULL ? _list->set.control_dir : _list->set.root_dir, "/", _list->set.subscription_fname, NULL); return subsfile_set_subscribed(_list, path, list->temp_prefix, name, set); } struct mailbox_list maildir_mailbox_list = { MEMBER(name) "maildir++", MEMBER(hierarchy_sep) '.', MEMBER(mailbox_name_max_length) PATH_MAX, { maildir_list_alloc, maildir_list_deinit, maildir_is_valid_mask, maildir_is_valid_existing_name, maildir_is_valid_create_name, maildir_list_get_path, maildir_list_get_mailbox_name_status, maildir_list_get_temp_prefix, maildir_list_iter_init, maildir_list_iter_next, maildir_list_iter_deinit, maildir_list_set_subscribed } };