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:
Michael Elkins 2002-01-16 19:47:28 +00:00
parent 2c648da5cf
commit c121ec912f
13 changed files with 276 additions and 242 deletions

View File

@ -1,5 +1,8 @@
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:
added --create/-C command line option to force creation of the local
maildir-style mailbox if nonexistent

8
NEWS
View File

@ -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]
Added `MaxMessages' configuration option to allow tracking of only the most

2
TODO
View File

@ -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
IMAP session. need to handled those asynchronous notifications properly.
add a way to automatically create and sync IMAP subfolders.

View File

@ -1,7 +1,7 @@
/* $Id$
*
* 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
* it under the terms of the GNU General Public License as published by

View File

@ -1,5 +1,5 @@
AC_INIT(isync.h)
AM_INIT_AUTOMAKE(isync,0.7)
AM_INIT_AUTOMAKE(isync,0.8)
AM_PROG_CC_STDC
AC_ARG_WITH(ssl-dir, [ --with-ssl-dir=DIR location where openssl is insalled],
[if test -d $withval/lib; then
@ -19,6 +19,7 @@ AC_CHECK_LIB(socket,socket)
AC_CHECK_LIB(nsl,inet_ntoa)
AC_CHECK_LIB(crypto,ERR_error_string)
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
if test `echo $CC | sed 's/^gcc.*/gcc/'` = gcc; then
CFLAGS="$CFLAGS -pipe -W -Wall -Wshadow -Wmissing-prototypes"

2
cram.c
View File

@ -1,7 +1,7 @@
/* $Id$
*
* 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
* it under the terms of the GNU General Public License as published by

2
imap.c
View File

@ -1,7 +1,7 @@
/* $Id$
*
* 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
* it under the terms of the GNU General Public License as published by

12
isync.1
View File

@ -1,6 +1,6 @@
.ig
\" 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
\" 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
\" 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
isync - synchronize IMAP4 and maildir mailboxes
@ -304,13 +304,9 @@ will then use the global value by default.
Default configuration file
..
.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
relies on using the message UIDs that info must be inserted into the
filename in a way which will be interoperable with existing readers. So
the UID is placed in the filename of the messages in the local maildir
mailbox rather than the :info field.
does not use NFS-safe locking. It will correctly prevent concurrent
synchronization of a mailbox on the same host, but not across NFS.
.P
When synchronizing multiple mailboxes on the same IMAP server, it is not
possible to select different SSL options for each mailbox. Only the options

13
isync.h
View File

@ -1,7 +1,7 @@
/* $Id$
*
* 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
* 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
*/
#define DB_DBM_HSEARCH 1
#include <sys/types.h>
#include <stdarg.h>
#if HAVE_LIBSSL
#include <openssl/ssl.h>
#endif
#include <db.h>
#include "debug.h"
typedef struct
@ -79,13 +82,13 @@ struct config
/* struct representing local mailbox file */
struct mailbox
{
DBM *db;
char *path;
message_t *msgs;
int lockfd;
unsigned int deleted; /* # of deleted messages */
unsigned int uidvalidity;
unsigned int maxuid; /* largest uid we know about */
unsigned int changed:1;
unsigned int maxuidchanged:1;
};
/* message dispositions */
@ -106,7 +109,6 @@ struct message
message_t *next;
unsigned int processed:1; /* message has already been evaluated */
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 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);
int maildir_expunge (mailbox_t *, int);
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);
void free_message (message_t *);

2
list.c
View File

@ -1,7 +1,7 @@
/* $Id$
*
* 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
* it under the terms of the GNU General Public License as published by

204
maildir.c
View File

@ -1,7 +1,7 @@
/* $Id$
*
* 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
* 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];
int fd;
int ret;
int ret = 0;
int len;
char buf[64];
unsigned int uid = 0;
@ -96,29 +96,59 @@ read_uid (const char *path, const char *file)
{
if (errno != ENOENT)
{
perror ("open");
perror (full);
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)
{
perror ("read");
ret = -1;
}
else
{
buf[len] = 0;
uid = atol (buf);
}
}
ret |= do_lock (fd, F_UNLCK);
close (fd);
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.
* if OPEN_FAST is set, we just check to make
* 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;
const char *subdirs[] = { "cur", "new", "tmp" };
int i;
datum key;
m = calloc (1, sizeof (mailbox_t));
m->lockfd = -1;
/* filename expansion happens here, not in the config parser */
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",
m->path, strerror (errno), errno);
free (m->path);
free (m);
return NULL;
goto err;
}
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",
buf, strerror (errno), errno);
free (m->path);
free (m);
return NULL;
goto err;
}
}
@ -177,9 +205,7 @@ maildir_open (const char *path, int flags)
{
fprintf (stderr, "ERROR: stat %s: %s (errno %d)\n", m->path,
strerror (errno), errno);
free (m->path);
free (m);
return NULL;
goto err;
}
}
else
@ -195,33 +221,37 @@ maildir_open (const char *path, int flags)
fprintf (stderr,
"ERROR: %s does not appear to be a valid maildir style mailbox\n",
m->path);
free (m->path);
free (m);
return 0;
goto err;
}
}
}
/* 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 */
m->uidvalidity = read_uid (m->path, "isyncuidvalidity");
if (m->uidvalidity == (unsigned int) -1)
{
free (m->path);
free (m);
return NULL;
}
goto err;
/* load the current maxuid */
if ((m->maxuid = read_uid (m->path, "isyncmaxuid")) == (unsigned int) -1)
{
free (m->path);
free (m);
return NULL;
}
goto err;
if (flags & OPEN_FAST)
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;
for (; count < 2; count++)
{
@ -231,10 +261,8 @@ maildir_open (const char *path, int flags)
d = opendir (buf);
if (!d)
{
free (m->path);
free (m);
perror ("opendir");
return 0;
goto err;
}
while ((e = readdir (d)))
{
@ -247,40 +275,25 @@ maildir_open (const char *path, int flags)
p->flags = 0;
p->new = (count == 0);
/* filename format is something like:
* <unique-prefix>,U=<n>:2,<flags>
* 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
/* determine the UID for this message. The basename (sans
* flags) is used as the key in the db
*/
s = strstr (p->file, ",U=");
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 */
}
}
strfcpy (buf, p->file, sizeof (buf));
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)
parse_info (p, s + 1);
if (p->flags & D_DELETED)
@ -290,6 +303,15 @@ maildir_open (const char *path, int flags)
closedir (d);
}
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,
@ -322,8 +344,8 @@ maildir_expunge (mailbox_t * mbox, int dead)
return 0;
}
static int
update_maxuid (mailbox_t * mbox)
int
maildir_update_maxuid (mailbox_t * mbox)
{
int fd;
char buf[64];
@ -355,7 +377,7 @@ update_maxuid (mailbox_t * mbox)
uid = atol (buf);
if (uid > mbox->maxuid)
{
puts ("Error, maxuid is now higher (fatal)");
fputs ("ERROR: maxuid is now higher (fatal)\n", stderr);
ret = -1;
}
@ -429,48 +451,14 @@ maildir_clean_tmp (const char *mbox)
}
}
int
void
maildir_close (mailbox_t * mbox)
{
message_t *cur = mbox->msgs;
char path[_POSIX_PATH_MAX];
char oldpath[_POSIX_PATH_MAX];
char *p;
int ret = 0;
if (mbox->db)
dbm_close (mbox->db);
if (mbox->changed)
{
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);
/* release the mutex on the mailbox */
maildir_unlock (mbox);
/* per the maildir(5) specification, delivery agents are supposed to
* 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);
memset (mbox, 0xff, sizeof (mailbox_t));
free (mbox);
return ret;
}
int

51
main.c
View File

@ -1,7 +1,7 @@
/* $Id$
*
* 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
* it under the terms of the GNU General Public License as published by
@ -67,7 +67,7 @@ static void
usage (void)
{
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);
puts (" -a, --all Synchronize all defined mailboxes");
puts (" -c, --config CONFIG read an alternate config file (default: ~/.isyncrc)");
@ -134,7 +134,7 @@ main (int argc, char **argv)
{
int i;
config_t *box = 0;
mailbox_t *mail;
mailbox_t *mail = 0;
imap_t *imap = 0;
int expunge = 0; /* by default, don't delete anything */
int fast = 0;
@ -250,6 +250,9 @@ main (int argc, char **argv)
if (!global.host)
{
fprintf (stderr, "%s: no such mailbox\n", argv[optind]);
/* continue is ok here because we are not handling the
* `all' case.
*/
continue;
}
global.path = argv[optind];
@ -257,6 +260,7 @@ main (int argc, char **argv)
}
}
do {
if (!box->pass)
{
/* 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:");
if (!global.pass)
{
puts ("Aborting, no password");
exit (1);
fprintf (stderr, "Skipping %s, no password", box->path);
break;
}
}
box->pass = strdup (global.pass);
@ -284,8 +288,8 @@ main (int argc, char **argv)
mail = maildir_open (box->path, i);
if (!mail)
{
fprintf (stderr, "ERROR: unable to load mailbox %s\n", box->path);
goto cleanup;
fprintf (stderr, "%s: unable to open mailbox\n", box->path);
break;
}
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",
box->path);
goto cleanup;
break;
}
if (!quiet)
@ -304,23 +308,33 @@ main (int argc, char **argv)
i |= (delete || box->delete) ? SYNC_DELETE : 0;
i |= (expunge || box->expunge) ? SYNC_EXPUNGE : 0;
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 ((expunge || box->expunge) && (imap->deleted || mail->deleted))
if ((expunge || box->expunge) &&
(imap->deleted || mail->deleted))
{
/* remove messages marked for deletion */
if (!quiet)
printf ("Expunging %d messages from server\n",
imap->deleted);
if (imap_expunge (imap))
exit (1);
{
imap_close (imap);
imap = NULL;
break;
}
if (!quiet)
printf ("Expunging %d messages from local mailbox\n",
mail->deleted);
if (maildir_expunge (mail, 0))
exit (1);
break;
}
/* remove messages deleted from server. this can safely be an
* `else' clause since dead messages are marked as deleted by
@ -330,14 +344,15 @@ main (int argc, char **argv)
maildir_expunge (mail, 1);
}
/* write changed flags back to the mailbox */
if (!quiet)
printf ("Committing changes to %s\n", mail->path);
} while (0);
if (maildir_close (mail))
exit (1);
/* we never sync the same mailbox twice, so close it now */
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)
box = box->next;
}

92
sync.c
View File

@ -1,7 +1,7 @@
/* $Id$
*
* 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
* 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;
}
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
sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
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)
{
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
@ -93,7 +112,6 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
if (cur->uid == (unsigned int) -1)
{
struct stat sb;
int uid;
if ((flags & SYNC_QUIET) == 0)
{
@ -132,35 +150,12 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
}
cur->size = sb.st_size;
uid = imap_append_message (imap, fd, cur);
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);
/* 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)
{
@ -187,7 +182,7 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
if (imap_copy_message (imap, cur->uid,
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);
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))
mbox->deleted++;
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 (;;)
{
/* 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 (),
Hostname, cur->uid, suffix);
Hostname, suffix);
if ((fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600)) > 0)
break;
if (errno != EEXIST)
{
perror ("open");
perror (path);
break;
}
@ -336,6 +351,11 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags,
*/
if (link (path, newpath))
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 */