mbox-list.c revision 450c93a252fea6c0ceb9353af20c2d22ab62d717
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher/* Copyright (C) 2002 Timo Sirainen */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#include "lib.h"
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#include "unlink-directory.h"
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#include "imap-match.h"
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#include "subscription-file/subscription-file.h"
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#include "mbox-index.h"
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#include "mbox-storage.h"
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#include <dirent.h>
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher#include <sys/stat.h>
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallaghertypedef struct {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher MailboxFunc func;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher void *context;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher} FindSubscribedContext;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherstatic int mbox_find_path(MailStorage *storage, ImapMatchGlob *glob,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher MailboxFunc func, void *context,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher const char *relative_dir, int *found_inbox)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher{
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher DIR *dirp;
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik struct dirent *d;
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik struct stat st;
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik const char *dir, *listpath;
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik char fulldir[1024], path[1024], fullpath[1024];
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik int failed, match;
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik size_t len;
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik t_push();
2bdadc5274df42738b97045cd01cd63d3651daf9Lukas Slebodnik
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (relative_dir == NULL)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher dir = storage->dir;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek else {
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek i_snprintf(fulldir, sizeof(fulldir), "%s/%s",
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek storage->dir, relative_dir);
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek dir = fulldir;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek }
fa0938a6e3cb928602633c3da0b909deb269369dLukas Slebodnik
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek dirp = opendir(dir);
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek if (dirp == NULL) {
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek if (errno != ENOENT && errno != ENOTDIR) {
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek mail_storage_set_critical(storage,
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek "opendir(%s) failed: %m", dir);
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek }
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek t_pop();
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek return FALSE;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek }
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek failed = FALSE;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek while ((d = readdir(dirp)) != NULL) {
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek const char *fname = d->d_name;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek /* skip all hidden files */
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek if (fname[0] == '.')
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek continue;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek /* skip all .lock files */
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek len = strlen(fname);
fa0938a6e3cb928602633c3da0b909deb269369dLukas Slebodnik if (len > 5 && strcmp(fname+len-5, ".lock") == 0)
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek continue;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek /* check the mask */
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek if (relative_dir == NULL)
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek listpath = fname;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek else {
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek i_snprintf(path, sizeof(path), "%s/%s",
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek relative_dir, fname);
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek listpath = path;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek }
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek if ((match = imap_match(glob, listpath)) < 0)
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek continue;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek /* see if it's a directory */
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek i_snprintf(fullpath, sizeof(fullpath), "%s/%s", dir, fname);
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek if (stat(fullpath, &st) != 0) {
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek if (errno == ENOENT)
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek continue; /* just deleted, ignore */
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek mail_storage_set_critical(storage, "stat(%s) failed: "
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek "%m", fullpath);
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek failed = TRUE;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek break;
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek }
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek
dbea04f585a30d001b574317c068cd03a4fa332bJakub Hrozek if (S_ISDIR(st.st_mode)) {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher /* subdirectory, scan it too */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher func(storage, listpath, MAILBOX_NOSELECT, context);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (!mbox_find_path(storage, glob, func,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher context, listpath, NULL)) {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher failed = TRUE;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher break;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher } else if (match > 0) {
fa0938a6e3cb928602633c3da0b909deb269369dLukas Slebodnik if (found_inbox != NULL &&
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher strcasecmp(listpath, "inbox") == 0)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher *found_inbox = TRUE;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher func(storage, listpath, MAILBOX_NOINFERIORS, context);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher t_pop();
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher (void)closedir(dirp);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return !failed;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher}
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherstatic const char *mask_get_dir(const char *mask)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher{
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher const char *p, *last_dir;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher last_dir = NULL;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher for (p = mask; *p != '\0' && *p != '%' && *p != '*'; p++) {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (*p == '/')
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher last_dir = p;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return last_dir != NULL ? t_strdup_until(mask, last_dir) : NULL;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher}
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherint mbox_find_mailboxes(MailStorage *storage, const char *mask,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher MailboxFunc func, void *context)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher{
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher ImapMatchGlob *glob;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher const char *relative_dir;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher int found_inbox;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher /* check that we're not trying to do any "../../" lists */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (!mbox_is_valid_mask(mask)) {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher mail_storage_set_error(storage, "Invalid mask");
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return FALSE;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher mail_storage_clear_error(storage);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher /* if we're matching only subdirectories, don't bother scanning the
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher parent directories */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher relative_dir = mask_get_dir(mask);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher glob = imap_match_init(mask, TRUE, '/');
fa0938a6e3cb928602633c3da0b909deb269369dLukas Slebodnik
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher found_inbox = FALSE;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (!mbox_find_path(storage, glob, func, context,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher relative_dir, &found_inbox))
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return FALSE;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (!found_inbox && relative_dir == NULL &&
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher imap_match(glob, "INBOX") > 0) {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher /* INBOX always exists, even if the file doesn't. */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher func(storage, "INBOX", MAILBOX_UNMARKED | MAILBOX_NOINFERIORS,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher context);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return TRUE;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher}
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagherstatic int mbox_subs_func(MailStorage *storage, const char *name,
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher void *context)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher{
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher FindSubscribedContext *ctx = context;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher MailboxFlags flags;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher struct stat st;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher char path[1024];
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher /* see if the mailbox exists, don't bother with the marked flags */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (strcasecmp(name, "INBOX") == 0) {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher /* inbox always exists */
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher flags = 0;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher } else {
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher i_snprintf(path, sizeof(path), "%s/%s", storage->dir, name);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher flags = stat(path, &st) == 0 && !S_ISDIR(st.st_mode) ?
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher 0 : MAILBOX_NOSELECT;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher }
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher ctx->func(storage, name, flags, ctx->context);
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return TRUE;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher}
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozekint mbox_find_subscribed(MailStorage *storage, const char *mask,
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozek MailboxFunc func, void *context)
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozek{
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozek FindSubscribedContext ctx;
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozek
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozek ctx.func = func;
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozek ctx.context = context;
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozek
2b4332767d299263a288e0a74bbfbc9de674de95Jakub Hrozek if (subsfile_foreach(storage, mask, mbox_subs_func, &ctx) <= 0)
return FALSE;
return TRUE;
}