updated year in copyright notice
the uid for each message in the maildir is now stored in a dbm database rather than the filename. this change was necessary because isync became confused if you copied a message to another folder, in which case the uid was invalid. as a result of the above change, isync now acquires a mutex on the mailbox to protect the dbm database from concurrent access. main() was reworked to continue gracefully when an error is encountered, and to always call maildir_close() so that the lock can be disabled, and the database closed.
This commit is contained in:
parent
2c648da5cf
commit
c121ec912f
|
@ -1,5 +1,8 @@
|
||||||
2001-11-20 me <me@sigpipe.org>
|
2001-11-20 me <me@sigpipe.org>
|
||||||
|
|
||||||
|
* ChangeLog, Makefile.am, isync.spec:
|
||||||
|
post 0.7-release commit
|
||||||
|
|
||||||
* Makefile.am, NEWS, isync.1, isync.h, maildir.c, main.c:
|
* Makefile.am, NEWS, isync.1, isync.h, maildir.c, main.c:
|
||||||
added --create/-C command line option to force creation of the local
|
added --create/-C command line option to force creation of the local
|
||||||
maildir-style mailbox if nonexistent
|
maildir-style mailbox if nonexistent
|
||||||
|
|
8
NEWS
8
NEWS
|
@ -1,3 +1,11 @@
|
||||||
|
[0.8]
|
||||||
|
|
||||||
|
IMPORTANT: In order to fix the problem where messages copied from one mailbox
|
||||||
|
to another were not uploaded to the new mailbox, the way Isync stores the UID
|
||||||
|
for each message needed to be changed. As a result, you MUST delete all the
|
||||||
|
messages in the local maildir box before using this version. Otherwise it
|
||||||
|
will upload every message to the server thinking its a new mail.
|
||||||
|
|
||||||
[0.7]
|
[0.7]
|
||||||
|
|
||||||
Added `MaxMessages' configuration option to allow tracking of only the most
|
Added `MaxMessages' configuration option to allow tracking of only the most
|
||||||
|
|
2
TODO
2
TODO
|
@ -4,3 +4,5 @@ add support for syncing with other: and shared: via NAMESPACE
|
||||||
|
|
||||||
isync gets confused when new mail is delivered while in the middle of an
|
isync gets confused when new mail is delivered while in the middle of an
|
||||||
IMAP session. need to handled those asynchronous notifications properly.
|
IMAP session. need to handled those asynchronous notifications properly.
|
||||||
|
|
||||||
|
add a way to automatically create and sync IMAP subfolders.
|
||||||
|
|
2
config.c
2
config.c
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$
|
/* $Id$
|
||||||
*
|
*
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
* isync - IMAP4 to maildir mailbox synchronizer
|
||||||
* Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
AC_INIT(isync.h)
|
AC_INIT(isync.h)
|
||||||
AM_INIT_AUTOMAKE(isync,0.7)
|
AM_INIT_AUTOMAKE(isync,0.8)
|
||||||
AM_PROG_CC_STDC
|
AM_PROG_CC_STDC
|
||||||
AC_ARG_WITH(ssl-dir, [ --with-ssl-dir=DIR location where openssl is insalled],
|
AC_ARG_WITH(ssl-dir, [ --with-ssl-dir=DIR location where openssl is insalled],
|
||||||
[if test -d $withval/lib; then
|
[if test -d $withval/lib; then
|
||||||
|
@ -19,6 +19,7 @@ AC_CHECK_LIB(socket,socket)
|
||||||
AC_CHECK_LIB(nsl,inet_ntoa)
|
AC_CHECK_LIB(nsl,inet_ntoa)
|
||||||
AC_CHECK_LIB(crypto,ERR_error_string)
|
AC_CHECK_LIB(crypto,ERR_error_string)
|
||||||
AC_CHECK_LIB(ssl,SSL_library_init)
|
AC_CHECK_LIB(ssl,SSL_library_init)
|
||||||
|
AC_CHECK_LIB(db,db_create)
|
||||||
dnl test for gcc. use the prefix so we know that gcc-3.0 is also gcc
|
dnl test for gcc. use the prefix so we know that gcc-3.0 is also gcc
|
||||||
if test `echo $CC | sed 's/^gcc.*/gcc/'` = gcc; then
|
if test `echo $CC | sed 's/^gcc.*/gcc/'` = gcc; then
|
||||||
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wmissing-prototypes"
|
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wmissing-prototypes"
|
||||||
|
|
2
cram.c
2
cram.c
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$
|
/* $Id$
|
||||||
*
|
*
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
* isync - IMAP4 to maildir mailbox synchronizer
|
||||||
* Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
2
imap.c
2
imap.c
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$
|
/* $Id$
|
||||||
*
|
*
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
* isync - IMAP4 to maildir mailbox synchronizer
|
||||||
* Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
12
isync.1
12
isync.1
|
@ -1,6 +1,6 @@
|
||||||
.ig
|
.ig
|
||||||
\" isync - IMAP4 to maildir mailbox synchronizer
|
\" isync - IMAP4 to maildir mailbox synchronizer
|
||||||
\" Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>
|
\" Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
\"
|
\"
|
||||||
\" This program is free software; you can redistribute it and/or modify
|
\" This program is free software; you can redistribute it and/or modify
|
||||||
\" it under the terms of the GNU General Public License as published by
|
\" it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
\" along with this program; if not, write to the Free Software
|
\" along with this program; if not, write to the Free Software
|
||||||
\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
..
|
..
|
||||||
.TH isync 1 "2001 Nov 20"
|
.TH isync 1 "2002 Jan 16"
|
||||||
..
|
..
|
||||||
.SH NAME
|
.SH NAME
|
||||||
isync - synchronize IMAP4 and maildir mailboxes
|
isync - synchronize IMAP4 and maildir mailboxes
|
||||||
|
@ -304,13 +304,9 @@ will then use the global value by default.
|
||||||
Default configuration file
|
Default configuration file
|
||||||
..
|
..
|
||||||
.SH BUGS
|
.SH BUGS
|
||||||
maildir(5) states that readers should not attempt to parse the filename of a
|
|
||||||
a message other than the :info field. However, since
|
|
||||||
.B isync
|
.B isync
|
||||||
relies on using the message UIDs that info must be inserted into the
|
does not use NFS-safe locking. It will correctly prevent concurrent
|
||||||
filename in a way which will be interoperable with existing readers. So
|
synchronization of a mailbox on the same host, but not across NFS.
|
||||||
the UID is placed in the filename of the messages in the local maildir
|
|
||||||
mailbox rather than the :info field.
|
|
||||||
.P
|
.P
|
||||||
When synchronizing multiple mailboxes on the same IMAP server, it is not
|
When synchronizing multiple mailboxes on the same IMAP server, it is not
|
||||||
possible to select different SSL options for each mailbox. Only the options
|
possible to select different SSL options for each mailbox. Only the options
|
||||||
|
|
13
isync.h
13
isync.h
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$
|
/* $Id$
|
||||||
*
|
*
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
* isync - IMAP4 to maildir mailbox synchronizer
|
||||||
* Copyright (C) 2000 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,11 +18,14 @@
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define DB_DBM_HSEARCH 1
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#if HAVE_LIBSSL
|
#if HAVE_LIBSSL
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <db.h>
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -79,13 +82,13 @@ struct config
|
||||||
/* struct representing local mailbox file */
|
/* struct representing local mailbox file */
|
||||||
struct mailbox
|
struct mailbox
|
||||||
{
|
{
|
||||||
|
DBM *db;
|
||||||
char *path;
|
char *path;
|
||||||
message_t *msgs;
|
message_t *msgs;
|
||||||
|
int lockfd;
|
||||||
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 maxuid; /* largest uid we know about */
|
||||||
unsigned int changed:1;
|
|
||||||
unsigned int maxuidchanged:1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* message dispositions */
|
/* message dispositions */
|
||||||
|
@ -106,7 +109,6 @@ struct message
|
||||||
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 */
|
||||||
unsigned int changed:1; /* flags changed */
|
|
||||||
unsigned int dead:1; /* message doesn't exist on the server */
|
unsigned int dead:1; /* message doesn't exist on the server */
|
||||||
unsigned int wanted:1; /* when using MaxMessages, keep this message */
|
unsigned int wanted:1; /* when using MaxMessages, keep this message */
|
||||||
};
|
};
|
||||||
|
@ -191,7 +193,8 @@ int imap_append_message (imap_t *, int, message_t *);
|
||||||
mailbox_t *maildir_open (const char *, int flags);
|
mailbox_t *maildir_open (const char *, int flags);
|
||||||
int maildir_expunge (mailbox_t *, int);
|
int maildir_expunge (mailbox_t *, int);
|
||||||
int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity);
|
int maildir_set_uidvalidity (mailbox_t *, unsigned int uidvalidity);
|
||||||
int maildir_close (mailbox_t *);
|
void maildir_close (mailbox_t *);
|
||||||
|
int maildir_update_maxuid (mailbox_t * mbox);
|
||||||
|
|
||||||
message_t * find_msg (message_t * list, unsigned int uid);
|
message_t * find_msg (message_t * list, unsigned int uid);
|
||||||
void free_message (message_t *);
|
void free_message (message_t *);
|
||||||
|
|
2
list.c
2
list.c
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$
|
/* $Id$
|
||||||
*
|
*
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
* isync - IMAP4 to maildir mailbox synchronizer
|
||||||
* Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|
204
maildir.c
204
maildir.c
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$
|
/* $Id$
|
||||||
*
|
*
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
* isync - IMAP4 to maildir mailbox synchronizer
|
||||||
* Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -85,7 +85,7 @@ read_uid (const char *path, const char *file)
|
||||||
{
|
{
|
||||||
char full[_POSIX_PATH_MAX];
|
char full[_POSIX_PATH_MAX];
|
||||||
int fd;
|
int fd;
|
||||||
int ret;
|
int ret = 0;
|
||||||
int len;
|
int len;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
unsigned int uid = 0;
|
unsigned int uid = 0;
|
||||||
|
@ -96,29 +96,59 @@ read_uid (const char *path, const char *file)
|
||||||
{
|
{
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
{
|
{
|
||||||
perror ("open");
|
perror (full);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0; /* doesn't exist */
|
return 0; /* doesn't exist */
|
||||||
}
|
}
|
||||||
ret = do_lock (fd, F_RDLCK);
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
len = read (fd, buf, sizeof (buf) - 1);
|
len = read (fd, buf, sizeof (buf) - 1);
|
||||||
if (len == -1)
|
if (len == -1)
|
||||||
|
{
|
||||||
|
perror ("read");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
uid = atol (buf);
|
uid = atol (buf);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ret |= do_lock (fd, F_UNLCK);
|
|
||||||
close (fd);
|
close (fd);
|
||||||
return ret ? (unsigned int) ret : uid;
|
return ret ? (unsigned int) ret : uid;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NOTE: this is NOT NFS safe */
|
||||||
|
static int
|
||||||
|
maildir_lock (mailbox_t * m)
|
||||||
|
{
|
||||||
|
char path[_POSIX_PATH_MAX];
|
||||||
|
|
||||||
|
snprintf (path, sizeof (path), "%s/isynclock", m->path);
|
||||||
|
m->lockfd = open (path, O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR);
|
||||||
|
if (m->lockfd == -1)
|
||||||
|
{
|
||||||
|
perror (path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (do_lock (m->lockfd, F_WRLCK))
|
||||||
|
{
|
||||||
|
close (m->lockfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
maildir_unlock (mailbox_t * m)
|
||||||
|
{
|
||||||
|
char path[_POSIX_PATH_MAX];
|
||||||
|
|
||||||
|
snprintf (path, sizeof (path), "%s/isynclock", m->path);
|
||||||
|
unlink (path);
|
||||||
|
do_lock (m->lockfd, F_UNLCK);
|
||||||
|
close (m->lockfd);
|
||||||
|
}
|
||||||
|
|
||||||
/* open a maildir mailbox.
|
/* open a maildir mailbox.
|
||||||
* if OPEN_FAST is set, we just check to make
|
* if OPEN_FAST is set, 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
|
||||||
|
@ -141,8 +171,10 @@ maildir_open (const char *path, int flags)
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
const char *subdirs[] = { "cur", "new", "tmp" };
|
const char *subdirs[] = { "cur", "new", "tmp" };
|
||||||
int i;
|
int i;
|
||||||
|
datum key;
|
||||||
|
|
||||||
m = calloc (1, sizeof (mailbox_t));
|
m = calloc (1, sizeof (mailbox_t));
|
||||||
|
m->lockfd = -1;
|
||||||
/* filename expansion happens here, not in the config parser */
|
/* filename expansion happens here, not in the config parser */
|
||||||
m->path = expand_strdup (path);
|
m->path = expand_strdup (path);
|
||||||
|
|
||||||
|
@ -154,9 +186,7 @@ maildir_open (const char *path, int flags)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "ERROR: mkdir %s: %s (errno %d)\n",
|
fprintf (stderr, "ERROR: mkdir %s: %s (errno %d)\n",
|
||||||
m->path, strerror (errno), errno);
|
m->path, strerror (errno), errno);
|
||||||
free (m->path);
|
goto err;
|
||||||
free (m);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
|
@ -166,9 +196,7 @@ maildir_open (const char *path, int flags)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "ERROR: mkdir %s: %s (errno %d)\n",
|
fprintf (stderr, "ERROR: mkdir %s: %s (errno %d)\n",
|
||||||
buf, strerror (errno), errno);
|
buf, strerror (errno), errno);
|
||||||
free (m->path);
|
goto err;
|
||||||
free (m);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,9 +205,7 @@ maildir_open (const char *path, int flags)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "ERROR: stat %s: %s (errno %d)\n", m->path,
|
fprintf (stderr, "ERROR: stat %s: %s (errno %d)\n", m->path,
|
||||||
strerror (errno), errno);
|
strerror (errno), errno);
|
||||||
free (m->path);
|
goto err;
|
||||||
free (m);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -195,33 +221,37 @@ maildir_open (const char *path, int flags)
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"ERROR: %s does not appear to be a valid maildir style mailbox\n",
|
"ERROR: %s does not appear to be a valid maildir style mailbox\n",
|
||||||
m->path);
|
m->path);
|
||||||
free (m->path);
|
goto err;
|
||||||
free (m);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we need a mutex on the maildir because of the state files that isync
|
||||||
|
* uses.
|
||||||
|
*/
|
||||||
|
if (maildir_lock (m))
|
||||||
|
goto err;
|
||||||
|
|
||||||
/* check for the uidvalidity value */
|
/* check for the uidvalidity value */
|
||||||
m->uidvalidity = read_uid (m->path, "isyncuidvalidity");
|
m->uidvalidity = read_uid (m->path, "isyncuidvalidity");
|
||||||
if (m->uidvalidity == (unsigned int) -1)
|
if (m->uidvalidity == (unsigned int) -1)
|
||||||
{
|
goto err;
|
||||||
free (m->path);
|
|
||||||
free (m);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load the current maxuid */
|
/* load the current maxuid */
|
||||||
if ((m->maxuid = read_uid (m->path, "isyncmaxuid")) == (unsigned int) -1)
|
if ((m->maxuid = read_uid (m->path, "isyncmaxuid")) == (unsigned int) -1)
|
||||||
{
|
goto err;
|
||||||
free (m->path);
|
|
||||||
free (m);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & OPEN_FAST)
|
if (flags & OPEN_FAST)
|
||||||
return m;
|
return m;
|
||||||
|
|
||||||
|
snprintf (buf, sizeof (buf), "%s/isyncuidmap", m->path);
|
||||||
|
m->db = dbm_open (buf, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||||
|
if (m->db == NULL)
|
||||||
|
{
|
||||||
|
fputs ("ERROR: unable to open UID db\n", stderr);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
cur = &m->msgs;
|
cur = &m->msgs;
|
||||||
for (; count < 2; count++)
|
for (; count < 2; count++)
|
||||||
{
|
{
|
||||||
|
@ -231,10 +261,8 @@ maildir_open (const char *path, int flags)
|
||||||
d = opendir (buf);
|
d = opendir (buf);
|
||||||
if (!d)
|
if (!d)
|
||||||
{
|
{
|
||||||
free (m->path);
|
|
||||||
free (m);
|
|
||||||
perror ("opendir");
|
perror ("opendir");
|
||||||
return 0;
|
goto err;
|
||||||
}
|
}
|
||||||
while ((e = readdir (d)))
|
while ((e = readdir (d)))
|
||||||
{
|
{
|
||||||
|
@ -247,40 +275,25 @@ maildir_open (const char *path, int flags)
|
||||||
p->flags = 0;
|
p->flags = 0;
|
||||||
p->new = (count == 0);
|
p->new = (count == 0);
|
||||||
|
|
||||||
/* filename format is something like:
|
/* determine the UID for this message. The basename (sans
|
||||||
* <unique-prefix>,U=<n>:2,<flags>
|
* flags) is used as the key in the db
|
||||||
* This is completely non-standard, but in order for mail
|
|
||||||
* clients to understand the flags, we have to use the
|
|
||||||
* standard :info as described by the qmail spec
|
|
||||||
*/
|
*/
|
||||||
s = strstr (p->file, ",U=");
|
strfcpy (buf, p->file, sizeof (buf));
|
||||||
if (!s)
|
|
||||||
s = strstr (p->file, "UID");
|
|
||||||
if (!s)
|
|
||||||
puts ("Warning, no UID for message");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p->uid = strtol (s + 3, &s, 10);
|
|
||||||
if (p->uid > m->maxuid)
|
|
||||||
{
|
|
||||||
m->maxuid = p->uid;
|
|
||||||
m->maxuidchanged = 1;
|
|
||||||
}
|
|
||||||
/* Courier-IMAP names it files
|
|
||||||
* unique,S=<size>:info
|
|
||||||
* so we need to put the UID before the size, hence here
|
|
||||||
* we check for a comma as a valid terminator as well,
|
|
||||||
* since the format will be
|
|
||||||
* unique,U=<uid>,S=<size>:info
|
|
||||||
*/
|
|
||||||
if (*s && *s != ':' && *s != ',')
|
|
||||||
{
|
|
||||||
puts ("Warning, unable to parse UID");
|
|
||||||
p->uid = -1; /* reset */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s = strchr (p->file, ':');
|
s = strchr (p->file, ':');
|
||||||
|
if (s)
|
||||||
|
*s = 0;
|
||||||
|
key.dptr = buf;
|
||||||
|
key.dsize = strlen (buf);
|
||||||
|
key = dbm_fetch (m->db, key);
|
||||||
|
if (key.dptr)
|
||||||
|
{
|
||||||
|
p->uid = *(int *) key.dptr;
|
||||||
|
if (p->uid > m->maxuid)
|
||||||
|
m->maxuid = p->uid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
puts ("Warning, no UID for message");
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
parse_info (p, s + 1);
|
parse_info (p, s + 1);
|
||||||
if (p->flags & D_DELETED)
|
if (p->flags & D_DELETED)
|
||||||
|
@ -290,6 +303,15 @@ maildir_open (const char *path, int flags)
|
||||||
closedir (d);
|
closedir (d);
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (m->db)
|
||||||
|
dbm_close (m->db);
|
||||||
|
if (m->lockfd != -1)
|
||||||
|
maildir_unlock (m);
|
||||||
|
free (m->path);
|
||||||
|
free (m);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* permanently remove messages from a maildir mailbox. if `dead' is nonzero,
|
/* permanently remove messages from a maildir mailbox. if `dead' is nonzero,
|
||||||
|
@ -322,8 +344,8 @@ maildir_expunge (mailbox_t * mbox, int dead)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
update_maxuid (mailbox_t * mbox)
|
maildir_update_maxuid (mailbox_t * mbox)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
@ -355,7 +377,7 @@ update_maxuid (mailbox_t * mbox)
|
||||||
uid = atol (buf);
|
uid = atol (buf);
|
||||||
if (uid > mbox->maxuid)
|
if (uid > mbox->maxuid)
|
||||||
{
|
{
|
||||||
puts ("Error, maxuid is now higher (fatal)");
|
fputs ("ERROR: maxuid is now higher (fatal)\n", stderr);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,48 +451,14 @@ maildir_clean_tmp (const char *mbox)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
maildir_close (mailbox_t * mbox)
|
maildir_close (mailbox_t * mbox)
|
||||||
{
|
{
|
||||||
message_t *cur = mbox->msgs;
|
if (mbox->db)
|
||||||
char path[_POSIX_PATH_MAX];
|
dbm_close (mbox->db);
|
||||||
char oldpath[_POSIX_PATH_MAX];
|
|
||||||
char *p;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (mbox->changed)
|
/* release the mutex on the mailbox */
|
||||||
{
|
maildir_unlock (mbox);
|
||||||
for (; cur; cur = cur->next)
|
|
||||||
{
|
|
||||||
if (cur->changed)
|
|
||||||
{
|
|
||||||
/* generate old path */
|
|
||||||
snprintf (oldpath, sizeof (oldpath), "%s/%s/%s",
|
|
||||||
mbox->path, cur->new ? "new" : "cur", cur->file);
|
|
||||||
|
|
||||||
/* truncate old flags (if present) */
|
|
||||||
p = strchr (cur->file, ':');
|
|
||||||
if (p)
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
/* generate new path - always put this in the cur/ directory
|
|
||||||
* because its no longer new
|
|
||||||
*/
|
|
||||||
snprintf (path, sizeof (path), "%s/cur/%s:2,%s%s%s%s",
|
|
||||||
mbox->path,
|
|
||||||
cur->file, (cur->flags & D_FLAGGED) ? "F" : "",
|
|
||||||
(cur->flags & D_ANSWERED) ? "R" : "",
|
|
||||||
(cur->flags & D_SEEN) ? "S" : "",
|
|
||||||
(cur->flags & D_DELETED) ? "T" : "");
|
|
||||||
|
|
||||||
if (rename (oldpath, path))
|
|
||||||
perror ("rename");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mbox->maxuidchanged)
|
|
||||||
ret = update_maxuid (mbox);
|
|
||||||
|
|
||||||
/* per the maildir(5) specification, delivery agents are supposed to
|
/* per the maildir(5) specification, delivery agents are supposed to
|
||||||
* set a 24-hour timer on items placed in the `tmp' directory.
|
* set a 24-hour timer on items placed in the `tmp' directory.
|
||||||
|
@ -481,8 +469,6 @@ maildir_close (mailbox_t * mbox)
|
||||||
free_message (mbox->msgs);
|
free_message (mbox->msgs);
|
||||||
memset (mbox, 0xff, sizeof (mailbox_t));
|
memset (mbox, 0xff, sizeof (mailbox_t));
|
||||||
free (mbox);
|
free (mbox);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
51
main.c
51
main.c
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$
|
/* $Id$
|
||||||
*
|
*
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
* isync - IMAP4 to maildir mailbox synchronizer
|
||||||
* Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -67,7 +67,7 @@ static void
|
||||||
usage (void)
|
usage (void)
|
||||||
{
|
{
|
||||||
printf ("%s %s IMAP4 to maildir synchronizer\n", PACKAGE, VERSION);
|
printf ("%s %s IMAP4 to maildir synchronizer\n", PACKAGE, VERSION);
|
||||||
puts ("Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>");
|
puts ("Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>");
|
||||||
printf ("usage: %s [ flags ] mailbox [mailbox ...]\n", PACKAGE);
|
printf ("usage: %s [ flags ] mailbox [mailbox ...]\n", PACKAGE);
|
||||||
puts (" -a, --all Synchronize all defined mailboxes");
|
puts (" -a, --all Synchronize all defined mailboxes");
|
||||||
puts (" -c, --config CONFIG read an alternate config file (default: ~/.isyncrc)");
|
puts (" -c, --config CONFIG read an alternate config file (default: ~/.isyncrc)");
|
||||||
|
@ -134,7 +134,7 @@ main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
config_t *box = 0;
|
config_t *box = 0;
|
||||||
mailbox_t *mail;
|
mailbox_t *mail = 0;
|
||||||
imap_t *imap = 0;
|
imap_t *imap = 0;
|
||||||
int expunge = 0; /* by default, don't delete anything */
|
int expunge = 0; /* by default, don't delete anything */
|
||||||
int fast = 0;
|
int fast = 0;
|
||||||
|
@ -250,6 +250,9 @@ main (int argc, char **argv)
|
||||||
if (!global.host)
|
if (!global.host)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s: no such mailbox\n", argv[optind]);
|
fprintf (stderr, "%s: no such mailbox\n", argv[optind]);
|
||||||
|
/* continue is ok here because we are not handling the
|
||||||
|
* `all' case.
|
||||||
|
*/
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
global.path = argv[optind];
|
global.path = argv[optind];
|
||||||
|
@ -257,6 +260,7 @@ main (int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
if (!box->pass)
|
if (!box->pass)
|
||||||
{
|
{
|
||||||
/* if we don't have a global password set, prompt the user for
|
/* if we don't have a global password set, prompt the user for
|
||||||
|
@ -267,8 +271,8 @@ main (int argc, char **argv)
|
||||||
global.pass = getpass ("Password:");
|
global.pass = getpass ("Password:");
|
||||||
if (!global.pass)
|
if (!global.pass)
|
||||||
{
|
{
|
||||||
puts ("Aborting, no password");
|
fprintf (stderr, "Skipping %s, no password", box->path);
|
||||||
exit (1);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
box->pass = strdup (global.pass);
|
box->pass = strdup (global.pass);
|
||||||
|
@ -284,8 +288,8 @@ main (int argc, char **argv)
|
||||||
mail = maildir_open (box->path, i);
|
mail = maildir_open (box->path, i);
|
||||||
if (!mail)
|
if (!mail)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "ERROR: unable to load mailbox %s\n", box->path);
|
fprintf (stderr, "%s: unable to open mailbox\n", box->path);
|
||||||
goto cleanup;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
imap = imap_open (box, fast ? mail->maxuid + 1 : 1, imap);
|
imap = imap_open (box, fast ? mail->maxuid + 1 : 1, imap);
|
||||||
|
@ -293,7 +297,7 @@ main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "%s: skipping mailbox due to IMAP error\n",
|
fprintf (stderr, "%s: skipping mailbox due to IMAP error\n",
|
||||||
box->path);
|
box->path);
|
||||||
goto cleanup;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
|
@ -304,23 +308,33 @@ main (int argc, char **argv)
|
||||||
i |= (delete || box->delete) ? SYNC_DELETE : 0;
|
i |= (delete || box->delete) ? SYNC_DELETE : 0;
|
||||||
i |= (expunge || box->expunge) ? SYNC_EXPUNGE : 0;
|
i |= (expunge || box->expunge) ? SYNC_EXPUNGE : 0;
|
||||||
if (sync_mailbox (mail, imap, i, box->max_size, box->max_messages))
|
if (sync_mailbox (mail, imap, i, box->max_size, box->max_messages))
|
||||||
exit (1);
|
{
|
||||||
|
imap_close (imap); /* Just to be safe. Don't really know
|
||||||
|
* what the problem was.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fast)
|
if (!fast)
|
||||||
{
|
{
|
||||||
if ((expunge || box->expunge) && (imap->deleted || mail->deleted))
|
if ((expunge || box->expunge) &&
|
||||||
|
(imap->deleted || mail->deleted))
|
||||||
{
|
{
|
||||||
/* remove messages marked for deletion */
|
/* remove messages marked for deletion */
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
printf ("Expunging %d messages from server\n",
|
printf ("Expunging %d messages from server\n",
|
||||||
imap->deleted);
|
imap->deleted);
|
||||||
if (imap_expunge (imap))
|
if (imap_expunge (imap))
|
||||||
exit (1);
|
{
|
||||||
|
imap_close (imap);
|
||||||
|
imap = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
printf ("Expunging %d messages from local mailbox\n",
|
printf ("Expunging %d messages from local mailbox\n",
|
||||||
mail->deleted);
|
mail->deleted);
|
||||||
if (maildir_expunge (mail, 0))
|
if (maildir_expunge (mail, 0))
|
||||||
exit (1);
|
break;
|
||||||
}
|
}
|
||||||
/* remove messages deleted from server. this can safely be an
|
/* remove messages deleted from server. this can safely be an
|
||||||
* `else' clause since dead messages are marked as deleted by
|
* `else' clause since dead messages are marked as deleted by
|
||||||
|
@ -330,14 +344,15 @@ main (int argc, char **argv)
|
||||||
maildir_expunge (mail, 1);
|
maildir_expunge (mail, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write changed flags back to the mailbox */
|
} while (0);
|
||||||
if (!quiet)
|
|
||||||
printf ("Committing changes to %s\n", mail->path);
|
|
||||||
|
|
||||||
if (maildir_close (mail))
|
/* we never sync the same mailbox twice, so close it now */
|
||||||
exit (1);
|
if (mail)
|
||||||
|
maildir_close (mail);
|
||||||
|
|
||||||
cleanup:
|
/* the imap connection is not closed so we can keep the connection
|
||||||
|
* open, and there is no IMAP command for un-SELECT-ing a mailbox.
|
||||||
|
*/
|
||||||
if (all)
|
if (all)
|
||||||
box = box->next;
|
box = box->next;
|
||||||
}
|
}
|
||||||
|
|
92
sync.c
92
sync.c
|
@ -1,7 +1,7 @@
|
||||||
/* $Id$
|
/* $Id$
|
||||||
*
|
*
|
||||||
* isync - IMAP4 to maildir mailbox synchronizer
|
* isync - IMAP4 to maildir mailbox synchronizer
|
||||||
* Copyright (C) 2000-1 Michael R. Elkins <me@mutt.org>
|
* Copyright (C) 2000-2 Michael R. Elkins <me@mutt.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -40,6 +40,24 @@ find_msg (message_t * list, unsigned int uid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_uid (DBM *db, const char *f, unsigned int uid)
|
||||||
|
{
|
||||||
|
char path[_POSIX_PATH_MAX];
|
||||||
|
char *s;
|
||||||
|
datum key, val;
|
||||||
|
|
||||||
|
strfcpy (path, f, sizeof (path));
|
||||||
|
s = strchr (path, ':');
|
||||||
|
if (s)
|
||||||
|
*s = 0;
|
||||||
|
key.dptr = path;
|
||||||
|
key.dsize = strlen (path);
|
||||||
|
val.dptr = (void*) &uid;
|
||||||
|
val.dsize = sizeof (uid);
|
||||||
|
dbm_store (db, key, val, DBM_REPLACE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
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, unsigned int max_msgs)
|
unsigned int max_size, unsigned int max_msgs)
|
||||||
|
@ -76,7 +94,8 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
|
||||||
if (mbox->maxuid == 0 || imap->maxuid > mbox->maxuid)
|
if (mbox->maxuid == 0 || imap->maxuid > mbox->maxuid)
|
||||||
{
|
{
|
||||||
mbox->maxuid = imap->maxuid;
|
mbox->maxuid = imap->maxuid;
|
||||||
mbox->maxuidchanged = 1;
|
if (maildir_update_maxuid (mbox))
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we are --fast mode, the mailbox wont have been loaded, so
|
/* if we are --fast mode, the mailbox wont have been loaded, so
|
||||||
|
@ -93,7 +112,6 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
|
||||||
if (cur->uid == (unsigned int) -1)
|
if (cur->uid == (unsigned int) -1)
|
||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int uid;
|
|
||||||
|
|
||||||
if ((flags & SYNC_QUIET) == 0)
|
if ((flags & SYNC_QUIET) == 0)
|
||||||
{
|
{
|
||||||
|
@ -132,35 +150,12 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
cur->size = sb.st_size;
|
cur->size = sb.st_size;
|
||||||
|
cur->uid = imap_append_message (imap, fd, cur);
|
||||||
uid = imap_append_message (imap, fd, cur);
|
/* if the server gave us back a uid, update the db */
|
||||||
|
if (cur->uid != (unsigned int) -1)
|
||||||
|
set_uid (mbox->db, cur->file, cur->uid);
|
||||||
|
|
||||||
close (fd);
|
close (fd);
|
||||||
|
|
||||||
/* if the server gave us back a uid, rename the file so
|
|
||||||
* we remember for next time
|
|
||||||
*/
|
|
||||||
if (uid != -1)
|
|
||||||
{
|
|
||||||
strfcpy (newpath, path, sizeof (newpath));
|
|
||||||
/* kill :info field */
|
|
||||||
p = strchr (newpath, ':');
|
|
||||||
if (p)
|
|
||||||
*p = 0;
|
|
||||||
|
|
||||||
/* XXX not quite right, should really always put the
|
|
||||||
* msg in "cur/", but i'm too tired right now.
|
|
||||||
*/
|
|
||||||
snprintf (newpath + strlen (newpath),
|
|
||||||
sizeof (newpath) - strlen (newpath),
|
|
||||||
",U=%d:2,%s%s%s%s", uid,
|
|
||||||
(cur->flags & D_FLAGGED) ? "F" : "",
|
|
||||||
(cur->flags & D_ANSWERED) ? "R" : "",
|
|
||||||
(cur->flags & D_SEEN) ? "S" : "",
|
|
||||||
(cur->flags & D_DELETED) ? "T" : "");
|
|
||||||
if (rename (path, newpath))
|
|
||||||
perror ("rename");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (flags & SYNC_DELETE)
|
else if (flags & SYNC_DELETE)
|
||||||
{
|
{
|
||||||
|
@ -187,7 +182,7 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
|
||||||
if (imap_copy_message (imap, cur->uid,
|
if (imap_copy_message (imap, cur->uid,
|
||||||
imap->box->copy_deleted_to))
|
imap->box->copy_deleted_to))
|
||||||
{
|
{
|
||||||
printf ("Error, unable to copy deleted message to \"%s\"\n",
|
fprintf (stderr, "ERROR: unable to copy deleted message to \"%s\"\n",
|
||||||
imap->box->copy_deleted_to);
|
imap->box->copy_deleted_to);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -208,8 +203,28 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
|
||||||
if ((cur->flags & D_DELETED) == 0 && (tmp->flags & D_DELETED))
|
if ((cur->flags & D_DELETED) == 0 && (tmp->flags & D_DELETED))
|
||||||
mbox->deleted++;
|
mbox->deleted++;
|
||||||
cur->flags |= (tmp->flags & ~(D_RECENT | D_DRAFT));
|
cur->flags |= (tmp->flags & ~(D_RECENT | D_DRAFT));
|
||||||
cur->changed = 1;
|
|
||||||
mbox->changed = 1;
|
/* generate old path */
|
||||||
|
snprintf (path, sizeof (path), "%s/%s/%s",
|
||||||
|
mbox->path, cur->new ? "new" : "cur", cur->file);
|
||||||
|
|
||||||
|
/* truncate old flags (if present) */
|
||||||
|
p = strchr (cur->file, ':');
|
||||||
|
if (p)
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
/* generate new path - always put this in the cur/ directory
|
||||||
|
* because its no longer new
|
||||||
|
*/
|
||||||
|
snprintf (newpath, sizeof (newpath), "%s/cur/%s:2,%s%s%s%s",
|
||||||
|
mbox->path,
|
||||||
|
cur->file, (cur->flags & D_FLAGGED) ? "F" : "",
|
||||||
|
(cur->flags & D_ANSWERED) ? "R" : "",
|
||||||
|
(cur->flags & D_SEEN) ? "S" : "",
|
||||||
|
(cur->flags & D_DELETED) ? "T" : "");
|
||||||
|
|
||||||
|
if (rename (path, newpath))
|
||||||
|
perror ("rename");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,15 +304,15 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* create new file */
|
/* create new file */
|
||||||
snprintf (path, sizeof (path), "%s/tmp/%ld_%d.%d.%s,U=%d%s",
|
snprintf (path, sizeof (path), "%s/tmp/%ld_%d.%d.%s%s",
|
||||||
mbox->path, time (0), MaildirCount++, getpid (),
|
mbox->path, time (0), MaildirCount++, getpid (),
|
||||||
Hostname, cur->uid, suffix);
|
Hostname, suffix);
|
||||||
|
|
||||||
if ((fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600)) > 0)
|
if ((fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600)) > 0)
|
||||||
break;
|
break;
|
||||||
if (errno != EEXIST)
|
if (errno != EEXIST)
|
||||||
{
|
{
|
||||||
perror ("open");
|
perror (path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +351,11 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
|
||||||
*/
|
*/
|
||||||
if (link (path, newpath))
|
if (link (path, newpath))
|
||||||
perror ("link");
|
perror ("link");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* update the db with the UID mapping for this file */
|
||||||
|
set_uid (mbox->db, newpath, cur->uid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* always remove the temp file */
|
/* always remove the temp file */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user