#include "imap4d.h"

int
inmsgset(Msgset *ms, uint id)
{
       for(; ms; ms = ms->next)
               if(ms->from <= id && ms->to >= id)
                       return 1;
       return 0;
}

/*
* we can't rely on uids being in order, but short-circuting saves us
* very little.  we have a few tens of thousands of messages at most.
* also use the msg list as the outer loop to avoid 1:5,3:7 returning
* duplicates.  this is allowed, but silly.  and could be a problem for
* internal uses that aren't idempotent, like (re)moving messages.
*/
static int
formsgsu(Box *box, Msgset *s, uint max, int (*f)(Box*, Msg*, int, void*), void *rock)
{
       int ok;
       Msg *m;
       Msgset *ms;

       ok = 1;
       for(m = box->msgs; m != nil && m->seq <= max; m = m->next)
               for(ms = s; ms != nil; ms = ms->next)
                       if(m->uid >= ms->from && m->uid <= ms->to){
                               if(!f(box, m, 1, rock))
                                       ok = 0;
                               break;
                       }
       return ok;
}

int
formsgsi(Box *box, Msgset *ms, uint max, int (*f)(Box*, Msg*, int, void*), void *rock)
{
       int ok, rok;
       uint id;
       Msg *m;

       ok = 1;
       for(; ms != nil; ms = ms->next){
               id = ms->from;
               rok = 0;
               for(m = box->msgs; m != nil && m->seq <= max; m = m->next){
                       if(m->seq > id)
                               break;  /* optimization */
                       if(m->seq == id){
                               if(!f(box, m, 0, rock))
                                       ok = 0;
                               if(id >= ms->to){
                                       rok = 1;
                                       break;  /* optimization */
                               }
                               if(ms->to == ~0UL)
                                       rok = 1;
                               id++;
                       }
               }
               if(!rok)
                       ok = 0;
       }
       return ok;
}

/*
* iterated over all of the items in the message set.
* errors are accumulated, but processing continues.
* if uids, then ignore non-existent messages.
* otherwise, that's an error.  additional note from the
* rfc:
*
* “Servers MAY coalesce overlaps and/or execute the
* sequence in any order.”
*/
int
formsgs(Box *box, Msgset *ms, uint max, int uids, int (*f)(Box*, Msg*, int, void*), void *rock)
{
       if(uids)
               return formsgsu(box, ms, max, f, rock);
       else
               return formsgsi(box, ms, max, f, rock);
}

Store*
mkstore(int sign, int op, int flags)
{
       Store *st;

       st = binalloc(&parsebin, sizeof *st, 1);
       if(st == nil)
               parseerr("out of memory");
       st->sign = sign;
       st->op = op;
       st->flags = flags;
       return st;
}

Fetch *
mkfetch(int op, Fetch *next)
{
       Fetch *f;

       f = binalloc(&parsebin, sizeof *f, 1);
       if(f == nil)
               parseerr("out of memory");
       f->op = op;
       f->next = next;
       return f;
}

Fetch*
revfetch(Fetch *f)
{
       Fetch *last, *next;

       last = nil;
       for(; f != nil; f = next){
               next = f->next;
               f->next = last;
               last = f;
       }
       return last;
}

Slist*
mkslist(char *s, Slist *next)
{
       Slist *sl;

       sl = binalloc(&parsebin, sizeof *sl, 0);
       if(sl == nil)
               parseerr("out of memory");
       sl->s = s;
       sl->next = next;
       return sl;
}

Slist*
revslist(Slist *sl)
{
       Slist *last, *next;

       last = nil;
       for(; sl != nil; sl = next){
               next = sl->next;
               sl->next = last;
               last = sl;
       }
       return last;
}

int
Bnlist(Biobuf *b, Nlist *nl, char *sep)
{
       char *s;
       int n;

       s = "";
       n = 0;
       for(; nl != nil; nl = nl->next){
               n += Bprint(b, "%s%ud", s, nl->n);
               s = sep;
       }
       return n;
}

int
Bslist(Biobuf *b, Slist *sl, char *sep)
{
       char *s;
       int n;

       s = "";
       n = 0;
       for(; sl != nil; sl = sl->next){
               n += Bprint(b, "%s%Z", s, sl->s);
               s = sep;
       }
       return n;
}