/* $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 "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]; char *eol; 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; } /* Position the cursor at the next newline */ do { if (eol = strchr(ln, '\n')) { fseek(f, -1 * strlen(eol + 1), SEEK_CUR); break; } } while(fgets(ln, sizeof(ln), f)); } 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; }