/* 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 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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; }