shithub: plan9front

Download patch

ref: 9162533526a8e92a3b111ef2e63f87ae23ad8134
parent: bb94fc197ea706fc302824b91d82a2d3afb08217
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Mar 10 19: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	Sun Mar  7 14:29:55 2021
+++ b/sys/src/cmd/upas/Mail/mail.h	Wed Mar 10 19:49:17 2021
@@ -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	Sun Mar  7 14:29:55 2021
+++ b/sys/src/cmd/upas/Mail/mbox.c	Wed Mar 10 19:49:17 2021
@@ -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,38 +679,43 @@
 	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");
 }