diff options
Diffstat (limited to 'mailbox/mbox/folder.c')
-rw-r--r-- | mailbox/mbox/folder.c | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/mailbox/mbox/folder.c b/mailbox/mbox/folder.c new file mode 100644 index 000000000..6568ab36a --- /dev/null +++ b/mailbox/mbox/folder.c @@ -0,0 +1,427 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <glob.h> +#include <fnmatch.h> +#include <stdio.h> +#include <stdlib.h> + +#include <folder0.h> +#include <registrar0.h> + +#include <mailutils/auth.h> +#include <mailutils/url.h> +#include <mailutils/stream.h> + +/* We export url parsing and the initialisation of + the mailbox, via the register entry/record. */ + +static struct _record _mbox_record = +{ + MU_MBOX_SCHEME, + _url_mbox_init, /* Mailbox init. */ + _mailbox_mbox_init, /* Mailbox init. */ + NULL, /* Mailer init. */ + _folder_mbox_init, /* Folder init. */ + NULL, /* No need for an back pointer. */ + NULL, /* _is_scheme method. */ + NULL, /* _get_url method. */ + NULL, /* _get_mailbox method. */ + NULL, /* _get_mailer method. */ + NULL /* _get_folder method. */ +}; +record_t mbox_record = &_mbox_record; + +static struct _record _file_record = +{ + MU_FILE_SCHEME, + _url_file_init, /* Mailbox init. */ + _mailbox_file_init, /* Mailbox init. */ + NULL, /* Mailer init. */ + _folder_mbox_init, /* Folder init. */ + NULL, /* No need for an owner. */ + NULL, /* _is_scheme method. */ + NULL, /* _get_url method. */ + NULL, /* _get_mailbox method. */ + NULL, /* _get_mailer method. */ + NULL /* _get_folder method. */ +}; +record_t file_record = &_file_record; + +static struct _record _path_record = +{ + MU_PATH_SCHEME, + _url_path_init, /* Mailbox init. */ + _mailbox_file_init, /* Mailbox init. */ + NULL, /* Mailer init. */ + _folder_mbox_init, /* Folder init. */ + NULL, /* No need for an owner. */ + NULL, /* is_scheme method. */ + NULL, /* get_url method. */ + NULL, /* get_mailbox method. */ + NULL, /* get_mailer method. */ + NULL /* get_folder method. */ +}; +record_t path_record = &_path_record; + +/* lsub/subscribe/unsubscribe are not needed. */ +static void folder_mbox_destroy __P ((folder_t)); +static int folder_mbox_open __P ((folder_t, int)); +static int folder_mbox_close __P ((folder_t)); +static int folder_mbox_delete __P ((folder_t, const char *)); +static int folder_mbox_rename __P ((folder_t , const char *, + const char *)); +static int folder_mbox_list __P ((folder_t, const char *, const char *, + struct folder_list *)); +static int folder_mbox_subscribe __P ((folder_t, const char *)); +static int folder_mbox_unsubscribe __P ((folder_t, const char *)); +static int folder_mbox_lsub __P ((folder_t, const char *, const char *, + struct folder_list *)); + + +static char *get_pathname __P ((const char *, const char *)); + +static int folder_mbox_get_authority __P ((folder_t folder, + authority_t * pauth)); + +struct _fmbox +{ + char *dirname; + char **subscribe; + size_t sublen; +}; +typedef struct _fmbox *fmbox_t; + + +int +_folder_mbox_init (folder_t folder) +{ + fmbox_t dfolder; + size_t name_len = 0; + int status = 0; + + /* We create an authority so the API is uniform across the mailbox + types. */ + status = folder_mbox_get_authority (folder, NULL); + if (status != 0) + return status; + + dfolder = folder->data = calloc (1, sizeof (*dfolder)); + if (dfolder == NULL) + return ENOMEM; + + url_get_path (folder->url, NULL, 0, &name_len); + dfolder->dirname = calloc (name_len + 1, sizeof (char)); + if (dfolder->dirname == NULL) + { + free (dfolder); + folder->data = NULL; + return ENOMEM; + } + url_get_path (folder->url, dfolder->dirname, name_len + 1, NULL); + + folder->_destroy = folder_mbox_destroy; + + folder->_open = folder_mbox_open; + folder->_close = folder_mbox_close; + + folder->_list = folder_mbox_list; + folder->_lsub = folder_mbox_lsub; + folder->_subscribe = folder_mbox_subscribe; + folder->_unsubscribe = folder_mbox_unsubscribe; + folder->_delete = folder_mbox_delete; + folder->_rename = folder_mbox_rename; + return 0; +} + +void +folder_mbox_destroy (folder_t folder) +{ + if (folder->data) + { + fmbox_t fmbox = folder->data; + if (fmbox->dirname) + free (fmbox->dirname); + if (fmbox->subscribe) + free (fmbox->subscribe); + free (folder->data); + folder->data = NULL; + } +} + +/* Noop. */ +static int +folder_mbox_open (folder_t folder, int flags) +{ + fmbox_t fmbox = folder->data; + if (flags & MU_STREAM_CREAT) + { + return (mkdir (fmbox->dirname, S_IRWXU) == 0) ? 0 : errno; + } + (void)(flags); + return 0; +} + +/* Noop. */ +static int +folder_mbox_close (folder_t folder) +{ + (void)(folder); + return 0; +} + +static int +folder_mbox_delete (folder_t folder, const char *filename) +{ + fmbox_t fmbox = folder->data; + if (filename) + { + int status = 0; + char *pathname = get_pathname (fmbox->dirname, filename); + if (pathname) + { + if (remove (pathname) != 0) + status = errno; + free (pathname); + } + else + status = ENOMEM; + return status; + } + return EINVAL; +} + +static int +folder_mbox_rename (folder_t folder, const char *oldpath, const char *newpath) +{ + fmbox_t fmbox = folder->data; + if (oldpath && newpath) + { + int status = 0; + char *pathold = get_pathname (fmbox->dirname, oldpath); + if (pathold) + { + char *pathnew = get_pathname (fmbox->dirname, newpath); + if (pathnew) + { + if (rename (pathold, pathnew) != 0) + status = errno; + free (pathnew); + } + else + status = ENOMEM; + free (pathold); + } + else + status = ENOMEM; + return status; + } + return EINVAL; +} + +/* The listing is not recursif and we use glob() some expansion for us. + Unfortunately glob() does not expand the '~'. We also return + The full pathname so it can be use to create other folders. */ +static int +folder_mbox_list (folder_t folder, const char *dirname, const char *pattern, + struct folder_list *pflist) +{ + fmbox_t fmbox = folder->data; + char *pathname = NULL; + int status; + size_t num = 0; + glob_t gl; + + if (dirname == NULL || dirname[0] == '\0') + dirname = (const char *)fmbox->dirname; + + pathname = get_pathname (dirname, pattern); + if (pathname) + { + memset(&gl, 0, sizeof(gl)); + status = glob (pathname, 0, NULL, &gl); + free (pathname); + num = gl.gl_pathc; + } + else + status = ENOMEM; + + /* Build the folder list from glob. */ + if (status == 0) + { + if (pflist) + { + struct list_response **plist; + plist = calloc (num, sizeof (*plist)); + if (plist) + { + size_t i; + struct stat stbuf; + for (i = 0; i < num; i++) + { + plist[i] = calloc (1, sizeof (**plist)); + if (plist[i] == NULL + || (plist[i]->name = strdup (gl.gl_pathv[i])) == NULL) + { + num = i; + break; + } + if (stat (gl.gl_pathv[i], &stbuf) == 0) + { + if (S_ISDIR(stbuf.st_mode)) + plist[i]->type = MU_FOLDER_ATTRIBUTE_DIRECTORY; + if (S_ISREG(stbuf.st_mode)) + plist[i]->type = MU_FOLDER_ATTRIBUTE_FILE; + } + plist[i]->separator = '/'; + } + } + pflist->element = plist; + pflist->num = num; + } + globfree (&gl); + } + else + { + status = (status == GLOB_NOSPACE) ? ENOMEM : EINVAL; + } + return status; +} + +static int +folder_mbox_lsub (folder_t folder, const char *ref, const char *name, + struct folder_list *pflist) +{ + fmbox_t fmbox = folder->data; + size_t j = 0; + + if (pflist == NULL) + return EINVAL; + + (void)ref; + if (name == NULL || *name == '\0') + name = "*"; + + if (fmbox->sublen > 0) + { + struct list_response **plist; + size_t i; + plist = calloc (fmbox->sublen, sizeof (*plist)); + for (i = 0; i < fmbox->sublen; i++) + { + if (fmbox->subscribe[i] + && fnmatch (name, fmbox->subscribe[i], 0) == 0) + { + plist[i] = calloc (1, sizeof (**plist)); + if (plist[i] == NULL + || (plist[i]->name = strdup (fmbox->subscribe[i])) == NULL) + break; + plist[i]->type = MU_FOLDER_ATTRIBUTE_FILE; + plist[i]->separator = '/'; + j++; + } + } + pflist->element = plist; + } + pflist->num = j; + return 0; +} + +static int +folder_mbox_subscribe (folder_t folder, const char *name) +{ + fmbox_t fmbox = folder->data; + char **tmp; + size_t i; + for (i = 0; i < fmbox->sublen; i++) + { + if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0) + return 0; + } + tmp = realloc (fmbox->subscribe, (fmbox->sublen + 1) * sizeof (*tmp)); + if (tmp == NULL) + return ENOMEM; + fmbox->subscribe = tmp; + fmbox->subscribe[fmbox->sublen] = strdup (name); + if (fmbox->subscribe[fmbox->sublen] == NULL) + return ENOMEM; + fmbox->sublen++; + return 0; +} + +static int +folder_mbox_unsubscribe (folder_t folder, const char *name) +{ + fmbox_t fmbox = folder->data; + size_t i; + for (i = 0; i < fmbox->sublen; i++) + { + if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0) + { + free (fmbox->subscribe[i]); + fmbox->subscribe[i] = NULL; + return 0; + } + } + return ENOENT; +} + +static char * +get_pathname (const char *dirname, const char *basename) +{ + char *pathname = NULL; + /* null basename gives dirname. */ + if (basename == NULL) + pathname = (dirname) ? strdup (dirname) : strdup ("."); + /* Absolute. */ + else if (basename[0] == '/') + pathname = strdup (basename); + /* Relative. */ + else + { + size_t len = strlen (basename); + pathname = calloc (strlen (dirname) + len + 2, sizeof (char)); + if (pathname) + sprintf (pathname, "%s/%s", dirname, basename); + } + return pathname; +} + +static int +folder_mbox_get_authority (folder_t folder, authority_t *pauth) +{ + int status = 0; + if (folder->authority == NULL) + { + status = authority_create_null (&folder->authority, folder); + } + if (!status && pauth) + *pauth = folder->authority; + return status; +} + |