Browse Source

added sync support for the arrival date of messages

initial patch by Marc Hoersken <info@marc-hoersken.de>
wip/maildir-uid-dupes-test
Oswald Buddenhagen 11 years ago
parent
commit
eb1f10762f
  1. 17
      configure.ac
  2. 2
      src/config.c
  3. 38
      src/drv_imap.c
  4. 15
      src/drv_maildir.c
  5. 2
      src/isync.h
  6. 10
      src/mbsync.1
  7. 1
      src/sync.c

17
configure.ac

@ -11,6 +11,23 @@ fi
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
AC_CACHE_CHECK([whether strftime supports %z], ob_cv_strftime_z,
[AC_TRY_RUN(
[#include <time.h>
#include <string.h>
int main(void)
{
time_t t = 0;
char buf[32];
strftime(buf, sizeof(buf), "%z", gmtime(&t));
return !!strcmp(buf, "+0000");
}
], [ob_cv_strftime_z=yes], [ob_cv_strftime_z=no], [ob_cv_strftime_z="yes (assumed)"])])
if test "x$ob_cv_strftime_z" = x"no"; then
AC_MSG_ERROR([libc lacks necessary feature])
fi
AC_CHECK_HEADERS(sys/poll.h sys/select.h)
AC_CHECK_FUNCS(vasprintf memrchr)

2
src/config.c

@ -362,6 +362,8 @@ load_config( const char *where, int pseudo )
max_size = parse_size( &cfile );
else if (!strcasecmp( "MaxMessages", cfile.cmd ))
channel->max_messages = parse_int( &cfile );
else if (!strcasecmp( "CopyArrivalDate", cfile.cmd ))
channel->use_internal_date = parse_bool( &cfile );
else if (!strcasecmp( "Pattern", cfile.cmd ) ||
!strcasecmp( "Patterns", cfile.cmd ))
{

38
src/drv_imap.c

@ -31,6 +31,7 @@
#include <limits.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/wait.h>
typedef struct imap_server_conf {
@ -710,6 +711,8 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
struct imap_cmd *cmdp;
int uid = 0, mask = 0, status = 0, size = 0;
unsigned i;
time_t date = 0;
struct tm datetime;
if (!is_list( list )) {
error( "IMAP error: bogus FETCH response\n" );
@ -751,6 +754,15 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
status |= M_FLAGS;
} else
error( "IMAP error: unable to parse FLAGS\n" );
} else if (!strcmp( "INTERNALDATE", tmp->val )) {
tmp = tmp->next;
if (is_atom( tmp )) {
if (strptime( tmp->val, "%d-%b-%Y %H:%M:%S %z", &datetime ))
date = mktime( &datetime );
else
error( "IMAP error: unable to parse INTERNALDATE format\n" );
} else
error( "IMAP error: unable to parse INTERNALDATE\n" );
} else if (!strcmp( "RFC822.SIZE", tmp->val )) {
tmp = tmp->next;
if (is_atom( tmp ))
@ -794,6 +806,7 @@ parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED )
msgdata = ((struct imap_cmd_fetch_msg *)cmdp)->msg_data;
msgdata->data = body;
msgdata->len = size;
msgdata->date = date;
if (status & M_FLAGS)
msgdata->flags = mask;
} else if (uid) { /* ignore async flag updates for now */
@ -1738,8 +1751,9 @@ imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data,
cmd->gen.gen.param.uid = msg->uid;
cmd->msg_data = data;
imap_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_done_simple_msg,
"UID FETCH %d (%sBODY.PEEK[])",
msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " );
"UID FETCH %d (%s%sBODY.PEEK[])", msg->uid,
!(msg->status & M_FLAGS) ? "FLAGS " : "",
(data->date== -1) ? "INTERNALDATE " : "" );
}
/******************* imap_set_flags *******************/
@ -1888,7 +1902,7 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd_out_uid *cmd;
int d;
char flagstr[128], buf[1024];
char flagstr[128], datestr[64], buf[1024];
d = 0;
if (data->flags) {
@ -1915,8 +1929,22 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
return;
}
}
imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
"APPEND \"%s\" %s", buf, flagstr );
if (data->date) {
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat"
/* configure ensures that %z actually works. */
#endif
strftime( datestr, sizeof(datestr), "%d-%b-%Y %H:%M:%S %z", localtime( &data->date ) );
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
"APPEND \"%s\" %s\"%s\" ", buf, flagstr, datestr );
} else {
imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
"APPEND \"%s\" %s", buf, flagstr );
}
}
static void

15
src/drv_maildir.c

@ -36,6 +36,7 @@
#include <sys/file.h>
#include <errno.h>
#include <time.h>
#include <utime.h>
#define USE_DB 1
#ifdef __linux__
@ -1124,6 +1125,8 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
}
fstat( fd, &st );
data->len = st.st_size;
if (data->date == -1)
data->date = st.st_mtime;
data->data = nfmalloc( data->len );
if (read( fd, data->data, data->len ) != data->len) {
sys_error( "Maildir error: cannot read %s", buf );
@ -1225,6 +1228,18 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
cb( DRV_BOX_BAD, 0, aux );
return;
}
if (data->date) {
/* Set atime and mtime according to INTERNALDATE or mtime of source message */
struct utimbuf utimebuf;
utimebuf.actime = utimebuf.modtime = data->date;
if (utime( buf, &utimebuf ) < 0) {
sys_error( "Maildir error: cannot set times for %s", buf );
cb( DRV_BOX_BAD, 0, aux );
return;
}
}
/* Moving seen messages to cur/ is strictly speaking incorrect, but makes mutt happy. */
nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%s%s", box, subdirs[!(data->flags & F_SEEN)], base, fbuf );
if (rename( buf, nbuf )) {

2
src/isync.h

@ -166,6 +166,7 @@ typedef struct channel_conf {
string_list_t *patterns;
int ops[2];
unsigned max_messages; /* for slave only */
unsigned use_internal_date:1;
} channel_conf_t;
typedef struct group_conf {
@ -245,6 +246,7 @@ set_bad_callback( store_t *ctx, void (*cb)( void *aux ), void *aux )
typedef struct {
char *data;
int len;
time_t date;
unsigned char flags;
} msg_data_t;

10
src/mbsync.1

@ -477,6 +477,16 @@ a global effect. The global settings are overridden by Channel-specific options,
which in turn are overridden by command line switches.
..
.TP
\fBCopyArrivalDate\fR {\fIyes\fR|\fIno\fR}
Selects whether their arrival time should be propagated together with
the messages.
Enabling this makes sense in order to keep the time stamp based message
sorting intact.
Note that IMAP does not guarantee that the time stamp (termed \fBinternal
date\fR) is actually the arrival time, but it is usually close enough.
(Default: \fIno\fR)
..
.TP
\fBSyncState\fR {\fB*\fR|\fIpath\fR}
Set the location of this Channel's synchronization state files. \fB*\fR means
that the state should be saved in a file named .mbsyncstate in the

1
src/sync.c

@ -281,6 +281,7 @@ copy_msg( copy_vars_t *vars )
t ^= 1;
vars->data.flags = vars->msg->flags;
vars->data.date = svars->chan->use_internal_date ? -1 : 0;
DRIVER_CALL_RET(fetch_msg( svars->ctx[t], vars->msg, &vars->data, msg_fetched, vars ));
}

Loading…
Cancel
Save