|
|
@ -94,10 +94,11 @@ typedef struct sync_rec { |
|
|
|
int uid[2]; |
|
|
|
int uid[2]; |
|
|
|
message_t *msg[2]; |
|
|
|
message_t *msg[2]; |
|
|
|
unsigned char status, flags, aflags[2], dflags[2]; |
|
|
|
unsigned char status, flags, aflags[2], dflags[2]; |
|
|
|
|
|
|
|
char tuid[TUIDL]; |
|
|
|
} sync_rec_t; |
|
|
|
} sync_rec_t; |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
static int |
|
|
|
findmsgs( sync_rec_t *srecs, store_t *ctx[], int t ) |
|
|
|
findmsgs( sync_rec_t *srecs, store_t *ctx[], int t, FILE *jfp ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
sync_rec_t *srec, *nsrec = 0; |
|
|
|
sync_rec_t *srec, *nsrec = 0; |
|
|
|
message_t *msg; |
|
|
|
message_t *msg; |
|
|
@ -105,6 +106,46 @@ findmsgs( sync_rec_t *srecs, store_t *ctx[], int t ) |
|
|
|
int uid; |
|
|
|
int uid; |
|
|
|
char fbuf[16]; /* enlarge when support for keywords is added */ |
|
|
|
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) { |
|
|
|
for (msg = ctx[t]->msgs; msg; msg = msg->next) { |
|
|
|
uid = msg->uid; |
|
|
|
uid = msg->uid; |
|
|
|
if (DFlags & DEBUG) { |
|
|
|
if (DFlags & DEBUG) { |
|
|
@ -136,8 +177,122 @@ findmsgs( sync_rec_t *srecs, store_t *ctx[], int t ) |
|
|
|
nsrec = srec->next; |
|
|
|
nsrec = srec->next; |
|
|
|
debug( "pairs %5d %s\n", srec->uid[1-t], diag ); |
|
|
|
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:
|
|
|
|
/* cases:
|
|
|
|
a) both non-null |
|
|
|
a) both non-null |
|
|
@ -179,7 +334,7 @@ clean_strdup( const char *s ) |
|
|
|
return cs; |
|
|
|
return cs; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#define JOURNAL_VERSION "1" |
|
|
|
#define JOURNAL_VERSION "2" |
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
int |
|
|
|
sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
@ -195,7 +350,6 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
int t1, t2, t3, t, uid, nmsgs; |
|
|
|
int t1, t2, t3, t, uid, nmsgs; |
|
|
|
int lfd, ret, line, sline, todel, *mexcs, nmexcs, rmexcs; |
|
|
|
int lfd, ret, line, sline, todel, *mexcs, nmexcs, rmexcs; |
|
|
|
unsigned char nflags, sflags, aflags, dflags; |
|
|
|
unsigned char nflags, sflags, aflags, dflags; |
|
|
|
msg_data_t msgdata; |
|
|
|
|
|
|
|
struct stat st; |
|
|
|
struct stat st; |
|
|
|
struct flock lck; |
|
|
|
struct flock lck; |
|
|
|
char fbuf[16]; /* enlarge when support for keywords is added */ |
|
|
|
char fbuf[16]; /* enlarge when support for keywords is added */ |
|
|
@ -301,6 +455,7 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
srec->flags = parse_flags( s ); |
|
|
|
srec->flags = parse_flags( s ); |
|
|
|
debug( " entry (%d,%d,%u,%s)\n", srec->uid[M], srec->uid[S], srec->flags, srec->status & S_EXPIRED ? "X" : "" ); |
|
|
|
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->msg[M] = srec->msg[S] = 0; |
|
|
|
|
|
|
|
srec->tuid[0] = 0; |
|
|
|
srec->next = 0; |
|
|
|
srec->next = 0; |
|
|
|
*srecadd = srec; |
|
|
|
*srecadd = srec; |
|
|
|
srecadd = &srec->next; |
|
|
|
srecadd = &srec->next; |
|
|
@ -339,9 +494,11 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
ret = SYNC_FAIL; |
|
|
|
ret = SYNC_FAIL; |
|
|
|
goto bail; |
|
|
|
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) : |
|
|
|
(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", &t1, &t2 ) != 2) : |
|
|
|
(sscanf( buf + 2, "%d %d %d", &t1, &t2, &t3 ) != 3)) |
|
|
|
(sscanf( buf + 2, "%d %d %d", &t1, &t2, &t3 ) != 3)) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -361,10 +518,11 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
srec = nfmalloc( sizeof(*srec) ); |
|
|
|
srec = nfmalloc( sizeof(*srec) ); |
|
|
|
srec->uid[M] = t1; |
|
|
|
srec->uid[M] = t1; |
|
|
|
srec->uid[S] = t2; |
|
|
|
srec->uid[S] = t2; |
|
|
|
srec->flags = t3; |
|
|
|
debug( " new entry(%d,%d)\n", t1, t2 ); |
|
|
|
debug( " new entry(%d,%d,%u)\n", t1, t2, t3 ); |
|
|
|
|
|
|
|
srec->msg[M] = srec->msg[S] = 0; |
|
|
|
srec->msg[M] = srec->msg[S] = 0; |
|
|
|
srec->status = 0; |
|
|
|
srec->status = 0; |
|
|
|
|
|
|
|
srec->flags = 0; |
|
|
|
|
|
|
|
srec->tuid[0] = 0; |
|
|
|
srec->next = 0; |
|
|
|
srec->next = 0; |
|
|
|
*srecadd = srec; |
|
|
|
*srecadd = srec; |
|
|
|
srecadd = &srec->next; |
|
|
|
srecadd = &srec->next; |
|
|
@ -386,13 +544,24 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
debug( "killed\n" ); |
|
|
|
debug( "killed\n" ); |
|
|
|
srec->status = S_DEAD; |
|
|
|
srec->status = S_DEAD; |
|
|
|
break; |
|
|
|
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 '<': |
|
|
|
case '<': |
|
|
|
debug( "master now %d\n", t3 ); |
|
|
|
debug( "master now %d\n", t3 ); |
|
|
|
srec->uid[M] = t3; |
|
|
|
srec->uid[M] = t3; |
|
|
|
|
|
|
|
srec->tuid[0] = 0; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '>': |
|
|
|
case '>': |
|
|
|
debug( "slave now %d\n", t3 ); |
|
|
|
debug( "slave now %d\n", t3 ); |
|
|
|
srec->uid[S] = t3; |
|
|
|
srec->uid[S] = t3; |
|
|
|
|
|
|
|
srec->tuid[0] = 0; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '*': |
|
|
|
case '*': |
|
|
|
debug( "flags now %d\n", t3 ); |
|
|
|
debug( "flags now %d\n", t3 ); |
|
|
@ -476,10 +645,17 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
if ((chan->ops[S] & (OP_NEW|OP_RENEW)) && chan->max_messages) |
|
|
|
if ((chan->ops[S] & (OP_NEW|OP_RENEW)) && chan->max_messages) |
|
|
|
opts[S] |= OPEN_OLD|OPEN_NEW|OPEN_FLAGS; |
|
|
|
opts[S] |= OPEN_OLD|OPEN_NEW|OPEN_FLAGS; |
|
|
|
if (line) |
|
|
|
if (line) |
|
|
|
for (srec = recs; srec; srec = srec->next) |
|
|
|
for (srec = recs; srec; srec = srec->next) { |
|
|
|
if (!(srec->status & S_DEAD) && ((mvBit(srec->status, S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED)) { |
|
|
|
if (srec->status & S_DEAD) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
if ((mvBit(srec->status, S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED) |
|
|
|
opts[S] |= OPEN_OLD|OPEN_FLAGS; |
|
|
|
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] ); |
|
|
|
driver[M]->prepare_opts( ctx[M], opts[M] ); |
|
|
|
driver[S]->prepare_opts( ctx[S], opts[S] ); |
|
|
|
driver[S]->prepare_opts( ctx[S], opts[S] ); |
|
|
@ -499,14 +675,12 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
case DRV_STORE_BAD: ret = SYNC_BAD(S); goto bail; |
|
|
|
case DRV_STORE_BAD: ret = SYNC_BAD(S); goto bail; |
|
|
|
case DRV_BOX_BAD: ret = SYNC_FAIL; goto bail; |
|
|
|
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) { |
|
|
|
if (suidval && suidval != ctx[S]->uidvalidity) { |
|
|
|
fprintf( stderr, "Error: UIDVALIDITY of slave changed\n" ); |
|
|
|
fprintf( stderr, "Error: UIDVALIDITY of slave changed\n" ); |
|
|
|
ret = SYNC_FAIL; |
|
|
|
ret = SYNC_FAIL; |
|
|
|
goto bail; |
|
|
|
goto bail; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
info( "%d messages, %d recent\n", ctx[S]->count, ctx[S]->recent ); |
|
|
|
|
|
|
|
|
|
|
|
s = strrchr( dname, '/' ); |
|
|
|
s = strrchr( dname, '/' ); |
|
|
|
*s = 0; |
|
|
|
*s = 0; |
|
|
@ -533,6 +707,9 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
if (!line) |
|
|
|
if (!line) |
|
|
|
Fprintf( jfp, JOURNAL_VERSION "\n" ); |
|
|
|
Fprintf( jfp, JOURNAL_VERSION "\n" ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((ret = findmsgs( recs, ctx, S, line ? jfp : 0 )) != SYNC_OK) |
|
|
|
|
|
|
|
goto finish; |
|
|
|
|
|
|
|
|
|
|
|
mexcs = 0; |
|
|
|
mexcs = 0; |
|
|
|
nmexcs = rmexcs = 0; |
|
|
|
nmexcs = rmexcs = 0; |
|
|
|
minwuid = INT_MAX; |
|
|
|
minwuid = INT_MAX; |
|
|
@ -607,14 +784,15 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
case DRV_STORE_BAD: ret = SYNC_BAD(M); goto finish; |
|
|
|
case DRV_STORE_BAD: ret = SYNC_BAD(M); goto finish; |
|
|
|
case DRV_BOX_BAD: ret = SYNC_FAIL; goto finish; |
|
|
|
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) { |
|
|
|
if (muidval && muidval != ctx[M]->uidvalidity) { |
|
|
|
fprintf( stderr, "Error: UIDVALIDITY of master changed\n" ); |
|
|
|
fprintf( stderr, "Error: UIDVALIDITY of master changed\n" ); |
|
|
|
ret = SYNC_FAIL; |
|
|
|
ret = SYNC_FAIL; |
|
|
|
goto finish; |
|
|
|
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) { |
|
|
|
if (!muidval || !suidval) { |
|
|
|
muidval = ctx[M]->uidvalidity; |
|
|
|
muidval = ctx[M]->uidvalidity; |
|
|
@ -628,66 +806,103 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
osrecadd = srecadd; |
|
|
|
osrecadd = srecadd; |
|
|
|
for (t = 0; t < 2; t++) { |
|
|
|
for (t = 0; t < 2; t++) { |
|
|
|
for (nmsgs = 0, tmsg = ctx[1-t]->msgs; tmsg; tmsg = tmsg->next) |
|
|
|
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] ); |
|
|
|
debug( "new message %d on %s\n", tmsg->uid, str_ms[1-t] ); |
|
|
|
if ((chan->ops[t] & OP_EXPUNGE) && (tmsg->flags & F_DELETED)) |
|
|
|
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 { |
|
|
|
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) { |
|
|
|
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) |
|
|
|
if (!nmsgs) |
|
|
|
info( t ? "Pulling new messages..." : "Pushing new messages..." ); |
|
|
|
info( t ? "Pulling new messages..." : "Pushing new messages..." ); |
|
|
|
else |
|
|
|
else |
|
|
|
infoc( '.' ); |
|
|
|
infoc( '.' ); |
|
|
|
nmsgs++; |
|
|
|
nmsgs++; |
|
|
|
msgdata.flags = tmsg->flags; |
|
|
|
if (tmsg->flags) { |
|
|
|
switch (driver[1-t]->fetch_msg( ctx[1-t], tmsg, &msgdata )) { |
|
|
|
srec->flags = tmsg->flags; |
|
|
|
case DRV_STORE_BAD: return SYNC_BAD(1-t); |
|
|
|
Fprintf( jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], srec->flags ); |
|
|
|
case DRV_BOX_BAD: return SYNC_FAIL; |
|
|
|
debug( " -> updated flags to %u\n", tmsg->flags ); |
|
|
|
case DRV_MSG_BAD: /* ok */ continue; |
|
|
|
} |
|
|
|
} |
|
|
|
for (t1 = 0; t1 < TUIDL; t1++) { |
|
|
|
tmsg->flags = msgdata.flags; |
|
|
|
t2 = arc4_getbyte() & 0x3f; |
|
|
|
switch (driver[t]->store_msg( ctx[t], &msgdata, &uid )) { |
|
|
|
srec->tuid[t1] = t2 < 26 ? t2 + 'A' : t2 < 52 ? t2 + 'a' - 26 : t2 < 62 ? t2 + '0' - 52 : t2 == 62 ? '+' : '/'; |
|
|
|
case DRV_STORE_BAD: return SYNC_BAD(t); |
|
|
|
} |
|
|
|
default: return SYNC_FAIL; |
|
|
|
Fprintf( jfp, "# %d %d %." stringify(TUIDL) "s\n", srec->uid[M], srec->uid[S], srec->tuid ); |
|
|
|
case DRV_OK: break; |
|
|
|
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 { |
|
|
|
} else { |
|
|
|
if (tmsg->srec) { |
|
|
|
if (tmsg->srec) { |
|
|
|
debug( " -> not %sing - still too big\n", str_hl[t] ); |
|
|
|
debug( " -> not %sing - still too big\n", str_hl[t] ); |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
debug( " not %sing - too big\n", str_hl[t] ); |
|
|
|
debug( " -> not %sing - too big\n", str_hl[t] ); |
|
|
|
uid = -1; |
|
|
|
uid = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
if (tmsg->srec) { |
|
|
|
if (srec->uid[t] != uid) { |
|
|
|
srec = tmsg->srec; |
|
|
|
debug( " -> new UID %d\n", uid ); |
|
|
|
Fprintf( jfp, "%c %d %d %d\n", "<>"[t], srec->uid[M], srec->uid[S], 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->uid[t] = uid; |
|
|
|
srec->flags = tmsg->flags; |
|
|
|
srec->tuid[0] = 0; |
|
|
|
srec->status = S_DONE; |
|
|
|
} |
|
|
|
if (tmsg->srec) |
|
|
|
if (!tmsg->srec) { |
|
|
|
Fprintf( jfp, "* %d %d %u\n", srec->uid[M], srec->uid[S], srec->flags ); |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
tmsg->srec = srec; |
|
|
|
tmsg->srec = srec; |
|
|
|
if (maxuid[1-t] < tmsg->uid) { |
|
|
|
if (maxuid[1-t] < tmsg->uid) { |
|
|
|
maxuid[1-t] = tmsg->uid; |
|
|
|
maxuid[1-t] = tmsg->uid; |
|
|
|
Fprintf( jfp, "%c %d\n", ")("[t], tmsg->uid ); |
|
|
|
Fprintf( jfp, "%c %d\n", ")("[t], tmsg->uid ); |
|
|
|
} |
|
|
|
} |
|
|
|
Fprintf( jfp, "+ %d %d %u\n", srec->uid[M], srec->uid[S], srec->flags ); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (nmsgs) |
|
|
|
if (nmsgs) |
|
|
|
info( " %d messages\n", nmsgs ); |
|
|
|
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" ); |
|
|
|
debug( "synchronizing old entries\n" ); |
|
|
|
for (srec = recs; srec != *osrecadd; srec = srec->next) { |
|
|
|
for (srec = recs; srec != *osrecadd; srec = srec->next) { |
|
|
@ -882,16 +1097,11 @@ sync_boxes( store_t *ctx[], const char *names[], channel_conf_t *chan ) |
|
|
|
if (!tmsg->srec || tmsg->srec->uid[1-t] < 0) { |
|
|
|
if (!tmsg->srec || tmsg->srec->uid[1-t] < 0) { |
|
|
|
if (!ctx[1-t]->conf->max_size || tmsg->size <= ctx[1-t]->conf->max_size) { |
|
|
|
if (!ctx[1-t]->conf->max_size || tmsg->size <= ctx[1-t]->conf->max_size) { |
|
|
|
debug( " remote trashing message %d\n", tmsg->uid ); |
|
|
|
debug( " remote trashing message %d\n", tmsg->uid ); |
|
|
|
msgdata.flags = tmsg->flags; |
|
|
|
switch ((ret = copy_msg( ctx, 1 - t, tmsg, 0, 0 ))) { |
|
|
|
switch (driver[t]->fetch_msg( ctx[t], tmsg, &msgdata )) { |
|
|
|
case SYNC_OK: break; |
|
|
|
case DRV_OK: break; |
|
|
|
case SYNC_NOGOOD: ret = SYNC_FAIL; goto nexex; |
|
|
|
case DRV_STORE_BAD: ret = SYNC_BAD(t); goto finish; |
|
|
|
case SYNC_FAIL: goto nexex; |
|
|
|
default: ret = SYNC_FAIL; goto nexex; |
|
|
|
default: goto finish; |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} else |
|
|
|
} else |
|
|
|
debug( " not remote trashing message %d - too big\n", tmsg->uid ); |
|
|
|
debug( " not remote trashing message %d - too big\n", tmsg->uid ); |
|
|
|