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