git: 9front

Download patch

ref: a4ab99da40e0e86aa61d145e038066e8210c27a9
parent: 1498545efb7f8cbaf6cf076a5988ef51d6f089ac
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");
 }
--