isync

mailbox synchronization program
git clone https://git.code.sf.net/p/isync/isync
Log | Files | Refs | README | LICENSE

commit bcecbe5eeb0040fe5e479b27274850d69c468f51
parent 89445383992992f812e44c657061992efb0fe939
Author: Michael Elkins <me@mutt.org>
Date:   Thu, 11 Jan 2001 10:13:47 +0000

broke config code into config.c

added support for uploading local messages with no UID to the IMAP server

added Expunge configuration option

added CopyDeletedTo configuration option

Diffstat:
MMakefile.am | 2+-
Aconfig.c | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mimap.c | 181++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Misync.1 | 13+++++++++++++
Misync.h | 12+++++++++++-
Misyncrc.sample | 8++++++++
Mmain.c | 226+++++++------------------------------------------------------------------------
Msync.c | 117++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
8 files changed, 579 insertions(+), 222 deletions(-)

diff --git a/Makefile.am b/Makefile.am @@ -1,5 +1,5 @@ bin_PROGRAMS=isync -isync_SOURCES=main.c imap.c sync.c maildir.c isync.h list.c cram.c +isync_SOURCES=main.c imap.c sync.c maildir.c isync.h list.c cram.c config.c man_MANS=isync.1 EXTRA_DIST=sample.isyncrc $(man_MANS) INCLUDES=$(RPM_OPT_FLAGS) diff --git a/config.c b/config.c @@ -0,0 +1,242 @@ +/* $Id$ + * + * isync - IMAP4 to maildir mailbox synchronizer + * Copyright (C) 2000 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <unistd.h> +#include <limits.h> +#include <errno.h> +#include <pwd.h> +#include <sys/types.h> +#include <string.h> +#include "isync.h" + +static config_t *box = 0; + +/* set defaults from the global configuration section */ +void +config_defaults (config_t * conf) +{ + conf->user = global.user; + conf->pass = global.pass; + conf->port = global.port; + conf->box = global.box; + conf->host = global.host; + conf->max_size = global.max_size; + conf->copy_deleted_to = global.copy_deleted_to; + conf->use_namespace = global.use_namespace; + conf->expunge = global.expunge; +#if HAVE_LIBSSL + conf->require_ssl = global.require_ssl; + conf->use_imaps = global.use_imaps; + conf->cert_file = global.cert_file; + conf->use_sslv2 = global.use_sslv2; + conf->use_sslv3 = global.use_sslv3; + conf->use_tlsv1 = global.use_tlsv1; +#endif +} + +void +load_config (const char *where) +{ + char path[_POSIX_PATH_MAX]; + char buf[1024]; + struct passwd *pw; + config_t **cur = &box; + int line = 0; + FILE *fp; + char *p, *cmd, *val; + + if (!where) + { + pw = getpwuid (getuid ()); + snprintf (path, sizeof (path), "%s/.isyncrc", pw->pw_dir); + where = path; + } + printf ("Reading %s\n", where); + + fp = fopen (where, "r"); + if (!fp) + { + if (errno != ENOENT) + { + perror ("fopen"); + return; + } + } + buf[sizeof buf - 1] = 0; + while ((fgets (buf, sizeof (buf) - 1, fp))) + { + p = buf; + cmd = next_arg (&p); + val = next_arg (&p); + line++; + if (!cmd || *cmd == '#') + continue; + if (!strncasecmp ("mailbox", cmd, 7)) + { + if (*cur) + cur = &(*cur)->next; + *cur = calloc (1, sizeof (config_t)); + config_defaults (*cur); + (*cur)->path = strdup (val); + } + else if (!strncasecmp ("host", cmd, 4)) + { +#if HAVE_LIBSSL + if (!strncasecmp ("imaps:", val, 6)) + { + val += 6; + if (*cur) + { + (*cur)->use_imaps = 1; + (*cur)->port = 993; + } + else + { + global.use_imaps = 1; + global.port = 993; + } + } +#endif + if (*cur) + (*cur)->host = strdup (val); + else + global.host = strdup (val); + } + else if (!strncasecmp ("user", cmd, 4)) + { + if (*cur) + (*cur)->user = strdup (val); + else + global.user = strdup (val); + } + else if (!strncasecmp ("pass", cmd, 4)) + { + if (*cur) + (*cur)->pass = strdup (val); + else + global.pass = strdup (val); + } + else if (!strncasecmp ("port", cmd, 4)) + { + if (*cur) + (*cur)->port = atoi (val); + else + global.port = atoi (val); + } + else if (!strncasecmp ("box", cmd, 3)) + { + if (*cur) + (*cur)->box = strdup (val); + else + global.box = strdup (val); + } + else if (!strncasecmp ("alias", cmd, 5)) + { + if (*cur) + (*cur)->alias = strdup (val); + } + else if (!strncasecmp ("maxsize", cmd, 7)) + { + if (*cur) + (*cur)->max_size = atol (val); + else + global.max_size = atol (val); + } + else if (!strncasecmp ("UseNamespace", cmd, 12)) + { + if (*cur) + (*cur)->use_namespace = (strcasecmp (val, "yes") == 0); + else + global.use_namespace = (strcasecmp (val, "yes") == 0); + } + else if (!strncasecmp ("CopyDeletedTo", cmd, 13)) + { + if (*cur) + (*cur)->copy_deleted_to = strdup (val); + else + global.copy_deleted_to = strdup (val); + } + else if (!strncasecmp ("Expunge", cmd, 7)) + { + if (*cur) + (*cur)->expunge = (strcasecmp (val, "yes") == 0); + else + global.expunge = (strcasecmp (val, "yes") == 0); + } +#if HAVE_LIBSSL + else if (!strncasecmp ("CertificateFile", cmd, 15)) + { + if (*cur) + (*cur)->cert_file = strdup (val); + else + global.cert_file = strdup (val); + } + else if (!strncasecmp ("RequireSSL", cmd, 10)) + { + if (*cur) + (*cur)->require_ssl = (strcasecmp (val, "yes") == 0); + else + global.require_ssl = (strcasecmp (val, "yes") == 0); + } + else if (!strncasecmp ("UseSSLv2", cmd, 8)) + { + if (*cur) + (*cur)->use_sslv2 = (strcasecmp (val, "yes") == 0); + else + global.use_sslv2 = (strcasecmp (val, "yes") == 0); + } + else if (!strncasecmp ("UseSSLv3", cmd, 8)) + { + if (*cur) + (*cur)->use_sslv3 = (strcasecmp (val, "yes") == 0); + else + global.use_sslv3 = (strcasecmp (val, "yes") == 0); + } + else if (!strncasecmp ("UseTLSv1", cmd, 8)) + { + if (*cur) + (*cur)->use_tlsv1 = (strcasecmp (val, "yes") == 0); + else + global.use_tlsv1 = (strcasecmp (val, "yes") == 0); + } + else if (!strncasecmp ("RequireCRAM", cmd, 11)) + { + if (*cur) + (*cur)->require_cram = (strcasecmp (val, "yes") == 0); + else + global.require_cram = (strcasecmp (val, "yes") == 0); + } +#endif + else if (buf[0]) + printf ("%s:%d:unknown command:%s", path, line, cmd); + } + fclose (fp); +} + +config_t * +find_box (const char *s) +{ + config_t *p = box; + + for (; p; p = p->next) + if (!strcmp (s, p->path) || (p->alias && !strcmp (s, p->alias))) + return p; + return 0; +} diff --git a/imap.c b/imap.c @@ -701,7 +701,7 @@ imap_open (config_t * box, unsigned int minuid, imap_t * imap) fputs ("Selecting mailbox... ", stdout); fflush (stdout); - if ((ret = imap_exec (imap, "SELECT %s%s", ns_prefix, box->box))) + if ((ret = imap_exec (imap, "SELECT \"%s%s\"", ns_prefix, box->box))) break; printf ("%d messages, %d recent\n", imap->count, imap->recent); @@ -903,3 +903,182 @@ imap_expunge (imap_t * imap) { return imap_exec (imap, "EXPUNGE"); } + +int +imap_copy_message (imap_t * imap, unsigned int uid, const char *mailbox) +{ + char *ns_prefix = ""; + + /* XXX for now assume personal namespace */ + if (imap->box->use_namespace && is_list (imap->ns_personal) && + is_list (imap->ns_personal->child) && + is_atom (imap->ns_personal->child->child)) + { + ns_prefix = imap->ns_personal->child->child->val; + } + + return imap_exec (imap, "UID COPY %u \"%s%s\"", uid, ns_prefix, mailbox); +} + +int +imap_append_message (imap_t * imap, int fd, message_t * msg) +{ + char buf[1024]; + size_t len; + size_t sofar = 0; + int lines = 0; + char flagstr[128]; + char *s; + size_t i; + size_t start, end; + char *arg; + + /* ugh, we need to count the number of newlines */ + while (sofar < msg->size) + { + len = msg->size - sofar; + if (len > sizeof (buf)) + len = sizeof (buf); + len = read (fd, buf, len); + if (len == (size_t) - 1) + { + perror ("read"); + return -1; + } + for (i = 0; i < len; i++) + if (buf[i] == '\n') + lines++; + sofar += len; + } + + flagstr[0] = 0; + if (msg->flags) + { + strcpy (flagstr, "("); + if (msg->flags & D_DELETED) + snprintf (flagstr + strlen (flagstr), + sizeof (flagstr) - strlen (flagstr), "%s\\Deleted", + flagstr[1] ? " " : ""); + if (msg->flags & D_ANSWERED) + snprintf (flagstr + strlen (flagstr), + sizeof (flagstr) - strlen (flagstr), "%s\\Answered", + flagstr[1] ? " " : ""); + if (msg->flags & D_SEEN) + snprintf (flagstr + strlen (flagstr), + sizeof (flagstr) - strlen (flagstr), "%s\\Seen", + flagstr[1] ? " " : ""); + if (msg->flags & D_FLAGGED) + snprintf (flagstr + strlen (flagstr), + sizeof (flagstr) - strlen (flagstr), "%s\\Flagged", + flagstr[1] ? " " : ""); + if (msg->flags & D_DRAFT) + snprintf (flagstr + strlen (flagstr), + sizeof (flagstr) - strlen (flagstr), "%s\\Draft", + flagstr[1] ? " " : ""); + snprintf (flagstr + strlen (flagstr), + sizeof (flagstr) - strlen (flagstr), ") "); + } + + snprintf (buf, sizeof (buf), "%d APPEND %s %s{%d}\r\n", ++Tag, + imap->box->box, flagstr, msg->size + lines); + socket_write (imap->sock, buf, strlen (buf)); + if (Verbose) + fputs (buf, stdout); + + if (buffer_gets (imap->buf, &s)) + return -1; + if (Verbose) + puts (s); + + if (*s != '+') + return -1; + + /* rewind */ + lseek (fd, 0, 0); + + sofar = 0; + while (sofar < msg->size) + { + len = msg->size - sofar; + if (len > sizeof (buf)) + len = sizeof (buf); + len = read (fd, buf, len); + if (len == (size_t) - 1) + return -1; + start = 0; + while (start < len) + { + end = start; + while (end < len && buf[end] != '\n') + end++; + if (start != end) + socket_write (imap->sock, buf + start, end - start); +/* if (Verbose) + { + buf[end] = 0; + puts (buf + start); + } */ + socket_write (imap->sock, "\r\n", 2); + start = end + 1; + } + sofar += len; + } + socket_write (imap->sock, "\r\n", 2); + + for (;;) + { + if (buffer_gets (imap->buf, &s)) + return -1; + + if (Verbose) + puts (s); + + arg = next_arg (&s); + if (*arg == '*') + { + /* XXX just ignore it for now */ + } + else if (atoi (arg) != Tag) + { + puts ("wrong tag"); + return -1; + } + else + { + int uid; + + arg = next_arg (&s); + if (strcmp (arg, "OK")) + return -1; + arg = next_arg (&s); + if (*arg != '[') + break; + arg++; + if (strcasecmp ("APPENDUID", arg)) + { + puts ("Error, expected APPENDUID"); + break; + } + arg = next_arg (&s); + if (!arg) + break; + if (atoi (arg) != imap->uidvalidity) + { + puts ("Error, UIDVALIDITY doesn't match APPENDUID"); + return -1; + } + arg = next_arg (&s); + if (!arg) + break; + uid = strtol (arg, &s, 10); + if (*s != ']') + { + /* parse error */ + break; + } + return uid; + } + } + + return 0; +} diff --git a/isync.1 b/isync.1 @@ -155,6 +155,19 @@ Defines an alias for the mailbox which can be used as a shortcut on the command line. .. .TP +\fBCopyDeletedTo\fR \fIstring\fR +Specifies the remote IMAP mailbox to copy deleted messages prior to +expunging (Default: none). +.. +.TP +\fBExpunge\fR \fIyes|no\fR +Specifies whether deleted messages are expunged by default (Default: no). +\fBNOTE:\fR The +.I -e +command line option overrides this setting when set to +\fIno\fR. +.. +.TP \fBMaxSize\fR \fIbytes\fR Sets a threshold for the maximum message size (in bytes) for which .B isync diff --git a/isync.h b/isync.h @@ -54,7 +54,8 @@ struct config char *pass; char *box; char *alias; - unsigned int max_size; + char *copy_deleted_to; + off_t max_size; config_t *next; #if HAVE_LIBSSL char *cert_file; @@ -66,6 +67,7 @@ struct config unsigned int require_cram:1; #endif unsigned int use_namespace:1; + unsigned int expunge:1; }; /* struct representing local mailbox file */ @@ -159,11 +161,17 @@ char *next_arg (char **); int sync_mailbox (mailbox_t *, imap_t *, int, unsigned int); +void config_defaults (config_t *); +void load_config (const char *); +config_t *find_box (const char *); + void imap_close (imap_t *); +int imap_copy_message (imap_t * imap, unsigned int uid, const char *mailbox); int imap_fetch_message (imap_t *, unsigned int, int); int imap_set_flags (imap_t *, unsigned int, unsigned int); int imap_expunge (imap_t *); imap_t *imap_open (config_t *, unsigned int, imap_t *); +int imap_append_message (imap_t *, int, message_t *); mailbox_t *maildir_open (const char *, int fast); int maildir_expunge (mailbox_t *, int); @@ -180,3 +188,5 @@ int is_atom (list_t *list); int is_list (list_t *list); int is_nil (list_t *list); void free_list (list_t *list); + +#define strfcpy(a,b,c) {strncpy(a,b,c);(a)[c-1]=0;} diff --git a/isyncrc.sample b/isyncrc.sample @@ -2,6 +2,12 @@ # Values here are used as defaults for any following Mailbox section that # doesn't specify it. +# by default, expunge deleted messages (same as -e on command line) +Expunge yes + +# copy deleted messages to the IMAP "Trash" folder +CopyDeletedTo "Trash" + # my default username, if different from the local username User me #Port 143 @@ -18,6 +24,8 @@ Host work.host.com Pass xxxxxxxx # define a shortcut so I can just use "isync work" from the command line Alias work +# don't auto expunge messages in this box (overridden by -e on command line) +Expunge no ### ### personal mailbox diff --git a/main.c b/main.c @@ -50,7 +50,6 @@ struct option Opts[] = { config_t global; unsigned int Tag = 0; -static config_t *box = 0; char Hostname[256]; int Verbose = 0; @@ -85,203 +84,6 @@ usage (void) exit (0); } -/* set defaults from the global configuration section */ -static void -config_defaults (config_t * conf) -{ - conf->user = global.user; - conf->pass = global.pass; - conf->port = global.port; - conf->box = global.box; - conf->host = global.host; - conf->max_size = global.max_size; - conf->use_namespace = global.use_namespace; -#if HAVE_LIBSSL - conf->require_ssl = global.require_ssl; - conf->use_imaps = global.use_imaps; - conf->cert_file = global.cert_file; - conf->use_sslv2 = global.use_sslv2; - conf->use_sslv3 = global.use_sslv3; - conf->use_tlsv1 = global.use_tlsv1; -#endif -} - -static void -load_config (char *where) -{ - char path[_POSIX_PATH_MAX]; - char buf[1024]; - struct passwd *pw; - config_t **cur = &box; - int line = 0; - FILE *fp; - char *p, *cmd, *val; - - if (!where) - { - pw = getpwuid (getuid ()); - snprintf (path, sizeof (path), "%s/.isyncrc", pw->pw_dir); - where = path; - } - printf ("Reading %s\n", where); - - fp = fopen (where, "r"); - if (!fp) - { - if (errno != ENOENT) - { - perror ("fopen"); - return; - } - } - buf[sizeof buf - 1] = 0; - while ((fgets (buf, sizeof (buf) - 1, fp))) - { - p = buf; - cmd = next_arg (&p); - val = next_arg (&p); - line++; - if (!cmd || *cmd == '#') - continue; - if (!strncasecmp ("mailbox", cmd, 7)) - { - if (*cur) - cur = &(*cur)->next; - *cur = calloc (1, sizeof (config_t)); - config_defaults (*cur); - (*cur)->path = strdup (val); - } - else if (!strncasecmp ("host", cmd, 4)) - { -#if HAVE_LIBSSL - if (!strncasecmp ("imaps:", val, 6)) - { - val += 6; - if (*cur) - { - (*cur)->use_imaps = 1; - (*cur)->port = 993; - } - else - { - global.use_imaps = 1; - global.port = 993; - } - } -#endif - if (*cur) - (*cur)->host = strdup (val); - else - global.host = strdup (val); - } - else if (!strncasecmp ("user", cmd, 4)) - { - if (*cur) - (*cur)->user = strdup (val); - else - global.user = strdup (val); - } - else if (!strncasecmp ("pass", cmd, 4)) - { - if (*cur) - (*cur)->pass = strdup (val); - else - global.pass = strdup (val); - } - else if (!strncasecmp ("port", cmd, 4)) - { - if (*cur) - (*cur)->port = atoi (val); - else - global.port = atoi (val); - } - else if (!strncasecmp ("box", cmd, 3)) - { - if (*cur) - (*cur)->box = strdup (val); - else - global.box = strdup (val); - } - else if (!strncasecmp ("alias", cmd, 5)) - { - if (*cur) - (*cur)->alias = strdup (val); - } - else if (!strncasecmp ("maxsize", cmd, 7)) - { - if (*cur) - (*cur)->max_size = atol (val); - else - global.max_size = atol (val); - } - else if (!strncasecmp ("UseNamespace", cmd, 12)) - { - if (*cur) - (*cur)->use_namespace = (strcasecmp (val, "yes") == 0); - else - global.use_namespace = (strcasecmp (val, "yes") == 0); - } -#if HAVE_LIBSSL - else if (!strncasecmp ("CertificateFile", cmd, 15)) - { - if (*cur) - (*cur)->cert_file = strdup (val); - else - global.cert_file = strdup (val); - } - else if (!strncasecmp ("RequireSSL", cmd, 10)) - { - if (*cur) - (*cur)->require_ssl = (strcasecmp (val, "yes") == 0); - else - global.require_ssl = (strcasecmp (val, "yes") == 0); - } - else if (!strncasecmp ("UseSSLv2", cmd, 8)) - { - if (*cur) - (*cur)->use_sslv2 = (strcasecmp (val, "yes") == 0); - else - global.use_sslv2 = (strcasecmp (val, "yes") == 0); - } - else if (!strncasecmp ("UseSSLv3", cmd, 8)) - { - if (*cur) - (*cur)->use_sslv3 = (strcasecmp (val, "yes") == 0); - else - global.use_sslv3 = (strcasecmp (val, "yes") == 0); - } - else if (!strncasecmp ("UseTLSv1", cmd, 8)) - { - if (*cur) - (*cur)->use_tlsv1 = (strcasecmp (val, "yes") == 0); - else - global.use_tlsv1 = (strcasecmp (val, "yes") == 0); - } - else if (!strncasecmp ("RequireCRAM", cmd, 11)) - { - if (*cur) - (*cur)->require_cram = (strcasecmp (val, "yes") == 0); - else - global.require_cram = (strcasecmp (val, "yes") == 0); - } -#endif - else if (buf[0]) - printf ("%s:%d:unknown command:%s", path, line, cmd); - } - fclose (fp); -} - -static config_t * -find_box (const char *s) -{ - config_t *p = box; - - for (; p; p = p->next) - if (!strcmp (s, p->path) || (p->alias && !strcmp (s, p->alias))) - return p; - return 0; -} - char * next_arg (char **s) { @@ -298,13 +100,25 @@ next_arg (char **s) *s = 0; return 0; } - ret = *s; - while (**s && !isspace ((unsigned char) **s)) - (*s)++; - if (**s) - *(*s)++ = 0; - if (!**s) - *s = 0; + if (**s == '"') + { + ++*s; + ret = *s; + *s = strchr (*s, '"'); + } + else + { + ret = *s; + while (**s && !isspace ((unsigned char) **s)) + (*s)++; + } + if (*s) + { + if (**s) + *(*s)++ = 0; + if (!**s) + *s = 0; + } return ret; } @@ -441,7 +255,7 @@ main (int argc, char **argv) puts ("Synchronizing"); i = delete ? SYNC_DELETE : 0; - i |= expunge ? SYNC_EXPUNGE : 0; + i |= (expunge || box->expunge) ? SYNC_EXPUNGE : 0; if (sync_mailbox (mail, imap, i, box->max_size)) exit (1); diff --git a/sync.c b/sync.c @@ -26,6 +26,7 @@ #include <fcntl.h> #include <string.h> #include <errno.h> +#include <sys/stat.h> #include "isync.h" static unsigned int MaildirCount = 0; @@ -40,7 +41,8 @@ find_msg (message_t * list, unsigned int uid) } int -sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, unsigned int max_size) +sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, + unsigned int max_size) { message_t *cur; message_t *tmp; @@ -83,17 +85,104 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, unsigned int max_size) tmp = find_msg (imap->msgs, cur->uid); if (!tmp) { - printf ("Warning, uid %d doesn't exist on server\n", cur->uid); - if (flags & SYNC_DELETE) + /* if this message wasn't fetched from the server, attempt to + * upload it + */ + if (cur->uid == (unsigned int) -1) { - cur->flags |= D_DELETED; - cur->dead = 1; - mbox->deleted++; + struct stat sb; + int fd; + int uid; + + /* upload the message if its not too big */ + snprintf (path, sizeof (path), "%s/%s/%s", mbox->path, + cur->new ? "new" : "cur", cur->file); + if (stat (path, &sb)) + { + printf ("Error, unable to stat %s: %s (errno %d)\n", + path, strerror (errno), errno); + + continue; /* not fatal */ + } + if (sb.st_size > imap->box->max_size) + { + printf + ("Warning, local message is too large (%ld), skipping...\n", + sb.st_size); + continue; + } + fd = open (path, O_RDONLY); + if (fd == -1) + { + printf ("Error, unable to open %s: %s (errno %d)\n", + path, strerror (errno), errno); + continue; + } + + cur->size = sb.st_size; + + uid = imap_append_message (imap, fd, cur); + + close (fd); + + /* if the server gave us back a uid, rename the file so + * we remember for next time + */ + if (uid != -1) + { + char newpath[_POSIX_PATH_MAX]; + char *p; + + 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 + { + printf ("Warning, uid %u doesn't exist on server\n", + cur->uid); + if (flags & SYNC_DELETE) + { + cur->flags |= D_DELETED; + cur->dead = 1; + mbox->deleted++; + } } continue; } tmp->processed = 1; + /* if the message is deleted, and CopyDeletedTo is set, and we + * are expunging, make a copy of the message now. + */ + if (((cur->flags | tmp->flags) & D_DELETED) != 0 && + (flags & SYNC_EXPUNGE) && imap->box->copy_deleted_to) + { + if (imap_copy_message (imap, cur->uid, + imap->box->copy_deleted_to)) + { + printf ("Error, unable to copy deleted message to \"%s\"\n", + imap->box->copy_deleted_to); + return -1; + } + } + /* check if local flags are different from server flags. * ignore \Recent and \Draft */ @@ -102,10 +191,11 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, unsigned int max_size) /* set local flags that don't exist on the server */ if (!(tmp->flags & D_DELETED) && (cur->flags & D_DELETED)) imap->deleted++; + imap_set_flags (imap, cur->uid, cur->flags & ~tmp->flags); /* update local flags */ - if((cur->flags & D_DELETED) == 0 && (tmp->flags & D_DELETED)) + if ((cur->flags & D_DELETED) == 0 && (tmp->flags & D_DELETED)) mbox->deleted++; cur->flags |= (tmp->flags & ~(D_RECENT | D_DRAFT)); cur->changed = 1; @@ -132,8 +222,9 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, unsigned int max_size) if (max_size && cur->size > max_size) { - printf ("Warning, message skipped because it is too big (%u)\n", - cur->size); + printf + ("Warning, message skipped because it is too big (%u)\n", + cur->size); continue; } @@ -148,13 +239,13 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, unsigned int max_size) (cur->flags & D_SEEN) ? "S" : "", (cur->flags & D_DELETED) ? "T" : ""); } - + for (;;) { /* create new file */ snprintf (path, sizeof (path), "%s/tmp/%s.%ld_%d.%d,U=%d%s", - mbox->path, Hostname, time (0), MaildirCount++, - getpid (), cur->uid, suffix); + mbox->path, Hostname, time (0), MaildirCount++, + getpid (), cur->uid, suffix); if ((fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600)) > 0) break; @@ -184,7 +275,7 @@ sync_mailbox (mailbox_t * mbox, imap_t * imap, int flags, unsigned int max_size) p = strrchr (path, '/'); snprintf (newpath, sizeof (newpath), "%s/%s%s", mbox->path, - (cur->flags & D_SEEN) ? "cur" : "new", p); + cur->flags ? "cur" : "new", p); /* its ok if this fails, the next time we sync the message * will get pulled down