CVS commit by ossi: 

wrap message storing into transactions. nice side effect: drivers don't
need to deal with line end conversion any move.


  M +0 -7      TODO   1.20
  M +30 -85    src/drv_imap.c   1.15
  M +39 -8     src/drv_maildir.c   1.10
  M +12 -4     src/isync.h   1.53
  M +268 -58   src/sync.c   1.70
  M +0 -14     src/util.c   1.6


--- isync/TODO  #1.19:1.20
@@ -12,11 +12,4 @@
 add a way to automatically create and sync subfolders.
 
-could store TUID even when UIDPLUS is supported. would avoid duplicated
-messages after abort before new UID arrives.
-
-decouple TUID search from append. that's a prerequisite for usable
-MULTIAPPEND, and is generally good for async. should be way faster, too,
-as it saves repeated mailbox rescans with single-file formats.
-
 use MULTIAPPEND and FETCH with multiple messages.
 

--- isync/src/drv_imap.c  #1.14:1.15
@@ -759,5 +759,5 @@ parse_fetch( imap_t *imap, char *cmd ) /
                                        size = atoi( tmp->val );
                                else
-                                       fprintf( stderr, "IMAP error: unable to 
parse SIZE\n" );
+                                       fprintf( stderr, "IMAP error: unable to 
parse RFC822.SIZE\n" );
                        } else if (!strcmp( "BODY[]", tmp->val )) {
                                tmp = tmp->next;
@@ -783,5 +783,4 @@ parse_fetch( imap_t *imap, char *cmd ) /
                msgdata->data = body;
                msgdata->len = size;
-               msgdata->crlf = 1;
                if (status & M_FLAGS)
                        msgdata->flags = mask;
@@ -867,8 +866,12 @@ parse_search( imap_t *imap, char *cmd )
        int uid;
 
-       arg = next_arg( &cmd );
-       if (!arg || !(uid = atoi( arg ))) {
+       if (!(arg = next_arg( &cmd )))
+               uid = -1;
+       else if (!(uid = atoi( arg ))) {
                fprintf( stderr, "IMAP error: malformed SEARCH response\n" );
                return;
+       } else if (next_arg( &cmd )) {
+               warn( "IMAP warning: SEARCH returns multiple matches\n" );
+               uid = -1; /* to avoid havoc */
        }
 
@@ -1547,6 +1550,4 @@ imap_trash_msg( store_t *gctx, message_t
 }
 
-#define TUIDL 8
-
 static int
 imap_store_msg( store_t *gctx, msg_data_t *data, int *uid )
@@ -1555,79 +1556,7 @@ imap_store_msg( store_t *gctx, msg_data_
        imap_t *imap = ctx->imap;
        struct imap_cmd_cb cb;
-       char *fmap, *buf;
        const char *prefix, *box;
-       int ret, i, j, d, len, extra, nocr;
-       int start, sbreak = 0, ebreak = 0;
-       char flagstr[128], tuid[TUIDL * 2 + 1];
-
-       memset( &cb, 0, sizeof(cb) );
-
-       fmap = data->data;
-       len = data->len;
-       nocr = !data->crlf;
-       extra = 0, i = 0;
-       if (!CAP(UIDPLUS) && uid) {
-         nloop:
-               start = i;
-               while (i < len)
-                       if (fmap[i++] == '\n') {
-                               extra += nocr;
-                               if (i - 2 + nocr == start) {
-                                       sbreak = ebreak = i - 2 + nocr;
-                                       goto mktid;
-                               }
-                               if (!memcmp( fmap + start, "X-TUID: ", 8 )) {
-                                       extra -= (ebreak = i) - (sbreak = 
start) + nocr;
-                                       goto mktid;
-                               }
-                               goto nloop;
-                       }
-               /* invalid message */
-               free( fmap );
-               return DRV_MSG_BAD;
-        mktid:
-               for (j = 0; j < TUIDL; j++)
-                       sprintf( tuid + j * 2, "%02x", arc4_getbyte() );
-               extra += 8 + TUIDL * 2 + 2;
-       }
-       if (nocr)
-               for (; i < len; i++)
-                       if (fmap[i] == '\n')
-                               extra++;
-
-       cb.dlen = len + extra;
-       buf = cb.data = nfmalloc( cb.dlen );
-       i = 0;
-       if (!CAP(UIDPLUS) && uid) {
-               if (nocr) {
-                       for (; i < sbreak; i++)
-                               if (fmap[i] == '\n') {
-                                       *buf++ = '\r';
-                                       *buf++ = '\n';
-                               } else
-                                       *buf++ = fmap[i];
-               } else {
-                       memcpy( buf, fmap, sbreak );
-                       buf += sbreak;
-               }
-               memcpy( buf, "X-TUID: ", 8 );
-               buf += 8;
-               memcpy( buf, tuid, TUIDL * 2 );
-               buf += TUIDL * 2;
-               *buf++ = '\r';
-               *buf++ = '\n';
-               i = ebreak;
-       }
-       if (nocr) {
-               for (; i < len; i++)
-                       if (fmap[i] == '\n') {
-                               *buf++ = '\r';
-                               *buf++ = '\n';
-                       } else
-                               *buf++ = fmap[i];
-       } else
-               memcpy( buf, fmap + i, len - i );
-
-       free( fmap );
+       int ret, d;
+       char flagstr[128];
 
        d = 0;
@@ -1638,4 +1567,7 @@ imap_store_msg( store_t *gctx, msg_data_
        flagstr[d] = 0;
 
+       memset( &cb, 0, sizeof(cb) );
+       cb.dlen = data->len;
+       cb.data = data->data;
        if (!uid) {
                box = gctx->conf->trash;
@@ -1650,4 +1582,5 @@ imap_store_msg( store_t *gctx, msg_data_
                /*if (ctx->currentnc)
                        imap->caps = imap->rcaps & ~(1 << LITERALPLUS);*/
+               *uid = -2;
        }
        cb.ctx = uid;
@@ -1663,11 +1596,21 @@ imap_store_msg( store_t *gctx, msg_data_
        }
 
-       if (CAP(UIDPLUS) || !uid)
                return DRV_OK;
+}
 
-       /* Didn't receive an APPENDUID */
+static int
+imap_find_msg( store_t *gctx, const char *tuid, int *uid )
+{
+       imap_store_t *ctx = (imap_store_t *)gctx;
+       struct imap_cmd_cb cb;
+       int ret;
+
+       memset( &cb, 0, sizeof(cb) );
+       cb.ctx = uid;
        cb.uid = -1; /* we're looking for a UID */
-       cb.data = 0; /* reset; ctx still set */
-       return imap_exec_m( ctx, &cb, "UID SEARCH HEADER X-TUID %s", tuid );
+       *uid = -1; /* in case we get no SEARCH response at all */
+       if ((ret = imap_exec_m( ctx, &cb, "UID SEARCH HEADER X-TUID %." 
stringify(TUIDL) "s", tuid )) != DRV_OK)
+               return ret;
+       return *uid < 0 ? DRV_MSG_BAD : DRV_OK;
 }
 
@@ -1814,4 +1757,5 @@ imap_parse_store( conffile_t *cfg, store
 
 struct driver imap_driver = {
+       DRV_CRLF,
        imap_parse_store,
        imap_open_store,
@@ -1823,4 +1767,5 @@ struct driver imap_driver = {
        imap_fetch_msg,
        imap_store_msg,
+       imap_find_msg,
        imap_set_flags,
        imap_trash_msg,

--- isync/src/drv_maildir.c  #1.9:1.10
@@ -58,4 +58,5 @@ typedef struct maildir_message {
        message_t gen;
        char *base;
+       char tuid[TUIDL];
 } maildir_message_t;
 
@@ -183,4 +184,5 @@ typedef struct {
        int size;
        unsigned uid:31, recent:1;
+       char tuid[TUIDL];
 } msg_t;
 
@@ -469,4 +471,5 @@ maildir_scan( maildir_store_t *ctx, msgl
 {
        DIR *d;
+       FILE *f;
        struct dirent *e;
        const char *u, *ru;
@@ -571,4 +574,5 @@ maildir_scan( maildir_store_t *ctx, msgl
                                        entry->recent = i;
                                        entry->size = 0;
+                                       entry->tuid[0] = 0;
                                }
                        }
@@ -616,5 +620,5 @@ maildir_scan( maildir_store_t *ctx, msgl
                                }
                                uid = entry->uid;
-                               if (ctx->gen.opts & OPEN_SIZE)
+                               if (ctx->gen.opts & (OPEN_SIZE|OPEN_FIND))
                                        nfsnprintf( buf + bl, sizeof(buf) - bl, 
"%s/%s", subdirs[entry->recent], entry->base );
 #ifdef USE_DB
@@ -625,5 +629,5 @@ maildir_scan( maildir_store_t *ctx, msgl
                                }
                                entry->uid = uid;
-                               if (ctx->gen.opts & OPEN_SIZE)
+                               if (ctx->gen.opts & (OPEN_SIZE|OPEN_FIND))
                                        nfsnprintf( buf + bl, sizeof(buf) - bl, 
"%s/%s", subdirs[entry->recent], entry->base );
 #endif /* USE_DB */
@@ -646,4 +650,5 @@ maildir_scan( maildir_store_t *ctx, msgl
                                nfsnprintf( nbuf + bl + 4, sizeof(nbuf) - bl - 
4, "%s", entry->base );
                                if (rename( nbuf, buf )) {
+                                 notok:
                                        if (errno != ENOENT) {
                                                perror( buf );
@@ -660,10 +665,21 @@ maildir_scan( maildir_store_t *ctx, msgl
                        }
                        if (ctx->gen.opts & OPEN_SIZE) {
-                               if (stat( buf, &st )) {
-                                       maildir_free_scan( msglist );
-                                       goto again;
-                               }
+                               if (stat( buf, &st ))
+                                       goto notok;
                                entry->size = st.st_size;
                        }
+                       if (ctx->gen.opts & OPEN_FIND) {
+                               if (!(f = fopen( buf, "r" )))
+                                       goto notok;
+                               while (fgets( nbuf, sizeof(nbuf), f )) {
+                                       if (!nbuf[0] || nbuf[0] == '\n')
+                                               break;
+                                       if (!memcmp( nbuf, "X-TUID: ", 8 ) && 
nbuf[8 + TUIDL] == '\n') {
+                                               memcpy( entry->tuid, nbuf + 8, 
TUIDL );
+                                               break;
+                                       }
+                               }
+                               fclose( f );
+                       }
                }
                ctx->uvok = 1;
@@ -682,4 +698,5 @@ maildir_init_msg( maildir_store_t *ctx, 
        entry->base = 0; /* prevent deletion */
        msg->gen.size = entry->size;
+       strncpy( msg->tuid, entry->tuid, TUIDL );
        if (entry->recent)
                msg->gen.status |= M_RECENT;
@@ -903,5 +920,4 @@ maildir_fetch_msg( store_t *gctx, messag
        }
        fstat( fd, &st );
-       data->crlf = 0;
        data->len = st.st_size;
        data->data = nfmalloc( data->len );
@@ -982,5 +998,4 @@ maildir_store_msg( store_t *gctx, msg_da
                }
        }
-       strip_cr( data );
        ret = write( fd, data->data, data->len );
        free( data->data );
@@ -1005,4 +1020,18 @@ maildir_store_msg( store_t *gctx, msg_da
 
 static int
+maildir_find_msg( store_t *gctx, const char *tuid, int *uid )
+{
+       message_t *msg;
+
+       /* using a hash table might turn out to be more appropriate ... */
+       for (msg = gctx->msgs; msg; msg = msg->next)
+               if (!(msg->status & M_DEAD) && !memcmp( ((maildir_message_t 
*)msg)->tuid, tuid, TUIDL )) {
+                       *uid = msg->uid;
+                       return DRV_OK;
+               }
+       return DRV_MSG_BAD;
+}
+
+static int
 maildir_set_flags( store_t *gctx, message_t *gmsg, int uid, int add, int del )
 {
@@ -1190,4 +1219,5 @@ maildir_parse_store( conffile_t *cfg, st
 
 struct driver maildir_driver = {
+       0,
        maildir_parse_store,
        maildir_open_store,
@@ -1199,4 +1229,5 @@ struct driver maildir_driver = {
        maildir_fetch_msg,
        maildir_store_msg,
+       maildir_find_msg,
        maildir_set_flags,
        maildir_trash_msg,

--- isync/src/isync.h  #1.52:1.53
@@ -32,4 +32,7 @@
 #define as(ar) (sizeof(ar)/sizeof(ar[0]))
 
+#define __stringify(x) #x
+#define stringify(x) __stringify(x)
+
 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
 # define ATTR_UNUSED __attribute__((unused))
@@ -138,4 +141,5 @@ typedef struct message {
 #define OPEN_SETFLAGS   (1<<6)
 #define OPEN_APPEND     (1<<7)
+#define OPEN_FIND       (1<<8)
 
 typedef struct store {
@@ -147,5 +151,5 @@ typedef struct store {
        message_t *msgs; /* own */
        int uidvalidity;
-       unsigned char opts; /* maybe preset? */
+       unsigned opts; /* maybe preset? */
        /* note that the following do _not_ reflect stats from msgs, but 
mailbox totals */
        int count; /* # of messages */
@@ -157,5 +161,4 @@ typedef struct {
        int len;
        unsigned char flags;
-       unsigned char crlf:1;
 } msg_data_t;
 
@@ -165,5 +168,10 @@ typedef struct {
 #define DRV_STORE_BAD   -3
 
+#define DRV_CRLF        1
+
+#define TUIDL 12
+
 struct driver {
+       int flags;
        int (*parse_store)( conffile_t *cfg, store_conf_t **storep, int *err );
        store_t *(*open_store)( store_conf_t *conf, store_t *oldctx );
@@ -175,4 +183,5 @@ struct driver {
        int (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data );
        int (*store_msg)( store_t *ctx, msg_data_t *data, int *uid ); /* if uid 
is null, store to trash */
+       int (*find_msg)( store_t *ctx, const char *tuid, int *uid );
        int (*set_flags)( store_t *ctx, message_t *msg, int uid, int add, int 
del ); /* msg can be null, therefore uid as a fallback */
        int (*trash_msg)( store_t *ctx, message_t *msg ); /* This may expunge 
the original message immediately, but it needn't to */
@@ -211,6 +220,4 @@ void free_string_list( string_list_t *li
 void free_generic_messages( message_t * );
 
-void strip_cr( msg_data_t *msgdata );
-
 void *nfmalloc( size_t sz );
 void *nfcalloc( size_t sz );
@@ -234,4 +241,5 @@ unsigned char arc4_getbyte( void );
 #define SYNC_FAIL    1
 #define SYNC_BAD(ms) (2+(ms))
+#define SYNC_NOGOOD  4 /* internal */
 
 int sync_boxes( store_t *ctx[], const char *names[], channel_conf_t * );

--- isync/src/sync.c  #1.69:1.70
@@ -95,8 +95,9 @@ typedef struct sync_rec {
        message_t *msg[2];
        unsigned char status, flags, aflags[2], dflags[2];
+       char tuid[TUIDL];
 } sync_rec_t;
 
-static void
-findmsgs( sync_rec_t *srecs, store_t *ctx[], int t )
+static int
+findmsgs( sync_rec_t *srecs, store_t *ctx[], int t, FILE *jfp )
 {
        sync_rec_t *srec, *nsrec = 0;
@@ -106,4 +107,44 @@ findmsgs( sync_rec_t *srecs, store_t *ct
        char fbuf[16]; /* enlarge when support for keywords is added */
 
+       if (jfp) {
+               /*
+                * Alternatively, the TUIDs could be fetched into the messages 
and
+                * looked up here. This would make the search faster (probably) 
and
+                * save roundtrips. On the downside, quite some additional data 
would
+                * have to be fetched for every message and the IMAP driver 
would be
+                * more complicated. This is a corner case anyway, so why 
bother.
+                */
+               debug( "finding previously copied messages\n" );
+               for (srec = srecs; srec; srec = srec->next) {
+                       if (srec->status & S_DEAD)
+                               continue;
+                       if (srec->uid[t] == -2 && srec->tuid[0]) {
+                               debug( "  pair(%d,%d): lookup %s, TUID %." 
stringify(TUIDL) "s\n", srec->uid[M], srec->uid[S], str_ms[t], srec->tuid );
+                               switch (ctx[t]->conf->driver->find_msg( ctx[t], 
srec->tuid, &uid )) {
+                               case DRV_STORE_BAD: return SYNC_BAD(t);
+                               case DRV_OK:
+                                       debug( "  -> new UID %d\n", uid );
+                                       Fprintf( jfp, "%c %d %d %d\n", "<>"[t], 
srec->uid[M], srec->uid[S], uid );
+                                       srec->uid[t] = uid;
+                                       srec->tuid[0] = 0;
+                                       break;
+                               default:
+                                       debug( "  -> TUID lost\n" );
+                                       Fprintf( jfp, "& %d %d\n", 
srec->uid[M], srec->uid[S] );
+                                       srec->flags = 0;
+                                       srec->tuid[0] = 0;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * Mapping msg -> srec (this variant) is dog slow for new messages.
+        * Mapping srec -> msg is dog slow for deleted messages.
+        * One solution would be using binary search on an index array.
+        * msgs are already sorted by UID, srecs would have to be sorted by 
uid[t].
+        */
+       debug( "matching messages against sync records\n" );
        for (msg = ctx[t]->msgs; msg; msg = msg->next) {
                uid = msg->uid;
@@ -137,6 +178,120 @@ findmsgs( sync_rec_t *srecs, store_t *ct
                debug( "pairs %5d %s\n", srec->uid[1-t], diag );
        }
+
+       return SYNC_OK;
 }
 
+static int
+copy_msg( store_t *ctx[], int t, message_t *tmsg, const char *tuid, int *uid )
+{
+       msg_data_t msgdata;
+       char *fmap, *buf;
+       int i, len, extra, cra, crd, scr, tcr;
+       int start, sbreak = 0, ebreak = 0;
+       char c;
+
+       msgdata.flags = tmsg->flags;
+       switch (ctx[1-t]->conf->driver->fetch_msg( ctx[1-t], tmsg, &msgdata )) {
+       case DRV_STORE_BAD: return SYNC_BAD(1-t);
+       case DRV_BOX_BAD: return SYNC_FAIL;
+       case DRV_MSG_BAD: return SYNC_NOGOOD;
+       }
+       tmsg->flags = msgdata.flags;
+
+       scr = (ctx[1-t]->conf->driver->flags / DRV_CRLF) & 1;
+       tcr = (ctx[t]->conf->driver->flags / DRV_CRLF) & 1;
+       if (tuid || scr != tcr) {
+               fmap = msgdata.data;
+               len = msgdata.len;
+               cra = crd = 0;
+               if (scr > tcr)
+                       crd = -1;
+               else if (scr < tcr)
+                       crd = 1;
+               extra = 0, i = 0;
+               if (tuid) {
+                       extra += 8 + TUIDL + 1 + tcr;
+                 nloop:
+                       start = i;
+                       while (i < len) {
+                               c = fmap[i++];
+                               if (c == '\r')
+                                       extra += crd;
+                               else if (c == '\n') {
+                                       extra += cra;
+                                       if (i - 2 + !scr == start) {
+                                               sbreak = ebreak = i - 2 + !scr; 
// precalc this!
+                                               goto oke;
+                                       }
+                                       if (!memcmp( fmap + start, "X-TUID: ", 
8 )) {
+                                               extra -= (ebreak = i) - (sbreak 
= start);
+                                               goto oke;
+                                       }
+                                       goto nloop;
+                               }
+                       }
+                       /* invalid message */
+                       free( fmap );
+                       return SYNC_NOGOOD;
+               }
+         oke:
+               if (cra || crd)
+                       for (; i < len; i++) {
+                               c = fmap[i++];
+                               if (c == '\r')
+                                       extra += crd;
+                               else if (c == '\n')
+                                       extra += cra;
+                       }
+
+               msgdata.len = len + extra;
+               buf = msgdata.data = nfmalloc( msgdata.len );
+               i = 0;
+               if (tuid) {
+                       if (cra) {
+                               for (; i < sbreak; i++) {
+                                       if (fmap[i] == '\n')
+                                               *buf++ = '\r';
+                                       *buf++ = fmap[i];
+                               }
+                       } else if (crd) {
+                               for (; i < sbreak; i++)
+                                       if (fmap[i] != '\r')
+                                               *buf++ = fmap[i];
+                       } else {
+                               memcpy( buf, fmap, sbreak );
+                               buf += sbreak;
+                       }
+                       memcpy( buf, "X-TUID: ", 8 );
+                       buf += 8;
+                       memcpy( buf, tuid, TUIDL );
+                       buf += TUIDL;
+                       if (tcr)
+                               *buf++ = '\r';
+                       *buf++ = '\n';
+                       i = ebreak;
+               }
+               if (cra) {
+                       for (; i < len; i++) {
+                               if (fmap[i] == '\n')
+                                       *buf++ = '\r';
+                               *buf++ = fmap[i];
+                       }
+               } else if (crd) {
+                       for (; i < len; i++)
+                               if (fmap[i] != '\r')
+                                       *buf++ = fmap[i];
+               } else
+                       memcpy( buf, fmap + i, len - i );
+
+               free( fmap );
+       }
+
+       switch (ctx[t]->conf->driver->store_msg( ctx[t], &msgdata, uid )) {
+       case DRV_STORE_BAD: return SYNC_BAD(t);
+       case DRV_OK: return SYNC_OK;
+       default: return SYNC_FAIL;
+       }
+}
 
 /* cases:
@@ -180,5 +335,5 @@ clean_strdup( const char *s )
 }
 
-#define JOURNAL_VERSION "1"
+#define JOURNAL_VERSION "2"
 
 int
@@ -196,5 +351,4 @@ sync_boxes( store_t *ctx[], const char *
        int lfd, ret, line, sline, todel, *mexcs, nmexcs, rmexcs;
        unsigned char nflags, sflags, aflags, dflags;
-       msg_data_t msgdata;
        struct stat st;
        struct flock lck;
@@ -302,4 +456,5 @@ sync_boxes( store_t *ctx[], const char *
                        debug( "  entry (%d,%d,%u,%s)\n", srec->uid[M], 
srec->uid[S], srec->flags, srec->status & S_EXPIRED ? "X" : "" );
                        srec->msg[M] = srec->msg[S] = 0;
+                       srec->tuid[0] = 0;
                        srec->next = 0;
                        *srecadd = srec;
@@ -340,7 +495,9 @@ sync_boxes( store_t *ctx[], const char *
                                        goto bail;
                                }
-                               if (buf[0] == '(' || buf[0] == ')' ?
+                               if (buf[0] == '#' ?
+                                     (t3 = 0, (sscanf( buf + 2, "%d %d %n", 
&t1, &t2, &t3 ) < 2) || !t3 || (t - t3 != TUIDL + 3)) :
+                                     buf[0] == '(' || buf[0] == ')' ?
                                        (sscanf( buf + 2, "%d", &t1 ) != 1) :
-                                   buf[0] == '-' || buf[0] == '|' || buf[0] == 
'/' || buf[0] == '\\' ?
+                                       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))
@@ -362,8 +519,9 @@ sync_boxes( store_t *ctx[], const char *
                                        srec->uid[M] = t1;
                                        srec->uid[S] = t2;
-                                       srec->flags = t3;
-                                       debug( "  new entry(%d,%d,%u)\n", t1, 
t2, t3 );
+                                       debug( "  new entry(%d,%d)\n", t1, t2 );
                                        srec->msg[M] = srec->msg[S] = 0;
                                        srec->status = 0;
+                                       srec->flags = 0;
+                                       srec->tuid[0] = 0;
                                        srec->next = 0;
                                        *srecadd = srec;
@@ -387,11 +545,22 @@ sync_boxes( store_t *ctx[], const char *
                                                srec->status = S_DEAD;
                                                break;
+                                       case '#':
+                                               debug( "TUID now %." 
stringify(TUIDL) "s\n", buf + t3 + 2 );
+                                               memcpy( srec->tuid, buf + t3 + 
2, TUIDL );
+                                               break;
+                                       case '&':
+                                               debug( "TUID %." 
stringify(TUIDL) "s lost\n", srec->tuid );
+                                               srec->flags = 0;
+                                               srec->tuid[0] = 0;
+                                               break;
                                        case '<':
                                                debug( "master now %d\n", t3 );
                                                srec->uid[M] = t3;
+                                               srec->tuid[0] = 0;
                                                break;
                                        case '>':
                                                debug( "slave now %d\n", t3 );
                                                srec->uid[S] = t3;
+                                               srec->tuid[0] = 0;
                                                break;
                                        case '*':
@@ -477,8 +646,15 @@ sync_boxes( store_t *ctx[], const char *
                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)) {
+               for (srec = recs; srec; srec = srec->next) {
+                       if (srec->status & S_DEAD)
+                               continue;
+                       if ((mvBit(srec->status, S_EXPIRE, S_EXPIRED) ^ 
srec->status) & S_EXPIRED)
                                opts[S] |= OPEN_OLD|OPEN_FLAGS;
-                               break;
+                       if (srec->tuid[0]) {
+                               if (srec->uid[M] == -2)
+                                       opts[M] |= OPEN_OLD|OPEN_FIND;
+                               else if (srec->uid[S] == -2)
+                                       opts[S] |= OPEN_OLD|OPEN_FIND;
+                       }
                        }
        driver[M]->prepare_opts( ctx[M], opts[M] );
@@ -500,7 +676,4 @@ sync_boxes( store_t *ctx[], const char *
        case DRV_BOX_BAD: ret = SYNC_FAIL; goto bail;
        }
-       info( "%d messages, %d recent\n", ctx[S]->count, ctx[S]->recent );
-       findmsgs( recs, ctx, S );
-
        if (suidval && suidval != ctx[S]->uidvalidity) {
                fprintf( stderr, "Error: UIDVALIDITY of slave changed\n" );
@@ -508,4 +681,5 @@ sync_boxes( store_t *ctx[], const char *
                goto bail;
        }
+       info( "%d messages, %d recent\n", ctx[S]->count, ctx[S]->recent );
 
        s = strrchr( dname, '/' );
@@ -534,4 +708,7 @@ sync_boxes( store_t *ctx[], const char *
                Fprintf( jfp, JOURNAL_VERSION "\n" );
 
+       if ((ret = findmsgs( recs, ctx, S, line ? jfp : 0 )) != SYNC_OK)
+               goto finish;
+
        mexcs = 0;
        nmexcs = rmexcs = 0;
@@ -608,7 +785,4 @@ sync_boxes( store_t *ctx[], const char *
        case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish;
        }
-       info( "%d messages, %d recent\n", ctx[M]->count, ctx[M]->recent );
-       findmsgs( recs, ctx, M );
-
        if (muidval && muidval != ctx[M]->uidvalidity) {
                fprintf( stderr, "Error: UIDVALIDITY of master changed\n" );
@@ -616,4 +790,8 @@ sync_boxes( store_t *ctx[], const char *
                goto finish;
        }
+       info( "%d messages, %d recent\n", ctx[M]->count, ctx[M]->recent );
+
+       if ((ret = findmsgs( recs, ctx, M, line ? jfp : 0 )) != SYNC_OK)
+               goto finish;
 
        if (!muidval || !suidval) {
@@ -629,11 +807,27 @@ sync_boxes( store_t *ctx[], const char *
        for (t = 0; t < 2; t++) {
                for (nmsgs = 0, tmsg = ctx[1-t]->msgs; tmsg; tmsg = tmsg->next)
-                       if (tmsg->srec ? tmsg->srec->uid[t] < 0 && 
(chan->ops[t] & OP_RENEW) : (chan->ops[t] & OP_NEW)) {
+                       if (tmsg->srec ? tmsg->srec->uid[t] < 0 && 
(tmsg->srec->uid[t] == -1 ? (chan->ops[t] & OP_RENEW) : (chan->ops[t] & 
OP_NEW)) : (chan->ops[t] & OP_NEW)) {
                                debug( "new message %d on %s\n", tmsg->uid, 
str_ms[1-t] );
                                if ((chan->ops[t] & OP_EXPUNGE) && (tmsg->flags 
& F_DELETED))
-                                       debug( "  not %sing - would be expunged 
anyway\n", str_hl[t] );
+                                       debug( "  -> not %sing - would be 
expunged anyway\n", str_hl[t] );
                                else {
+                                       if (tmsg->srec) {
+                                               srec = tmsg->srec;
+                                               srec->status |= S_DONE;
+                                               debug( "  -> pair(%d,%d) 
exists\n", srec->uid[M], srec->uid[S] );
+                                       } else {
+                                               srec = nfmalloc( sizeof(*srec) 
);
+                                               srec->next = 0;
+                                               *srecadd = srec;
+                                               srecadd = &srec->next;
+                                               srec->status = S_DONE;
+                                               srec->flags = 0;
+                                               srec->tuid[0] = 0;
+                                               srec->uid[1-t] = tmsg->uid;
+                                               srec->uid[t] = -2;
+                                               Fprintf( jfp, "+ %d %d\n", 
srec->uid[M], srec->uid[S] );
+                                               debug( "  -> pair(%d,%d) 
created\n", srec->uid[M], srec->uid[S] );
+                                       }
                                        if ((tmsg->flags & F_FLAGGED) || 
!chan->stores[t]->max_size || tmsg->size <= chan->stores[t]->max_size) {
-                                               debug( "  %sing it\n", 
str_hl[t] );
                                                if (!nmsgs)
                                                        info( t ? "Pulling new 
messages..." : "Pushing new messages..." );
@@ -641,15 +835,24 @@ sync_boxes( store_t *ctx[], const char *
                                                        infoc( '.' );
                                                nmsgs++;
-                                               msgdata.flags = tmsg->flags;
-                                               switch (driver[1-t]->fetch_msg( 
ctx[1-t], tmsg, &msgdata )) {
-                                               case DRV_STORE_BAD: return 
SYNC_BAD(1-t);
-                                               case DRV_BOX_BAD: return 
SYNC_FAIL;
-                                               case DRV_MSG_BAD: /* ok */ 
continue;
+                                               if (tmsg->flags) {
+                                                       srec->flags = 
tmsg->flags;
+                                                       Fprintf( jfp, "* %d %d 
%u\n", srec->uid[M], srec->uid[S], srec->flags );
+                                                       debug( "  -> updated 
flags to %u\n", tmsg->flags );
                                                }
-                                               tmsg->flags = msgdata.flags;
-                                               switch (driver[t]->store_msg( 
ctx[t], &msgdata, &uid )) {
-                                               case DRV_STORE_BAD: return 
SYNC_BAD(t);
-                                               default: return SYNC_FAIL;
-                                               case DRV_OK: break;
+                                               for (t1 = 0; t1 < TUIDL; t1++) {
+                                                       t2 = arc4_getbyte() & 
0x3f;
+                                                       srec->tuid[t1] = t2 < 
26 ? t2 + 'A' : t2 < 52 ? t2 + 'a' - 26 : t2 < 62 ? t2 + '0' - 52 : t2 == 62 ? 
'+' : '/';
+                                               }
+                                               Fprintf( jfp, "# %d %d %." 
stringify(TUIDL) "s\n", srec->uid[M], srec->uid[S], srec->tuid );
+                                               debug( "  -> %sing message, 
TUID %." stringify(TUIDL) "s\n", str_hl[t], srec->tuid );
+                                               switch ((ret = copy_msg( ctx, 
t, tmsg, srec->tuid, &uid ))) {
+                                               case SYNC_OK: break;
+                                               case SYNC_NOGOOD:
+                                                       /* The error is either 
transient or the message is gone. */
+                                                       debug( "  -> killing 
(%d,%d)\n", srec->uid[M], srec->uid[S] );
+                                                       srec->status = S_DEAD;
+                                                       Fprintf( jfp, "- %d 
%d\n", srec->uid[M], srec->uid[S] );
+                                                       continue;
+                                               default: goto finish;
                                                }
                                        } else {
@@ -658,23 +861,14 @@ sync_boxes( store_t *ctx[], const char *
                                                        continue;
                                                }
-                                               debug( "  not %sing - too 
big\n", str_hl[t] );
+                                               debug( "  -> not %sing - too 
big\n", str_hl[t] );
                                                uid = -1;
                                        }
-                                       if (tmsg->srec) {
-                                               srec = tmsg->srec;
+                                       if (srec->uid[t] != uid) {
+                                               debug( "  -> new UID %d\n", uid 
);
                                                Fprintf( jfp, "%c %d %d %d\n", 
"<>"[t], srec->uid[M], srec->uid[S], uid );
-                                       } else {
-                                               srec = nfmalloc( sizeof(*srec) 
);
-                                               srec->next = 0;
-                                               *srecadd = srec;
-                                               srecadd = &srec->next;
-                                               srec->uid[1-t] = tmsg->uid;
-                                       }
                                        srec->uid[t] = uid;
-                                       srec->flags = tmsg->flags;
-                                       srec->status = S_DONE;
-                                       if (tmsg->srec)
-                                               Fprintf( jfp, "* %d %d %u\n", 
srec->uid[M], srec->uid[S], srec->flags );
-                                       else {
+                                               srec->tuid[0] = 0;
+                                       }
+                                       if (!tmsg->srec) {
                                                tmsg->srec = srec;
                                                if (maxuid[1-t] < tmsg->uid) {
@@ -682,5 +876,4 @@ sync_boxes( store_t *ctx[], const char *
                                                        Fprintf( jfp, "%c 
%d\n", ")("[t], tmsg->uid );
                                                }
-                                               Fprintf( jfp, "+ %d %d %u\n", 
srec->uid[M], srec->uid[S], srec->flags );
                                        }
                                }
@@ -689,4 +882,26 @@ sync_boxes( store_t *ctx[], const char *
                        info( " %d messages\n", nmsgs );
        }
+       debug( "finding just copied messages\n" );
+       for (srec = recs; srec; srec = srec->next) {
+               if (srec->status & S_DEAD)
+                       continue;
+               if (srec->tuid[0]) {
+                       t = (srec->uid[M] == -2) ? M : S;
+                       debug( "  pair(%d,%d): lookup %s, TUID %." 
stringify(TUIDL) "s\n", srec->uid[M], srec->uid[S], str_ms[t], srec->tuid );
+                       switch (driver[t]->find_msg( ctx[t], srec->tuid, &uid 
)) {
+                       case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
+                       case DRV_OK:
+                               debug( "  -> new UID %d\n", uid );
+                               break;
+                       default:
+                               warn( "Warning: cannot find newly stored 
message %." stringify(TUIDL) "s on %s.\n", srec->tuid, str_ms[t] );
+                               uid = 0;
+                               break;
+                       }
+                       Fprintf( jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], 
srec->uid[S], uid );
+                       srec->uid[t] = uid;
+                       srec->tuid[0] = 0;
+               }
+       }
 
        debug( "synchronizing old entries\n" );
@@ -883,14 +1098,9 @@ sync_boxes( store_t *ctx[], const char *
                                                        if 
(!ctx[1-t]->conf->max_size || tmsg->size <= ctx[1-t]->conf->max_size) {
                                                                debug( "  
remote trashing message %d\n", tmsg->uid );
-                                                               msgdata.flags = 
tmsg->flags;
-                                                               switch 
(driver[t]->fetch_msg( ctx[t], tmsg, &msgdata )) {
-                                                               case DRV_OK: 
break;
-                                                               case 
DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish;
-                                                               default: ret = 
SYNC_FAIL; goto nexex;
-                                                               }
-                                                               switch 
(driver[1-t]->store_msg( ctx[1-t], &msgdata, 0 )) {
-                                                               case DRV_OK: 
break;
-                                                               case 
DRV_STORE_BAD: ret = SYNC_BAD(1-t); goto finish;
-                                                               default: ret = 
SYNC_FAIL; goto nexex;
+                                                               switch ((ret = 
copy_msg( ctx, 1 - t, tmsg, 0, 0 ))) {
+                                                               case SYNC_OK: 
break;
+                                                               case 
SYNC_NOGOOD: ret = SYNC_FAIL; goto nexex;
+                                                               case SYNC_FAIL: 
goto nexex;
+                                                               default: goto 
finish;
                                                                }
                                                        } else

--- isync/src/util.c  #1.5:1.6
@@ -146,18 +146,4 @@ free_generic_messages( message_t *msgs )
 }
 
-void
-strip_cr( msg_data_t *msgdata )
-{
-       int i, o;
-
-       if (msgdata->crlf) {
-               for (i = o = 0; i < msgdata->len; i++)
-                       if (msgdata->data[i] != '\r')
-                               msgdata->data[o++] = msgdata->data[i];
-               msgdata->len = o;
-               msgdata->crlf = 0;
-       }
-}
-
 #ifndef HAVE_VASPRINTF
 static int




-------------------------------------------------------
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