#endif
#ifdef USE_IMAP
-#include "imap.h"
+#include "imap/imap.h"
+#include "imap/mx_imap.h"
#endif
#ifdef USE_POP
-#include "pop.h"
+#include "pop/pop.h"
+#include "pop/mx_pop.h"
#endif
#ifdef USE_NNTP
-#include "nntp.h"
+#include "nntp/nntp.h"
+#include "nntp/mx_nntp.h"
#endif
#ifdef BUFFY_SIZE
#include "lib/mem.h"
#include "lib/intl.h"
#include "lib/str.h"
+#include "lib/list.h"
#include <dirent.h>
#include <fcntl.h>
#include <utime.h>
#endif
+static list2_t* MailboxFormats = NULL;
+#define MX_COMMAND(idx,cmd) ((mx_t*) MailboxFormats->data[idx])->cmd
+#define MX_IDX(idx) (idx >= 0 && idx < MailboxFormats->length)
#define mutt_is_spool(s) (safe_strcmp (Spoolfile, s) == 0)
#endif /* USE_DOTLOCK */
+/* looks up index of type for path in MailboxFormats */
+static int mx_get_idx (const char* path) {
+ int i = 0, t = 0;
+ struct stat st;
+
+ /* first, test all non-local folders to avoid stat() call */
+ for (i = 0; i < MailboxFormats->length; i++) {
+ if (!MX_COMMAND(i,local))
+ t = MX_COMMAND(i,mx_is_magic)(path, NULL);
+ if (t >= 1)
+ return (t-1);
+ }
+ if (stat (path, &st) == 0) {
+ /* if stat() succeeded, keep testing until success and
+ * pass stat() info so that we only need to do it once */
+ for (i = 0; i < MailboxFormats->length; i++) {
+ if (MX_COMMAND(i,local))
+ t = MX_COMMAND(i,mx_is_magic)(path, &st);
+ if (t >= 1)
+ return (t-1);
+ }
+ }
+ return (-1);
+}
+
/* Args:
* excl if excl != 0, request an exclusive lock
* dot if dot != 0, try to dotlock the file
close (fd);
}
-/* try to figure out what type of mailbox ``path'' is
- *
- * return values:
- * M_* mailbox type
- * 0 not a mailbox
- * -1 error
- */
-
-#ifdef USE_IMAP
-int mx_is_imap (const char *p)
-{
- url_scheme_t scheme;
-
- if (!p)
- return 0;
-
- if (*p == '{')
- return 1;
-
- scheme = url_check_scheme (p);
- if (scheme == U_IMAP || scheme == U_IMAPS)
- return 1;
-
- return 0;
-}
-#endif
-
-#ifdef USE_POP
-int mx_is_pop (const char *p)
-{
- url_scheme_t scheme;
-
- if (!p)
- return 0;
-
- scheme = url_check_scheme (p);
- if (scheme == U_POP || scheme == U_POPS)
- return 1;
-
- return 0;
-}
-#endif
-
-#ifdef USE_NNTP
-int mx_is_nntp (const char *p)
-{
- url_scheme_t scheme;
-
- if (!p)
- return 0;
-
- scheme = url_check_scheme (p);
- if (scheme == U_NNTP || scheme == U_NNTPS)
- return 1;
-
- return 0;
-}
-#endif
-
-int mx_get_magic (const char *path)
-{
- struct stat st;
- int magic = 0;
- char tmp[_POSIX_PATH_MAX];
- FILE *f;
-
-#ifdef USE_IMAP
- if (mx_is_imap (path))
- return M_IMAP;
-#endif /* USE_IMAP */
-
-#ifdef USE_POP
- if (mx_is_pop (path))
- return M_POP;
-#endif /* USE_POP */
-
-#ifdef USE_NNTP
- if (mx_is_nntp (path))
- return M_NNTP;
-#endif /* USE_NNTP */
-
- if (stat (path, &st) == -1) {
- dprint (1,
- (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n",
- path, strerror (errno), errno));
- return (-1);
- }
-
- if (S_ISDIR (st.st_mode)) {
- /* check for maildir-style mailbox */
-
- snprintf (tmp, sizeof (tmp), "%s/cur", path);
- if (stat (tmp, &st) == 0 && S_ISDIR (st.st_mode))
- return (M_MAILDIR);
-
- /* check for mh-style mailbox */
-
- snprintf (tmp, sizeof (tmp), "%s/.mh_sequences", path);
- if (access (tmp, F_OK) == 0)
- return (M_MH);
-
- snprintf (tmp, sizeof (tmp), "%s/.xmhcache", path);
- if (access (tmp, F_OK) == 0)
- return (M_MH);
-
- snprintf (tmp, sizeof (tmp), "%s/.mew_cache", path);
- if (access (tmp, F_OK) == 0)
- return (M_MH);
-
- snprintf (tmp, sizeof (tmp), "%s/.mew-cache", path);
- if (access (tmp, F_OK) == 0)
- return (M_MH);
-
- snprintf (tmp, sizeof (tmp), "%s/.sylpheed_cache", path);
- if (access (tmp, F_OK) == 0)
- return (M_MH);
-
- /*
- * ok, this isn't an mh folder, but mh mode can be used to read
- * Usenet news from the spool. ;-)
- */
-
- snprintf (tmp, sizeof (tmp), "%s/.overview", path);
- if (access (tmp, F_OK) == 0)
- return (M_MH);
-
- }
- else if (st.st_size == 0) {
- /* hard to tell what zero-length files are, so assume the default magic */
- if (DefaultMagic == M_MBOX || DefaultMagic == M_MMDF)
- return (DefaultMagic);
- else
- return (M_MBOX);
- }
- else if ((f = fopen (path, "r")) != NULL) {
-#ifndef BUFFY_SIZE
- struct utimbuf times;
-#endif
+/* try to figure out what type of mailbox ``path'' is */
+int mx_get_magic (const char *path) {
+ int i = 0;
- fgets (tmp, sizeof (tmp), f);
- if (safe_strncmp ("From ", tmp, 5) == 0)
- magic = M_MBOX;
- else if (safe_strcmp (MMDF_SEP, tmp) == 0)
- magic = M_MMDF;
- safe_fclose (&f);
-#ifndef BUFFY_SIZE
- /* need to restore the times here, the file was not really accessed,
- * only the type was accessed. This is important, because detection
- * of "new mail" depends on those times set correctly.
- */
- times.actime = st.st_atime;
- times.modtime = st.st_mtime;
- utime (path, ×);
-#endif
- }
- else {
- dprint (1,
- (debugfile,
- "mx_get_magic(): unable to open file %s for reading.\n", path));
- mutt_perror (path);
+ if (safe_strlen (path) == 0)
return (-1);
- }
-
-#ifdef USE_COMPRESSED
- if (magic == 0 && mutt_can_read_compressed (path))
- return M_COMPRESSED;
-#endif
+ if ((i = mx_get_idx (path)) >= 0)
+ return (MX_COMMAND(i,type));
+ return (-1);
+}
- return (magic);
+int mx_is_local (int m) {
+ if (!MX_IDX(m))
+ return (0);
+ return (MX_COMMAND(m,local));
}
/*
* we use the normal access() flags. */
int mx_access (const char *path, int flags)
{
-#ifdef USE_IMAP
- if (mx_is_imap (path))
- return imap_access (path, flags);
-#endif
+ int i = 0;
- return access (path, flags);
+ if ((i = mx_get_idx (path)) >= 0 && MX_COMMAND(i,mx_access))
+ return (MX_COMMAND(i,mx_access)(path,flags));
+ return (0);
}
static int mx_open_mailbox_append (CONTEXT * ctx, int flags)
#ifdef USE_IMAP
- if (mx_is_imap (ctx->path))
+ if (mx_get_magic (ctx->path) == M_IMAP)
return imap_open_mailbox_append (ctx);
#endif
return ctx;
}
- ctx->magic = mx_get_magic (path);
+ if (!MX_IDX(ctx->magic-1))
+ ctx->magic = mx_get_magic (path);
#ifdef USE_COMPRESSED
if (ctx->magic == M_COMPRESSED)
if (!ctx->quiet)
mutt_message (_("Reading %s..."), ctx->path);
- switch (ctx->magic) {
- case M_MH:
- rc = mh_read_dir (ctx, NULL);
- break;
-
- case M_MAILDIR:
- rc = maildir_read_dir (ctx);
- break;
-
- case M_MMDF:
- case M_MBOX:
- rc = mbox_open_mailbox (ctx);
- break;
-
-#ifdef USE_IMAP
- case M_IMAP:
- rc = imap_open_mailbox (ctx);
- break;
-#endif /* USE_IMAP */
-
-#ifdef USE_POP
- case M_POP:
- rc = pop_open_mailbox (ctx);
- break;
-#endif /* USE_POP */
-
-#ifdef USE_NNTP
- case M_NNTP:
- rc = nntp_open_mailbox (ctx);
- break;
-#endif /* USE_NNTP */
-
- default:
- rc = -1;
- break;
- }
+ rc = MX_COMMAND(ctx->magic-1,mx_open_mailbox)(ctx);
if (rc == 0) {
if ((flags & M_NOSORT) == 0) {
/* try to use server-side copy first */
i = 1;
- if (ctx->magic == M_IMAP && mx_is_imap (mbox)) {
+ if (ctx->magic == M_IMAP && imap_is_magic (mbox, NULL) == M_IMAP) {
/* tag messages for moving, and clear old tags, if any */
for (i = 0; i < ctx->msgcount; i++)
if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted
if (r == 0 && (ctx->magic == M_MBOX || ctx->magic == M_MMDF)
&& (fflush (msg->fp) == EOF || fsync (fileno (msg->fp)) == -1)) {
- mutt_perror _("Can't write message");
+ mutt_perror (_("Can't write message"));
r = -1;
}
*/
int mx_check_empty (const char *path)
{
- switch (mx_get_magic (path)) {
- case M_MBOX:
- case M_MMDF:
- return mbox_check_empty (path);
- case M_MH:
- return mh_check_empty (path);
- case M_MAILDIR:
- return maildir_check_empty (path);
- default:
- errno = EINVAL;
- return -1;
+ int i = 0;
+ if ((i = mx_get_idx (path)) >= 0 && MX_COMMAND(i,mx_check_empty))
+ return (MX_COMMAND(i,mx_check_empty)(path));
+ errno = EINVAL;
+ return (-1);
+}
+
+int mx_acl_check (CONTEXT* ctx, int flag) {
+ if (!ctx || !MX_IDX(ctx->magic-1))
+ return (0);
+ /* if no acl_check defined for module, assume permission is granted */
+ if (!MX_COMMAND(ctx->magic-1,mx_acl_check))
+ return (1);
+ return (MX_COMMAND(ctx->magic-1,mx_acl_check)(ctx,flag));
+}
+
+void mx_init (void) {
+#ifdef DEBUG
+ int i = 0;
+#endif
+ list_push_back (&MailboxFormats, (void*) mbox_reg_mx ());
+ list_push_back (&MailboxFormats, (void*) mmdf_reg_mx ());
+ list_push_back (&MailboxFormats, (void*) mh_reg_mx ());
+ list_push_back (&MailboxFormats, (void*) maildir_reg_mx ());
+#ifdef USE_IMAP
+ list_push_back (&MailboxFormats, (void*) imap_reg_mx ());
+#endif
+#ifdef USE_POP
+ list_push_back (&MailboxFormats, (void*) pop_reg_mx ());
+#endif
+#ifdef USE_NNTP
+ list_push_back (&MailboxFormats, (void*) nntp_reg_mx ());
+#endif
+#ifdef USE_COMPRESSED
+ list_push_back (&MailboxFormats, (void*) compress_reg_mx ());
+#endif
+#ifdef DEBUG
+ /* check module registration for completeness with debug versions */
+#define EXITWITHERR(m) do { fprintf(stderr, "error: incomplete mx module: %s is missing for type %i\n",m,i);exit(1); } while (0)
+ for (i = 0; i < MailboxFormats->length; i++) {
+ if (MX_COMMAND(i,type) < 1) EXITWITHERR("type");
+ if (!MX_COMMAND(i,mx_is_magic)) EXITWITHERR("mx_is_magic");
+ if (!MX_COMMAND(i,mx_open_mailbox)) EXITWITHERR("mx_open_mailbox");
}
- /* not reached */
+#undef EXITWITHERR
+#endif /* DEBUG */
}