code: plan9front

Download patch

ref: 9162533526a8e92a3b111ef2e63f87ae23ad8134
parent: bb94fc197ea706fc302824b91d82a2d3afb08217
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Mar 10 11:49:17 EST 2021

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.

--- a/sys/src/cmd/upas/Mail/mail.h
+++ b/sys/src/cmd/upas/Mail/mail.h
@@ -15,6 +15,7 @@
 	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 {
--- a/sys/src/cmd/upas/Mail/mbox.c
+++ b/sys/src/cmd/upas/Mail/mbox.c
@@ -144,7 +144,7 @@
 				break;
 			o += p->child[i]->nsub + 1;
 		}
-		if(!(p->state & Sdummy)){
+		if(!(p->state & (Sdummy|Szap))){
 			o++;
 			d++;
 		}
@@ -157,7 +157,7 @@
 			break;
 		if(m->state & Stoplev){
 			n += mbox.mesg[i]->nsub;
-			if(!(m->state & Sdummy))
+			if(!(m->state & (Sdummy|Szap)))
 				n++;
 		}
 
@@ -679,18 +679,17 @@
 	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);
@@ -697,20 +696,26 @@
 		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");
 }