Mail: separate deletion from relinking messages

Mutating lists that are being iterated is needlessly error
prone, and we were removing the wrong message in some cases
if it the dummy got inserted in the right place.

Separating deletion into a redraw/relink and zap phase
simplifies the problem.
This commit is contained in:
Ori Bernstein 2021-03-10 16:49:17 -08:00
parent bb94fc197e
commit 9162533526
2 changed files with 17 additions and 11 deletions

View file

@ -15,6 +15,7 @@ enum {
Sdummy = 1<<0, /* message placeholder */
Stoplev = 1<<1, /* not a response to anything */
Sopen = 1<<2, /* opened for viewing */
Szap = 1<<3, /* flushed, to be removed from list */
};
enum {

View file

@ -144,7 +144,7 @@ mesglineno(Mesg *msg, int *depth)
break;
o += p->child[i]->nsub + 1;
}
if(!(p->state & Sdummy)){
if(!(p->state & (Sdummy|Szap))){
o++;
d++;
}
@ -157,7 +157,7 @@ mesglineno(Mesg *msg, int *depth)
break;
if(m->state & Stoplev){
n += mbox.mesg[i]->nsub;
if(!(m->state & Sdummy))
if(!(m->state & (Sdummy|Szap)))
n++;
}
@ -679,38 +679,43 @@ mbflush(char **, int)
char *path;
Mesg *m, *p;
i = 0;
path = estrjoin(maildir, "/ctl", nil);
fd = open(path, OWRITE);
free(path);
if(fd == -1)
sysfatal("open mbox: %r");
while(i < mbox.nmesg){
for(i = 0; i < mbox.nmesg; i++){
m = mbox.mesg[i];
if((m->state & Sopen) || !(m->flags & (Fdel|Ftodel))){
i++;
p = m->parent;
if(m->state & (Sopen|Szap) || (m->flags & (Fdel|Ftodel)) == 0)
continue;
}
ln = mesglineno(m, nil);
fprint(mbox.addr, "%d,%d", ln, ln+m->nsub);
write(mbox.data, "", 0);
if(m->flags & Ftodel)
fprint(fd, "delete %s %d", mailbox, atoi(m->name));
p = m->parent;
removeid(m);
m->state |= Szap;
if(p == nil && m->nsub != 0){
p = placeholder(m->messageid, m->time, 1);
p->nsub = m->nsub + 1;
mbox.mesg[i] = p;
}
if(p != nil)
relinkmsg(p, m);
for(j = 0; j < m->nchild; j++)
mbredraw(m->child[j], 1, 1);
memmove(&mbox.mesg[i], &mbox.mesg[i+1], (mbox.nmesg - i)*sizeof(Mesg*));
mbox.nmesg--;
}
for(i = 0, j = 0; i < mbox.nmesg; i++){
m = mbox.mesg[i];
if((m->state & Szap) != 0)
mesgfree(m);
else
mbox.mesg[j++] = m;
}
close(fd);
fprint(mbox.ctl, "clean\n");
}