|
@@ -0,0 +1,445 @@
|
|
|
+#!/bin/sh -e
|
|
|
+## 30-aysnc-imap.dpatch by Theodore Y. Ts'o <tytso@mit.edu>
|
|
|
+##
|
|
|
+## DP: Add the beginnings of asynchronous IMAP support. So far, we only
|
|
|
+## DP: support asynchronous flag setting, since that's the easist.
|
|
|
+## DP: Eventually we need to support asynchronous message fetches and
|
|
|
+## DP: uploads.
|
|
|
+
|
|
|
+if [ $# -ne 1 ]; then
|
|
|
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
|
|
|
+patch_opts="${patch_opts:--f --no-backup-if-mismatch}"
|
|
|
+
|
|
|
+case "$1" in
|
|
|
+ -patch) patch $patch_opts -p1 < $0;;
|
|
|
+ -unpatch) patch $patch_opts -p1 -R < $0;;
|
|
|
+ *)
|
|
|
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
|
|
|
+ exit 1;;
|
|
|
+esac
|
|
|
+
|
|
|
+exit 0
|
|
|
+
|
|
|
+@DPATCH@
|
|
|
+diff -urNad /usr/projects/isync/SF-cvs/isync/src/imap.c isync/src/imap.c
|
|
|
+--- /usr/projects/isync/SF-cvs/isync/src/imap.c 2004-01-14 18:31:49.000000000 -0500
|
|
|
++++ isync/src/imap.c 2004-01-14 18:39:18.000000000 -0500
|
|
|
+@@ -3,6 +3,7 @@
|
|
|
+ * isync - IMAP4 to maildir mailbox synchronizer
|
|
|
+ * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
|
|
+ * Copyright (C) 2002-2003 Oswald Buddenhagen <ossi@users.sf.net>
|
|
|
++ * Copyright (C) 2004 Theodore Ts'o <tytso@alum.mit.edu>
|
|
|
+ *
|
|
|
+ * 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
|
|
|
+@@ -35,13 +36,33 @@
|
|
|
+ #include <string.h>
|
|
|
+ #include <ctype.h>
|
|
|
+ #include <sys/socket.h>
|
|
|
++#include <sys/ioctl.h>
|
|
|
+ #include <netinet/in.h>
|
|
|
++#include <netinet/tcp.h>
|
|
|
+ #include <arpa/inet.h>
|
|
|
+ #include <netdb.h>
|
|
|
+ #if HAVE_LIBSSL
|
|
|
+ # include <openssl/err.h>
|
|
|
+ #endif
|
|
|
+
|
|
|
++struct imap_cmd {
|
|
|
++ unsigned int tag;
|
|
|
++ char *cmd;
|
|
|
++ int flags;
|
|
|
++ int response;
|
|
|
++ struct imap_cmd *next;
|
|
|
++ int (*complete_fn) (imap_t *imap, struct imap_cmd * cmd);
|
|
|
++};
|
|
|
++
|
|
|
++#define IMAP_FLAG_DONE 0x0001
|
|
|
++
|
|
|
++static struct imap_cmd *in_progress = NULL;
|
|
|
++static int num_in_progress = 0;
|
|
|
++int max_in_progress_high = 50;
|
|
|
++int max_in_progress_low = 10;
|
|
|
++
|
|
|
++static struct imap_cmd *get_cmd_result(imap_t *imap);
|
|
|
++
|
|
|
+ const char *Flags[] = {
|
|
|
+ "\\Seen",
|
|
|
+ "\\Answered",
|
|
|
+@@ -199,6 +220,22 @@
|
|
|
+ return write (sock->fd, buf, len);
|
|
|
+ }
|
|
|
+
|
|
|
++static int
|
|
|
++socket_pending(Socket_t *sock)
|
|
|
++{
|
|
|
++ int num = -1;
|
|
|
++
|
|
|
++ if (ioctl(sock->fd, FIONREAD, &num) < 0)
|
|
|
++ return -1;
|
|
|
++ if (num > 0)
|
|
|
++ return num;
|
|
|
++#if HAVE_LIBSSL
|
|
|
++ if (sock->use_ssl)
|
|
|
++ return SSL_pending (sock->ssl);
|
|
|
++#endif
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
+ static void
|
|
|
+ socket_perror (const char *func, Socket_t *sock, int ret)
|
|
|
+ {
|
|
|
+@@ -301,16 +338,20 @@
|
|
|
+ }
|
|
|
+
|
|
|
+ static int
|
|
|
+-parse_fetch (imap_t * imap, list_t * list)
|
|
|
++parse_fetch (imap_t * imap, char *cmd)
|
|
|
+ {
|
|
|
+- list_t *tmp;
|
|
|
++ list_t *tmp, *list;
|
|
|
+ unsigned int uid = 0;
|
|
|
+ unsigned int mask = 0;
|
|
|
+ unsigned int size = 0;
|
|
|
+ message_t *cur;
|
|
|
+
|
|
|
+- if (!is_list (list))
|
|
|
++ list = parse_list (cmd, 0);
|
|
|
++
|
|
|
++ if (!is_list (list)) {
|
|
|
++ free_list(list);
|
|
|
+ return -1;
|
|
|
++ }
|
|
|
+
|
|
|
+ for (tmp = list->child; tmp; tmp = tmp->next)
|
|
|
+ {
|
|
|
+@@ -325,6 +366,7 @@
|
|
|
+ if (uid < imap->minuid)
|
|
|
+ {
|
|
|
+ /* already saw this message */
|
|
|
++ free_list(list);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ else if (uid > imap->maxuid)
|
|
|
+@@ -387,6 +429,7 @@
|
|
|
+ cur->flags = mask;
|
|
|
+ cur->size = size;
|
|
|
+
|
|
|
++ free_list(list);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -415,39 +458,114 @@
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+-static int
|
|
|
+-imap_exec (imap_t * imap, const char *fmt, ...)
|
|
|
++static struct imap_cmd *issue_imap_cmd(imap_t *imap,
|
|
|
++ const char *fmt, ...)
|
|
|
+ {
|
|
|
+ va_list ap;
|
|
|
+- char tmp[256];
|
|
|
+- char buf[256];
|
|
|
+- char *cmd;
|
|
|
+- char *arg;
|
|
|
+- char *arg1;
|
|
|
+- config_t *box;
|
|
|
++ char tmp[1024];
|
|
|
++ char buf[1024];
|
|
|
++ struct imap_cmd *cmd;
|
|
|
+ int n;
|
|
|
+
|
|
|
++ cmd = malloc(sizeof(struct imap_cmd));
|
|
|
++ if (!cmd)
|
|
|
++ return NULL;
|
|
|
++
|
|
|
++ cmd->tag = ++Tag;
|
|
|
++ cmd->flags = 0;
|
|
|
++ cmd->response = 0;
|
|
|
++ cmd->complete_fn = 0;
|
|
|
++
|
|
|
+ va_start (ap, fmt);
|
|
|
+ vsnprintf (tmp, sizeof (tmp), fmt, ap);
|
|
|
+ va_end (ap);
|
|
|
+
|
|
|
+- snprintf (buf, sizeof (buf), "%d %s\r\n", ++Tag, tmp);
|
|
|
++ cmd->cmd = malloc(strlen(tmp)+1);
|
|
|
++ if (cmd->cmd)
|
|
|
++ strcpy(cmd->cmd, tmp);
|
|
|
++
|
|
|
++ snprintf (buf, sizeof (buf), "%d %s\r\n", cmd->tag, tmp);
|
|
|
+ if (Verbose) {
|
|
|
+- printf (">>> %s", buf);
|
|
|
++ if (num_in_progress)
|
|
|
++ printf("(%d in progress) ", num_in_progress);
|
|
|
++ if (strncmp(tmp, "LOGIN", 5))
|
|
|
++ printf (">>> %s", buf);
|
|
|
++ else
|
|
|
++ printf (">>> LOGIN USERNAME PASSWORD\n");
|
|
|
+ fflush (stdout);
|
|
|
+ }
|
|
|
+ n = socket_write (imap->sock, buf, strlen (buf));
|
|
|
+ if (n <= 0)
|
|
|
+ {
|
|
|
+ socket_perror ("write", imap->sock, n);
|
|
|
+- return -1;
|
|
|
++ free(cmd);
|
|
|
++ return NULL;
|
|
|
++ }
|
|
|
++ cmd->next = in_progress;
|
|
|
++ in_progress = cmd;
|
|
|
++ num_in_progress++;
|
|
|
++ if ((num_in_progress > max_in_progress_high) ||
|
|
|
++ socket_pending(imap->sock)) {
|
|
|
++ while ((num_in_progress > max_in_progress_low) ||
|
|
|
++ socket_pending(imap->sock)) {
|
|
|
++ if (Verbose && socket_pending(imap->sock))
|
|
|
++ printf("(Socket input pending)\n");
|
|
|
++ get_cmd_result(imap);
|
|
|
++ }
|
|
|
+ }
|
|
|
++ return cmd;
|
|
|
++}
|
|
|
++
|
|
|
++static struct imap_cmd *find_imap_cmd(unsigned int tag)
|
|
|
++{
|
|
|
++ struct imap_cmd *cmd, *prev;
|
|
|
++
|
|
|
++ for (prev=NULL, cmd=in_progress; cmd; cmd = cmd->next) {
|
|
|
++ if (tag == cmd->tag) {
|
|
|
++ return cmd;
|
|
|
++ }
|
|
|
++ prev = cmd;
|
|
|
++ }
|
|
|
++ return NULL;
|
|
|
++}
|
|
|
++
|
|
|
++static void dequeue_imap_cmd(unsigned int tag)
|
|
|
++{
|
|
|
++ struct imap_cmd *cmd, *prev;
|
|
|
++
|
|
|
++ for (prev=NULL, cmd=in_progress; cmd; cmd = cmd->next) {
|
|
|
++ if (tag != cmd->tag) {
|
|
|
++ prev = cmd;
|
|
|
++ continue;
|
|
|
++ }
|
|
|
++ if (prev)
|
|
|
++ prev->next = cmd->next;
|
|
|
++ else
|
|
|
++ in_progress = cmd->next;
|
|
|
++ cmd->next = 0;
|
|
|
++ if (cmd->cmd)
|
|
|
++ free(cmd->cmd);
|
|
|
++ cmd->cmd = 0;
|
|
|
++ free(cmd);
|
|
|
++ break;
|
|
|
++ }
|
|
|
++}
|
|
|
++
|
|
|
++static struct imap_cmd *get_cmd_result(imap_t *imap)
|
|
|
++{
|
|
|
++ char *cmd;
|
|
|
++ char *arg;
|
|
|
++ char *arg1;
|
|
|
++ config_t *box;
|
|
|
++ int n;
|
|
|
++ unsigned int tag;
|
|
|
++ struct imap_cmd *cmdp;
|
|
|
+
|
|
|
+ for (;;)
|
|
|
+ {
|
|
|
+ next:
|
|
|
+ if (buffer_gets (imap->buf, &cmd))
|
|
|
+- return -1;
|
|
|
++ return NULL;
|
|
|
+
|
|
|
+ arg = next_arg (&cmd);
|
|
|
+ if (*arg == '*')
|
|
|
+@@ -456,7 +574,7 @@
|
|
|
+ if (!arg)
|
|
|
+ {
|
|
|
+ fprintf (stderr, "IMAP error: unable to parse untagged response\n");
|
|
|
+- return -1;
|
|
|
++ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!strcmp ("NAMESPACE", arg))
|
|
|
+@@ -528,23 +646,14 @@
|
|
|
+ imap->recent = atoi (arg);
|
|
|
+ else if (!strcmp ("FETCH", arg1))
|
|
|
+ {
|
|
|
+- list_t *list;
|
|
|
+-
|
|
|
+- list = parse_list (cmd, 0);
|
|
|
+-
|
|
|
+- if (parse_fetch (imap, list))
|
|
|
+- {
|
|
|
+- free_list (list);
|
|
|
+- return -1;
|
|
|
+- }
|
|
|
+-
|
|
|
+- free_list (list);
|
|
|
++ if (parse_fetch (imap, cmd))
|
|
|
++ return NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ fprintf (stderr, "IMAP error: unable to parse untagged response\n");
|
|
|
+- return -1;
|
|
|
++ return NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #if HAVE_LIBSSL
|
|
|
+@@ -555,7 +664,7 @@
|
|
|
+ if (!imap->cram)
|
|
|
+ {
|
|
|
+ fprintf (stderr, "IMAP error, not doing CRAM-MD5 authentication\n");
|
|
|
+- return -1;
|
|
|
++ return NULL;
|
|
|
+ }
|
|
|
+ resp = cram (cmd, imap->box->user, imap->box->pass);
|
|
|
+
|
|
|
+@@ -568,34 +677,88 @@
|
|
|
+ if (n <= 0)
|
|
|
+ {
|
|
|
+ socket_perror ("write", imap->sock, n);
|
|
|
+- return -1;
|
|
|
++ return NULL;
|
|
|
+ }
|
|
|
+ n = socket_write (imap->sock, "\r\n", 2);
|
|
|
+ if (n <= 0)
|
|
|
+ {
|
|
|
+ socket_perror ("write", imap->sock, n);
|
|
|
+- return -1;
|
|
|
++ return NULL;
|
|
|
+ }
|
|
|
+ imap->cram = 0;
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+- else if ((size_t) atol (arg) != Tag)
|
|
|
+- {
|
|
|
+- fprintf (stderr, "IMAP error: wrong tag\n");
|
|
|
+- return -1;
|
|
|
+- }
|
|
|
+- else
|
|
|
+- {
|
|
|
+- arg = next_arg (&cmd);
|
|
|
+- parse_response_code (imap, cmd);
|
|
|
+- if (!strcmp ("OK", arg))
|
|
|
+- return 0;
|
|
|
+- return -1;
|
|
|
++ else {
|
|
|
++ tag = (unsigned int) atol (arg);
|
|
|
++ cmdp = find_imap_cmd(tag);
|
|
|
++ if (!cmdp) {
|
|
|
++ fprintf(stderr, "IMAP error: sent unknown tag: %u\n",
|
|
|
++ tag);
|
|
|
++ return NULL;
|
|
|
++ }
|
|
|
++ arg = next_arg (&cmd);
|
|
|
++ if (strncmp("OK", arg, 2)) {
|
|
|
++ fprintf(stderr, "tag %u returned error: %s\n",
|
|
|
++ tag, arg);
|
|
|
++ cmdp->response = -1;
|
|
|
++ }
|
|
|
++ parse_response_code (imap, cmd);
|
|
|
++ num_in_progress--;
|
|
|
++ cmdp->flags |= IMAP_FLAG_DONE;
|
|
|
++ if (Verbose)
|
|
|
++ printf("Tag %u completed with response %d\n",
|
|
|
++ cmdp->tag, cmdp->response);
|
|
|
++ return cmdp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* not reached */
|
|
|
+ }
|
|
|
+
|
|
|
++static void flush_imap_cmds(imap_t *imap)
|
|
|
++{
|
|
|
++ struct imap_cmd *cmdp;
|
|
|
++
|
|
|
++ while (num_in_progress) {
|
|
|
++ if (in_progress && in_progress->flags & IMAP_FLAG_DONE) {
|
|
|
++ dequeue_imap_cmd(in_progress->tag);
|
|
|
++ continue;
|
|
|
++ }
|
|
|
++ cmdp = get_cmd_result(imap);
|
|
|
++ if (!cmdp)
|
|
|
++ printf("Error trying to flush pending imap cmds\n");
|
|
|
++ }
|
|
|
++}
|
|
|
++
|
|
|
++static int
|
|
|
++imap_exec (imap_t * imap, const char *fmt, ...)
|
|
|
++{
|
|
|
++ va_list ap;
|
|
|
++ char tmp[1024];
|
|
|
++ struct imap_cmd *cmdp, *waitp;
|
|
|
++ int result;
|
|
|
++
|
|
|
++ va_start (ap, fmt);
|
|
|
++ vsnprintf (tmp, sizeof (tmp), fmt, ap);
|
|
|
++ va_end (ap);
|
|
|
++
|
|
|
++ cmdp = issue_imap_cmd(imap, "%s", tmp);
|
|
|
++ if (!cmdp)
|
|
|
++ return -1;
|
|
|
++
|
|
|
++ if (cmdp->flags & IMAP_FLAG_DONE)
|
|
|
++ return cmdp->response;
|
|
|
++
|
|
|
++ do {
|
|
|
++ waitp = get_cmd_result(imap);
|
|
|
++ } while (waitp->tag != cmdp->tag);
|
|
|
++
|
|
|
++ result = cmdp->response;
|
|
|
++ dequeue_imap_cmd(cmdp->tag);
|
|
|
++
|
|
|
++ return cmdp->response;
|
|
|
++
|
|
|
++}
|
|
|
++
|
|
|
+ #ifdef HAVE_LIBSSL
|
|
|
+ static int
|
|
|
+ start_tls (imap_t *imap, config_t * cfg)
|
|
|
+@@ -1039,6 +1202,7 @@
|
|
|
+ size_t n;
|
|
|
+ char buf[1024];
|
|
|
+
|
|
|
++ flush_imap_cmds(imap);
|
|
|
+ send_server (imap->sock, "UID FETCH %d BODY.PEEK[]", uid);
|
|
|
+
|
|
|
+ for (;;)
|
|
|
+@@ -1160,7 +1324,9 @@
|
|
|
+ (buf[0] != 0) ? " " : "", Flags[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+- return imap_exec (imap, "UID STORE %d +FLAGS.SILENT (%s)", uid, buf);
|
|
|
++ if (issue_imap_cmd(imap, "UID STORE %d +FLAGS.SILENT (%s)", uid, buf))
|
|
|
++ return 0;
|
|
|
++ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ int
|
|
|
+@@ -1249,6 +1415,7 @@
|
|
|
+ strcat (flagstr,") ");
|
|
|
+ }
|
|
|
+
|
|
|
++ flush_imap_cmds(imap);
|
|
|
+ send_server (imap->sock, "APPEND %s%s %s{%d}",
|
|
|
+ imap->prefix, imap->box->box, flagstr, len + extra);
|
|
|
+
|
|
|
+@@ -1341,6 +1508,7 @@
|
|
|
+ }
|
|
|
+
|
|
|
+ /* didn't receive an APPENDUID */
|
|
|
++ flush_imap_cmds(imap);
|
|
|
+ send_server (imap->sock,
|
|
|
+ "UID SEARCH HEADER X-TUID %08lx%05lx%04x",
|
|
|
+ tv.tv_sec, tv.tv_usec, pid);
|