imapfilter/response.c

847 lines
19 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <regex.h>
#include "imapfilter.h"
#include "session.h"
#include "buffer.h"
#include "regexp.h"
extern options opts;
buffer ibuf; /* Input buffer. */
enum { /* Server data responses to be parsed;
* regular expressions index. */
DATA_RESPONSE_TAGGED,
DATA_RESPONSE_CAPABILITY,
DATA_RESPONSE_AUTHENTICATE,
DATA_RESPONSE_NAMESPACE,
DATA_RESPONSE_STATUS,
DATA_RESPONSE_STATUS_MESSAGES,
DATA_RESPONSE_STATUS_RECENT,
DATA_RESPONSE_STATUS_UNSEEN,
DATA_RESPONSE_STATUS_UIDNEXT,
DATA_RESPONSE_EXAMINE_EXISTS,
DATA_RESPONSE_EXAMINE_RECENT,
DATA_RESPONSE_LIST,
DATA_RESPONSE_SEARCH,
DATA_RESPONSE_FETCH,
DATA_RESPONSE_FETCH_FLAGS,
DATA_RESPONSE_FETCH_DATE,
DATA_RESPONSE_FETCH_SIZE,
DATA_RESPONSE_FETCH_STRUCTURE,
DATA_RESPONSE_FETCH_BODY,
DATA_RESPONSE_IDLE,
};
regexp responses[] = { /* Server data responses to be parsed;
* regular expressions patterns. */
{ "([[:xdigit:]]{4,4}) (OK|NO|BAD) [[:print:]]*\r\n", NULL, 0, NULL },
{ "\\* CAPABILITY ([[:print:]]*)\r\n", NULL, 0, NULL },
{ "\\+ ([[:graph:]]*)\r\n", NULL, 0, NULL },
{ "\\* NAMESPACE (NIL|\\(\\(\"([[:graph:]]*)\" \"([[:print:]])\"\\)"
"[[:print:]]*\\)) (NIL|\\([[:print:]]*\\)) (NIL|\\([[:print:]]*\\))"
"\r\n", NULL, 0, NULL },
{ "\\* STATUS [[:print:]]* \\(([[:alnum:] ]*)\\) *\r\n", NULL, 0, NULL },
{ "MESSAGES ([[:digit:]]+)", NULL, 0, NULL },
{ "RECENT ([[:digit:]]+)", NULL, 0, NULL },
{ "UNSEEN ([[:digit:]]+)", NULL, 0, NULL },
{ "UIDNEXT ([[:digit:]]+)", NULL, 0, NULL },
{ "\\* ([[:digit:]]+) EXISTS\r\n", NULL, 0, NULL },
{ "\\* ([[:digit:]]+) RECENT\r\n", NULL, 0, NULL },
{ "\\* (LIST|LSUB) \\(([[:print:]]*)\\) (\"[[:print:]]\"|NIL) "
"(\"([[:print:]]+)\"|([[:print:]]+)|\\{([[:digit:]]+)\\}\r\n"
"([[:print:]]*))\r\n", NULL, 0, NULL },
{ "\\* SEARCH ?([[:digit:] ]*)\r\n", NULL, 0, NULL },
{ "\\* [[:digit:]]+ FETCH \\(([[:print:]]*)\\)\r\n", NULL, 0, NULL },
{ "FLAGS \\(([[:print:]]*)\\)", NULL, 0, NULL },
{ "INTERNALDATE \"([[:print:]]*)\"", NULL, 0, NULL },
{ "RFC822.SIZE ([[:digit:]]+)", NULL, 0, NULL },
{ "BODYSTRUCTURE (\\([[:print:]]+\\))", NULL, 0, NULL },
{ "\\* [[:digit:]]+ FETCH \\([[:print:]]*BODY\\[[[:print:]]*\\] "
"(\\{([[:digit:]]+)\\}\r\n|\"([[:print:]]*)\")", NULL, 0, NULL },
{ "\\* [[:digit:]]+ (RECENT|EXISTS)\r\n", NULL, 0, NULL },
{ NULL, NULL, 0, NULL }
};
int receive_response(session *ssn, char *buf, long timeout, int timeoutfail);
int check_tag(char *buf, session *ssn, int tag);
int check_bye(char *buf);
int check_continuation(char *buf);
int check_trycreate(char *buf);
/*
* Read data the server sent.
*/
int
receive_response(session *ssn, char *buf, long timeout, int timeoutfail)
{
ssize_t n;
if ((n = socket_read(ssn, buf, INPUT_BUF, timeout ? timeout :
(long)(get_option_number("timeout")), timeoutfail)) == -1)
return -1;
if (opts.debug > 0) {
int i;
debug("getting response (%d):\n\n", ssn->socket);
for (i = 0; i < n; i++)
debugc(buf[i]);
debug("\n");
}
return n;
}
/*
* Search for tagged response in the data that the server sent.
*/
int
check_tag(char *buf, session *ssn, int tag)
{
int r;
char t[4 + 1];
regexp *re;
r = STATUS_RESPONSE_NONE;
snprintf(t, sizeof(t), "%04X", tag);
re = &responses[DATA_RESPONSE_TAGGED];
if (!regexec(re->preg, buf, re->nmatch, re->pmatch, 0)) {
if (!strncasecmp(buf + re->pmatch[1].rm_so, t,
strlen(t))) {
if (!strncasecmp(buf + re->pmatch[2].rm_so,
"OK", strlen("OK")))
r = STATUS_RESPONSE_OK;
else if (!strncasecmp(buf + re->pmatch[2].rm_so,
"NO", strlen("NO")))
r = STATUS_RESPONSE_NO;
else if (!strncasecmp(buf + re->pmatch[2].rm_so,
"BAD", strlen("BAD")))
r = STATUS_RESPONSE_BAD;
}
}
if (r != STATUS_RESPONSE_NONE)
verbose("S (%d): %s", ssn->socket, buf + re->pmatch[0].rm_so);
if (r == STATUS_RESPONSE_NO || r == STATUS_RESPONSE_BAD)
error("IMAP (%d): %s", ssn->socket, buf + re->pmatch[0].rm_so);
return r;
}
/*
* Check if server sent a BYE response (connection is closed immediately).
*/
int
check_bye(char *buf)
{
if (xstrcasestr(buf, "* BYE") &&
!xstrcasestr(buf, " LOGOUT "))
return 1;
else
return 0;
}
/*
* Check if server sent a PREAUTH response (connection already authenticated
* by external means).
*/
int
check_preauth(char *buf)
{
if (xstrcasestr(ibuf.data, "* PREAUTH"))
return 1;
else
return 0;
}
/*
* Check if the server sent a continuation request.
*/
int
check_continuation(char *buf)
{
if ((buf[0] == '+' && buf[1] == ' ') || xstrcasestr(buf, "\r\n+ "))
return 1;
else
return 0;
}
/*
* Check if the server sent a TRYCREATE response.
*/
int
check_trycreate(char *buf)
{
if (xstrcasestr(buf, "[TRYCREATE]"))
return 1;
else
return 0;
}
/*
* Get server data and make sure there is a tagged response inside them.
*/
int
response_generic(session *ssn, int tag)
{
int r;
ssize_t n;
if (tag == -1)
return -1;
buffer_reset(&ibuf);
do {
buffer_check(&ibuf, ibuf.len + INPUT_BUF);
if ((n = receive_response(ssn, ibuf.data + ibuf.len, 0, 1)) == -1)
return -1;
ibuf.len += n;
if (check_bye(ibuf.data))
return -1;
} while ((r = check_tag(ibuf.data, ssn, tag)) == STATUS_RESPONSE_NONE);
if (r == STATUS_RESPONSE_NO &&
(check_trycreate(ibuf.data) || get_option_boolean("create")))
return STATUS_RESPONSE_TRYCREATE;
return r;
}
/*
* Get server data and make sure there is a continuation response inside them.
*/
int
response_continuation(session *ssn)
{
ssize_t n;
buffer_reset(&ibuf);
do {
buffer_check(&ibuf, ibuf.len + INPUT_BUF);
if ((n = receive_response(ssn, ibuf.data + ibuf.len, 0, 1)) == -1)
return -1;
ibuf.len += n;
if (check_bye(ibuf.data))
return -1;
} while (!check_continuation(ibuf.data));
return STATUS_RESPONSE_CONTINUE;
}
/*
* Process the greeting that server sends during connection.
*/
int
response_greeting(session *ssn)
{
buffer_reset(&ibuf);
if (receive_response(ssn, ibuf.data, 0, 1) == -1)
return -1;
verbose("S (%d): %s", ssn->socket, ibuf.data);
if (check_bye(ibuf.data))
return -1;
if (check_preauth(ibuf.data))
return STATUS_RESPONSE_PREAUTH;
return STATUS_RESPONSE_NONE;
}
/*
* Process the data that server sent due to IMAP CAPABILITY client request.
*/
int
response_capability(session *ssn, int tag)
{
int r;
char *s;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
ssn->protocol = PROTOCOL_NONE;
re = &responses[DATA_RESPONSE_CAPABILITY];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
if (xstrcasestr(s, "IMAP4rev1"))
ssn->protocol = PROTOCOL_IMAP4REV1;
else if (xstrcasestr(s, "IMAP4"))
ssn->protocol = PROTOCOL_IMAP4;
else {
error("server supports neither the IMAP4rev1 nor the "
"IMAP4 protocol\n");
return -1;
}
ssn->capabilities = CAPABILITY_NONE;
if (xstrcasestr(s, "NAMESPACE"))
ssn->capabilities |= CAPABILITY_NAMESPACE;
#ifndef NO_CRAMMD5
if (xstrcasestr(s, "AUTH=CRAM-MD5"))
ssn->capabilities |= CAPABILITY_CRAMMD5;
#endif
#ifndef NO_SSLTLS
if (xstrcasestr(s, "STARTTLS"))
ssn->capabilities |= CAPABILITY_STARTTLS;
#endif
if (xstrcasestr(s, "CHILDREN"))
ssn->capabilities |= CAPABILITY_CHILDREN;
if (xstrcasestr(s, "IDLE"))
ssn->capabilities |= CAPABILITY_IDLE;
xfree(s);
}
return r;
}
#ifndef NO_CRAMMD5
/*
* Process the data that server sent due to IMAP AUTHENTICATE client request.
*/
int
response_authenticate(session *ssn, int tag, unsigned char **cont)
{
int r;
regexp *re;
re = &responses[DATA_RESPONSE_AUTHENTICATE];
if ((r = response_continuation(ssn)) == STATUS_RESPONSE_CONTINUE &&
!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0))
*cont = (unsigned char *)xstrndup(ibuf.data + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
return r;
}
#endif
/*
* Process the data that server sent due to IMAP NAMESPACE client request.
*/
int
response_namespace(session *ssn, int tag)
{
int r, n;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
ssn->ns.prefix = NULL;
ssn->ns.delim = '\0';
re = &responses[DATA_RESPONSE_NAMESPACE];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
n = re->pmatch[2].rm_eo - re->pmatch[2].rm_so;
if (n > 0)
ssn->ns.prefix = xstrndup(ibuf.data +
re->pmatch[2].rm_so, n);
ssn->ns.delim = *(ibuf.data + re->pmatch[3].rm_so);
}
debug("namespace (%d): '%s' '%c'\n", ssn->socket,
(ssn->ns.prefix ? ssn->ns.prefix : ""), ssn->ns.delim);
return r;
}
/*
* Process the data that server sent due to IMAP STATUS client request.
*/
int
response_status(session *ssn, int tag, unsigned int *exist,
unsigned int *recent, unsigned int *unseen, unsigned int *uidnext)
{
int r;
char *s;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
re = &responses[DATA_RESPONSE_STATUS];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
re = &responses[DATA_RESPONSE_STATUS_MESSAGES];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*exist = strtol(s + re->pmatch[1].rm_so, NULL, 10);
re = &responses[DATA_RESPONSE_STATUS_RECENT];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*recent = strtol(s + re->pmatch[1].rm_so, NULL, 10);
re = &responses[DATA_RESPONSE_STATUS_UNSEEN];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*unseen = strtol(s + re->pmatch[1].rm_so, NULL, 10);
re = &responses[DATA_RESPONSE_STATUS_UIDNEXT];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*uidnext = strtol(s + re->pmatch[1].rm_so, NULL, 10);
xfree(s);
}
return r;
}
/*
* Process the data that server sent due to IMAP EXAMINE client request.
*/
int
response_examine(session *ssn, int tag, unsigned int *exist,
unsigned int *recent)
{
int r;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
re = &responses[DATA_RESPONSE_EXAMINE_EXISTS];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0))
*exist = strtol(ibuf.data + re->pmatch[1].rm_so, NULL, 10);
re = &responses[DATA_RESPONSE_EXAMINE_RECENT];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0))
*recent = strtol(ibuf.data + re->pmatch[1].rm_so, NULL, 10);
return r;
}
/*
* Process the data that server sent due to IMAP SELECT client request.
*/
int
response_select(session *ssn, int tag)
{
int r;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
if (xstrcasestr(ibuf.data, "[READ-ONLY]"))
return STATUS_RESPONSE_READONLY;
return r;
}
/*
* Process the data that server sent due to IMAP LIST or IMAP LSUB client
* request.
*/
int
response_list(session *ssn, int tag, char **mboxs, char **folders)
{
int r, n;
char *b, *a, *s, *m, *f;
const char *v;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
m = *mboxs = (char *)xmalloc((ibuf.len + 1) * sizeof(char));
f = *folders = (char *)xmalloc((ibuf.len + 1) * sizeof(char));
*m = *f = '\0';
re = &responses[DATA_RESPONSE_LIST];
b = ibuf.data;
while (!regexec(re->preg, b, re->nmatch, re->pmatch, 0)) {
a = xstrndup(b + re->pmatch[2].rm_so,
re->pmatch[2].rm_eo - re->pmatch[2].rm_so);
if (re->pmatch[5].rm_so != -1 && re->pmatch[5].rm_so != -1)
s = xstrndup(b + re->pmatch[5].rm_so,
re->pmatch[5].rm_eo - re->pmatch[5].rm_so);
else if (re->pmatch[6].rm_so != -1 &&
re->pmatch[6].rm_so != -1)
s = xstrndup(b + re->pmatch[6].rm_so,
re->pmatch[6].rm_eo - re->pmatch[6].rm_so);
else
s = xstrndup(b + re->pmatch[8].rm_so, strtoul(b +
re->pmatch[7].rm_so, NULL, 10));
v = reverse_namespace(s, ssn->ns.prefix, ssn->ns.delim);
n = strlen(v);
if (!xstrcasestr(a, "\\NoSelect")) {
xstrncpy(m, v, ibuf.len - (m - *mboxs));
m += n;
xstrncpy(m, "\n", ibuf.len - (m - *mboxs));
m += strlen("\n");
}
if (!xstrcasestr(a, "\\NoInferiors") &&
(!(ssn->capabilities & CAPABILITY_CHILDREN) ||
((ssn->capabilities & CAPABILITY_CHILDREN) &&
(xstrcasestr(a, "\\HasChildren")) &&
!xstrcasestr(a, "\\HasNoChildren")))) {
xstrncpy(f, v, ibuf.len - (f - *folders));
f += n;
xstrncpy(f, "\n", ibuf.len - (f - *folders));
f += strlen("\n");
}
b += re->pmatch[0].rm_eo;
xfree(a);
xfree(s);
}
return r;
}
/*
* Process the data that server sent due to IMAP SEARCH client request.
*/
int
response_search(session *ssn, int tag, char **mesgs)
{
int r;
unsigned int min;
regexp *re;
char *b, *m;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
re = &responses[DATA_RESPONSE_SEARCH];
b = ibuf.data;
m = NULL;
while (!regexec(re->preg, b, re->nmatch, re->pmatch, 0)) {
if (!*mesgs) {
m = *mesgs = (char *)xmalloc((ibuf.len + 1) *
sizeof(char));
*m = '\0';
}
min = (unsigned int)(re->pmatch[1].rm_eo - re->pmatch[1].rm_so) < ibuf.len ?
(unsigned int)(re->pmatch[1].rm_eo - re->pmatch[1].rm_so) :
ibuf.len;
xstrncpy(m, b + re->pmatch[1].rm_so, min);
m += min;
xstrncpy(m++, " ", ibuf.len - min);
b += re->pmatch[0].rm_eo;
}
return r;
}
/*
* Process the data that server sent due to IMAP FETCH FAST client request.
*/
int
response_fetchfast(session *ssn, int tag, char **flags, char **date,
char **size)
{
int r;
char *s;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
re = &responses[DATA_RESPONSE_FETCH];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
re = &responses[DATA_RESPONSE_FETCH_FLAGS];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*flags = xstrndup(s + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
re = &responses[DATA_RESPONSE_FETCH_DATE];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*date = xstrndup(s + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
re = &responses[DATA_RESPONSE_FETCH_SIZE];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*size = xstrndup(s + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
xfree(s);
}
return r;
}
/*
* Process the data that server sent due to IMAP FETCH FLAGS client request.
*/
int
response_fetchflags(session *ssn, int tag, char **flags)
{
int r;
char *s;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
re = &responses[DATA_RESPONSE_FETCH];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
re = &responses[DATA_RESPONSE_FETCH_FLAGS];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*flags = xstrndup(s + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
xfree(s);
}
return r;
}
/*
* Process the data that server sent due to IMAP FETCH INTERNALDATE client
* request.
*/
int
response_fetchdate(session *ssn, int tag, char **date)
{
int r;
char *s;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
re = &responses[DATA_RESPONSE_FETCH];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
re = &responses[DATA_RESPONSE_FETCH_DATE];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*date = xstrndup(s + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
xfree(s);
}
return r;
}
/*
* Process the data that server sent due to IMAP FETCH RFC822.SIZE client
* request.
*/
int
response_fetchsize(session *ssn, int tag, char **size)
{
int r;
char *s;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
re = &responses[DATA_RESPONSE_FETCH];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
re = &responses[DATA_RESPONSE_FETCH_SIZE];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0))
*size = xstrndup(s + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
xfree(s);
}
return r;
}
/*
* Process the data that server sent due to IMAP FETCH BODYSTRUCTURE client
* request.
*/
int
response_fetchstructure(session *ssn, int tag, char **structure)
{
int r;
char *s;
regexp *re;
if ((r = response_generic(ssn, tag)) == -1)
return -1;
re = &responses[DATA_RESPONSE_FETCH];
if (!regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0)) {
s = xstrndup(ibuf.data + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
re = &responses[DATA_RESPONSE_FETCH_STRUCTURE];
if (!regexec(re->preg, s, re->nmatch, re->pmatch, 0)) {
*structure = xstrndup(s + re->pmatch[1].rm_so,
re->pmatch[1].rm_eo - re->pmatch[1].rm_so);
}
xfree(s);
}
return r;
}
/*
* Process the data that server sent due to IMAP FETCH BODY[] client request,
* ie. FETCH BODY[HEADER], FETCH BODY[TEXT], FETCH BODY[HEADER.FIELDS
* (<fields>)], FETCH BODY[<part>].
*/
int
response_fetchbody(session *ssn, int tag, char **body, size_t *len)
{
int r, match;
unsigned int offset;
ssize_t n;
regexp *re;
if (tag == -1)
return -1;
buffer_reset(&ibuf);
match = -1;
offset = 0;
re = &responses[DATA_RESPONSE_FETCH_BODY];
do {
buffer_check(&ibuf, ibuf.len + INPUT_BUF);
if ((n = receive_response(ssn, ibuf.data + ibuf.len, 0, 1)) == -1)
return -1;
ibuf.len += n;
if (match != 0) {
match = regexec(re->preg, ibuf.data, re->nmatch,
re->pmatch, 0);
if (match == 0 && re->pmatch[2].rm_so != -1 &&
re->pmatch[2].rm_eo != -1) {
*len = strtoul(ibuf.data + re->pmatch[2].rm_so,
NULL, 10);
offset = re->pmatch[0].rm_eo + *len;
}
}
if (offset != 0 && ibuf.len >= offset) {
if (check_bye(ibuf.data + offset))
return -1;
}
} while (ibuf.len < offset || (r = check_tag(ibuf.data + offset, ssn,
tag)) == STATUS_RESPONSE_NONE);
if (match == 0) {
if (re->pmatch[2].rm_so != -1 &&
re->pmatch[2].rm_eo != -1) {
*body = ibuf.data + re->pmatch[0].rm_eo;
} else {
*body = ibuf.data + re->pmatch[3].rm_so;
*len = re->pmatch[3].rm_eo - re->pmatch[3].rm_so;
}
}
return r;
}
/*
* Process the data that server sent due to IMAP IDLE client request.
*/
int
response_idle(session *ssn, int tag)
{
regexp *re;
re = &responses[DATA_RESPONSE_IDLE];
do {
buffer_reset(&ibuf);
switch (receive_response(ssn, ibuf.data,
get_option_number("keepalive") * 60, 0)) {
case -1:
return -1;
break; /* NOTREACHED */
case 0:
return STATUS_RESPONSE_TIMEOUT;
break; /* NOTREACHED */
}
verbose("S (%d): %s", ssn->socket, ibuf.data);
if (check_bye(ibuf.data))
return -1;
} while (regexec(re->preg, ibuf.data, re->nmatch, re->pmatch, 0));
return STATUS_RESPONSE_UNTAGGED;
}