diff options
Diffstat (limited to 'src/unix.c')
-rw-r--r-- | src/unix.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/src/unix.c b/src/unix.c new file mode 100644 index 0000000..181ff7a --- /dev/null +++ b/src/unix.c @@ -0,0 +1,218 @@ +/* $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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <errno.h> + +#include "module.h" +#include "newmail.h" +#include "util.h" + +struct data { + char *path; + enum nm_query query; + nm_query_cb_t cb; + void *user; + oop_source *oop; +}; + +static int _query(struct nm_spool *s, enum nm_query query, struct nm_status *status) { + struct data *data = (struct data*) s->data; + status->new = status->cur = -1; + + + if (query & (NM_QUERY_NCUR|NM_QUERY_NNEW)) { + FILE *f; + struct stat st; + int hdr=1, old=0; + + if (!(f = fopen(data->path, "r"))) { + + if (errno == ENOENT) { + status->new = status->cur = 0; + return 0; + } else { + nm_error(NM_ERROR_NOFILE|NM_ERROR_SYSTEM, NULL); + return -1; + } + + } + + if (fstat(fileno(f), &st) < 0) { + nm_error(NM_ERROR_NOFILE|NM_ERROR_SYSTEM, "fstat() failed"); + fclose(f); + return -1; + } + + if (!S_ISREG(st.st_mode)) { + nm_error(NM_ERROR_NOFILE, "Mailbox not a regular file"); + fclose(f); + return -1; + } + + status->cur = 0; + + while (!feof(f)) { + static char ln[128]; + + if (!fgets(ln, sizeof(ln), f)) + break; + + if (strncmp(ln, "From ", 5) == 0) { + hdr = 1; + status->cur++; + } else if (hdr && strcmp(ln, "\n") == 0) + hdr = 0; + else if (hdr && strncmp(ln, "Status: ", 8) == 0) { + old++; + hdr = 0; + } + } + + fclose(f); + + status->new = status->cur-old; + + return 0; + + } else if (query & (NM_QUERY_CUR|NM_QUERY_NEW)) { + struct stat st; + + if (stat(data->path, &st) < 0) { + if (errno == ENOENT) { + status->cur = status->new = 0; + return 0; + } + + nm_error(NM_ERROR_NOFILE|NM_ERROR_SYSTEM, NULL); + return -1; + } + + if (!S_ISREG(st.st_mode)) { + nm_error(NM_ERROR_NOFILE, "Mailbox not a regular file"); + return -1; + } + + status->cur = st.st_size != 0 ? 1 : 0; + status->new = status->cur && (st.st_atime < st.st_mtime) ? 1 : 0; + return 0; + } + + return -1; +} + +static void * _cb(oop_source *source, struct timeval tv, void *user) { + struct nm_status status; + struct nm_spool *s = (struct nm_spool *) user; + struct data *data = (struct data*) s->data; + + if (_query(s, data->query, &status) < 0) + data->cb(s, NULL, data->user); + else + data->cb(s, &status, data->user); + + data->cb = NULL; + data->user = NULL; + data->query = 0; + data->oop = NULL; + + return OOP_CONTINUE; +} + + +static int _query_submit(struct nm_spool *s, enum nm_query query, oop_source *oop, nm_query_cb_t cb, void *user) { + struct data *data = (struct data*) s->data; + + if (data->cb) { + nm_error(NM_ERROR_ALREADY, NULL); + return -1; + } + + data->cb = cb; + data->user = user; + data->query = query; + data->oop = oop; + + data->oop->on_time(data->oop, OOP_TIME_NOW, _cb, s); + + return 0; +} + +static int _configure(struct nm_spool *s) { + return -1; +} + +static int _info(struct nm_spool *s, struct nm_info *i) { + struct data *data = (struct data*) s->data; + + snprintf(i->text, sizeof(i->text), "Unix mail spool %s", data->path); + i->flags = NM_FLAG_SYNCHRONOUS; + + return 0; +} + +static void _done(struct nm_spool *s) { + struct data *data = (struct data*) s->data; + + if (data) { + if (data->cb && data->oop) + data->oop->cancel_time(data->oop, OOP_TIME_NOW, _cb, s); + + nm_free(data->path); + nm_free(data); + } +} + +int nm_init(struct nm_spool *s) { + struct data *data; + char *def; + + if (!(def = getenv("MAIL"))) { + static char fn[PATH_MAX]; + static struct stat st; + + def = fn; + + snprintf(fn, sizeof(fn), "/var/mail/%s", getenv("USER")); + if (stat(fn, &st) < 0 || !S_ISREG(st.st_mode)) + snprintf(fn, sizeof(fn), "/var/spool/mail/%s", getenv("USER")); + } + + s->query = _query; + s->query_submit = _query_submit; + s->configure = _configure; + s->info = _info; + s->done = _done; + + if (!s->path) + s->path = nm_strdup("@AUTOMATIC@.unix"); + + data = nm_malloc(sizeof(struct data)); + memset(data, 0, sizeof(struct data)); + data->path = nm_strdup(nm_specials(nm_config_get(s->config, "Path", def))); + s->data = (void*) data; + return 0; +} + + |