diff options
Diffstat (limited to 'src/newmail.c')
-rw-r--r-- | src/newmail.c | 339 |
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); +} + |