summaryrefslogtreecommitdiffstats
path: root/src/newmail.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/newmail.c')
-rw-r--r--src/newmail.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/newmail.c b/src/newmail.c
new file mode 100644
index 0000000..7d513c9
--- /dev/null
+++ b/src/newmail.c
@@ -0,0 +1,339 @@
+/* $Id$ */
+
+/***
+ This file is part of libnewmail
+
+ libnewmail is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libnewmail 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libnewmail; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <limits.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ltdl.h>
+
+#include "newmail.h"
+#include "module.h"
+#include "config.h"
+#include "util.h"
+
+#ifndef NM_LIBRARY_PATH
+#define NM_LIBRARY_PATH "/home/lennart/projects/libnewmail/src"
+#endif
+
+#define NM_PRIVATE_CONFIG_PATH ".newmail"
+#define NM_GLOBAL_CONFIG_PATH "/etc/newmail"
+
+void* (*nm_malloc)(size_t) = malloc;
+void* (*nm_realloc)(void *,size_t) = realloc;
+void (*nm_free)(void *) = free;
+
+enum nm_error nm_errno = 0;
+char *nm_explanation = 0;
+
+static void _ltdl_init(int b) {
+ static int n = 0;
+
+ if (b) {
+ if (n++ == 0) {
+ lt_dlinit();
+ lt_dladdsearchdir(NM_LIBRARY_PATH);
+ }
+ } else {
+ if (--n == 0)
+ lt_dlexit();
+ }
+}
+
+
+int nm_list(nm_enum_cb_t cb, const void*user) {
+ static char p[PATH_MAX];
+ DIR *d;
+ struct dirent *de;
+ int n = 0;
+
+ if (!cb) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ return -1;
+ }
+
+ snprintf(p, sizeof(p), "%s/"NM_PRIVATE_CONFIG_PATH, getenv("HOME"));
+ if (!(d = opendir(p)))
+ if (!(d = opendir(NM_GLOBAL_CONFIG_PATH)))
+ return 0;
+
+ while ((de = readdir(d))) {
+ static char fn[PATH_MAX];
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ snprintf(fn, sizeof(fn), "%s/%s", p, de->d_name);
+ cb(fn, user);
+ n++;
+ }
+
+ closedir(d);
+
+ return n;
+}
+
+const char *nm_strerror(enum nm_error n, int e, const char *explanation) {
+ char *p = NULL;
+ static char t[256];
+
+ switch (n & ~(NM_ERROR_SYSTEM|NM_ERROR_EXPLANATION)) {
+ case NM_ERROR_SUCCESS: p = "Success"; break;
+ case NM_ERROR_NOCONFIG: p = "No configuration available"; break;
+ case NM_ERROR_INVPAR: p = "Invalid parameters"; break;
+ case NM_ERROR_MEMORY: p = "Not enough memory"; break;
+ case NM_ERROR_INVNAME: p = "Invalid name"; break;
+ case NM_ERROR_DLFAIL: p = "Module not found"; break;
+ case NM_ERROR_NOTIMPL: p = "Not implemented"; break;
+ case NM_ERROR_NOFILE: p = "Could not open file"; break;
+ case NM_ERROR_FORK: p = "fork() failure"; break;
+ case NM_ERROR_ALREADY: p = "Asynchronous check already scheduled"; break;
+ case NM_ERROR_CONTEXT: p = "Function call in wrong context"; break;
+ case NM_ERROR_INTERNAL: p = "Internal error"; break;
+ case NM_ERROR_SERVFAIL: p = "Server failure"; break;
+ case NM_ERROR_SERVNOTFOUND: p = "Server not found"; break;
+ default: p = "Unknown error"; break;
+ }
+
+ if (n & NM_ERROR_SYSTEM) {
+ snprintf(t, sizeof(t), "%s (%s)", p, strerror(e));
+ p = t;
+ } else if (n & NM_ERROR_EXPLANATION) {
+ snprintf(t, sizeof(t), "%s (Explanation: %s)", p, explanation);
+ p = t;
+ }
+
+ return p;
+}
+
+void nm_perror(const char *s) {
+ fprintf(stderr, "%s: %s\n", s, nm_strerror(nm_errno, errno, nm_explanation));
+}
+
+int nm_info(struct nm_spool *s, struct nm_info *i) {
+ char *p;
+
+ if (!s || !i) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ goto fail;
+ }
+
+ if (!s->info) {
+ nm_error(NM_ERROR_NOTIMPL, NULL);
+ goto fail;
+ }
+
+ memset(i, 0, sizeof(struct nm_info));
+
+ strncpy(i->path, s->path ? s->path : "n/a", sizeof(i->path));
+ i->path[sizeof(i->path)-1] = 0;
+
+ if (!(p = strrchr(i->path, '/')))
+ p = i->path;
+ else
+ p++;
+
+ strncpy(i->name, p, sizeof(i->name));
+ i->name[sizeof(i->name)-1] = 0;
+
+ if ((p = strrchr(i->name, '.'))) {
+ *p = 0;
+ p++;
+
+ strncpy(i->type, p, sizeof(i->type));
+ i->type[sizeof(i->type)-1] = 0;
+ }
+
+ return s->info(s, i);
+
+fail:
+
+ return -1;
+}
+
+int nm_query(struct nm_spool *s, enum nm_query query, struct nm_status *st) {
+
+ if (!s || !st) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ goto fail;
+ }
+
+ if (!s->query) {
+ nm_error(NM_ERROR_NOTIMPL, NULL);
+ goto fail;
+ }
+
+ return s->query(s, query, st);
+
+fail:
+ return -1;
+}
+
+
+int nm_query_submit(struct nm_spool *s, enum nm_query query, oop_source *oop, nm_query_cb_t cb, const void *user) {
+
+ if (!s || !cb || !oop) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ goto fail;
+ }
+
+ if (!s->query_submit) {
+ nm_error(NM_ERROR_NOTIMPL, NULL);
+ goto fail;
+ }
+
+ return s->query_submit(s, query, oop, cb, (void*) user);
+
+fail:
+ return -1;
+}
+
+static int _nm_load(struct nm_spool *s, char *p) {
+ char t[PATH_MAX];
+ nm_init_t init;
+
+ _ltdl_init(1);
+
+
+ snprintf(t, sizeof(t), "lib%s", p);
+ if (!(s->dl = lt_dlopenext(t))) {
+ nm_error(NM_ERROR_DLFAIL|NM_ERROR_EXPLANATION, lt_dlerror());
+ goto fail;
+ }
+
+ if (!(init = lt_dlsym(s->dl, "nm_init"))) {
+ nm_error(NM_ERROR_DLFAIL|NM_ERROR_EXPLANATION, lt_dlerror());
+ goto fail;
+ }
+
+ if (init(s) < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+
+ if (s->dl)
+ lt_dlclose(s->dl);
+
+ _ltdl_init(0);
+
+ return -1;
+}
+
+struct nm_spool* nm_open(const char *spool) {
+ struct nm_spool* s = NULL;
+ static char p[PATH_MAX];
+
+ if (!spool) {
+ char *r;
+ snprintf(p, sizeof(p), "%s/"NM_PRIVATE_CONFIG_PATH"/.default", getenv("HOME"));
+
+ if ((r = realpath(p, NULL)))
+ if ((s = nm_open(r))) {
+ free(r);
+ return s;
+ }
+
+ snprintf(p, sizeof(p), NM_GLOBAL_CONFIG_PATH"/.default");
+
+ if ((r = realpath(p, NULL)))
+ if ((s = nm_open(r))) {
+ free(r);
+ return s;
+ }
+ }
+
+ if (!(s = nm_malloc(sizeof(struct nm_spool)))) {
+ nm_error(NM_ERROR_MEMORY, NULL);
+ goto fail;
+ }
+ memset(s, 0, sizeof(struct nm_spool));
+
+ if (spool) {
+ char *d;
+
+ if (!(s->config = nm_config_open(spool)))
+ goto fail;
+
+ if (!(s->path = nm_strdup(spool))) {
+ nm_error(NM_ERROR_MEMORY, NULL);
+ goto fail;
+ }
+
+ if (!(d = strrchr(spool, '.'))) {
+ nm_error(NM_ERROR_INVNAME, NULL);
+ goto fail;
+ }
+ d++;
+
+ if (_nm_load(s, d) < 0)
+ goto fail;
+
+ } else {
+ if (_nm_load(s, "maildir") < 0)
+ if (_nm_load(s, "unix") < 0)
+ goto fail;
+ }
+
+ return s;
+
+fail:
+ if (s) {
+ if (s->config)
+ nm_config_close(s->config);
+
+
+ if (s->path)
+ nm_free(s->path);
+
+ nm_free(s);
+ }
+
+ return NULL;
+}
+
+void nm_close(struct nm_spool *s) {
+
+ if (!s) {
+ nm_error(NM_ERROR_INVPAR, NULL);
+ return;
+ }
+
+ if (s->done)
+ s->done(s);
+
+ if (s->config)
+ nm_config_close(s->config);
+
+ if (s->path)
+ nm_free(s->path);
+
+ if (s->dl)
+ lt_dlclose(s->dl);
+
+ nm_free(s);
+
+ _ltdl_init(0);
+}
+