CVS commit by ossi: 

major overhaul of flag change propagation and MaxMessages handling:
- wrap message (un)expirations into transactions
- no redundand flag propagations in conjunction with expirations
- better prepared for the upcoming async operation


  M +0 -1      isync.h   1.52
  M +139 -95   sync.c   1.69


--- isync/src/isync.h  #1.51:1.52
@@ -119,5 +119,4 @@ typedef struct group_conf {
 #define M_DEAD         (1<<1) /* expunged */
 #define M_FLAGS        (1<<2) /* flags fetched */
-#define M_EXPIRE       (1<<3) /* kicked out by MaxMessages */
 
 typedef struct message {

--- isync/src/sync.c  #1.68:1.69
@@ -80,8 +80,12 @@ make_flags( int flags, char *buf )
 
 #define S_DEAD         (1<<0)
-#define S_EXPIRED      (1<<1)
+#define S_DONE         (1<<1)
 #define S_DEL(ms)      (1<<(2+(ms)))
-#define S_EXP_S        (1<<4)
-#define S_DONE         (1<<6)
+#define S_EXPIRED      (1<<4)
+#define S_EXPIRE       (1<<5)
+#define S_NEXPIRE      (1<<6)
+#define S_EXP_S        (1<<7)
+
+#define mvBit(in,ib,ob) ((unsigned char)(((unsigned)in) * (ob) / (ib)))
 
 typedef struct sync_rec {
@@ -90,5 +94,5 @@ typedef struct sync_rec {
        int uid[2];
        message_t *msg[2];
-       unsigned char flags, status;
+       unsigned char status, flags, aflags[2], dflags[2];
 } sync_rec_t;
 
@@ -187,9 +191,9 @@ sync_boxes( store_t *ctx[], const char *
        FILE *dfp, *jfp, *nfp;
        int opts[2];
-       int nom, nos, del[2], ex[2];
+       int nom, nos, del[2], ex[2], nex;
        int muidval, suidval, smaxxuid, maxuid[2], minwuid, maxwuid;
        int t1, t2, t3, t, uid, nmsgs;
-       int lfd, ret, line, sline, todel, delt, *mexcs, nmexcs, rmexcs;
-       unsigned char nflags;
+       int lfd, ret, line, sline, todel, *mexcs, nmexcs, rmexcs;
+       unsigned char nflags, sflags, aflags, dflags;
        msg_data_t msgdata;
        struct stat st;
@@ -292,5 +296,5 @@ sync_boxes( store_t *ctx[], const char *
                        if (*s == 'X') {
                                s++;
-                               srec->status = S_EXPIRED;
+                               srec->status = S_EXPIRE | S_EXPIRED;
                        } else
                                srec->status = 0;
@@ -338,5 +342,5 @@ sync_boxes( store_t *ctx[], const char *
                                if (buf[0] == '(' || buf[0] == ')' ?
                                        (sscanf( buf + 2, "%d", &t1 ) != 1) :
-                                   buf[0] == '-' || buf[0] == '|' ?
+                                   buf[0] == '-' || buf[0] == '|' || buf[0] == 
'/' || buf[0] == '\\' ?
                                        (sscanf( buf + 2, "%d %d", &t1, &t2 ) 
!= 2) :
                                        (sscanf( buf + 2, "%d %d %d", &t1, &t2, 
&t3 ) != 3))
@@ -396,8 +400,24 @@ sync_boxes( store_t *ctx[], const char *
                                                break;
                                        case '~':
-                                               debug( "expired now %d\n", t3 );
+                                               debug( "expire now %d\n", t3 );
+                                               if (t3)
+                                                       srec->status |= 
S_EXPIRE;
+                                               else
+                                                       srec->status &= 
~S_EXPIRE;
+                                               break;
+                                       case '\\':
+                                               t3 = (srec->status & S_EXPIRED);
+                                               debug( "expire back to %d\n", 
t3 / S_EXPIRED );
+                                               if (t3)
+                                                       srec->status |= 
S_EXPIRE;
+                                               else
+                                                       srec->status &= 
~S_EXPIRE;
+                                               break;
+                                       case '/':
+                                               t3 = (srec->status & S_EXPIRE);
+                                               debug( "expired now %d\n", t3 / 
S_EXPIRE );
                                                if (t3) {
-                                                       if (smaxxuid < t2)
-                                                               smaxxuid = t2;
+                                                       if (smaxxuid < 
srec->uid[S])
+                                                               smaxxuid = 
srec->uid[S];
                                                        srec->status |= 
S_EXPIRED;
                                                } else
@@ -456,4 +476,10 @@ sync_boxes( store_t *ctx[], const char *
        if ((chan->ops[S] & (OP_NEW|OP_RENEW)) && chan->max_messages)
                opts[S] |= OPEN_OLD|OPEN_NEW|OPEN_FLAGS;
+       if (line)
+               for (srec = recs; srec; srec = srec->next)
+                       if (!(srec->status & S_DEAD) && ((mvBit(srec->status, 
S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED)) {
+                               opts[S] |= OPEN_OLD|OPEN_FLAGS;
+                               break;
+                       }
        driver[M]->prepare_opts( ctx[M], opts[M] );
        driver[S]->prepare_opts( ctx[S], opts[S] );
@@ -679,14 +705,9 @@ sync_boxes( store_t *ctx[], const char *
                        del[M] = nom && (srec->uid[M] > 0);
                        del[S] = nos && (srec->uid[S] > 0);
-                       if (srec->msg[M] && (srec->msg[M]->flags & F_DELETED))
-                               srec->status |= S_DEL(M);
-                       if (srec->msg[S] && (srec->msg[S]->flags & F_DELETED))
-                               srec->status |= S_DEL(S);
-                       nflags = srec->flags;
 
                        for (t = 0; t < 2; t++) {
-                               int unex;
-                               unsigned char sflags, aflags, dflags;
-
+                               srec->aflags[t] = srec->dflags[t] = 0;
+                               if (srec->msg[t] && (srec->msg[t]->flags & 
F_DELETED))
+                                       srec->status |= S_DEL(t);
                                /* excludes (push) c.3) d.2) d.3) d.4) / (pull) 
b.3) d.7) d.8) d.9) */
                                if (!srec->uid[t]) {
@@ -695,5 +716,5 @@ sync_boxes( store_t *ctx[], const char *
                                } else if (del[1-t]) {
                                        /* c.4) d.9) / b.4) d.4) */
-                                       if (srec->msg[t] && srec->msg[t]->flags 
!= nflags)
+                                       if (srec->msg[t] && 
(srec->msg[t]->status & M_FLAGS) && srec->msg[t]->flags != srec->flags)
                                                info( "Info: conflicting 
changes in (%d,%d)\n", srec->uid[M], srec->uid[S] );
                                        if (chan->ops[t] & OP_DELETE) {
@@ -720,99 +741,122 @@ sync_boxes( store_t *ctx[], const char *
                                        if (chan->ops[t] & OP_FLAGS) {
                                                sflags = srec->msg[1-t]->flags;
-                                               aflags = sflags & ~nflags;
-                                               dflags = ~sflags & nflags;
-                                               unex = 0;
-                                               if (srec->status & S_EXPIRED) {
-                                                       if (!t) {
-                                                               if ((aflags & 
~F_DELETED) || dflags)
-                                                                       info( 
"Info: Flags of expired message changed in (%d,%d)\n", srec->uid[M], 
srec->uid[S] );
-                                                               continue;
-                                                       } else {
-                                                               if ((sflags & 
F_FLAGGED) && !(sflags & F_DELETED)) {
-                                                                       unex = 
1;
-                                                                       dflags 
|= F_DELETED;
-                                                               } else
-                                                                       
continue;
-                                                       }
-                                               }
-                                               if ((chan->ops[t] & OP_EXPUNGE) 
&& (sflags & F_DELETED) &&
-                                                   (!ctx[t]->conf->trash || 
ctx[t]->conf->trash_only_new))
-                                               {
-                                                       aflags &= F_DELETED;
-                                                       dflags = 0;
-                                               }
+                                               if ((srec->status & 
(S_EXPIRE|S_EXPIRED)) && !t)
+                                                       sflags &= ~F_DELETED;
+                                               srec->aflags[t] = sflags & 
~srec->flags;
+                                               srec->dflags[t] = ~sflags & 
srec->flags;
                                                if (DFlags & DEBUG) {
                                                        char afbuf[16], 
dfbuf[16]; /* enlarge when support for keywords is added */
-                                                       make_flags( aflags, 
afbuf );
-                                                       make_flags( dflags, 
dfbuf );
+                                                       make_flags( 
srec->aflags[t], afbuf );
+                                                       make_flags( 
srec->dflags[t], dfbuf );
                                                        debug( "  %sing flags: 
+%s -%s\n", str_hl[t], afbuf, dfbuf );
                                                }
-                                               switch ((aflags | dflags) ? 
driver[t]->set_flags( ctx[t], srec->msg[t], srec->uid[t], aflags, dflags ) : 
DRV_OK) {
-                                               case DRV_STORE_BAD: ret = 
SYNC_BAD(t); goto finish;
-                                               case DRV_BOX_BAD: ret = 
SYNC_FAIL; goto finish;
-                                               default: /* ok */ break;
-                                               case DRV_OK:
-                                                       if (aflags & F_DELETED)
-                                                               srec->status |= 
S_DEL(t);
-                                                       else if (dflags & 
F_DELETED)
-                                                               srec->status &= 
~S_DEL(t);
-                                                       nflags = (nflags | 
aflags) & ~dflags;
-                                                       if (unex) {
-                                                               debug( 
"unexpiring pair(%d,%d)\n", srec->uid[M], srec->uid[S] );
-                                                               /* log last, so 
deletion can't be misinterpreted! */
-                                                               Fprintf( jfp, 
"~ %d %d 0\n", srec->uid[M], srec->uid[S] );
-                                                               srec->status &= 
~S_EXPIRED;
-                                                       }
-                                               }
                                        } else
                                                debug( "  not %sing flags\n", 
str_hl[t] );
                                } /* else b.4) / c.4) */
                        }
-
-                       if (srec->flags != nflags) {
-                               debug( "  updating flags (%u -> %u)\n", 
srec->flags, nflags );
-                               srec->flags = nflags;
-                               Fprintf( jfp, "* %d %d %u\n", srec->uid[M], 
srec->uid[S], nflags );
-                       }
                }
        }
 
-       if ((chan->ops[S] & (OP_NEW|OP_RENEW)) && chan->max_messages) {
-               debug( "expiring excess entries\n" );
+       if ((chan->ops[S] & (OP_NEW|OP_RENEW|OP_FLAGS)) && chan->max_messages) {
+               /* Flagged and not yet synced messages older than the first not
+                * expired message are not counted. */
                todel = ctx[S]->count - chan->max_messages;
+               debug( "scheduling %d excess messages for expiration\n", todel 
);
                for (tmsg = ctx[S]->msgs; tmsg && todel > 0; tmsg = tmsg->next)
-                       if (!(tmsg->status & M_DEAD) && (tmsg->flags & 
F_DELETED))
+                       if (!(tmsg->status & M_DEAD) && (srec = tmsg->srec) &&
+                           ((tmsg->flags | srec->aflags[S]) & ~srec->dflags[S] 
& F_DELETED) &&
+                           !(srec->status & (S_EXPIRE|S_EXPIRED)))
                                todel--;
-               delt = 0;
-               for (tmsg = ctx[S]->msgs; tmsg && todel > 0; tmsg = tmsg->next) 
{
-                       if ((tmsg->status & M_DEAD) || (tmsg->flags & 
F_DELETED))
+               debug( "%d non-deleted excess messages\n", todel );
+               for (tmsg = ctx[S]->msgs; tmsg; tmsg = tmsg->next) {
+                       if (tmsg->status & M_DEAD)
                                continue;
-                       if ((tmsg->flags & F_FLAGGED) || !tmsg->srec || 
tmsg->srec->uid[M] <= 0) /* add M_DESYNCED? */
+                       if (!(srec = tmsg->srec) || srec->uid[M] <= 0)
                                todel--;
-                       else if (!(tmsg->status & M_RECENT)) {
-                               tmsg->status |= M_EXPIRE;
-                               delt++;
+                       else {
+                               nflags = (tmsg->flags | srec->aflags[S]) & 
~srec->dflags[S];
+                               if (!(nflags & F_DELETED) || (srec->status & 
(S_EXPIRE|S_EXPIRED))) {
+                                       if (nflags & F_FLAGGED)
+                                               todel--;
+                                       else if (!(tmsg->status & M_RECENT) &&
+                                                (todel > 0 ||
+                                                 ((srec->status & 
(S_EXPIRE|S_EXPIRED)) == (S_EXPIRE|S_EXPIRED)) ||
+                                                 ((srec->status & 
(S_EXPIRE|S_EXPIRED)) && (tmsg->flags & F_DELETED)))) {
+                                               srec->status |= S_NEXPIRE;
+                                               debug( "  pair(%d,%d)\n", 
srec->uid[M], srec->uid[S] );
                                todel--;
                        }
                }
-               if (delt) {
+                       }
+               }
+               debug( "%d excess messages remain\n", todel );
                        for (srec = recs; srec; srec = srec->next) {
-                               if (srec->status & (S_DEAD|S_EXPIRED))
+                       if ((srec->status & (S_DEAD|S_DONE)) || !srec->msg[S])
                                        continue;
-                               if (srec->msg[S] && (srec->msg[S]->status & 
M_EXPIRE)) {
-                                       debug( "  expiring pair(%d,%d)\n", 
srec->uid[M], srec->uid[S] );
-                                       /* log first, so deletion can't be 
misinterpreted! */
-                                       Fprintf( jfp, "~ %d %d 1\n", 
srec->uid[M], srec->uid[S] );
-                                       if (smaxxuid < srec->uid[S])
-                                               smaxxuid = srec->uid[S];
-                                       srec->status |= S_EXPIRED;
-                                       switch (driver[S]->set_flags( ctx[S], 
srec->msg[S], 0, F_DELETED, 0 )) {
-                                       case DRV_STORE_BAD: ret = SYNC_BAD(S); 
goto finish;
+                       nex = (srec->status / S_NEXPIRE) & 1;
+                       if (nex != ((srec->status / S_EXPIRED) & 1)) {
+                               if (nex != ((srec->status / S_EXPIRE) & 1)) {
+                                       Fprintf( jfp, "~ %d %d %d\n", 
srec->uid[M], srec->uid[S], nex );
+                                       debug( "  pair(%d,%d): %d (pre)\n", 
srec->uid[M], srec->uid[S], nex );
+                                       srec->status = (srec->status & 
~S_EXPIRE) | (nex * S_EXPIRE);
+                               } else
+                                       debug( "  pair(%d,%d): %d (pending)\n", 
srec->uid[M], srec->uid[S], nex );
+                       }
+               }
+       }
+       debug( "synchronizing flags\n" );
+       for (srec = recs; srec != *osrecadd; srec = srec->next) {
+               if (srec->status & (S_DEAD|S_DONE))
+                       continue;
+               for (t = 0; t < 2; t++) {
+                       aflags = srec->aflags[t];
+                       dflags = srec->dflags[t];
+                       if (t && ((mvBit(srec->status, S_EXPIRE, S_EXPIRED) ^ 
srec->status) & S_EXPIRED)) {
+                               if (srec->status & S_NEXPIRE)
+                                       aflags |= F_DELETED;
+                               else
+                                       dflags |= F_DELETED;
+                       }
+                       if ((chan->ops[t] & OP_EXPUNGE) && (((srec->msg[t] ? 
srec->msg[t]->flags : 0) | aflags) & ~dflags & F_DELETED) &&
+                           (!ctx[t]->conf->trash || 
ctx[t]->conf->trash_only_new))
+                       {
+                               srec->aflags[t] &= F_DELETED;
+                               aflags &= F_DELETED;
+                               srec->dflags[t] = dflags = 0;
+                       }
+                       if (srec->msg[t] && (srec->msg[t]->status & M_FLAGS)) {
+                               aflags &= ~srec->msg[t]->flags;
+                               dflags &= srec->msg[t]->flags;
+                       }
+                       switch ((aflags | dflags) ? driver[t]->set_flags( 
ctx[t], srec->msg[t], srec->uid[t], aflags, dflags ) : DRV_OK) {
+                       case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
                                        case DRV_BOX_BAD: ret = SYNC_FAIL; goto 
finish;
-                                       default: /* ok */ break;
-                                       case DRV_OK: srec->status |= S_DEL(S);
+                       default: /* ok */ srec->aflags[t] = srec->dflags[t] = 
0; break;
+                       case DRV_OK:
+                               if (aflags & F_DELETED)
+                                       srec->status |= S_DEL(t);
+                               else if (dflags & F_DELETED)
+                                       srec->status &= ~S_DEL(t);
+                               if (t) {
+                                       nex = (srec->status / S_NEXPIRE) & 1;
+                                       if (nex != ((srec->status / S_EXPIRED) 
& 1)) {
+                                               if (nex && (smaxxuid < 
srec->uid[S]))
+                                                       smaxxuid = srec->uid[S];
+                                               Fprintf( jfp, "/ %d %d\n", 
srec->uid[M], srec->uid[S] );
+                                               debug( "  pair(%d,%d): expired 
%d (commit)\n", srec->uid[M], srec->uid[S], nex );
+                                               srec->status = (srec->status & 
~S_EXPIRED) | (nex * S_EXPIRED);
+                                       } else if (nex != ((srec->status / 
S_EXPIRE) & 1)) {
+                                               Fprintf( jfp, "\\ %d %d\n", 
srec->uid[M], srec->uid[S] );
+                                               debug( "  pair(%d,%d): expire 
%d (cancel)\n", srec->uid[M], srec->uid[S], nex );
+                                               srec->status = (srec->status & 
~S_EXPIRE) | (nex * S_EXPIRE);
+                                       }
                                        }
                                }
                        }
+               nflags = (srec->flags | srec->aflags[M] | srec->aflags[S]) & 
~(srec->dflags[M] | srec->dflags[S]);
+               if (srec->flags != nflags) {
+                       debug( "  pair(%d,%d): updating flags (%u -> %u)\n", 
srec->uid[M], srec->uid[S], srec->flags, nflags );
+                       srec->flags = nflags;
+                       Fprintf( jfp, "* %d %d %u\n", srec->uid[M], 
srec->uid[S], nflags );
                }
        }




-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=103432&bid=230486&dat=121642
_______________________________________________
isync-devel mailing list
isync-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to