added MaxSize configuration variable
fixed --fast to work robustly without relying on the \Recent flag in messages
This commit is contained in:
parent
a8f9af4296
commit
0527181f45
50
ChangeLog
50
ChangeLog
|
@ -1,5 +1,55 @@
|
||||||
2000-12-21 Michael Elkins <me@sigipe.org>
|
2000-12-21 Michael Elkins <me@sigipe.org>
|
||||||
|
|
||||||
|
* imap.c, isync.h, maildir.c, sync.c:
|
||||||
|
RFC822.PEEK is obsolete in RFC2060. Use BODY.PEEK[] instead, which does
|
||||||
|
the same thing
|
||||||
|
|
||||||
|
keep track of the uidvalidity so isync can detect if the mailbox on the
|
||||||
|
server has changed since the last sync.
|
||||||
|
|
||||||
|
* NEWS: updated NEWS for 0.3 release
|
||||||
|
|
||||||
|
* Makefile.am, isync.spec:
|
||||||
|
added support for building RPMS
|
||||||
|
|
||||||
|
* Makefile.am, isync.1:
|
||||||
|
added target for creating html version of the man page
|
||||||
|
|
||||||
|
documented the imaps: prefix to the Host command
|
||||||
|
|
||||||
|
* imap.c, sync.c:
|
||||||
|
can't assume flag order when fetching a message. just search for the
|
||||||
|
first `{' to find the message size.
|
||||||
|
|
||||||
|
* isync.1, sync.c:
|
||||||
|
added BUGS section to manpage detailing the fact that we break the
|
||||||
|
maildir(5) spec by parsing the filename
|
||||||
|
|
||||||
|
change message delivery to use the method described in maildir(5)
|
||||||
|
|
||||||
|
* configure.in, main.c, sync.c:
|
||||||
|
use getpass() to get the user's password
|
||||||
|
|
||||||
|
unlink the temp file if we are unable to fetch a new message from the
|
||||||
|
server.
|
||||||
|
|
||||||
|
update version to 0.3
|
||||||
|
|
||||||
|
* isync.1: fixed typo in man page for --verbose option
|
||||||
|
|
||||||
|
* Makefile.am, README, TODO, imap.c, isync.h, list.c:
|
||||||
|
added generic IMAP list parser and rewrote imap_exec() to handle
|
||||||
|
arbitrary data instead of hardcoded
|
||||||
|
|
||||||
|
* Makefile.am, README, configure.in, main.c:
|
||||||
|
fixes to compile cleanly under Solaris 2.7
|
||||||
|
|
||||||
|
* configure.in, imap.c, isync.1, isync.h, main.c:
|
||||||
|
added OpenSSL support
|
||||||
|
|
||||||
|
* ChangeLog, configure.in, main.c:
|
||||||
|
config options were not case insensitive
|
||||||
|
|
||||||
* imap.c, isync.h, maildir.c, main.c, sync.c:
|
* imap.c, isync.h, maildir.c, main.c, sync.c:
|
||||||
don't fetch deleted messages when expunging
|
don't fetch deleted messages when expunging
|
||||||
|
|
||||||
|
|
14
NEWS
14
NEWS
|
@ -1,3 +1,17 @@
|
||||||
|
[0.4]
|
||||||
|
|
||||||
|
Added MaxSize configuration option to limit downloading of new messages from
|
||||||
|
the server to less than some threshold.
|
||||||
|
|
||||||
|
More robust --fast option works without using \Recent flags, so the previous
|
||||||
|
problem with multiple accesses killing these flags is no longer a problem.
|
||||||
|
|
||||||
|
RFC2060 obsoleted RFC822.PEEK, use BODY.PEEK[] instead which does the same
|
||||||
|
job.
|
||||||
|
|
||||||
|
Don't need to request UID in a FETCH when doing UID FETCH (RFC2060 states
|
||||||
|
that its automatically returned).
|
||||||
|
|
||||||
[0.3]
|
[0.3]
|
||||||
|
|
||||||
Fixed to clean up temp maildir files when the fetch of a new message failed.
|
Fixed to clean up temp maildir files when the fetch of a new message failed.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
AC_INIT(isync.h)
|
AC_INIT(isync.h)
|
||||||
AM_INIT_AUTOMAKE(isync,0.3)
|
AM_INIT_AUTOMAKE(isync,0.4)
|
||||||
AM_PROG_CC_STDC
|
AM_PROG_CC_STDC
|
||||||
if test $CC = gcc; then
|
if test $CC = gcc; then
|
||||||
CFLAGS="$CFLAGS -pipe"
|
CFLAGS="$CFLAGS -pipe"
|
||||||
|
|
159
imap.c
159
imap.c
|
@ -150,9 +150,13 @@ buffer_gets (buffer_t * b, char **s)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_fetch (imap_t * imap, list_t * list, message_t * cur)
|
parse_fetch (imap_t * imap, list_t * list)
|
||||||
{
|
{
|
||||||
list_t *tmp;
|
list_t *tmp;
|
||||||
|
unsigned int uid = 0;
|
||||||
|
unsigned int mask = 0;
|
||||||
|
unsigned int size = 0;
|
||||||
|
message_t *cur;
|
||||||
|
|
||||||
if (!is_list (list))
|
if (!is_list (list))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -165,7 +169,14 @@ parse_fetch (imap_t * imap, list_t * list, message_t * cur)
|
||||||
{
|
{
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
if (is_atom (tmp))
|
if (is_atom (tmp))
|
||||||
cur->uid = atoi (tmp->val);
|
{
|
||||||
|
uid = atoi (tmp->val);
|
||||||
|
if (uid < imap->minuid)
|
||||||
|
{
|
||||||
|
/* already saw this message */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
puts ("Error, unable to parse UID");
|
puts ("Error, unable to parse UID");
|
||||||
}
|
}
|
||||||
|
@ -181,20 +192,17 @@ parse_fetch (imap_t * imap, list_t * list, message_t * cur)
|
||||||
if (is_atom (flags))
|
if (is_atom (flags))
|
||||||
{
|
{
|
||||||
if (!strcmp ("\\Seen", flags->val))
|
if (!strcmp ("\\Seen", flags->val))
|
||||||
cur->flags |= D_SEEN;
|
mask |= D_SEEN;
|
||||||
else if (!strcmp ("\\Flagged", flags->val))
|
else if (!strcmp ("\\Flagged", flags->val))
|
||||||
cur->flags |= D_FLAGGED;
|
mask |= D_FLAGGED;
|
||||||
else if (!strcmp ("\\Deleted", flags->val))
|
else if (!strcmp ("\\Deleted", flags->val))
|
||||||
{
|
mask |= D_DELETED;
|
||||||
cur->flags |= D_DELETED;
|
|
||||||
imap->deleted++;
|
|
||||||
}
|
|
||||||
else if (!strcmp ("\\Answered", flags->val))
|
else if (!strcmp ("\\Answered", flags->val))
|
||||||
cur->flags |= D_ANSWERED;
|
mask |= D_ANSWERED;
|
||||||
else if (!strcmp ("\\Draft", flags->val))
|
else if (!strcmp ("\\Draft", flags->val))
|
||||||
cur->flags |= D_DRAFT;
|
mask |= D_DRAFT;
|
||||||
else if (!strcmp ("\\Recent", flags->val))
|
else if (!strcmp ("\\Recent", flags->val))
|
||||||
cur->flags |= D_RECENT;
|
mask |= D_RECENT;
|
||||||
else
|
else
|
||||||
printf ("Warning, unknown flag %s\n",
|
printf ("Warning, unknown flag %s\n",
|
||||||
flags->val);
|
flags->val);
|
||||||
|
@ -206,8 +214,26 @@ parse_fetch (imap_t * imap, list_t * list, message_t * cur)
|
||||||
else
|
else
|
||||||
puts ("Error, unable to parse FLAGS");
|
puts ("Error, unable to parse FLAGS");
|
||||||
}
|
}
|
||||||
|
else if (!strcmp ("RFC822.SIZE", tmp->val))
|
||||||
|
{
|
||||||
|
tmp = tmp->next;
|
||||||
|
if (is_atom (tmp))
|
||||||
|
size = atol (tmp->val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = calloc (1, sizeof (message_t));
|
||||||
|
cur->next = imap->msgs;
|
||||||
|
imap->msgs = cur;
|
||||||
|
|
||||||
|
if (mask & D_DELETED)
|
||||||
|
imap->deleted++;
|
||||||
|
|
||||||
|
cur->uid = uid;
|
||||||
|
cur->flags = mask;
|
||||||
|
cur->size = size;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,8 +272,6 @@ imap_exec (imap_t * imap, const char *fmt, ...)
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char *arg;
|
char *arg;
|
||||||
char *arg1;
|
char *arg1;
|
||||||
message_t **cur = 0;
|
|
||||||
message_t **rec = 0;
|
|
||||||
|
|
||||||
va_start (ap, fmt);
|
va_start (ap, fmt);
|
||||||
vsnprintf (tmp, sizeof (tmp), fmt, ap);
|
vsnprintf (tmp, sizeof (tmp), fmt, ap);
|
||||||
|
@ -281,22 +305,6 @@ imap_exec (imap_t * imap, const char *fmt, ...)
|
||||||
imap->ns_other = parse_list (cmd, &cmd);
|
imap->ns_other = parse_list (cmd, &cmd);
|
||||||
imap->ns_shared = parse_list (cmd, 0);
|
imap->ns_shared = parse_list (cmd, 0);
|
||||||
}
|
}
|
||||||
else if (!strcmp ("SEARCH", arg))
|
|
||||||
{
|
|
||||||
if (!rec)
|
|
||||||
{
|
|
||||||
rec = &imap->recent_msgs;
|
|
||||||
while (*rec)
|
|
||||||
rec = &(*rec)->next;
|
|
||||||
}
|
|
||||||
/* parse rest of `cmd' */
|
|
||||||
while ((arg = next_arg (&cmd)))
|
|
||||||
{
|
|
||||||
*rec = calloc (1, sizeof (message_t));
|
|
||||||
(*rec)->uid = atoi (arg);
|
|
||||||
rec = &(*rec)->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!strcmp ("OK", arg) || !strcmp ("BAD", arg) ||
|
else if (!strcmp ("OK", arg) || !strcmp ("BAD", arg) ||
|
||||||
!strcmp ("NO", arg) || !strcmp ("PREAUTH", arg) ||
|
!strcmp ("NO", arg) || !strcmp ("PREAUTH", arg) ||
|
||||||
!strcmp ("BYE", arg))
|
!strcmp ("BYE", arg))
|
||||||
|
@ -313,25 +321,15 @@ imap_exec (imap_t * imap, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
list_t *list;
|
list_t *list;
|
||||||
|
|
||||||
if (!cur)
|
|
||||||
{
|
|
||||||
cur = &imap->msgs;
|
|
||||||
while (*cur)
|
|
||||||
cur = &(*cur)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
list = parse_list (cmd, 0);
|
list = parse_list (cmd, 0);
|
||||||
|
|
||||||
*cur = calloc (1, sizeof (message_t));
|
if (parse_fetch (imap, list))
|
||||||
if (parse_fetch (imap, list, *cur))
|
|
||||||
{
|
{
|
||||||
free_list (list);
|
free_list (list);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_list (list);
|
free_list (list);
|
||||||
|
|
||||||
cur = &(*cur)->next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -357,66 +355,20 @@ imap_exec (imap_t * imap, const char *fmt, ...)
|
||||||
/* not reached */
|
/* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/* `box' is the config info for the maildrop to sync. `minuid' is the
|
||||||
fetch_recent_flags (imap_t * imap)
|
* minimum UID to consider. in normal mode this will be 1, but in --fast
|
||||||
{
|
* mode we only fetch messages newer than the last one seen in the local
|
||||||
char buf[1024];
|
* mailbox.
|
||||||
message_t **cur = &imap->recent_msgs;
|
*/
|
||||||
message_t *tmp;
|
|
||||||
unsigned int start = -1;
|
|
||||||
unsigned int last = -1;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
buf[0] = 0;
|
|
||||||
while (*cur)
|
|
||||||
{
|
|
||||||
tmp = *cur;
|
|
||||||
|
|
||||||
if (last == (unsigned int) -1)
|
|
||||||
{
|
|
||||||
/* init */
|
|
||||||
start = tmp->uid;
|
|
||||||
last = tmp->uid;
|
|
||||||
}
|
|
||||||
else if (tmp->uid == last + 1)
|
|
||||||
last++;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* out of sequence */
|
|
||||||
if (start == last)
|
|
||||||
ret = imap_exec (imap, "UID FETCH %d (UID FLAGS)", start);
|
|
||||||
else
|
|
||||||
ret =
|
|
||||||
imap_exec (imap, "UID FETCH %d:%d (UID FLAGS)", start,
|
|
||||||
last);
|
|
||||||
start = tmp->uid;
|
|
||||||
last = tmp->uid;
|
|
||||||
}
|
|
||||||
free (tmp);
|
|
||||||
*cur = (*cur)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start != (unsigned int) -1)
|
|
||||||
{
|
|
||||||
if (start == last)
|
|
||||||
ret = imap_exec (imap, "UID FETCH %d (UID FLAGS)", start);
|
|
||||||
else
|
|
||||||
ret =
|
|
||||||
imap_exec (imap, "UID FETCH %d:%d (UID FLAGS)", start, last);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
imap_t *
|
imap_t *
|
||||||
imap_open (config_t * box, int fast)
|
imap_open (config_t * box, unsigned int minuid)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
imap_t *imap;
|
imap_t *imap;
|
||||||
int s;
|
int s;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
struct hostent *he;
|
struct hostent *he;
|
||||||
char *ns_prefix = 0;
|
char *ns_prefix = "";
|
||||||
#if HAVE_LIBSSL
|
#if HAVE_LIBSSL
|
||||||
int use_ssl = 0;
|
int use_ssl = 0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -463,6 +415,7 @@ imap_open (config_t * box, int fast)
|
||||||
imap->buf = calloc (1, sizeof (buffer_t));
|
imap->buf = calloc (1, sizeof (buffer_t));
|
||||||
imap->buf->sock = imap->sock;
|
imap->buf->sock = imap->sock;
|
||||||
imap->box = box;
|
imap->box = box;
|
||||||
|
imap->minuid = minuid;
|
||||||
|
|
||||||
#if HAVE_LIBSSL
|
#if HAVE_LIBSSL
|
||||||
if (!box->use_imaps)
|
if (!box->use_imaps)
|
||||||
|
@ -520,28 +473,18 @@ imap_open (config_t * box, int fast)
|
||||||
{
|
{
|
||||||
fputs ("Selecting mailbox... ", stdout);
|
fputs ("Selecting mailbox... ", stdout);
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
ret = imap_exec (imap, "SELECT %s%s",
|
ret = imap_exec (imap, "SELECT %s%s", ns_prefix, box->box);
|
||||||
ns_prefix ? ns_prefix : "", box->box);
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
printf ("%d messages, %d recent\n", imap->count, imap->recent);
|
printf ("%d messages, %d recent\n", imap->count, imap->recent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
|
||||||
if (fast)
|
|
||||||
{
|
|
||||||
if (imap->recent > 0)
|
|
||||||
{
|
|
||||||
puts ("Fetching info for recent messages");
|
|
||||||
ret = imap_exec (imap, "UID SEARCH RECENT");
|
|
||||||
if (!ret)
|
|
||||||
ret = fetch_recent_flags (imap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (imap->count > 0)
|
|
||||||
{
|
{
|
||||||
puts ("Reading IMAP mailbox index");
|
puts ("Reading IMAP mailbox index");
|
||||||
ret = imap_exec (imap, "FETCH 1:%d (UID FLAGS)", imap->count);
|
if (imap->count > 0)
|
||||||
|
{
|
||||||
|
ret = imap_exec (imap, "UID FETCH %d:* (FLAGS RFC822.SIZE)",
|
||||||
|
imap->minuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
isync.1
15
isync.1
|
@ -66,12 +66,6 @@ Causes
|
||||||
to skip the step of synchronzing message flags between the local maildir
|
to skip the step of synchronzing message flags between the local maildir
|
||||||
mailbox and the IMAP mailbox. Only new messages existing on the server will
|
mailbox and the IMAP mailbox. Only new messages existing on the server will
|
||||||
be fetched into the local mailbox.
|
be fetched into the local mailbox.
|
||||||
.B NOTE:
|
|
||||||
This command works by checking the \\Recent flag on messages in the IMAP
|
|
||||||
mailbox. If you access the IMAP mailbox from multiple locations, the
|
|
||||||
\\Recent flag will be lost between sessions, so you must do a full
|
|
||||||
synchronization to fetch the messages which do not exist in the local
|
|
||||||
mailbox.
|
|
||||||
.TP
|
.TP
|
||||||
.B -h, --help
|
.B -h, --help
|
||||||
Displays a summary of command line options
|
Displays a summary of command line options
|
||||||
|
@ -158,6 +152,15 @@ Defines an alias for the mailbox which can be used as a shortcut on the
|
||||||
command line.
|
command line.
|
||||||
..
|
..
|
||||||
.TP
|
.TP
|
||||||
|
\fBMaxSize\fR \fIbytes\fR
|
||||||
|
Sets a threshold for the maximum message size (in bytes) for which
|
||||||
|
.B isync
|
||||||
|
should fetch from the server. This is useful for weeding out messages with
|
||||||
|
large attachments. If
|
||||||
|
.I bytes
|
||||||
|
is 0, the maximum file size is
|
||||||
|
.B unlimited.
|
||||||
|
.TP
|
||||||
\fBRequireSSL\fR \fIyes|no\fR
|
\fBRequireSSL\fR \fIyes|no\fR
|
||||||
.B isync
|
.B isync
|
||||||
will abort the connection if a TLS/SSL session to the IMAP
|
will abort the connection if a TLS/SSL session to the IMAP
|
||||||
|
|
17
isync.h
17
isync.h
|
@ -54,6 +54,7 @@ struct config
|
||||||
char *pass;
|
char *pass;
|
||||||
char *box;
|
char *box;
|
||||||
char *alias;
|
char *alias;
|
||||||
|
unsigned int max_size;
|
||||||
config_t *next;
|
config_t *next;
|
||||||
#if HAVE_LIBSSL
|
#if HAVE_LIBSSL
|
||||||
char *cert_file;
|
char *cert_file;
|
||||||
|
@ -69,7 +70,9 @@ struct mailbox
|
||||||
message_t *msgs;
|
message_t *msgs;
|
||||||
unsigned int deleted; /* # of deleted messages */
|
unsigned int deleted; /* # of deleted messages */
|
||||||
unsigned int uidvalidity;
|
unsigned int uidvalidity;
|
||||||
|
unsigned int maxuid; /* largest uid we know about */
|
||||||
unsigned int changed:1;
|
unsigned int changed:1;
|
||||||
|
unsigned int maxuidchanged:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* message dispositions */
|
/* message dispositions */
|
||||||
|
@ -86,6 +89,7 @@ struct message
|
||||||
char *file;
|
char *file;
|
||||||
unsigned int uid;
|
unsigned int uid;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
unsigned int size;
|
||||||
message_t *next;
|
message_t *next;
|
||||||
unsigned int processed:1; /* message has already been evaluated */
|
unsigned int processed:1; /* message has already been evaluated */
|
||||||
unsigned int new:1; /* message is in the new/ subdir */
|
unsigned int new:1; /* message is in the new/ subdir */
|
||||||
|
@ -119,6 +123,8 @@ typedef struct
|
||||||
*/
|
*/
|
||||||
unsigned int deleted; /* # of deleted messages */
|
unsigned int deleted; /* # of deleted messages */
|
||||||
unsigned int uidvalidity;
|
unsigned int uidvalidity;
|
||||||
|
unsigned int maxuid;
|
||||||
|
unsigned int minuid;
|
||||||
/* NAMESPACE info */
|
/* NAMESPACE info */
|
||||||
list_t *ns_personal;
|
list_t *ns_personal;
|
||||||
list_t *ns_other;
|
list_t *ns_other;
|
||||||
|
@ -127,9 +133,8 @@ typedef struct
|
||||||
imap_t;
|
imap_t;
|
||||||
|
|
||||||
/* flags for sync_mailbox */
|
/* flags for sync_mailbox */
|
||||||
#define SYNC_FAST (1<<0) /* don't sync flags, only fetch new msgs */
|
#define SYNC_DELETE (1<<0) /* delete local that don't exist on server */
|
||||||
#define SYNC_DELETE (1<<1) /* delete local that don't exist on server */
|
#define SYNC_EXPUNGE (1<<1) /* don't fetch deleted messages */
|
||||||
#define SYNC_EXPUNGE (1<<2) /* don't fetch deleted messages */
|
|
||||||
|
|
||||||
extern config_t global;
|
extern config_t global;
|
||||||
extern unsigned int Tag;
|
extern unsigned int Tag;
|
||||||
|
@ -142,19 +147,21 @@ extern SSL_CTX *SSLContext;
|
||||||
|
|
||||||
char *next_arg (char **);
|
char *next_arg (char **);
|
||||||
|
|
||||||
int sync_mailbox (mailbox_t *, imap_t *, int);
|
int sync_mailbox (mailbox_t *, imap_t *, int, unsigned int);
|
||||||
|
|
||||||
void imap_close (imap_t *);
|
void imap_close (imap_t *);
|
||||||
int imap_fetch_message (imap_t *, unsigned int, int);
|
int imap_fetch_message (imap_t *, unsigned int, int);
|
||||||
int imap_set_flags (imap_t *, unsigned int, unsigned int);
|
int imap_set_flags (imap_t *, unsigned int, unsigned int);
|
||||||
int imap_expunge (imap_t *);
|
int imap_expunge (imap_t *);
|
||||||
imap_t *imap_open (config_t *, int);
|
imap_t *imap_open (config_t *, unsigned int);
|
||||||
|
|
||||||
mailbox_t *maildir_open (const char *, int fast);
|
mailbox_t *maildir_open (const char *, int fast);
|
||||||
int maildir_expunge (mailbox_t *, int);
|
int maildir_expunge (mailbox_t *, int);
|
||||||
int maildir_sync (mailbox_t *);
|
int maildir_sync (mailbox_t *);
|
||||||
int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity);
|
int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity);
|
||||||
|
|
||||||
|
message_t * find_msg (message_t * list, unsigned int uid);
|
||||||
|
|
||||||
/* parse an IMAP list construct */
|
/* parse an IMAP list construct */
|
||||||
list_t * parse_list (char *s, char **end);
|
list_t * parse_list (char *s, char **end);
|
||||||
int is_atom (list_t *list);
|
int is_atom (list_t *list);
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
User me
|
User me
|
||||||
#Port 143
|
#Port 143
|
||||||
#Box INBOX
|
#Box INBOX
|
||||||
|
# don't download messages larger than 200K bytes
|
||||||
|
MaxSize 200000
|
||||||
|
|
||||||
###
|
###
|
||||||
### work mailbox
|
### work mailbox
|
||||||
|
|
174
maildir.c
174
maildir.c
|
@ -25,8 +25,38 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "isync.h"
|
#include "isync.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_lock (int fd, int flag)
|
||||||
|
{
|
||||||
|
struct flock lck;
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (fstat (fd, &sb))
|
||||||
|
{
|
||||||
|
perror ("fstat");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (&lck, 0, sizeof (lck));
|
||||||
|
lck.l_type = flag;
|
||||||
|
lck.l_whence = SEEK_SET;
|
||||||
|
lck.l_start = 0;
|
||||||
|
lck.l_len = sb.st_size;
|
||||||
|
|
||||||
|
if (fcntl (fd, F_SETLK, &lck))
|
||||||
|
{
|
||||||
|
perror ("fcntl");
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* 2,<flags> */
|
/* 2,<flags> */
|
||||||
static void
|
static void
|
||||||
parse_info (message_t * m, char *s)
|
parse_info (message_t * m, char *s)
|
||||||
|
@ -49,6 +79,45 @@ parse_info (message_t * m, char *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
read_uid (const char *path, const char *file)
|
||||||
|
{
|
||||||
|
char full[_POSIX_PATH_MAX];
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
int len;
|
||||||
|
char buf[64];
|
||||||
|
unsigned int uid = 0;
|
||||||
|
|
||||||
|
snprintf (full, sizeof (full), "%s/%s", path, file);
|
||||||
|
fd = open (full, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
if (errno != ENOENT)
|
||||||
|
{
|
||||||
|
perror ("open");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0; /* doesn't exist */
|
||||||
|
}
|
||||||
|
ret = do_lock (fd, F_RDLCK);
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
len = read (fd, buf, sizeof (buf) - 1);
|
||||||
|
if (len == -1)
|
||||||
|
ret = -1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buf[len] = 0;
|
||||||
|
uid = atol (buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret |= do_lock (fd, F_UNLCK);
|
||||||
|
close (fd);
|
||||||
|
return ret ? ret : uid;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* open a maildir mailbox. if `fast' is nonzero, we just check to make
|
/* open a maildir mailbox. if `fast' is nonzero, we just check to make
|
||||||
* sure its a valid mailbox and don't actually parse it. any IMAP messages
|
* sure its a valid mailbox and don't actually parse it. any IMAP messages
|
||||||
* with the \Recent flag set are guaranteed not to be in the mailbox yet,
|
* with the \Recent flag set are guaranteed not to be in the mailbox yet,
|
||||||
|
@ -66,7 +135,6 @@ maildir_open (const char *path, int fast)
|
||||||
mailbox_t *m;
|
mailbox_t *m;
|
||||||
char *s;
|
char *s;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
/* check to make sure this looks like a valid maildir box */
|
/* check to make sure this looks like a valid maildir box */
|
||||||
snprintf (buf, sizeof (buf), "%s/new", path);
|
snprintf (buf, sizeof (buf), "%s/new", path);
|
||||||
|
@ -84,16 +152,22 @@ maildir_open (const char *path, int fast)
|
||||||
|
|
||||||
m = calloc (1, sizeof (mailbox_t));
|
m = calloc (1, sizeof (mailbox_t));
|
||||||
m->path = strdup (path);
|
m->path = strdup (path);
|
||||||
m->uidvalidity = -1;
|
|
||||||
|
|
||||||
/* check for the uidvalidity value */
|
/* check for the uidvalidity value */
|
||||||
snprintf (buf, sizeof (buf), "%s/isyncuidvalidity", path);
|
m->uidvalidity = read_uid (path, "isyncuidvalidity");
|
||||||
if ((fp = fopen (buf, "r")))
|
if (m->uidvalidity == (unsigned int) -1)
|
||||||
{
|
{
|
||||||
buf[sizeof (buf) - 1] = 0;
|
free (m->path);
|
||||||
if (fgets (buf, sizeof (buf) - 1, fp))
|
free (m);
|
||||||
m->uidvalidity = atol (buf);
|
return NULL;
|
||||||
fclose (fp);
|
}
|
||||||
|
|
||||||
|
/* load the current maxuid */
|
||||||
|
if ((m->maxuid = read_uid (path, "isyncmaxuid")) == (unsigned int) -1)
|
||||||
|
{
|
||||||
|
free (m->path);
|
||||||
|
free (m);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fast)
|
if (fast)
|
||||||
|
@ -108,6 +182,8 @@ maildir_open (const char *path, int fast)
|
||||||
d = opendir (buf);
|
d = opendir (buf);
|
||||||
if (!d)
|
if (!d)
|
||||||
{
|
{
|
||||||
|
free (m->path);
|
||||||
|
free (m);
|
||||||
perror ("opendir");
|
perror ("opendir");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -130,10 +206,15 @@ maildir_open (const char *path, int fast)
|
||||||
*/
|
*/
|
||||||
s = strstr (p->file, "UID");
|
s = strstr (p->file, "UID");
|
||||||
if (!s)
|
if (!s)
|
||||||
puts ("warning, no uid for message");
|
puts ("Warning, no uid for message");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p->uid = strtol (s + 3, &s, 10);
|
p->uid = strtol (s + 3, &s, 10);
|
||||||
|
if (p->uid > m->maxuid)
|
||||||
|
{
|
||||||
|
m->maxuid = p->uid;
|
||||||
|
m->maxuidchanged = 1;
|
||||||
|
}
|
||||||
if (*s && *s != ':')
|
if (*s && *s != ':')
|
||||||
{
|
{
|
||||||
puts ("warning, unable to parse uid");
|
puts ("warning, unable to parse uid");
|
||||||
|
@ -183,6 +264,70 @@ maildir_expunge (mailbox_t * mbox, int dead)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
update_maxuid (mailbox_t * mbox)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[64];
|
||||||
|
size_t len;
|
||||||
|
unsigned int uid;
|
||||||
|
char path[_POSIX_PATH_MAX];
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
snprintf (path, sizeof (path), "%s/isyncmaxuid", mbox->path);
|
||||||
|
fd = open (path, O_RDWR | O_CREAT, 0600);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
perror ("open");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lock the file */
|
||||||
|
if (do_lock (fd, F_WRLCK))
|
||||||
|
{
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read the file again just to make sure it wasn't updated while
|
||||||
|
* we were doing something else
|
||||||
|
*/
|
||||||
|
len = read (fd, buf, sizeof (buf) - 1);
|
||||||
|
buf[len] = 0;
|
||||||
|
uid = atol (buf);
|
||||||
|
if (uid > mbox->maxuid)
|
||||||
|
{
|
||||||
|
puts ("Error, maxuid is now higher (fatal)");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
/* rewind */
|
||||||
|
lseek (fd, 0, SEEK_SET);
|
||||||
|
|
||||||
|
/* write out the file */
|
||||||
|
snprintf (buf, sizeof (buf), "%u\n", mbox->maxuid);
|
||||||
|
len = write (fd, buf, strlen (buf));
|
||||||
|
if (len == (size_t) - 1)
|
||||||
|
{
|
||||||
|
perror ("write");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = ftruncate (fd, len);
|
||||||
|
if (ret)
|
||||||
|
perror ("ftruncate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= do_lock (fd, F_UNLCK);
|
||||||
|
ret |= close (fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
maildir_sync (mailbox_t * mbox)
|
maildir_sync (mailbox_t * mbox)
|
||||||
{
|
{
|
||||||
|
@ -190,6 +335,7 @@ maildir_sync (mailbox_t * mbox)
|
||||||
char path[_POSIX_PATH_MAX];
|
char path[_POSIX_PATH_MAX];
|
||||||
char oldpath[_POSIX_PATH_MAX];
|
char oldpath[_POSIX_PATH_MAX];
|
||||||
char *p;
|
char *p;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (mbox->changed)
|
if (mbox->changed)
|
||||||
{
|
{
|
||||||
|
@ -219,7 +365,11 @@ maildir_sync (mailbox_t * mbox)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
if (mbox->maxuidchanged)
|
||||||
|
ret = update_maxuid (mbox);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -242,7 +392,7 @@ maildir_set_uidvalidity (mailbox_t * mbox, unsigned int uidvalidity)
|
||||||
ret = write (fd, buf, strlen (buf));
|
ret = write (fd, buf, strlen (buf));
|
||||||
|
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
perror("write");
|
perror ("write");
|
||||||
else if ((size_t) ret != strlen (buf))
|
else if ((size_t) ret != strlen (buf))
|
||||||
ret = -1;
|
ret = -1;
|
||||||
else
|
else
|
||||||
|
@ -250,7 +400,7 @@ maildir_set_uidvalidity (mailbox_t * mbox, unsigned int uidvalidity)
|
||||||
|
|
||||||
if (close (fd))
|
if (close (fd))
|
||||||
{
|
{
|
||||||
perror("close");
|
perror ("close");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
main.c
19
main.c
|
@ -95,6 +95,7 @@ config_defaults (config_t * conf)
|
||||||
conf->port = global.port;
|
conf->port = global.port;
|
||||||
conf->box = global.box;
|
conf->box = global.box;
|
||||||
conf->host = global.host;
|
conf->host = global.host;
|
||||||
|
conf->max_size = global.max_size;
|
||||||
#if HAVE_LIBSSL
|
#if HAVE_LIBSSL
|
||||||
conf->require_ssl = global.require_ssl;
|
conf->require_ssl = global.require_ssl;
|
||||||
conf->use_imaps = global.use_imaps;
|
conf->use_imaps = global.use_imaps;
|
||||||
|
@ -206,6 +207,13 @@ load_config (char *where)
|
||||||
if (*cur)
|
if (*cur)
|
||||||
(*cur)->alias = strdup (p);
|
(*cur)->alias = strdup (p);
|
||||||
}
|
}
|
||||||
|
else if (!strncasecmp ("maxsize", buf, 7))
|
||||||
|
{
|
||||||
|
if (*cur)
|
||||||
|
(*cur)->max_size = atol (p);
|
||||||
|
else
|
||||||
|
global.max_size = atol (p);
|
||||||
|
}
|
||||||
#if HAVE_LIBSSL
|
#if HAVE_LIBSSL
|
||||||
else if (!strncasecmp ("CertificateFile", buf, 15))
|
else if (!strncasecmp ("CertificateFile", buf, 15))
|
||||||
{
|
{
|
||||||
|
@ -285,6 +293,7 @@ main (int argc, char **argv)
|
||||||
global.port = 143;
|
global.port = 143;
|
||||||
global.box = "INBOX";
|
global.box = "INBOX";
|
||||||
global.user = strdup (pw->pw_name);
|
global.user = strdup (pw->pw_name);
|
||||||
|
global.max_size = 100000;
|
||||||
#if HAVE_LIBSSL
|
#if HAVE_LIBSSL
|
||||||
/* this will probably annoy people, but its the best default just in
|
/* this will probably annoy people, but its the best default just in
|
||||||
* case people forget to turn it on
|
* case people forget to turn it on
|
||||||
|
@ -380,16 +389,14 @@ main (int argc, char **argv)
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
imap = imap_open (box, fast);
|
imap = imap_open (box, fast ? mail->maxuid + 1 : 1);
|
||||||
if (!imap)
|
if (!imap)
|
||||||
exit (1);
|
exit (1);
|
||||||
|
|
||||||
puts ("Synchronizing");
|
puts ("Synchronizing");
|
||||||
i = 0;
|
i = delete ? SYNC_DELETE : 0;
|
||||||
i |= (fast) ? SYNC_FAST : 0;
|
i |= expunge ? SYNC_EXPUNGE : 0;
|
||||||
i |= (delete) ? SYNC_DELETE : 0;
|
if (sync_mailbox (mail, imap, i, box->max_size))
|
||||||
i |= (expunge) ? SYNC_EXPUNGE : 0;
|
|
||||||
if (sync_mailbox (mail, imap, i))
|
|
||||||
exit (1);
|
exit (1);
|
||||||
|
|
||||||
if (!fast)
|
if (!fast)
|
||||||
|
|
26
sync.c
26
sync.c
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
static unsigned int MaildirCount = 0;
|
static unsigned int MaildirCount = 0;
|
||||||
|
|
||||||
static message_t *
|
message_t *
|
||||||
find_msg (message_t * list, unsigned int uid)
|
find_msg (message_t * list, unsigned int uid)
|
||||||
{
|
{
|
||||||
for (; list; list = list->next)
|
for (; list; list = list->next)
|
||||||
|
@ -41,7 +41,7 @@ find_msg (message_t * list, unsigned int uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
|
sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, unsigned int max_size)
|
||||||
{
|
{
|
||||||
message_t *cur;
|
message_t *cur;
|
||||||
message_t *tmp;
|
message_t *tmp;
|
||||||
|
@ -69,12 +69,21 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mbox->maxuid == (unsigned int) -1 || imap->maxuid > mbox->maxuid)
|
||||||
|
{
|
||||||
|
mbox->maxuid = imap->maxuid;
|
||||||
|
mbox->maxuidchanged = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we are --fast mode, the mailbox wont have been loaded, so
|
||||||
|
* this next step is skipped.
|
||||||
|
*/
|
||||||
for (cur = mbox->msgs; cur; cur = cur->next)
|
for (cur = mbox->msgs; cur; cur = cur->next)
|
||||||
{
|
{
|
||||||
tmp = find_msg (imap->msgs, cur->uid);
|
tmp = find_msg (imap->msgs, cur->uid);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
{
|
{
|
||||||
printf ("warning, uid %d doesn't exist on server\n", cur->uid);
|
printf ("Warning, uid %d doesn't exist on server\n", cur->uid);
|
||||||
if (flags & SYNC_DELETE)
|
if (flags & SYNC_DELETE)
|
||||||
{
|
{
|
||||||
cur->flags |= D_DELETED;
|
cur->flags |= D_DELETED;
|
||||||
|
@ -85,8 +94,6 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
|
||||||
}
|
}
|
||||||
tmp->processed = 1;
|
tmp->processed = 1;
|
||||||
|
|
||||||
if (!(flags & SYNC_FAST))
|
|
||||||
{
|
|
||||||
/* check if local flags are different from server flags.
|
/* check if local flags are different from server flags.
|
||||||
* ignore \Recent and \Draft
|
* ignore \Recent and \Draft
|
||||||
*/
|
*/
|
||||||
|
@ -105,7 +112,6 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
|
||||||
mbox->changed = 1;
|
mbox->changed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fputs ("Fetching new messages", stdout);
|
fputs ("Fetching new messages", stdout);
|
||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
|
@ -124,6 +130,13 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (max_size && cur->size > max_size)
|
||||||
|
{
|
||||||
|
printf ("Warning, message skipped because it is too big (%u)\n",
|
||||||
|
cur->size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* create new file */
|
/* create new file */
|
||||||
|
@ -150,7 +163,6 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags)
|
||||||
(cur->flags & D_ANSWERED) ? "R" : "",
|
(cur->flags & D_ANSWERED) ? "R" : "",
|
||||||
(cur->flags & D_SEEN) ? "S" : "",
|
(cur->flags & D_SEEN) ? "S" : "",
|
||||||
(cur->flags & D_DELETED) ? "T" : "");
|
(cur->flags & D_DELETED) ? "T" : "");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* give some visual feedback that something is happening */
|
/* give some visual feedback that something is happening */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user