/* $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 #include #include #include #include #include #include #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; const 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, 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, 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); }