added sync support for the arrival date of messages

initial patch by Marc Hoersken <info@marc-hoersken.de>
This commit is contained in:
Oswald Buddenhagen 2013-07-28 15:55:13 +02:00
parent 6577bf3e61
commit eb1f10762f
7 changed files with 80 additions and 5 deletions

View File

@ -11,6 +11,23 @@ fi
CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" 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_HEADERS(sys/poll.h sys/select.h)
AC_CHECK_FUNCS(vasprintf memrchr) AC_CHECK_FUNCS(vasprintf memrchr)

View File

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

View File

@ -31,6 +31,7 @@
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <time.h>
#include <sys/wait.h> #include <sys/wait.h>
typedef struct imap_server_conf { 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; struct imap_cmd *cmdp;
int uid = 0, mask = 0, status = 0, size = 0; int uid = 0, mask = 0, status = 0, size = 0;
unsigned i; unsigned i;
time_t date = 0;
struct tm datetime;
if (!is_list( list )) { if (!is_list( list )) {
error( "IMAP error: bogus FETCH response\n" ); 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; status |= M_FLAGS;
} else } else
error( "IMAP error: unable to parse FLAGS\n" ); 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 )) { } else if (!strcmp( "RFC822.SIZE", tmp->val )) {
tmp = tmp->next; tmp = tmp->next;
if (is_atom( tmp )) 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 = ((struct imap_cmd_fetch_msg *)cmdp)->msg_data;
msgdata->data = body; msgdata->data = body;
msgdata->len = size; msgdata->len = size;
msgdata->date = date;
if (status & M_FLAGS) if (status & M_FLAGS)
msgdata->flags = mask; msgdata->flags = mask;
} else if (uid) { /* ignore async flag updates for now */ } 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->gen.gen.param.uid = msg->uid;
cmd->msg_data = data; cmd->msg_data = data;
imap_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_done_simple_msg, imap_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_done_simple_msg,
"UID FETCH %d (%sBODY.PEEK[])", "UID FETCH %d (%s%sBODY.PEEK[])", msg->uid,
msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " ); !(msg->status & M_FLAGS) ? "FLAGS " : "",
(data->date== -1) ? "INTERNALDATE " : "" );
} }
/******************* imap_set_flags *******************/ /******************* 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; imap_store_t *ctx = (imap_store_t *)gctx;
struct imap_cmd_out_uid *cmd; struct imap_cmd_out_uid *cmd;
int d; int d;
char flagstr[128], buf[1024]; char flagstr[128], datestr[64], buf[1024];
d = 0; d = 0;
if (data->flags) { if (data->flags) {
@ -1915,9 +1929,23 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
return; return;
} }
} }
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, imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
"APPEND \"%s\" %s", buf, flagstr ); "APPEND \"%s\" %s", buf, flagstr );
} }
}
static void static void
imap_store_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int response ) imap_store_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int response )

View File

@ -36,6 +36,7 @@
#include <sys/file.h> #include <sys/file.h>
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <utime.h>
#define USE_DB 1 #define USE_DB 1
#ifdef __linux__ #ifdef __linux__
@ -1124,6 +1125,8 @@ maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data,
} }
fstat( fd, &st ); fstat( fd, &st );
data->len = st.st_size; data->len = st.st_size;
if (data->date == -1)
data->date = st.st_mtime;
data->data = nfmalloc( data->len ); data->data = nfmalloc( data->len );
if (read( fd, data->data, data->len ) != data->len) { if (read( fd, data->data, data->len ) != data->len) {
sys_error( "Maildir error: cannot read %s", buf ); 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 ); cb( DRV_BOX_BAD, 0, aux );
return; 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. */ /* 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 ); nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%s%s", box, subdirs[!(data->flags & F_SEEN)], base, fbuf );
if (rename( buf, nbuf )) { if (rename( buf, nbuf )) {

View File

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

View File

@ -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. which in turn are overridden by command line switches.
.. ..
.TP .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} \fBSyncState\fR {\fB*\fR|\fIpath\fR}
Set the location of this Channel's synchronization state files. \fB*\fR means 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 that the state should be saved in a file named .mbsyncstate in the

View File

@ -281,6 +281,7 @@ copy_msg( copy_vars_t *vars )
t ^= 1; t ^= 1;
vars->data.flags = vars->msg->flags; 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 )); DRIVER_CALL_RET(fetch_msg( svars->ctx[t], vars->msg, &vars->data, msg_fetched, vars ));
} }