Commit 4faa3659 4faa3659d6140a25f05cf03e27429c7f1408851c by Sergey Poznyakoff

Process untagged responses synchronously.

* include/mailutils/imap.h (mu_imap_response_action_t): Move to
sys/imap.h
(mu_imap_foreach_response): Remove.
* include/mailutils/sys/imap.h (_mu_imap)<untagged_resp>: Remove.
All sources updated.
(_mu_imap_response): Change sigature.
(_mu_imap_untagged_response_clear)
(_mu_imap_untagged_response_add): Remove.
(_mu_imap_untagged_response_to_list)
(_mu_imap_process_untagged_response): New protos.
* libproto/imap/connect.c: Use _mu_imap_untagged_response_to_list
and _mu_imap_process_untagged_response.
* libproto/imap/create.c: Update.
* libproto/imap/destroy.c: Update.
* libproto/imap/disconnect.c: Update.
* libproto/imap/capability.c: Update calls to _mu_imap_response
* libproto/imap/id.c: Likewise.
* libproto/imap/login.c: Likewise.
* libproto/imap/logout.c: Likewise.
* libproto/imap/select.c: Likewise.
* libproto/imap/status.c: Likewise.
* libproto/imap/resplist.c (_mu_imap_untagged_response_clear): Remove.
(_mu_imap_untagged_response_add): Remove.
(_mu_imap_untagged_response_to_list): New function.
* libproto/imap/response.c (_mu_imap_response): Take response-processing
function and its closure as arguments.
* libproto/imap/resproc.c (_mu_imap_process_untagged_response): New
function.
(mu_imap_foreach_response): Remove.

