#include "gettext.h"
/* imap_version values */
-#define IMAP2 -1 /* IMAP2 or IMAP2BIS, RFC1176 */
#define IMAP4 0 /* IMAP4 rev 0, RFC1730 */
#define IMAP4rev1 1 /* IMAP4 rev 1, RFC2060 */
return(PS_SUCCESS);
}
-static int imap_response(int sock, char *argbuf)
+static int imap_response(int sock, char *argbuf, struct RecvSplit *rs)
/* parse command response */
{
char buf[MSGBUFSIZE+1];
int ok;
char *cp;
- if ((ok = gen_recv(sock, buf, sizeof(buf))))
+ if (rs)
+ ok = gen_recv_split(sock, buf, sizeof(buf), rs);
+ else
+ ok = gen_recv(sock, buf, sizeof(buf));
+ if (ok != PS_SUCCESS)
return(ok);
/* all tokens in responses are caseblind */
{
int ok;
- while ((ok = imap_response(sock, argbuf)) == PS_UNTAGGED)
+ while ((ok = imap_response(sock, argbuf, NULL)) == PS_UNTAGGED)
; /* wait for the tagged response */
return(ok);
}
result[j] = '\0';
}
-static void capa_probe(int sock, struct query *ctl)
+static int capa_probe(int sock, struct query *ctl)
/* set capability variables from a CAPA probe */
{
int ok;
report(stdout, GT_("Protocol identified as IMAP4 rev 0\n"));
}
}
- else if (ok == PS_ERROR)
- {
- imap_version = IMAP2;
- if (outlevel >= O_DEBUG)
- report(stdout, GT_("Protocol identified as IMAP2 or IMAP2BIS\n"));
- }
+ else
+ return ok;
/*
* Handle idling. We depend on coming through here on startup
report(stdout, GT_("will idle after poll\n"));
}
- peek_capable = (imap_version >= IMAP4);
+ peek_capable = TRUE;
+
+ return PS_SUCCESS;
}
static int do_authcert (int sock, const char *command, const char *name)
else
expunge_period = 1;
- capa_probe(sock, ctl);
+ if ((ok = capa_probe(sock, ctl)))
+ return ok;
/*
* If either (a) we saw a PREAUTH token in the greeting, or
* whether TLS is mandatory or opportunistic unless SSLOpen() fails
* (see below). */
if (gen_transact(sock, "STARTTLS") == PS_SUCCESS
- && SSLOpen(sock, ctl->sslcert, ctl->sslkey, "tls1", ctl->sslcertck,
+ && (set_timeout(mytimeout), SSLOpen(sock, ctl->sslcert, ctl->sslkey, "tls1", ctl->sslcertck,
ctl->sslcertfile, ctl->sslcertpath, ctl->sslfingerprint, commonname,
- ctl->server.pollname, &ctl->remotename) != -1)
+ ctl->server.pollname, &ctl->remotename)) != -1)
{
/*
* RFC 2595 says this:
* Now that we're confident in our TLS connection we can
* guarantee a secure capability re-probe.
*/
- capa_probe(sock, ctl);
+ if ((ok = capa_probe(sock, ctl)))
+ return ok;
if (outlevel >= O_VERBOSE)
{
report(stdout, GT_("%s: upgrade to TLS succeeded.\n"), commonname);
} else if (must_tls(ctl)) {
/* Config required TLS but we couldn't guarantee it, so we must
* stop. */
+ set_timeout(0);
report(stderr, GT_("%s: upgrade to TLS failed.\n"), commonname);
return PS_SOCKET;
} else {
+ set_timeout(0);
if (outlevel >= O_VERBOSE) {
report(stdout, GT_("%s: opportunistic upgrade to TLS failed, trying to continue\n"), commonname);
}
return(ok);
}
-/* maximum number of numbers we can process in "SEARCH" response */
-# define IMAP_SEARCH_MAX 1000
-
static int imap_search(int sock, struct query *ctl, int count)
/* search for unseen messages */
{
- int ok, first, last;
+ int ok;
char buf[MSGBUFSIZE+1], *cp;
/* Don't count deleted messages. Enabled only for IMAP4 servers or
* higher and only when keeping mails. This flag will have an
* effect only when user has marked some unread mails for deletion
* using another e-mail client. */
- flag skipdeleted = (imap_version >= IMAP4) && ctl->keep;
+ flag skipdeleted = ctl->keep;
const char *undeleted;
- /* Skip range search if there are less than or equal to
- * IMAP_SEARCH_MAX mails. */
- flag skiprangesearch = (count <= IMAP_SEARCH_MAX);
+ /* structure to keep the end portion of the incomplete response */
+ struct RecvSplit rs;
/* startcount is higher than count so that if there are no
* unseen messages, imap_getsizes() will not need to do
* anything! */
startcount = count + 1;
- for (first = 1, last = IMAP_SEARCH_MAX; first <= count; first += IMAP_SEARCH_MAX, last += IMAP_SEARCH_MAX)
+ for (;;)
{
- if (last > count)
- last = count;
-
-restartsearch:
undeleted = (skipdeleted ? " UNDELETED" : "");
- if (skiprangesearch)
- gen_send(sock, "SEARCH UNSEEN%s", undeleted);
- else if (last == first)
- gen_send(sock, "SEARCH %d UNSEEN%s", last, undeleted);
- else
- gen_send(sock, "SEARCH %d:%d UNSEEN%s", first, last, undeleted);
- while ((ok = imap_response(sock, buf)) == PS_UNTAGGED)
+ gen_send(sock, "SEARCH UNSEEN%s", undeleted);
+ gen_recv_split_init("* SEARCH", &rs);
+ while ((ok = imap_response(sock, buf, &rs)) == PS_UNTAGGED)
{
if ((cp = strstr(buf, "* SEARCH")))
{
}
}
}
- /* if there is a protocol error on the first loop, try a
- * different search command */
- if (ok == PS_ERROR && first == 1)
+ if (ok != PS_ERROR) /* success or non-protocol error */
+ return(ok);
+
+ /* there is a protocol error. try a different search command. */
+ if (skipdeleted)
{
- if (skipdeleted)
- {
- /* retry with "SEARCH 1:1000 UNSEEN" */
- skipdeleted = FALSE;
- goto restartsearch;
- }
- if (!skiprangesearch)
- {
- /* retry with "SEARCH UNSEEN" */
- skiprangesearch = TRUE;
- goto restartsearch;
- }
- /* try with "FETCH 1:n FLAGS" */
- goto fetchflags;
+ /* retry with "SEARCH UNSEEN" */
+ skipdeleted = FALSE;
+ continue;
}
- if (ok != PS_SUCCESS)
- return(ok);
- /* loop back only when searching in range */
- if (skiprangesearch)
- break;
+ /* try with "FETCH 1:n FLAGS" */
+ break;
}
- return(PS_SUCCESS);
-fetchflags:
if (count == 1)
gen_send(sock, "FETCH %d FLAGS", count);
else
gen_send(sock, "FETCH %d:%d FLAGS", 1, count);
- while ((ok = imap_response(sock, buf)) == PS_UNTAGGED)
+ while ((ok = imap_response(sock, buf, NULL)) == PS_UNTAGGED)
{
unsigned int num;
int consumed;
gen_send(sock, "FETCH %d:%d RFC822.SIZE", first, last);
else /* no unseen messages! */
return(PS_SUCCESS);
- while ((ok = imap_response(sock, buf)) == PS_UNTAGGED)
+ while ((ok = imap_response(sock, buf, NULL)) == PS_UNTAGGED)
{
unsigned int size;
int num;
gen_send(sock, "FETCH %d RFC822.HEADER", number);
/* looking for FETCH response */
- if ((ok = imap_response(sock, buf)) == PS_UNTAGGED)
+ if ((ok = imap_response(sock, buf, NULL)) == PS_UNTAGGED)
{
int consumed;
/* expected response formats:
/* try to recover for some responses */
if (!strncmp(buf, "* NO", 4) ||
- !strncmp(buf, "* BAD", 5))
+ !strncmp(buf, "* BAD", 5) ||
+ strstr(buf, "FETCH ()"))
{
return(PS_TRANSIENT);
}
/* an unexpected tagged response */
if (outlevel > O_SILENT)
report(stderr, GT_("Incorrect FETCH response: %s.\n"), buf);
- return(PS_ERROR);
+ return(PS_TRANSIENT);
}
return(ok);
}
* equivalent". However, we know of at least one server that
* treats them differently in the presence of MIME attachments;
* the latter form downloads the attachment, the former does not.
- * The server is InterChange, and the fool who implemented this
- * misfeature ought to be strung up by his thumbs.
+ * The server is InterChange.
*
* When I tried working around this by disabling use of the 4rev1 form,
* I found that doing this breaks operation with M$ Exchange.
* Annoyingly enough, Exchange's refusal to cope is technically legal
- * under RFC2062. Trust Microsoft, the Great Enemy of interoperability
- * standards, to find a way to make standards compliance irritating....
+ * under RFC2062.
*/
switch (imap_version)
{
case IMAP4rev1: /* RFC 2060 */
+ default:
gen_send(sock, "FETCH %d BODY.PEEK[TEXT]", number);
break;
case IMAP4: /* RFC 1730 */
gen_send(sock, "FETCH %d RFC822.TEXT.PEEK", number);
break;
-
- default: /* RFC 1176 */
- gen_send(sock, "FETCH %d RFC822.TEXT", number);
- break;
}
/* looking for FETCH response */
number -= expunged;
/*
- * Use SILENT if possible as a minor throughput optimization.
- * Note: this has been dropped from IMAP4rev1.
- *
* We set Seen because there are some IMAP servers (notably HP
* OpenMail) that do message-receipt DSNs, but only when the seen
* bit is set. This is the appropriate time -- we get here right
* after the local SMTP response that says delivery was
* successful.
*/
- if ((ok = gen_transact(sock,
- imap_version == IMAP4
- ? "STORE %d +FLAGS.SILENT (\\Seen \\Deleted)"
- : "STORE %d +FLAGS (\\Seen \\Deleted)",
- number)))
+ if ((ok = gen_transact(sock, "STORE %d +FLAGS.SILENT (\\Seen \\Deleted)", number)))
return(ok);
else
deletions++;
/* expunges change the message numbers */
number -= expunged;
- return(gen_transact(sock,
- imap_version == IMAP4
- ? "STORE %d +FLAGS.SILENT (\\Seen)"
- : "STORE %d +FLAGS (\\Seen)",
- number));
+ return(gen_transact(sock,"STORE %d +FLAGS.SILENT (\\Seen)", number));
}
static int imap_end_mailbox_poll(int sock, struct query *ctl)