#include #include #include #include extern const char *__progname; #include "seq.h" #include "msgarg.h" #define M_FIRST (-1) #define M_LAST (-2) #define M_CUR (-3) #define M_NEXT (-4) #define M_PREV (-5) #define M_ABSENT (-6) static char *get_msgno(char *s, int *mp) { int v; char *ep; if (!strncmp(s,"first",5)) { *mp = M_FIRST; return(s+5); } if (!strncmp(s,"last",4)) { *mp = M_LAST; return(s+4); } if (!strncmp(s,"next",4)) { *mp = M_NEXT; return(s+4); } if (!strncmp(s,"prev",4)) { *mp = M_PREV; return(s+4); } if (!strncmp(s,"cur",3)) { *mp = M_CUR; return(s+3); } v = strtol(s,&ep,0); if ((ep == s) || (v < 0)) { *mp = M_ABSENT; return(s); } *mp = v; return(ep); } static int scannum(char *s, int *ip, char **ep) { int v; char *e; v = strtol(s,&e,0); if (s == e) return(0); *ip = v; *ep = e; return(1); } static int canbeginrange(int p) { switch (p) { case M_LAST: case M_NEXT: case M_PREV: return(0); } return(1); } static int canendrange(int p) { switch (p) { case M_FIRST: case M_NEXT: case M_PREV: return(0); } return(1); } int msgarg_parse(char *s, ARG *a, char **endp) { char *e; int n; int p1; int p2; if (*s == '+') { s ++; a->folder = s; while (*s && (*s != ':')) s ++; if (! *s) { a->type = AT_NOMSG; if (endp) *endp = s; return(1); } *s++ = '\0'; } else { a->folder = 0; } if (!strncmp(s,"all",3)) { a->type = AT_RANGE; a->u.range.first = MA_LIMIT; a->u.range.last = MA_LIMIT; if (endp) *endp = s + 3; return(1); } e = get_msgno(s,&p1); if ((*e == '-') && canbeginrange(p1)) { char *e2; e2 = get_msgno(e+1,&p2); if (! canendrange(p2)) { p2 = M_ABSENT; e2 = e + 1; } a->type = AT_RANGE; switch (p1) { case M_FIRST: case M_ABSENT: a->u.range.first = MA_LIMIT; break; case M_CUR: a->u.range.first = MA_CUR; break; default: a->u.range.first = p1; break; } switch (p2) { case M_LAST: case M_ABSENT: a->u.range.last = MA_LIMIT; break; case M_CUR: a->u.range.last = MA_CUR; break; default: a->u.range.last = p2; break; } if (endp) *endp = e2; return(1); } switch (p1) { case M_FIRST: { int base; base = AT_FIRST; if (0) { case M_LAST: base = AT_LAST; } if (0) { case M_NEXT: base = AT_NEXT; } if (0) { case M_PREV: base = AT_PREV; } if ((*e == '#') && scannum(e+1,&n,&e)) { a->type = base + AT__N; a->u.n = n; } else if (scannum(e,&n,&e)) { a->type = base + AT__M; a->u.n = n; } else { a->type = base + AT__M; a->u.n = 1; } if (endp) *endp = e; } return(1); break; case M_CUR: a->type = AT_SINGLE; a->u.n = MA_CUR; if (endp) *endp = e; return(1); break; case M_ABSENT: if (*e == ':') e ++; if (*e) { a->type = AT_SEQNAM; a->u.seqnam = e; if (endp) *endp = e + strlen(e); return(1); } return(0); break; } a->type = AT_SINGLE; a->u.n = p1; if (endp) *endp = e; return(1); } static void print_msg_error(FOLDER *f, int which, int err, int syserr) { const char *tag; switch (which) { case FM_PREV: tag = "previous"; break; case FM_CUR: tag = "current"; break; case FM_NEXT: tag = "next"; break; default: abort(); break; } switch (err) { case FOLDER_SYSCALLERR: fprintf(stderr,"%s: can't get %s message number in +%s: %s\n",__progname,tag,folder_name(f),strerror(syserr)); break; case FOLDER_NOSUCH: fprintf(stderr,"%s: no %s message in +%s\n",__progname,tag,folder_name(f)); break; case FOLDER_INVARG: default: abort(); break; } } void msgarg_handle(ARG *a, FOLDER *f, void (*fn)(int *, int, void *), void *cookie) { int *msgs; int m; int n; int i; int i0; switch (a->type) { case AT_SINGLE: if (a->u.n == MA_CUR) { m = folder_msg(f,FM_CUR); if (m < 0) { print_msg_error(f,FM_CUR,m,errno); return; } } else { m = a->u.n; } (*fn)(&m,1,cookie); break; case AT_FIRST+AT__M: m = a->u.n; msgs = malloc(m*sizeof(int)); n = folder_get_msgnos(f,m,-1,msgs); (*fn)(msgs,(nu.n; msgs = malloc(m*sizeof(int)); n = folder_get_msgnos(f,m,-1,msgs); for (i=0;(iu.n; msgs = malloc(m*sizeof(int)); n = folder_get_msgnos(f,m,-1,msgs); if (n > m) { if (folder_get_msgnos(f,m,n-m,msgs) != n) { fprintf(stderr,"%s: phase error on +%s\n",__progname,folder_name(f)); free(msgs); return; } } else { m = n; } (*fn)(msgs,m,cookie); free(msgs); break; case AT_LAST+AT__N: { int max; m = a->u.n; msgs = malloc(m*sizeof(int)); n = folder_get_msgnos(f,m,-1,msgs); if (n > m) { if (folder_get_msgnos(f,m,n-m,msgs) < 0) { fprintf(stderr,"%s: phase error on +%s\n",__progname,folder_name(f)); free(msgs); return; } i = m; } else { i = n; } max = msgs[i-1]; for (i--;(i>=0)&&(max-msgs[i]u.n; if (i0+m > n) m = n - i0; (*fn)(msgs+i0,m,cookie); free(msgs); break; case AT_NEXT+AT__N: i = folder_msg(f,FM_NEXT); if (i < 0) { print_msg_error(f,FM_NEXT,i,errno); return; } n = folder_get_msgnos(f,0,-1,0); msgs = malloc(n*sizeof(int)); m = folder_get_msgnos(f,n,0,msgs); if (m != n) { fprintf(stderr,"%s: phase error on +%s\n",__progname,folder_name(f)); free(msgs); return; } for (i0=0;(i0u.n; for (i=i0;(iu.n; if (m > i0) m = i0; if (m > 0) (*fn)(msgs+i0-m,m,cookie); free(msgs); break; case AT_PREV+AT__N: i = folder_msg(f,FM_PREV); if (i < 0) { print_msg_error(f,FM_PREV,i,errno); return; } n = folder_get_msgnos(f,0,-1,0); msgs = malloc(n*sizeof(int)); m = folder_get_msgnos(f,n,0,msgs); if (m != n) { fprintf(stderr,"%s: phase error on +%s\n",__progname,folder_name(f)); free(msgs); return; } for (i0=0;(i0u.n; for (i=i0;(i>=0)&&(msgs[i0]-msgs[i]u.range.first == MA_CUR) || (a->u.range.last == MA_CUR)) { cur = folder_msg(f,FM_CUR); if (cur < 0) { print_msg_error(f,FM_CUR,cur,errno); return; } } switch (a->u.range.first) { case MA_LIMIT: first = 0; break; case MA_CUR: first = cur; break; default: first = a->u.range.first; break; } switch (a->u.range.last) { case MA_LIMIT: do { n = folder_get_msgnos(f,0,-1,0); i = folder_get_msgnos(f,1,n-1,&last); } while (i < 0); break; case MA_CUR: last = cur; break; default: last = a->u.range.last; } msgs = 0; do { free(msgs); n = folder_get_msgnos(f,0,-1,0); msgs = malloc(n*sizeof(int)); } while (folder_get_msgnos(f,n,0,msgs) < 0); for (i=0;(iu.seqnam); n = seq_get(s,0,0,0); msgs = malloc(n*sizeof(int)); seq_get(s,n,0,msgs); seqs_abort(ss); (*fn)(msgs,n,cookie); free(msgs); } else { fprintf(stderr,"%s: can't open sequence database in +%s: %s\n",__progname,folder_name(f),strerror(errno)); } } break; default: fprintf(stderr,"%s: impossible arglist type %d\n",__progname,a->type); abort(); break; } }