From 6fdb9350ecdfd0dc7f65975ac9b4d6ba00161b19 Mon Sep 17 00:00:00 2001 From: Sunil Shetye Date: Tue, 3 May 2011 01:06:34 +0530 Subject: Do not search for UNSEEN messages in ranges. Add gen_recv_split() to split long protocol messages when the message prefix matches Order of search commands: IMAP> A010 SEARCH UNSEEN UNDELETED (IMAP4 or higher) IMAP> A011 SEARCH UNSEEN IMAP> A012 FETCH 1:n FLAGS --- transact.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) (limited to 'transact.c') diff --git a/transact.c b/transact.c index 758e5aaf..ff3a12ec 100644 --- a/transact.c +++ b/transact.c @@ -1586,6 +1586,98 @@ int gen_recv(int sock /** socket to which server is connected */, } } +/* + * gen_recv_split() splits the response from a server which is too + * long to fit into the buffer into multiple lines. If the prefix is + * set as "MY FEATURES" and the response from the server is too long + * to fit in the buffer, as in: + * + * "MY FEATURES ABC DEF GHI JKLMNOPQRS TU VWX YZ" + * + * Repeated calls to gen_recv_split() may return: + * + * "MY FEATURES ABC DEF GHI" + * "MY FEATURES JKLMNOPQRS" + * "MY FEATURES TU VWX YZ" + * + * A response not beginning with the prefix "MY FEATURES" will not be + * split. + * + * To use: + * - Declare a variable of type struct RecvSplit + * - Call gen_recv_split_init() once + * - Call gen_recv_split() in a loop + */ + +void gen_recv_split_init (const char *prefix, struct RecvSplit *rs) +{ + snprintf(rs->prefix, sizeof(rs->prefix), "%s", prefix); + rs->cached = 0; + rs->buf[0] = '\0'; +} + +int gen_recv_split(int sock /** socket to which server is connected */, + char *buf /* buffer to receive input */, + int size /* length of buffer */, + struct RecvSplit *rs /* cached information across calls */) +{ + size_t n = 0; + int foundnewline = 0; + char *p; + int oldphase = phase; /* we don't have to be re-entrant */ + + /* if this is not our first call, prepare the buffer */ + if (rs->cached) + { + snprintf (buf, size, "%s%s", rs->prefix, rs->buf); + n = strlen(buf); + /* clear the cache for the next call */ + rs->cached = 0; + rs->buf[0] = '\0'; + } + + phase = SERVER_WAIT; + set_timeout(mytimeout); + if (SockRead(sock, buf + n, size - n) == -1) + { + set_timeout(0); + phase = oldphase; + return(PS_SOCKET); + } + set_timeout(0); + + n = strlen(buf); + if (n > 0 && buf[n-1] == '\n') + { + buf[--n] = '\0'; + foundnewline = 1; + } + if (n > 0 && buf[n-1] == '\r') + buf[--n] = '\0'; + + if (foundnewline /* we have found a complete line */ + || strncmp(buf, rs->prefix, strlen(rs->prefix)) /* mismatch in prefix */ + || !(p = strrchr(buf, ' ')) /* no space found in response */ + || p < buf + strlen(rs->prefix)) /* space is at the wrong location */ + { + if (outlevel >= O_MONITOR) + report(stdout, "%s< %s\n", protocol->name, buf); + phase = oldphase; + return(PS_SUCCESS); + } + + /* we are ready to cache some information now. */ + rs->cached = 1; + snprintf (rs->buf, sizeof(rs->buf), "%s", p); + *p = '\0'; + if (outlevel >= O_MONITOR) + report(stdout, "%s< %s\n", protocol->name, buf); + if (outlevel >= O_DEBUG) + report(stdout, "%s< %s%s...\n", protocol->name, rs->prefix, rs->buf); + phase = oldphase; + return(PS_SUCCESS); +} + #if defined(HAVE_STDARG_H) int gen_transact(int sock, const char *fmt, ... ) #else -- cgit v1.2.3