// SPDX-FileCopyrightText: 2002-2022 Oswald Buddenhagen // SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-isync-GPL-exception // // mbsync - mailbox synchronizer // #define DEBUG_FLAG DEBUG_SYNC #include "sync.h" #include "sync_p_enum.h" BIT_ENUM( S_DEAD, // ephemeral: the entry was killed and should be ignored S_EXPIRE, // the entry is being expired (near side message removal scheduled) S_EXPIRED, // the entry is expired (near side message removal confirmed) S_NEXPIRE, // temporary: new expiration state S_PENDING, // the entry is new and awaits propagation (possibly a retry) S_DUMMY(2), // f/n message is only a placeholder S_SKIPPED, // pre-1.4 legacy: the entry was not propagated (message is too big) S_DEL(2), // ephemeral: f/n message would be subject to expunge S_DELETE, // ephemeral: flags propagation is a deletion S_UPGRADE, // ephemeral: upgrading placeholder, do not apply MaxSize S_PURGE, // ephemeral: placeholder is being nuked S_PURGED, // ephemeral: placeholder was nuked ) // This is the persistent status of the sync record, with regard to the journal. #define S_LOGGED (S_EXPIRE | S_EXPIRED | S_PENDING | S_DUMMY(F) | S_DUMMY(N) | S_SKIPPED) typedef struct sync_rec { struct sync_rec *next; /* string_list_t *keywords; */ uint uid[2]; message_t *msg[2]; ushort status; uchar flags, pflags, aflags[2], dflags[2]; char tuid[TUIDL]; } sync_rec_t; static_assert_bits(F, sync_rec_t, flags); static_assert_bits(S, sync_rec_t, status); typedef struct { int t[2]; void (*cb)( int sts, void *aux ), *aux; char *dname, *jname, *nname, *lname, *box_name[2]; FILE *jfp, *nfp; sync_rec_t *srecs, **srecadd; channel_conf_t *chan; store_t *ctx[2]; driver_t *drv[2]; const char *orig_name[2]; message_t *msgs[2], *new_msgs[2]; uint_array_alloc_t trashed_msgs[2]; int state[2], lfd, ret, existing, replayed; uint ref_count, nsrecs, opts[2]; uint new_pending[2], flags_pending[2], trash_pending[2]; uint maxuid[2]; // highest UID that was already propagated uint oldmaxuid[2]; // highest UID that was already propagated before this run uint uidval[2]; // UID validity value uint newuidval[2]; // UID validity obtained from driver uint finduid[2]; // TUID lookup makes sense only for UIDs >= this uint maxxfuid; // highest expired UID on far side uchar good_flags[2], bad_flags[2]; } sync_vars_t; int prepare_state( sync_vars_t *svars ); int lock_state( sync_vars_t *svars ); int load_state( sync_vars_t *svars ); void save_state( sync_vars_t *svars ); void delete_state( sync_vars_t *svars ); void ATTR_PRINTFLIKE(2, 3) jFprintf( sync_vars_t *svars, const char *msg, ... ); #define JLOG_(log_fmt, log_args, dbg_fmt, ...) \ do { \ debug( "-> log: " log_fmt " (" dbg_fmt ")\n", __VA_ARGS__ ); \ jFprintf( svars, log_fmt "\n", deparen(log_args) ); \ } while (0) #define JLOG3(log_fmt, log_args, dbg_fmt) \ JLOG_(log_fmt, log_args, dbg_fmt, deparen(log_args)) #define JLOG4(log_fmt, log_args, dbg_fmt, dbg_args) \ JLOG_(log_fmt, log_args, dbg_fmt, deparen(log_args), deparen(dbg_args)) #define JLOG_SEL(_1, _2, _3, _4, x, ...) x #define JLOG(...) JLOG_SEL(__VA_ARGS__, JLOG4, JLOG3, NO_JLOG2, NO_JLOG1)(__VA_ARGS__) void assign_uid( sync_vars_t *svars, sync_rec_t *srec, int t, uint uid ); #define ASSIGN_UID(srec, t, nuid, ...) \ do { \ JLOG( "%c %u %u %u", ("<>"[t], srec->uid[F], srec->uid[N], nuid), __VA_ARGS__ ); \ assign_uid( svars, srec, t, nuid ); \ } while (0) void assign_tuid( sync_vars_t *svars, sync_rec_t *srec ); int match_tuids( sync_vars_t *svars, int t, message_t *msgs ); sync_rec_t *upgrade_srec( sync_vars_t *svars, sync_rec_t *srec );