Commit de237686 de2376862a1d3a9f00602eea7976751266287401 by Sergey Poznyakoff

Clean-up state changes in imap client. Fix error handling in it and in pop3.

* include/mailutils/imap.h (mu_imap_state): Rename to struct
mu_imap_session_state, prefix all values with MU_IMAP_STATE_.
All uses updated.
* include/mailutils/sys/imap.h (mu_imap_client_state): Prefix all
values with MU_IMAP_CLIENT. Rename MU_IMAP_NO_STATE to MU_IMAP_READY.
All uses updated.
(_mu_imap)<state>: Rename to client_state, fix data type.
(imap_state): Rename to imap_state. All uses updated.
(MU_IMAP_CHECK_EAGAIN): Reset state to MU_IMAP_CLIENT_READY if
MU_ERR_REPLY or MU_ERR_BADREPLY is reported.
* include/mailutils/sys/pop3.h (MU_POP3_CHECK_EAGAIN): Reset state
to MU_POP3_NO_STATE, if MU_ERR_REPLY or MU_ERR_BADREPLY is reported.
* libproto/imap/fetch.c (_date_mapper): Avoid overwriting resp->type.
* libproto/imap/select.c (_mu_imap_collect_flags): Initialize *res
prior to collecting flags into it.
* mu/imap.c: Install a FETCH callback.
1 parent b848706b
......@@ -33,13 +33,13 @@ extern "C" {
typedef struct _mu_imap *mu_imap_t;
enum mu_imap_state
enum mu_imap_session_state
{
MU_IMAP_STATE_INIT, /* Initial state */
MU_IMAP_STATE_NONAUTH, /* Non-Authenticated State */
MU_IMAP_STATE_AUTH, /* Authenticated State */
MU_IMAP_STATE_SELECTED, /* Selected State */
MU_IMAP_STATE_LOGOUT, /* Logout State */
MU_IMAP_SESSION_INIT, /* Initial state (disconnected) */
MU_IMAP_SESSION_NONAUTH, /* Non-Authenticated State */
MU_IMAP_SESSION_AUTH, /* Authenticated State */
MU_IMAP_SESSION_SELECTED, /* Selected State */
MU_IMAP_SESSION_LOGOUT, /* Logout State */
};
int mu_imap_create (mu_imap_t *pimap);
......
......@@ -45,20 +45,19 @@ extern "C" {
enum mu_imap_client_state
{
MU_IMAP_NO_STATE,
MU_IMAP_ERROR,
MU_IMAP_CONNECT,
MU_IMAP_GREETINGS,
MU_IMAP_CONNECTED,
MU_IMAP_CAPABILITY_RX,
MU_IMAP_LOGIN_RX,
MU_IMAP_LOGOUT_RX,
MU_IMAP_ID_RX,
MU_IMAP_SELECT_RX,
MU_IMAP_STATUS_RX,
MU_IMAP_NOOP_RX,
MU_IMAP_FETCH_RX,
MU_IMAP_CLOSING
MU_IMAP_CLIENT_READY,
MU_IMAP_CLIENT_ERROR,
MU_IMAP_CLIENT_CONNECT_RX,
MU_IMAP_CLIENT_GREETINGS,
MU_IMAP_CLIENT_CAPABILITY_RX,
MU_IMAP_CLIENT_LOGIN_RX,
MU_IMAP_CLIENT_LOGOUT_RX,
MU_IMAP_CLIENT_ID_RX,
MU_IMAP_CLIENT_SELECT_RX,
MU_IMAP_CLIENT_STATUS_RX,
MU_IMAP_CLIENT_NOOP_RX,
MU_IMAP_CLIENT_FETCH_RX,
MU_IMAP_CLIENT_CLOSING
};
enum mu_imap_response
......@@ -79,8 +78,8 @@ struct _mu_imap
char *errstr;
size_t errsize;
enum mu_imap_state state;
enum mu_imap_state imap_state;
enum mu_imap_client_state client_state;
enum mu_imap_session_state session_state;
/* Tag */
size_t tag_len; /* Length of the command tag */
......@@ -129,39 +128,41 @@ int _mu_imap_xscript_level (mu_imap_t imap, int xlev);
/* If status indicates an error, return.
*/
#define MU_IMAP_CHECK_ERROR(imap, status) \
do \
{ \
if (status != 0) \
{ \
imap->state = MU_IMAP_ERROR; \
return status; \
} \
} \
#define MU_IMAP_CHECK_ERROR(imap, status) \
do \
{ \
if (status != 0) \
{ \
imap->client_state = MU_IMAP_CLIENT_ERROR; \
return status; \
} \
} \
while (0)
/* Check if status indicates an error.
If the error is recoverable just return the status.
Otherwise, set the error state and return the status
*/
#define MU_IMAP_CHECK_EAGAIN(imap, status) \
do \
{ \
switch (status) \
{ \
case 0: \
break; \
case EAGAIN: \
case EINPROGRESS: \
case EINTR: \
case MU_ERR_REPLY: \
case MU_ERR_BADREPLY: \
return status; \
default: \
imap->state = MU_IMAP_ERROR; \
return status; \
} \
} \
#define MU_IMAP_CHECK_EAGAIN(imap, status) \
do \
{ \
switch (status) \
{ \
case 0: \
break; \
case EAGAIN: \
case EINPROGRESS: \
case EINTR: \
return status; \
case MU_ERR_REPLY: \
case MU_ERR_BADREPLY: \
imap->client_state = MU_IMAP_CLIENT_READY; \
return status; \
default: \
imap->client_state = MU_IMAP_CLIENT_ERROR; \
return status; \
} \
} \
while (0)
int _mu_imap_seterrstr (mu_imap_t imap, const char *str, size_t len);
......
......@@ -107,8 +107,10 @@ int _mu_pop3_init (mu_pop3_t pop3);
case EAGAIN: \
case EINPROGRESS: \
case EINTR: \
return status; \
case MU_ERR_REPLY: \
case MU_ERR_BADREPLY: \
pop3->state = MU_POP3_NO_STATE; \
return status; \
default: \
pop3->state = MU_POP3_ERROR; \
......
......@@ -82,7 +82,8 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
if (imap->session_state == MU_IMAP_SESSION_INIT ||
imap->client_state != MU_IMAP_CLIENT_READY)
return MU_ERR_SEQ;
if (imap->capa)
......@@ -103,21 +104,21 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
mu_list_set_destroy_item (imap->capa, mu_list_free_item);
}
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s CAPABILITY\r\n",
imap->tag_str);
MU_IMAP_CHECK_EAGAIN (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->state = MU_IMAP_CAPABILITY_RX;
imap->client_state = MU_IMAP_CLIENT_CAPABILITY_RX;
case MU_IMAP_CAPABILITY_RX:
case MU_IMAP_CLIENT_CAPABILITY_RX:
status = _mu_imap_response (imap, _capability_response_action,
NULL);
imap->state = MU_IMAP_CONNECTED;
imap->client_state = MU_IMAP_CLIENT_READY;
MU_IMAP_CHECK_EAGAIN (imap, status);
if (imap->resp_code != MU_IMAP_OK)
return MU_ERR_REPLY;
......@@ -130,7 +131,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
}
break;
case MU_IMAP_ERROR:
case MU_IMAP_CLIENT_ERROR:
status = ECANCELED;
break;
......
......@@ -49,7 +49,8 @@ mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier)
imap->io = io;
if (MU_IMAP_FISSET (imap, MU_IMAP_TRACE))
_mu_imap_trace_enable (imap);
imap->state = MU_IMAP_CONNECT;
imap->client_state = MU_IMAP_CLIENT_READY;
imap->session_state = MU_IMAP_SESSION_INIT;
return 0;
}
......
......@@ -45,22 +45,25 @@ mu_imap_connect (mu_imap_t imap)
_mu_imap_clrerrstr (imap);
switch (imap->state)
switch (imap->client_state)
{
default:
case MU_IMAP_NO_STATE:
status = mu_imap_disconnect (imap);
if (status != 0)
case MU_IMAP_CLIENT_READY:
if (imap->session_state != MU_IMAP_SESSION_INIT)
{
/* Sleep for 2 seconds (FIXME: Must be configurable) */
struct timeval tval;
tval.tv_sec = 2;
tval.tv_usec = 0;
select (0, NULL, NULL, NULL, &tval);
status = mu_imap_disconnect (imap);
if (status != 0)
{
/* Sleep for 2 seconds (FIXME: Must be configurable) */
struct timeval tval;
tval.tv_sec = 2;
tval.tv_usec = 0;
select (0, NULL, NULL, NULL, &tval);
}
}
imap->state = MU_IMAP_CONNECT;
imap->client_state = MU_IMAP_CLIENT_CONNECT_RX;
case MU_IMAP_CONNECT:
case MU_IMAP_CLIENT_CONNECT_RX:
/* Establish the connection. */
if (!mu_stream_is_open (imap->io->_imap_stream))
{
......@@ -68,9 +71,9 @@ mu_imap_connect (mu_imap_t imap)
MU_IMAP_CHECK_EAGAIN (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
}
imap->state = MU_IMAP_GREETINGS;
imap->client_state = MU_IMAP_CLIENT_GREETINGS;
case MU_IMAP_GREETINGS:
case MU_IMAP_CLIENT_GREETINGS:
status = mu_imapio_getline (imap->io);
MU_IMAP_CHECK_EAGAIN (imap, status);
mu_imapio_get_words (imap->io, &wc, &wv);
......@@ -79,7 +82,7 @@ mu_imap_connect (mu_imap_t imap)
mu_imapio_getbuf (imap->io, &bufptr, &bufsize);
mu_error ("mu_imap_connect: invalid server response: %s",
bufptr);
imap->state = MU_IMAP_ERROR;
imap->client_state = MU_IMAP_CLIENT_ERROR;
return MU_ERR_BADREPLY;
}
else
......@@ -92,18 +95,18 @@ mu_imap_connect (mu_imap_t imap)
_mu_imap_process_untagged_response (imap, list, NULL, NULL);
mu_list_destroy (&list);
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
status = 0;
break;
case MU_IMAP_CLOSING:
case MU_IMAP_CLIENT_CLOSING:
status = EACCES;
break;
default:
imap->state = MU_IMAP_ERROR;
imap->client_state = MU_IMAP_CLIENT_ERROR;
status = MU_ERR_BADREPLY;
}
}
......
......@@ -60,6 +60,7 @@ _mu_imap_init (mu_imap_t imap)
if (rc)
return rc;
}
imap->state = MU_IMAP_NO_STATE; /* Init with no state. */
imap->client_state = MU_IMAP_CLIENT_READY;
imap->session_state = MU_IMAP_SESSION_INIT;
return 0;
}
......
......@@ -32,7 +32,7 @@ mu_imap_disconnect (mu_imap_t imap)
if (imap == NULL)
return EINVAL;
imap->state = MU_IMAP_NO_STATE;
imap->client_state = MU_IMAP_CLIENT_READY;
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
mu_list_clear (imap->capa);
......
......@@ -37,24 +37,22 @@ mu_imap_fetch (mu_imap_t imap, const char *msgset, const char *items)
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
return MU_ERR_SEQ;
if (imap->imap_state != MU_IMAP_STATE_SELECTED)
if (imap->session_state != MU_IMAP_SESSION_SELECTED)
return MU_ERR_SEQ;
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s FETCH %s %s\r\n",
imap->tag_str, msgset, items);
MU_IMAP_CHECK_ERROR (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->state = MU_IMAP_FETCH_RX;
imap->client_state = MU_IMAP_CLIENT_FETCH_RX;
case MU_IMAP_FETCH_RX:
case MU_IMAP_CLIENT_FETCH_RX:
status = _mu_imap_response (imap, NULL, NULL);
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
......@@ -71,7 +69,7 @@ mu_imap_fetch (mu_imap_t imap, const char *msgset, const char *items)
status = MU_ERR_BADREPLY;
break;
}
imap->state = MU_IMAP_CONNECTED;
imap->client_state = MU_IMAP_CLIENT_READY;
break;
default:
......@@ -221,7 +219,9 @@ _body_mapper (struct imap_list_element **elt,
break;
}
}
else
p = NULL;
if (partc)
{
size_t i;
......@@ -237,7 +237,7 @@ _body_mapper (struct imap_list_element **elt,
resp->body.partc = partc;
resp->body.partv = partv;
if (p)
if (p && *p)
{
size_t len = strlen (p);
resp->body.key = malloc (len);
......@@ -338,20 +338,22 @@ static int
_date_mapper (struct imap_list_element **elt,
union mu_imap_fetch_response **return_resp)
{
struct mu_imap_fetch_internaldate idate;
union mu_imap_fetch_response *resp;
int rc;
const char *p;
struct tm tm;
struct mu_timezone tz;
if (elt[1]->type != imap_eltype_string)
return MU_ERR_FAILURE;
p = elt[1]->v.string;
if (mu_parse_imap_date_time (&p, &idate.tm, &idate.tz))
if (mu_parse_imap_date_time (&p, &tm, &tz))
return MU_ERR_FAILURE;
rc = alloc_response (&resp, MU_IMAP_FETCH_INTERNALDATE);
if (rc)
return rc;
resp->internaldate = idate;
resp->internaldate.tm = tm;
resp->internaldate.tz = tz;
*return_resp = resp;
return 0;
}
......
......@@ -84,12 +84,12 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc)
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
if (imap->session_state == MU_IMAP_SESSION_INIT)
return MU_ERR_SEQ;
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s ID ", imap->tag_str);
......@@ -121,9 +121,9 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc)
status = mu_imapio_printf (imap->io, "\r\n");
MU_IMAP_CHECK_ERROR (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->state = MU_IMAP_ID_RX;
imap->client_state = MU_IMAP_CLIENT_ID_RX;
case MU_IMAP_ID_RX:
case MU_IMAP_CLIENT_ID_RX:
status = _mu_imap_response (imap, parse_id_reply, passoc);
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
......@@ -140,7 +140,7 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc)
status = MU_ERR_BADREPLY;
break;
}
imap->state = MU_IMAP_CONNECTED;
imap->client_state = MU_IMAP_CLIENT_READY;
break;
default:
......
......@@ -33,14 +33,12 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
return MU_ERR_SEQ;
if (imap->imap_state != MU_IMAP_STATE_NONAUTH)
if (imap->session_state != MU_IMAP_SESSION_NONAUTH)
return MU_ERR_SEQ;
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
if (mu_imap_trace_mask (imap, MU_IMAP_TRACE_QRY, MU_XSCRIPT_SECURE))
_mu_imap_xscript_level (imap, MU_XSCRIPT_SECURE);
status = _mu_imap_tag_next (imap);
......@@ -51,16 +49,16 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
/* FIXME: how to obscure the passwd in the stream buffer? */
MU_IMAP_CHECK_EAGAIN (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->state = MU_IMAP_LOGIN_RX;
imap->client_state = MU_IMAP_CLIENT_LOGIN_RX;
case MU_IMAP_LOGIN_RX:
case MU_IMAP_CLIENT_LOGIN_RX:
status = _mu_imap_response (imap, NULL, NULL);
imap->state = MU_IMAP_CONNECTED;
imap->client_state = MU_IMAP_CLIENT_READY;
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
{
case MU_IMAP_OK:
imap->imap_state = MU_IMAP_STATE_AUTH;
imap->session_state = MU_IMAP_SESSION_AUTH;
break;
case MU_IMAP_NO:
......
......@@ -32,25 +32,26 @@ mu_imap_logout (mu_imap_t imap)
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
if (!(imap->session_state == MU_IMAP_SESSION_AUTH ||
imap->session_state == MU_IMAP_SESSION_SELECTED))
return MU_ERR_SEQ;
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s LOGOUT\r\n",
imap->tag_str);
MU_IMAP_CHECK_EAGAIN (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->state = MU_IMAP_LOGOUT_RX;
imap->client_state = MU_IMAP_CLIENT_LOGOUT_RX;
case MU_IMAP_LOGOUT_RX:
case MU_IMAP_CLIENT_LOGOUT_RX:
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;
imap->client_state = MU_IMAP_CLIENT_READY;
imap->session_state = MU_IMAP_SESSION_LOGOUT;
break;
default:
......
......@@ -33,20 +33,20 @@ mu_imap_noop (mu_imap_t imap)
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
if (imap->session_state == MU_IMAP_SESSION_INIT)
return MU_ERR_SEQ;
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s NOOP\r\n", imap->tag_str);
MU_IMAP_CHECK_ERROR (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->state = MU_IMAP_NOOP_RX;
imap->client_state = MU_IMAP_CLIENT_NOOP_RX;
case MU_IMAP_NOOP_RX:
case MU_IMAP_CLIENT_NOOP_RX:
status = _mu_imap_response (imap, NULL, NULL);
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
......@@ -63,7 +63,7 @@ mu_imap_noop (mu_imap_t imap)
status = MU_ERR_BADREPLY;
break;
}
imap->state = MU_IMAP_CONNECTED;
imap->client_state = MU_IMAP_CLIENT_READY;
break;
default:
......
......@@ -64,7 +64,7 @@ _new_imap_list_element (mu_imap_t imap, enum imap_eltype type)
struct imap_list_element *elt = calloc (1, sizeof (*elt));
if (!elt)
{
imap->state = MU_IMAP_ERROR;
imap->client_state = MU_IMAP_CLIENT_ERROR;
}
else
elt->type = type;
......@@ -238,7 +238,7 @@ _mu_imap_untagged_response_to_list (mu_imap_t imap, mu_list_t *plist)
{
if (elt)
_imap_list_free (elt);
imap->state = MU_IMAP_ERROR;
imap->client_state = MU_IMAP_CLIENT_ERROR;
return pb.pb_err;
}
*plist = elt->v.list;
......
......@@ -59,7 +59,7 @@ _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
mu_imapio_get_words (imap->io, &wc, &wv);
if (wc == 0)
{
imap->state = MU_IMAP_ERROR;
imap->client_state = MU_IMAP_CLIENT_ERROR;
status = MU_ERR_BADREPLY;/* FIXME: ECONNRESET ? */
break;
}
......@@ -80,7 +80,7 @@ _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
/* Handle the tagged response */
if (wc < 2)
{
/*imap->state = MU_IMAP_ERROR;*/
/*imap->client_state = MU_IMAP_CLIENT_ERROR;*/
status = MU_ERR_BADREPLY;
}
else if (strcmp (wv[1], "OK") == 0)
......@@ -104,12 +104,12 @@ _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
}
else
{
imap->state = MU_IMAP_ERROR;
imap->client_state = MU_IMAP_CLIENT_ERROR;
status = MU_ERR_BADREPLY;
}
}
else
imap->state = MU_IMAP_ERROR;
imap->client_state = MU_IMAP_CLIENT_ERROR;
break;
}
return status;
......
......@@ -143,10 +143,10 @@ ok_response (mu_imap_t imap, mu_list_t resp, void *data)
if (mu_list_tail (resp, (void*) &arg) || arg->type != imap_eltype_string)
arg = NULL;
mu_imap_callback (imap, MU_IMAP_CB_OK, rcode, arg ? arg->v.string : NULL);
if (imap->state == MU_IMAP_GREETINGS)
if (imap->client_state == MU_IMAP_CLIENT_GREETINGS)
{
imap->state = MU_IMAP_CONNECTED;
imap->imap_state = MU_IMAP_STATE_NONAUTH;
imap->client_state = MU_IMAP_CLIENT_READY;
imap->session_state = MU_IMAP_SESSION_NONAUTH;
}
}
......@@ -165,29 +165,29 @@ static void
no_response (mu_imap_t imap, mu_list_t resp, void *data)
{
default_response (imap, MU_IMAP_CB_NO, resp, data);
if (imap->state == MU_IMAP_GREETINGS)
imap->state = MU_IMAP_ERROR;
if (imap->client_state == MU_IMAP_CLIENT_GREETINGS)
imap->client_state = MU_IMAP_CLIENT_ERROR;
}
static void
bad_response (mu_imap_t imap, mu_list_t resp, void *data)
{
default_response (imap, MU_IMAP_CB_BAD, resp, data);
if (imap->state == MU_IMAP_GREETINGS)
imap->state = MU_IMAP_ERROR;
if (imap->client_state == MU_IMAP_CLIENT_GREETINGS)
imap->client_state = MU_IMAP_CLIENT_ERROR;
}
static void
bye_response (mu_imap_t imap, mu_list_t resp, void *data)
{
default_response (imap, MU_IMAP_CB_BYE, resp, data);
imap->state = MU_IMAP_CLOSING;
imap->client_state = MU_IMAP_CLIENT_CLOSING;
}
static void
preauth_response (mu_imap_t imap, mu_list_t resp, void *data)
{
if (imap->state == MU_IMAP_GREETINGS)
if (imap->client_state == MU_IMAP_CLIENT_GREETINGS)
{
struct imap_list_element *arg;
......@@ -196,8 +196,8 @@ preauth_response (mu_imap_t imap, mu_list_t resp, void *data)
mu_imap_callback (imap, MU_IMAP_CB_PREAUTH,
parse_response_code (imap, resp),
arg ? arg->v.string : NULL);
imap->state = MU_IMAP_CONNECTED;
imap->imap_state = MU_IMAP_STATE_AUTH;
imap->client_state = MU_IMAP_CLIENT_READY;
imap->session_state = MU_IMAP_SESSION_AUTH;
}
else
mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
......
......@@ -43,6 +43,7 @@ _mu_imap_collect_flags (struct imap_list_element *arg, int *res)
{
if (arg->type != imap_eltype_list)
return EINVAL;
*res = 0;
mu_list_foreach (arg->v.list, _collect_flags, res);
return 0;
}
......@@ -72,15 +73,13 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
return MU_ERR_SEQ;
if (imap->imap_state != MU_IMAP_STATE_AUTH &&
imap->imap_state != MU_IMAP_STATE_SELECTED)
if (imap->session_state != MU_IMAP_SESSION_AUTH &&
imap->session_state != MU_IMAP_SESSION_SELECTED)
return MU_ERR_SEQ;
if (!mbox)
{
if (imap->imap_state == MU_IMAP_STATE_SELECTED)
if (imap->session_state == MU_IMAP_SESSION_SELECTED)
{
if (ps)
*ps = imap->mbox_stat;
......@@ -97,9 +96,9 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
return 0;
}
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s %s %s\r\n",
......@@ -108,21 +107,21 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
mbox);
MU_IMAP_CHECK_ERROR (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->state = MU_IMAP_SELECT_RX;
imap->client_state = MU_IMAP_CLIENT_SELECT_RX;
case MU_IMAP_SELECT_RX:
case MU_IMAP_CLIENT_SELECT_RX:
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)
{
case MU_IMAP_OK:
imap->imap_state = MU_IMAP_STATE_SELECTED;
imap->session_state = MU_IMAP_SESSION_SELECTED;
free (imap->mbox_name);
imap->mbox_name = strdup (mbox);
if (!imap->mbox_name)
{
imap->state = MU_IMAP_ERROR;
imap->client_state = MU_IMAP_CLIENT_ERROR;
return errno;
}
imap->mbox_writable = writable;
......@@ -138,7 +137,7 @@ mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
status = MU_ERR_BADREPLY;
break;
}
imap->state = MU_IMAP_CONNECTED;
imap->client_state = MU_IMAP_CLIENT_READY;
break;
default:
......
......@@ -36,7 +36,7 @@ mu_imap_state (mu_imap_t imap, int *pstate)
{
if (imap == NULL || pstate == NULL)
return EINVAL;
*pstate = imap->imap_state;
*pstate = imap->session_state;
return 0;
}
......
......@@ -126,10 +126,8 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
return EINVAL;
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
return MU_ERR_SEQ;
if (imap->imap_state != MU_IMAP_STATE_AUTH &&
imap->imap_state != MU_IMAP_STATE_SELECTED)
if (imap->session_state != MU_IMAP_SESSION_AUTH &&
imap->session_state != MU_IMAP_SESSION_SELECTED)
return MU_ERR_SEQ;
if (!ps)
return MU_ERR_OUT_PTR_NULL;
......@@ -138,7 +136,7 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
if (!mboxname)
{
if (imap->imap_state == MU_IMAP_STATE_SELECTED)
if (imap->session_state == MU_IMAP_SESSION_SELECTED)
{
if (ps)
*ps = imap->mbox_stat;
......@@ -154,9 +152,9 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
return 0;
}
switch (imap->state)
switch (imap->client_state)
{
case MU_IMAP_CONNECTED:
case MU_IMAP_CLIENT_READY:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s STATUS %s (",
......@@ -179,9 +177,9 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
status = mu_imapio_send (imap->io, ")\r\n", 3);
MU_IMAP_CHECK_ERROR (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
imap->state = MU_IMAP_STATUS_RX;
imap->client_state = MU_IMAP_CLIENT_STATUS_RX;
case MU_IMAP_STATUS_RX:
case MU_IMAP_CLIENT_STATUS_RX:
{
struct status_data sd = { mboxname, ps };
......@@ -200,7 +198,7 @@ mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
status = MU_ERR_BADREPLY;
break;
}
imap->state = MU_IMAP_CONNECTED;
imap->client_state = MU_IMAP_CLIENT_READY;
}
break;
......
......@@ -62,17 +62,17 @@ static struct argp imap_argp = {
static mu_imap_t imap;
static enum mu_imap_state
static enum mu_imap_session_state
current_imap_state ()
{
int state;
if (imap == NULL)
state = MU_IMAP_STATE_INIT;
state = MU_IMAP_SESSION_INIT;
else
{
mu_imap_state (imap, &state);
if (state == MU_IMAP_STATE_LOGOUT)
state = MU_IMAP_STATE_INIT;
if (state == MU_IMAP_SESSION_LOGOUT)
state = MU_IMAP_SESSION_INIT;
}
return state;
}
......@@ -131,12 +131,12 @@ static char *username;
static void
imap_prompt_env ()
{
enum mu_imap_state state = current_imap_state ();
enum mu_imap_session_state state = current_imap_state ();
if (!mutool_prompt_env)
mutool_prompt_env = xcalloc (2*7 + 1, sizeof(mutool_prompt_env[0]));
mutool_prompt_env[0] = "user";
mutool_prompt_env[1] = (state >= MU_IMAP_STATE_AUTH && username) ?
mutool_prompt_env[1] = (state >= MU_IMAP_SESSION_AUTH && username) ?
username : "[nouser]";
mutool_prompt_env[2] = "host";
......@@ -188,7 +188,133 @@ imap_bad_callback (void *data, int code, size_t sdat, void *pdat)
const char *text = pdat;
mu_diag_output (MU_DIAG_CRIT, "SERVER ALERT: %s", text);
}
/* Fetch callback */
static void
format_email (mu_stream_t str, const char *name, mu_address_t addr)
{
mu_stream_printf (str, " %s = ", name);
if (!addr)
mu_stream_printf (str, "NIL");
else
{
size_t sz = mu_address_format_string (addr, NULL, 0);
char *buf = xmalloc (sz + 1);
mu_address_format_string (addr, buf, sz);
mu_stream_write (str, buf, strlen (buf), NULL);
}
mu_stream_printf (str, "\n");
}
static void
format_date (mu_stream_t str, char *name,
struct tm *tm, struct mu_timezone *tz)
{
char date[128];
strftime (date, sizeof (date), "%a %b %e %H:%M:%S", tm);
mu_stream_printf (str, " %s = %s", name, date);
if (tz->tz_name)
mu_stream_printf (str, " %s", tz->tz_name);
else
{
int off = tz->utc_offset;
if (off < 0)
{
mu_stream_printf (str, " -");
off = - off;
}
else
mu_stream_printf (str, " +");
off /= 60;
mu_stream_printf (str, "%02d%02d", off / 60, off % 60);
}
mu_stream_printf (str, "\n");
}
static int
fetch_response_printer (void *item, void *data)
{
union mu_imap_fetch_response *resp = item;
mu_stream_t str = data;
switch (resp->type)
{
case MU_IMAP_FETCH_BODY:
mu_stream_printf (str, "BODY [%s]", resp->body.key);
if (resp->body.partv)
{
size_t i;
mu_stream_printf (str, ", part: ");
for (i = 0; i < resp->body.partc; i++)
mu_stream_printf (str, "%lu.",
(unsigned long) resp->body.partv[i]);
}
mu_stream_printf (str, "\nBEGIN%s\nEND\n", resp->body.text);
break;
case MU_IMAP_FETCH_BODYSTRUCTURE:
/* FIXME */
mu_stream_printf (str, "BODYSTRUCTURE (not yet implemented)\n");
break;
case MU_IMAP_FETCH_ENVELOPE:
{
mu_stream_printf (str, "ENVELOPE:\n");
format_date (str, "date", &resp->envelope.date, &resp->envelope.tz);
format_email (str, "from", resp->envelope.from);
format_email (str, "sender", resp->envelope.sender);
format_email (str, "reply-to", resp->envelope.reply_to);
format_email (str, "to", resp->envelope.to);
format_email (str, "cc", resp->envelope.cc);
format_email (str, "bcc", resp->envelope.bcc);
mu_stream_printf (str, " in-reply-to = %s\n",
resp->envelope.in_reply_to ?
resp->envelope.in_reply_to : "NIL");
mu_stream_printf (str, " message-id = %s\n",
resp->envelope.message_id ?
resp->envelope.message_id : "NIL");
}
break;
case MU_IMAP_FETCH_FLAGS:
mu_stream_printf (str, " flags = ");
mu_imap_format_flags (str, resp->flags.flags);
mu_stream_printf (str, "\n");
break;
case MU_IMAP_FETCH_INTERNALDATE:
format_date (str, "internaldate", &resp->internaldate.tm,
&resp->internaldate.tz);
break;
case MU_IMAP_FETCH_RFC822_SIZE:
mu_stream_printf (str, " size = %lu\n",
(unsigned long) resp->rfc822_size.size);
break;
case MU_IMAP_FETCH_UID:
mu_stream_printf (str, " UID = %lu\n",
(unsigned long) resp->uid.uid);
}
return 0;
}
static void
imap_fetch_callback (void *data, int code, size_t sdat, void *pdat)
{
mu_stream_t str = data;
mu_list_t list = pdat;
mu_stream_printf (str, "Message #%lu:\n", (unsigned long) sdat);
mu_list_foreach (list, fetch_response_printer, str);
mu_stream_printf (str, "\n\n");
}
static int
com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
......@@ -212,7 +338,7 @@ com_connect (int argc, char **argv)
int status;
int tls = 0;
int i = 1;
enum mu_imap_state state;
enum mu_imap_session_state state;
for (i = 1; i < argc; i++)
{
......@@ -234,7 +360,7 @@ com_connect (int argc, char **argv)
state = current_imap_state ();
if (state != MU_IMAP_STATE_INIT)
if (state != MU_IMAP_SESSION_INIT)
com_disconnect (0, NULL);
status = mu_imap_create (&imap);
......@@ -292,7 +418,9 @@ com_connect (int argc, char **argv)
mu_imap_register_callback_function (imap, MU_IMAP_CB_BAD,
imap_bad_callback,
NULL);
mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH,
imap_fetch_callback,
mu_strout);
status = mu_imap_connect (imap);
if (status)
......@@ -600,7 +728,17 @@ com_noop (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
static int
com_fetch (int argc, char **argv)
{
int status = mu_imap_fetch (imap, argv[1], argv[2]);
int status;
mu_stream_t out = mutool_open_pager ();
mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH,
imap_fetch_callback,
out);
status = mu_imap_fetch (imap, argv[1], argv[2]);
mu_stream_destroy (&out);
mu_imap_register_callback_function (imap, MU_IMAP_CB_FETCH,
imap_fetch_callback,
mu_strout);
if (status)
report_failure ("fetch", status);
return 0;
......