#include #include #include #include #include #include extern const char *__progname; #include "message.h" #include "wrap.h" #include "folder.h" #include "deconst.h" typedef struct hdr HDR; struct hdr { HDR *link; char *name; char *value; } ; struct mm_message { FOLDER *f; int num; const char *path; FILE *fp; int ohow; void *resvn; int locked; int headers_valid; char *unixfrom; HDR *headers; long int bodyseek; } ; static void make_message_path(MESSAGE *m) { char nt[64]; char *t; sprintf(&nt[0],"%d",m->num); t = malloc(strlen(folder_path(m->f))+1+strlen(&nt[0])+1); sprintf(t,"%s/%s",folder_path(m->f),&nt[0]); m->path = t; } static void load_headers(MESSAGE *m) { char *buf; int len; int have; int c; char *colon; HDR *h; HDR **tail; if (m->headers_valid) return; m->headers_valid = 1; m->unixfrom = 0; tail = &m->headers; fseek(m->fp,0,SEEK_SET); buf = malloc(1); len = 0; have = 0; while (1) { len = 0; while (1) { c = getc(m->fp); if (c == '\n') { int c2; if (len == 0) break; c2 = getc(m->fp); if (c2 != EOF) ungetc(c2,m->fp); if ((c2 != ' ') && (c2 != '\t')) break; } if (c == EOF) break; if (len >= have) buf = realloc(buf,(have=len+8)+1); buf[len++] = c; } buf[len] = '\0'; if (len == 0) break; if (!strncmp(buf,"From ",5)) { if (m->unixfrom) free(m->unixfrom); m->unixfrom = strdup(buf); continue; } colon = index(buf,':'); if (colon == 0) { fprintf(stderr,"%s: invalid header line ignored (no colon): %s\n",__progname,buf); continue; } *colon++ = '\0'; h = malloc(sizeof(HDR)); h->name = strdup(buf); while (*colon && ((*colon == ' ') || (*colon == '\t'))) colon ++; h->value = strdup(colon); *tail = h; tail = &h->link; } *tail = 0; free(buf); fseek(m->fp,0,SEEK_SET); while (1) { c = getc(m->fp); if (c == '\n') { c = getc(m->fp); if ((c == '\n') || (c == EOF)) break; } if (c == EOF) break; } m->bodyseek = ftell(m->fp); } const char *message_path(MESSAGE *m) { return(m->path); } FILE *message_fp(MESSAGE *m) { return(m->fp); } MESSAGE *message_make(FOLDER *f, int n) { MESSAGE *m; m = malloc(sizeof(MESSAGE)); m->f = f; m->num = n; make_message_path(m); m->fp = 0; m->resvn = folder_must_remain_locked(f,"message_make"); m->locked = 0; m->headers_valid = 0; return(m); } int message_lock(MESSAGE *m, unsigned int how) { int lockop; switch (how & (MSG_SHARED|MSG_EXCLUSIVE)) { case MSG_SHARED: lockop = LOCK_SH; break; case MSG_EXCLUSIVE: lockop = LOCK_EX; break; default: errno = EINVAL; return(-1); break; } switch (how & (MSG_WAIT|MSG_NOWAIT)) { case MSG_WAIT: break; case MSG_NOWAIT: lockop |= LOCK_NB; break; default: errno = EINVAL; return(-1); break; } if (m->locked) { m->locked ++; return(0); } if (! m->fp) { errno = EBADF; return(-1); } if (flock(fileno(m->fp),lockop) < 0) return(-1); m->locked = 1; return(0); } void message_unlock(MESSAGE *m) { if (m->locked < 1) { fprintf(stderr,"%s: unlocking un-locked message\n",__progname); abort(); } if (m->locked > 1) { m->locked --; return; } if (m->fp) flock(fileno(m->fp),LOCK_UN); m->locked = 0; } void message_close(MESSAGE *m) { if (m->fp) fclose(m->fp); m->locked = 0; m->fp = 0; } void message_free(MESSAGE *m) { message_close(m); folder_may_be_unlocked(m->f,m->resvn); free(deconst(m->path)); if (m->headers_valid) { HDR *h; HDR *hr; free(m->unixfrom); hr = m->headers; while (hr) { h = hr; hr = h->link; free(h->name); free(h->value); free(h); } } free(m); } int message_open(MESSAGE *m, int how, int mode) { int fd; const char *fhow; switch (how & (O_RDONLY|O_WRONLY|O_RDWR)) { case O_RDONLY: fhow = "r"; break; case O_WRONLY: fhow = "w"; break; case O_RDWR: fhow = "r+"; break; default: errno = EINVAL; return(-1); break; } if (m->fp) { errno = EALREADY; return(-1); } m->ohow = how; fd = open(m->path,how,mode); if (fd < 0) return(-1); fcntl(fd,F_SETFD,1); m->fp = fdopen(fd,fhow); if (m->fp == 0) { int e; e = errno; close(fd); errno = e; return(-1); } if (how & (O_SHLOCK|O_EXLOCK)) m->locked = 1; return(0); } int message_number(MESSAGE *m) { return(m->num); } FOLDER *message_folder(MESSAGE *m) { return(m->f); } const char *message_header_val(MESSAGE *m, const char *s) { HDR *h; load_headers(m); for (h=m->headers;h;h=h->link) if (!strcasecmp(h->name,s)) return(h->value); return(0); } int message_header_scan(MESSAGE *m, int (*fn)(MESSAGE *, const char *, const char *, void *), void *cookie) { HDR *h; int rv; load_headers(m); for (h=m->headers;h;h=h->link) { rv = (*fn)(m,h->name,h->value,cookie); if (rv) return(rv); } return(0); } char *message_body_line(MESSAGE *m) { char *buf; int have; int len; int c; if (! m->headers_valid) message_body_begin(m); buf = malloc(1); have = 0; len = 0; while (1) { c = getc(m->fp); if (c == EOF) { if (len == 0) { free(buf); return(0); } c = '\n'; } if (c == '\n') { buf[len] = '\0'; return(buf); } if (len >= have) buf = realloc(buf,(have=len+32)+1); buf[len++] = c; } } void message_body_begin(MESSAGE *m) { load_headers(m); fseek(m->fp,m->bodyseek,SEEK_SET); } const char *message_unix_from(MESSAGE *m) { load_headers(m); return(m->unixfrom); }