upas/fs imap fixes and improvements
do incremental imap fetches after startup, fixes validity handling, record flags correctly when we aren't in the process of directly updating a message, fixes off by one in flag parsing, fixes mis-indexing messages in sync when we get an unsolicited fetch response.
This commit is contained in:
parent
08d6b0f043
commit
84c4c81cee
1 changed files with 93 additions and 35 deletions
|
@ -35,6 +35,7 @@ typedef struct {
|
||||||
uvlong uid;
|
uvlong uid;
|
||||||
ulong sizes;
|
ulong sizes;
|
||||||
ulong dates;
|
ulong dates;
|
||||||
|
ulong flags;
|
||||||
} Fetchi;
|
} Fetchi;
|
||||||
|
|
||||||
typedef struct Imap Imap;
|
typedef struct Imap Imap;
|
||||||
|
@ -51,9 +52,23 @@ struct Imap {
|
||||||
|
|
||||||
ulong tag;
|
ulong tag;
|
||||||
ulong validity;
|
ulong validity;
|
||||||
|
ulong newvalidity;
|
||||||
int nmsg;
|
int nmsg;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These variables are how we keep track
|
||||||
|
* of what's been added or deleted. They
|
||||||
|
* keep a count of the number of uids we
|
||||||
|
* have processed this sync (nuid), and
|
||||||
|
* the number we processed last sync
|
||||||
|
* (muid).
|
||||||
|
*
|
||||||
|
* We keep the latest imap state in fetchi,
|
||||||
|
* and imap4read syncs the information in
|
||||||
|
* it with the messages. That's how we know
|
||||||
|
* something changed on the server.
|
||||||
|
*/
|
||||||
Fetchi *f;
|
Fetchi *f;
|
||||||
int nuid;
|
int nuid;
|
||||||
int muid;
|
int muid;
|
||||||
|
@ -163,6 +178,7 @@ enum {
|
||||||
Fetch,
|
Fetch,
|
||||||
Cap,
|
Cap,
|
||||||
Auth,
|
Auth,
|
||||||
|
Expunge,
|
||||||
|
|
||||||
Unknown,
|
Unknown,
|
||||||
};
|
};
|
||||||
|
@ -177,6 +193,7 @@ static char *verblist[] = {
|
||||||
[Fetch] "fetch",
|
[Fetch] "fetch",
|
||||||
[Cap] "capability",
|
[Cap] "capability",
|
||||||
[Auth] "authenticate",
|
[Auth] "authenticate",
|
||||||
|
[Expunge] "expunge",
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -187,7 +204,7 @@ verbcode(char *verb)
|
||||||
|
|
||||||
if(q = strchr(verb, ' '))
|
if(q = strchr(verb, ' '))
|
||||||
*q = '\0';
|
*q = '\0';
|
||||||
for(i = 0; i < nelem(verblist) - 1; i++)
|
for(i = 0; i < nelem(verblist); i++)
|
||||||
if(strcmp(verblist[i], verb) == 0)
|
if(strcmp(verblist[i], verb) == 0)
|
||||||
break;
|
break;
|
||||||
if(q)
|
if(q)
|
||||||
|
@ -200,6 +217,7 @@ mkuid(Imap *i, char *id)
|
||||||
{
|
{
|
||||||
vlong v;
|
vlong v;
|
||||||
|
|
||||||
|
idprint(i, "mkuid: validity: %lud, idstr: '%s', val: %lud\n", i->validity, id, strtoul(id, 0, 10));
|
||||||
v = (vlong)i->validity<<32;
|
v = (vlong)i->validity<<32;
|
||||||
return v | strtoul(id, 0, 10);
|
return v | strtoul(id, 0, 10);
|
||||||
}
|
}
|
||||||
|
@ -230,27 +248,30 @@ static struct{
|
||||||
"\\Stored", Fstored,
|
"\\Stored", Fstored,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static int
|
||||||
parseflags(Message *m, char *s)
|
parseflags(char *s)
|
||||||
{
|
{
|
||||||
char *f[10];
|
char *f[10];
|
||||||
int i, j, j0, n;
|
int i, j, j0, n, flg;
|
||||||
|
|
||||||
n = tokenize(s, f, nelem(f));
|
n = tokenize(s, f, nelem(f));
|
||||||
qsort(f, n, sizeof *f, (int (*)(void*,void*))strcmp);
|
qsort(f, n, sizeof *f, (int (*)(void*,void*))strcmp);
|
||||||
j = 0;
|
j = 0;
|
||||||
for(i = 0; i < n; i++)
|
flg = 0;
|
||||||
|
for(i = 0; i < n; i++){
|
||||||
for(j0 = j;; j++){
|
for(j0 = j;; j++){
|
||||||
if(j == nelem(ftab)){
|
if(j == nelem(ftab)){
|
||||||
j = j0; /* restart search */
|
j = j0; /* restart search */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(strcmp(f[i], ftab[j].flag) == 0){
|
if(cistrcmp(f[i], ftab[j].flag) == 0){
|
||||||
m->flags |= ftab[j].e;
|
flg |= ftab[j].e;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return flg;
|
||||||
|
}
|
||||||
|
|
||||||
/* "17-Jul-1996 02:44:25 -0700" */
|
/* "17-Jul-1996 02:44:25 -0700" */
|
||||||
long
|
long
|
||||||
|
@ -323,7 +344,7 @@ imaptokenize(char *s, char **args, int maxargs)
|
||||||
}
|
}
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
fetchrsp(Imap *imap, char *p, Mailbox *, Message *m)
|
fetchrsp(Imap *imap, char *p, Mailbox *, Message *m, int idx)
|
||||||
{
|
{
|
||||||
char *f[15], *s, *q;
|
char *f[15], *s, *q;
|
||||||
int i, n, a;
|
int i, n, a;
|
||||||
|
@ -332,6 +353,11 @@ fetchrsp(Imap *imap, char *p, Mailbox *, Message *m)
|
||||||
static char error[256];
|
static char error[256];
|
||||||
extern void msgrealloc(Message*, ulong);
|
extern void msgrealloc(Message*, ulong);
|
||||||
|
|
||||||
|
if(idx < 0 || idx >= imap->muid){
|
||||||
|
snprint(error, sizeof error, "fetchrsp: bad idx %d", idx);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
redux:
|
redux:
|
||||||
n = imaptokenize(p, f, nelem(f));
|
n = imaptokenize(p, f, nelem(f));
|
||||||
if(n%2)
|
if(n%2)
|
||||||
|
@ -341,23 +367,26 @@ redux:
|
||||||
l = internaltounix(f[i + 1]);
|
l = internaltounix(f[i + 1]);
|
||||||
if(l < 418319360)
|
if(l < 418319360)
|
||||||
abort();
|
abort();
|
||||||
if(imap->nuid < imap->muid)
|
if(idx < imap->muid)
|
||||||
imap->f[imap->nuid].dates = l;
|
imap->f[idx].dates = l;
|
||||||
}else if(strcmp(f[i], "rfc822.size") == 0){
|
}else if(strcmp(f[i], "rfc822.size") == 0){
|
||||||
l = strtoul(f[i + 1], 0, 0);
|
l = strtoul(f[i + 1], 0, 0);
|
||||||
if(m)
|
if(m)
|
||||||
m->size = l;
|
m->size = l;
|
||||||
else if(imap->nuid < imap->muid)
|
else if(idx < imap->muid)
|
||||||
imap->f[imap->nuid].sizes = l;
|
imap->f[idx].sizes = l;
|
||||||
}else if(strcmp(f[i], "uid") == 0){
|
}else if(strcmp(f[i], "uid") == 0){
|
||||||
v = mkuid(imap, f[1]);
|
v = mkuid(imap, f[i + 1]);
|
||||||
if(m)
|
if(m)
|
||||||
m->imapuid = v;
|
m->imapuid = v;
|
||||||
if(imap->nuid < imap->muid)
|
if(idx < imap->muid)
|
||||||
imap->f[imap->nuid].uid = v;
|
imap->f[idx].uid = v;
|
||||||
}else if(strcmp(f[i], "flags") == 0){
|
}else if(strcmp(f[i], "flags") == 0){
|
||||||
|
l = parseflags(f[i + 1]);
|
||||||
if(m)
|
if(m)
|
||||||
parseflags(m, f[i + 1]);
|
m->flags = l;
|
||||||
|
if(idx < imap->muid)
|
||||||
|
imap->f[idx].flags = l;
|
||||||
}else if(strncmp(f[i], "body[]", 6) == 0){
|
}else if(strncmp(f[i], "body[]", 6) == 0){
|
||||||
s = f[i]+6;
|
s = f[i]+6;
|
||||||
o = 0;
|
o = 0;
|
||||||
|
@ -396,7 +425,7 @@ redux:
|
||||||
}else
|
}else
|
||||||
return confused;
|
return confused;
|
||||||
}
|
}
|
||||||
return 0;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -428,7 +457,7 @@ static char*
|
||||||
imap4resp0(Imap *imap, Mailbox *mb, Message *m)
|
imap4resp0(Imap *imap, Mailbox *mb, Message *m)
|
||||||
{
|
{
|
||||||
char *e, *line, *p, *ep, *op, *q, *verb;
|
char *e, *line, *p, *ep, *op, *q, *verb;
|
||||||
int n, unexp;
|
int n, idx, unexp;
|
||||||
static char error[256];
|
static char error[256];
|
||||||
|
|
||||||
unexp = 0;
|
unexp = 0;
|
||||||
|
@ -484,7 +513,7 @@ imap4resp0(Imap *imap, Mailbox *mb, Message *m)
|
||||||
if(q = strstr(p, "messages"))
|
if(q = strstr(p, "messages"))
|
||||||
imap->nmsg = strtoul(q + 8, 0, 10);
|
imap->nmsg = strtoul(q + 8, 0, 10);
|
||||||
if(q = strstr(p, "uidvalidity"))
|
if(q = strstr(p, "uidvalidity"))
|
||||||
imap->validity = strtoul(q + 11, 0, 10);
|
imap->newvalidity = strtoul(q + 11, 0, 10);
|
||||||
break;
|
break;
|
||||||
case Fetch:
|
case Fetch:
|
||||||
if(*p == '('){
|
if(*p == '('){
|
||||||
|
@ -492,9 +521,20 @@ imap4resp0(Imap *imap, Mailbox *mb, Message *m)
|
||||||
if(ep[-1] == ')')
|
if(ep[-1] == ')')
|
||||||
*--ep = 0;
|
*--ep = 0;
|
||||||
}
|
}
|
||||||
if(e = fetchrsp(imap, p, mb, m))
|
if(e = fetchrsp(imap, p, mb, m, n - 1))
|
||||||
eprint("imap: fetchrsp: %s\n", e);
|
eprint("imap: fetchrsp: %s\n", e);
|
||||||
imap->nuid++;
|
if(n > 0 && n <= imap->muid && n > imap->nuid)
|
||||||
|
imap->nuid = n;
|
||||||
|
break;
|
||||||
|
case Expunge:
|
||||||
|
if(n < 1 || n > imap->muid){
|
||||||
|
snprint(error, sizeof(error), "bad expunge %d (nmsg %d)", n, imap->nuid);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
idx = n - 1;
|
||||||
|
memmove(&imap->f[idx], &imap->f[idx + 1], (imap->nmsg - idx - 1)*sizeof(imap->f[0]));
|
||||||
|
imap->nmsg--;
|
||||||
|
imap->nuid--;
|
||||||
break;
|
break;
|
||||||
case Auth:
|
case Auth:
|
||||||
break;
|
break;
|
||||||
|
@ -903,15 +943,30 @@ imap4read(Imap *imap, Mailbox *mb)
|
||||||
Fetchi *f;
|
Fetchi *f;
|
||||||
Message *m, **ll;
|
Message *m, **ll;
|
||||||
|
|
||||||
|
again:
|
||||||
imap4cmd(imap, "status %Z (messages uidvalidity)", imap->mbox);
|
imap4cmd(imap, "status %Z (messages uidvalidity)", imap->mbox);
|
||||||
if(!isokay(s = imap4resp(imap)))
|
if(!isokay(s = imap4resp(imap)))
|
||||||
return s;
|
return s;
|
||||||
|
/* the world shifted: start over */
|
||||||
|
if(imap->validity != imap->newvalidity){
|
||||||
|
imap->validity = imap->newvalidity;
|
||||||
imap->nuid = 0;
|
imap->nuid = 0;
|
||||||
imap->muid = imap->nmsg;
|
imap->muid = 0;
|
||||||
|
imap->nmsg = 0;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
imap->f = erealloc(imap->f, imap->nmsg*sizeof imap->f[0]);
|
imap->f = erealloc(imap->f, imap->nmsg*sizeof imap->f[0]);
|
||||||
|
if(imap->nmsg > imap->muid)
|
||||||
|
memset(&imap->f[imap->muid], 0, (imap->nmsg - imap->muid)*sizeof(imap->f[0]));
|
||||||
|
imap->muid = imap->nmsg;
|
||||||
if(imap->nmsg > 0){
|
if(imap->nmsg > 0){
|
||||||
imap4cmd(imap, "uid fetch 1:* (uid rfc822.size internaldate)");
|
n = imap->nuid;
|
||||||
|
if(n == 0)
|
||||||
|
n = 1;
|
||||||
|
if(n > imap->nmsg)
|
||||||
|
n = imap->nmsg;
|
||||||
|
imap4cmd(imap, "fetch %d:%d (uid flags rfc822.size internaldate)", n, imap->nmsg);
|
||||||
if(!isokay(s = imap4resp(imap)))
|
if(!isokay(s = imap4resp(imap)))
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -949,6 +1004,7 @@ imap4read(Imap *imap, Mailbox *mb)
|
||||||
m->imapuid = f[i].uid;
|
m->imapuid = f[i].uid;
|
||||||
m->fileid = datesec(imap, i);
|
m->fileid = datesec(imap, i);
|
||||||
m->size = f[i].sizes;
|
m->size = f[i].sizes;
|
||||||
|
m->flags = f[i].flags;
|
||||||
m->next = *ll;
|
m->next = *ll;
|
||||||
*ll = m;
|
*ll = m;
|
||||||
ll = &m->next;
|
ll = &m->next;
|
||||||
|
@ -960,6 +1016,8 @@ imap4read(Imap *imap, Mailbox *mb)
|
||||||
m->deleted = Disappear;
|
m->deleted = Disappear;
|
||||||
ll = &m->next;
|
ll = &m->next;
|
||||||
}else{
|
}else{
|
||||||
|
/* TODO: flag this as changed, plumb. */
|
||||||
|
m->flags = f[i].flags;
|
||||||
ll = &m->next;
|
ll = &m->next;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue