123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- #!/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-15 14:24:40.000000000 -0500
- +++ isync/src/imap.c 2004-01-15 20:36:15.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,121 @@
- }
- }
-
- -static int
- -imap_exec (imap_t * imap, const char *fmt, ...)
- +static void print_imap_command(const char *cmd, FILE *f)
- +{
- + if (strncmp(cmd, "LOGIN", 5))
- + fputs(cmd, f);
- + else
- + fputs("LOGIN USERNAME PASSWORD", f);
- +}
- +
- +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);
- + printf(">>> %d ", cmd->tag);
- + print_imap_command(tmp, stdout);
- + fputc('\n', stdout);
- 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 +581,7 @@
- if (!arg)
- {
- fprintf (stderr, "IMAP error: unable to parse untagged response\n");
- - return -1;
- + return NULL;
- }
-
- if (!strcmp ("NAMESPACE", arg))
- @@ -528,23 +653,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 +671,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 +684,94 @@
- 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)) {
- + if (cmdp->cmd) {
- + fputc('\'', stderr);
- + print_imap_command(cmdp->cmd, stderr);
- + fputc('\'', stderr);
- + } else
- + fprintf(stderr, "tag %u", tag);
- + fprintf(stderr, " returned an error (%s): %s\n",
- + arg, cmd ? cmd : "");
- + 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 +1215,7 @@
- size_t n;
- char buf[1024];
-
- + flush_imap_cmds(imap);
- send_server (imap->sock, "UID FETCH %d BODY.PEEK[]", uid);
-
- for (;;)
- @@ -1160,7 +1337,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 +1428,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 +1521,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);
|