This is based on behavior in the Debian cyrus-imapd-2.4 source package version 2.4.12-2. I have included a patch against that version. By code inspection, the same bug very probably still exists in master. I have also reported this in the Debian bug tracker:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=747561 When using imtest with an SSL connection ("imtest -s ...") against an Exchange IMAP server, long responses from the server sometimes cause the program to hang after only partially printing the response, often before printing a newline. This makes using imtest with the Gnus nnimap back end mostly useless against my Exchange server. One such long server response can result from running the "UID SEARCH ALL" command on a mailbox containing thousands of messages. A given response text will not always consistently hang the program, which implies a race condition. Sending any input to imtest, e.g., a NOOP command, will wake up imtest and cause it to print the remainder of the response. Unsolicited responses from the server, such as an inactivity timeout, can also cause the remainder of the response to be printed. Using the "-v" flag to imtest shows that prior to the hang, a read returns well over 4k bytes, but the printed output corresponding to that read prints exactly 4096 bytes before hanging. The cause is imtest/imtest.c:interactive() inappropriately using the condition (pin->cnt > 0) to determine whether to continue looping calling lib/prot.c:prot_read(). The buffer that prot_read() uses to read from SSL_read() is exactly 4096 bytes long (PROT_BUFSIZE). When an SSL record with a plaintext larger than 4096 bytes arrives, repeated calls to prot_read() by interactive() will eventually lead to pin->cnt (the protstream handle for the input from the IMAP socket) reaching zero while data remains to be read from the SSL buffers. Further calls to prot_read() will actually not block in this condition, but the readable condition is possibly already cleared on the socket file descriptor, depending on timing races with other output from the server. If the socket readable condition is cleared when pin->cnt reaches zero, the program blocks in select() until there is some user input or an unsolicited server response. It is possible that the Exchange server needs to have a very large MTU configured for this bug to trigger. The fix is to call SSL_pending() when pin->cnt reaches zero to determine if there really is no more input to read. An architecturally cleaner fix might be possible, but I imagine that involves rewriting interactive() to work with prot_select().
--- a/imtest/imtest.c +++ b/imtest/imtest.c @@ -1205,6 +1205,24 @@ gotsigint = 1; } +/* If SSL_read() reads a record with more than PROT_BUFSIZE plaintext + * bytes, s->cnt can reach 0 even though more data is available. + * Check SSL_pending() in that case, otherwise more data might be + * available to SSL_read() but the read state could still be cleared + * on the file descriptor. */ +static int remaining(struct protstream *s) +{ +#ifdef HAVE_SSL + if (s->cnt == 0 && s->tls_conn != NULL) { + int n = SSL_pending(s->tls_conn); + if (verbose) + printf("SSL_pending=%d\n", n); + return n; + } +#endif + return s->cnt; +} + /* This needs to support 3 modes: * * 1. Terminal Interface Only @@ -1369,7 +1387,7 @@ buf[count] = '\0'; printf("%s", buf); } - } while (pin->cnt > 0); + } while (remaining(pin) > 0); } else if ((FD_ISSET(fd, &rset)) && (FD_ISSET(sock, &wset)) && (donewritingfile == 0)) { /* This does input for both socket and file modes */