mirror of https://git.code.sf.net/p/isync/isync
Theodore Ts'o
21 years ago
1 changed files with 445 additions and 0 deletions
@ -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); |
Loading…
Reference in new issue