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:
M | Makefile.am | | | 2 | +- |
A | config.c | | | 242 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | imap.c | | | 181 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
M | isync.1 | | | 13 | +++++++++++++ |
M | isync.h | | | 12 | +++++++++++- |
M | isyncrc.sample | | | 8 | ++++++++ |
M | main.c | | | 226 | +++++++------------------------------------------------------------------------ |
M | sync.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