* mu/imap.c: Install a BYE callback.
1 parent 80b012f7
......@@ -101,13 +101,6 @@ int mu_imap_status (mu_imap_t imap, const char *mbox, struct mu_imap_stat *ps);
extern struct mu_kwd _mu_imap_status_name_table[];
typedef void (*mu_imap_response_action_t) (mu_imap_t imap, mu_list_t resp,
void *data);
int mu_imap_foreach_response (mu_imap_t imap, mu_imap_response_action_t fun,
void *data);
/* The following five callbacks correspond to members of struct
mu_imap_stat and take a pointer to struct mu_imap_stat as their
only argument. */
......
......@@ -63,9 +63,6 @@ struct _mu_imap
/* Holds the recect response code */
enum mu_imap_response resp_code;
/* Untagged responses */
mu_list_t untagged_resp;
/* Error string (if any) */
char *errstr;
size_t errsize;
......@@ -162,10 +159,17 @@ void _mu_imap_clrerrstr (mu_imap_t imap);
int _mu_imap_tag_next (mu_imap_t imap);
int _mu_imap_tag_clr (mu_imap_t imap);
int _mu_imap_response (mu_imap_t imap);
int _mu_imap_untagged_response_clear (mu_imap_t imap);
int _mu_imap_untagged_response_add (mu_imap_t imap);
typedef void (*mu_imap_response_action_t) (mu_imap_t imap, mu_list_t resp,
void *data);
int _mu_imap_untagged_response_to_list (mu_imap_t imap, mu_list_t *plist);
int _mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list,
mu_imap_response_action_t fun,
void *data);
int _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
void *data);
int _mu_imap_list_element_is_string (struct imap_list_element *elt,
const char *str);
......
......@@ -115,24 +115,19 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
imap->state = MU_IMAP_CAPABILITY_RX;
case MU_IMAP_CAPABILITY_RX:
status = _mu_imap_response (imap);
status = _mu_imap_response (imap, _capability_response_action,
NULL);
imap->state = MU_IMAP_CONNECTED;
MU_IMAP_CHECK_EAGAIN (imap, status);
if (imap->resp_code != MU_IMAP_OK)
return MU_ERR_REPLY;
else
{
imap->state = MU_IMAP_CONNECTED;
status = mu_imap_foreach_response (imap,
_capability_response_action,
NULL);
if (status == 0)
{
if (piter)
status = mu_list_get_iterator (imap->capa, piter);
else
status = 0;
}
}
break;
case MU_IMAP_ERROR:
......
......@@ -44,9 +44,6 @@ mu_imap_connect (mu_imap_t imap)
return EINVAL;
_mu_imap_clrerrstr (imap);
status = _mu_imap_untagged_response_clear (imap);
if (status)
return status;
switch (imap->state)
{
......@@ -87,8 +84,14 @@ mu_imap_connect (mu_imap_t imap)
}
else
{
_mu_imap_untagged_response_add (imap);
mu_imap_foreach_response (imap, NULL, NULL);
mu_list_t list;
status = _mu_imap_untagged_response_to_list (imap, &list);
if (status)
break;
_mu_imap_process_untagged_response (imap, list, NULL, NULL);
mu_list_destroy (&list);
switch (imap->state)
{
case MU_IMAP_CONNECTED:
......
......@@ -53,8 +53,6 @@ _mu_imap_init (mu_imap_t imap)
{
int rc;
if (imap->untagged_resp)
mu_list_clear (imap->untagged_resp);
mu_list_destroy (&imap->capa);
_mu_imap_clrerrstr (imap);
rc = _mu_imap_tag_clr (imap);
......
......@@ -39,7 +39,6 @@ mu_imap_destroy (mu_imap_t *pimap)
if (imap->tag_buf)
free (imap->tag_buf);
mu_list_destroy (&imap->untagged_resp);
mu_list_destroy (&imap->capa);
mu_imapio_destroy (&imap->io);
......
......@@ -35,7 +35,6 @@ mu_imap_disconnect (mu_imap_t imap)
imap->state = MU_IMAP_NO_STATE;
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
mu_list_clear (imap->untagged_resp);
mu_list_clear (imap->capa);
/* Close the stream. */
......
......@@ -49,36 +49,30 @@ _id_mapper (void **itmv, size_t itmc, void *call_data)
}
static void
_id_response_action (mu_imap_t imap, mu_list_t response, void *data)
parse_id_reply (mu_imap_t imap, mu_list_t resp, void *data)
{
mu_assoc_t assoc = data;
int rc;
mu_assoc_t *passoc = data;
struct imap_list_element *elt;
elt = _mu_imap_list_at (response, 0);
if (!data)
return;
elt = _mu_imap_list_at (resp, 0);
if (elt && _mu_imap_list_element_is_string (elt, "ID"))
{
elt = _mu_imap_list_at (response, 1);
elt = _mu_imap_list_at (resp, 1);
if (elt->type == imap_eltype_list)
mu_list_gmap (elt->v.list, _id_mapper, 2, assoc);
}
}
static int
parse_id_reply (mu_imap_t imap, mu_assoc_t *passoc)
{
int rc;
{
mu_assoc_t assoc;
rc = mu_assoc_create (&assoc, sizeof (char**), MU_ASSOC_ICASE);
if (rc)
return rc;
return;
mu_assoc_set_free (assoc, _id_free);
rc = mu_imap_foreach_response (imap, _id_response_action, assoc);
if (rc)
return rc;
mu_list_gmap (elt->v.list, _id_mapper, 2, assoc);
*passoc = assoc;
return 0;
}
}
}
int
......@@ -130,14 +124,12 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc)
imap->state = MU_IMAP_ID_RX;
case MU_IMAP_ID_RX:
status = _mu_imap_response (imap);
status = _mu_imap_response (imap, parse_id_reply, passoc);
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
{
case MU_IMAP_OK:
imap->imap_state = MU_IMAP_STATE_AUTH;
if (passoc)
status = parse_id_reply (imap, passoc);
status = 0;
break;
case MU_IMAP_NO:
......
......@@ -54,7 +54,8 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
imap->state = MU_IMAP_LOGIN_RX;
case MU_IMAP_LOGIN_RX:
status = _mu_imap_response (imap);
status = _mu_imap_response (imap, NULL, NULL);
imap->state = MU_IMAP_CONNECTED;
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
{
......@@ -70,7 +71,6 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
status = MU_ERR_BADREPLY;
break;
}
imap->state = MU_IMAP_CONNECTED;
break;
default:
......
......@@ -47,7 +47,7 @@ mu_imap_logout (mu_imap_t imap)
imap->state = MU_IMAP_LOGOUT_RX;
case MU_IMAP_LOGOUT_RX:
status = _mu_imap_response (imap);
status = _mu_imap_response (imap, NULL, NULL);
MU_IMAP_CHECK_EAGAIN (imap, status);
imap->state = MU_IMAP_NO_STATE;
imap->imap_state = MU_IMAP_STATE_LOGOUT;
......
......@@ -55,16 +55,6 @@ _mu_imap_response_list_create (mu_imap_t imap, mu_list_t *plist)
return 0;
}
int
_mu_imap_untagged_response_clear (mu_imap_t imap)
{
if (imap->untagged_resp)
mu_list_clear (imap->untagged_resp);
else
return _mu_imap_response_list_create (imap, &imap->untagged_resp);
return 0;
}
#define IS_LBRACE(p) ((p)[0] == '(')
#define IS_RBRACE(p) ((p)[0] == ')')
......@@ -235,7 +225,7 @@ _parse_element (struct parsebuf *pb)
}
int
_mu_imap_untagged_response_add (mu_imap_t imap)
_mu_imap_untagged_response_to_list (mu_imap_t imap, mu_list_t *plist)
{
struct imap_list_element *elt;
struct parsebuf pb;
......@@ -251,7 +241,8 @@ _mu_imap_untagged_response_add (mu_imap_t imap)
imap->state = MU_IMAP_ERROR;
return pb.pb_err;
}
mu_list_append (imap->untagged_resp, elt);
*plist = elt->v.list;
free (elt);
return 0;
}
......
......@@ -35,7 +35,8 @@ response_to_errstr (mu_imap_t imap, size_t argc, char **argv)
}
int
_mu_imap_response (mu_imap_t imap)
_mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
void *data)
{
int status = 0;
......@@ -46,9 +47,6 @@ _mu_imap_response (mu_imap_t imap)
return 0;
_mu_imap_clrerrstr (imap);
status = _mu_imap_untagged_response_clear (imap);
if (status)
return status;
while (1)
{
......@@ -68,7 +66,12 @@ _mu_imap_response (mu_imap_t imap)
if (strcmp (wv[0], "*") == 0)
{
_mu_imap_untagged_response_add (imap);/* FIXME: error checking */
mu_list_t list;
status = _mu_imap_untagged_response_to_list (imap, &list);
if (status)
break;
_mu_imap_process_untagged_response (imap, list, fun, data);
mu_list_destroy (&list);
continue;
}
else if (strlen (wv[0]) == imap->tag_len &&
......
......@@ -306,21 +306,15 @@ _process_unsolicited_response (mu_imap_t imap, mu_list_t resp)
return 1;
}
static int
_process_response (void *item, void *data)
int
_mu_imap_process_untagged_response (mu_imap_t imap, mu_list_t list,
mu_imap_response_action_t fun,
void *data)
{
struct imap_list_element *elt = item;
struct response_closure *clos = data;
if (elt->type != imap_eltype_list)
if (_process_unsolicited_response (imap, list))
{
mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
("ignoring string response \"%s\"", elt->v.string));
}
else if (_process_unsolicited_response (clos->imap, elt->v.list))
{
if (clos->fun)
clos->fun (clos->imap, elt->v.list, clos->data);
if (fun)
fun (imap, list, data);
else
mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
("ignoring unexpected response"));
......@@ -328,14 +322,4 @@ _process_response (void *item, void *data)
return 0;
}
int
mu_imap_foreach_response (mu_imap_t imap, mu_imap_response_action_t fun,
void *data)
{
struct response_closure clos;
clos.imap = imap;
clos.fun = fun;
clos.data = data;
return mu_list_foreach (imap->untagged_resp, _process_response, &clos);
}
......
......@@ -111,7 +111,8 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
imap->state = MU_IMAP_SELECT_RX;
case MU_IMAP_SELECT_RX:
status = _mu_imap_response (imap);
memset (&imap->mbox_stat, 0, sizeof (imap->mbox_stat));
status = _mu_imap_response (imap, _select_response_action, NULL);
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
{
......@@ -125,8 +126,6 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
return errno;
}
imap->mbox_writable = writable;
memset (&imap->mbox_stat, 0, sizeof (imap->mbox_stat));
mu_imap_foreach_response (imap, _select_response_action, NULL);
if (ps)
*ps = imap->mbox_stat;
break;
......
......@@ -182,16 +182,14 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
imap->state = MU_IMAP_STATUS_RX;
case MU_IMAP_STATUS_RX:
status = _mu_imap_response (imap);
{
struct status_data sd = { mboxname, ps };
status = _mu_imap_response (imap, _status_response_action, &sd);
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
{
case MU_IMAP_OK:
{
struct status_data sd = { mboxname, ps };
status = mu_imap_foreach_response (imap, _status_response_action,
&sd);
}
break;
case MU_IMAP_NO:
......@@ -203,6 +201,7 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
break;
}
imap->state = MU_IMAP_CONNECTED;
}
break;
default:
......
......@@ -163,6 +163,18 @@ imap_popauth_callback (void *data, int code, va_list ap)
mu_diag_output (MU_DIAG_INFO, _("session authenticated"));
}
static void
imap_bye_callback (void *data, int code, va_list ap)
{
int rcode = va_arg (ap, int);
const char *text = va_arg (ap, const char *);
if (text)
mu_diag_output (MU_DIAG_INFO, _("server is closing connection: %s"), text);
else
mu_diag_output (MU_DIAG_INFO, _("server is closing connection"));
}
static int
com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
{
......@@ -259,6 +271,9 @@ com_connect (int argc, char **argv)
mu_imap_register_callback_function (imap, MU_IMAP_CB_PREAUTH,
imap_popauth_callback,
NULL);
mu_imap_register_callback_function (imap, MU_IMAP_CB_BYE,
imap_bye_callback,
NULL);
status = mu_imap_connect (imap);
......