Selaa lähdekoodia

Initial asynchronous flags setting patch.

Theodore Ts'o 21 vuotta sitten
vanhempi
sitoutus
75bffd0947
1 muutettua tiedostoa jossa 445 lisäystä ja 0 poistoa
  1. 445 0
      debian/patches/30-async-imap.dpatch

+ 445 - 0
debian/patches/30-async-imap.dpatch

@@ -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);