Commit f7942ced f7942ced21d97774e678be261cc5b9094e47e8da by Sergey Poznyakoff

Rewrite existing imap client support using imapio.

1 parent a4a3755e
......@@ -53,7 +53,7 @@ int mu_imap_capability_test (mu_imap_t imap, const char *name,
int mu_imap_login (mu_imap_t imap, const char *user, const char *pass);
int mu_imap_logout (mu_imap_t imap);
int mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist);
int mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc);
int mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier);
int mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier);
......
......@@ -22,6 +22,7 @@
# include <mailutils/sys/mailbox.h>
# include <mailutils/sys/registrar.h>
# include <mailutils/sys/auth.h>
# include <mailutils/imapio.h>
# include <mailutils/imap.h>
# ifdef __cplusplus
......@@ -29,7 +30,7 @@ extern "C" {
# endif
#define MU_IMAP_RESP 0x01
#define MU_IMAP_TRACE 0x02
#define MU_IMAP_TRACE 0x02
#define MU_IMAP_XSCRIPT_MASK(n) (1<<((n)+1))
enum mu_imap_client_state
......@@ -56,9 +57,7 @@ struct _mu_imap
{
int flags;
/* Holds the tagged response to the last command */
char *tagbuf;
size_t tagsize;
/* Holds the recect response code */
enum mu_imap_response resp_code;
/* Untagged responses */
......@@ -68,10 +67,6 @@ struct _mu_imap
char *errstr;
size_t errsize;
/* Input line buffer */
char *rdbuf;
size_t rdsize;
enum mu_imap_state state;
enum mu_imap_state imap_state;
......@@ -81,7 +76,23 @@ struct _mu_imap
char *tag_str; /* String representation (tag_len + 1 bytes, asciiz) */
mu_list_t capa;
mu_stream_t carrier;
mu_imapio_t io;
};
enum imap_eltype
{
imap_eltype_string,
imap_eltype_list
};
struct imap_list_element
{
enum imap_eltype type;
union
{
mu_list_t list;
char *string;
} v;
};
#define MU_IMAP_FSET(p,f) ((p)->flags |= (f))
......@@ -137,6 +148,9 @@ 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);
# ifdef __cplusplus
}
......
......@@ -39,6 +39,7 @@ libmu_imap_la_SOURCES = \
id.c\
login.c\
logout.c\
resplist.c\
response.c\
state.c\
tag.c\
......
......@@ -19,13 +19,14 @@
# include <config.h>
#endif
#include <string.h>
#include <mailutils/types.h>
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/list.h>
#include <mailutils/wordsplit.h>
#include <mailutils/iterator.h>
#include <mailutils/sys/imap.h>
static int
......@@ -50,7 +51,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
if (imap == NULL)
return EINVAL;
if (!imap->carrier)
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
return MU_ERR_SEQ;
......@@ -78,7 +79,7 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
case MU_IMAP_CONNECTED:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_stream_printf (imap->carrier, "%s CAPABILITY\r\n",
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);
......@@ -92,35 +93,35 @@ mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter)
else
{
size_t count;
char *str;
struct imap_list_element *elt;
imap->state = MU_IMAP_CONNECTED;
mu_list_count (imap->untagged_resp, &count);
if (mu_list_get (imap->untagged_resp, 0, (void*)&str) == 0)
if (mu_list_get (imap->untagged_resp, 0, (void*)&elt) == 0)
{
size_t i;
/* Top-level elements are always of imap_eltype_list type. */
mu_iterator_t itr;
struct mu_wordsplit ws;
if (mu_wordsplit (str, &ws,
MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
MU_WRDSF_QUOTE | MU_WRDSF_SQUEEZE_DELIMS))
{
int ec = errno;
mu_error ("mu_imap_capability: cannot split line: %s",
mu_wordsplit_strerror (&ws));
return ec;
}
if (ws.ws_wordc > 1 &&
mu_c_strcasecmp (ws.ws_wordv[0], "CAPABILITY") == 0)
mu_list_get_iterator (elt->v.list, &itr);
mu_iterator_first (itr);
if (mu_iterator_is_done (itr))
return MU_ERR_PARSE;
mu_iterator_current (itr, (void **) &elt);
if (elt->type == imap_eltype_string &&
strcmp (elt->v.string, "CAPABILITY") == 0)
{
for (i = 1; i < ws.ws_wordc; i++)
for (mu_iterator_next (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
mu_list_append (imap->capa, ws.ws_wordv[i]);
ws.ws_wordv[i] = NULL;
mu_iterator_current (itr, (void **) &elt);
if (elt->type == imap_eltype_string)
{
mu_list_append (imap->capa, elt->v.string);
elt->v.string = NULL;
}
}
}
mu_wordsplit_free (&ws);
mu_iterator_destroy (&itr);
}
if (piter)
status = mu_list_get_iterator (imap->capa, piter);
......
......@@ -23,23 +23,30 @@
#include <stdlib.h>
#include <errno.h>
#include <mailutils/errno.h>
#include <mailutils/imapio.h>
#include <mailutils/sys/imap.h>
#include <mailutils/sys/imapio.h>
int
mu_imap_set_carrier (mu_imap_t imap, mu_stream_t carrier)
{
int rc;
mu_imapio_t io;
/* Sanity checks. */
if (imap == NULL)
return EINVAL;
if (imap->carrier)
rc = mu_imapio_create (&io, carrier);
if (rc)
return rc;
if (imap->io)
{
/* Close any old carrier. */
mu_imap_disconnect (imap);
mu_stream_destroy (&imap->carrier);
mu_imapio_free (imap->io);
}
mu_stream_ref (carrier);
imap->carrier = carrier;
imap->io = io;
if (MU_IMAP_FISSET (imap, MU_IMAP_TRACE))
_mu_imap_trace_enable (imap);
imap->state = MU_IMAP_CONNECT;
......@@ -55,8 +62,8 @@ mu_imap_get_carrier (mu_imap_t imap, mu_stream_t *pcarrier)
if (pcarrier == NULL)
return MU_ERR_OUT_PTR_NULL;
mu_stream_ref (imap->carrier);
*pcarrier = imap->carrier;
mu_stream_ref (imap->io->_imap_stream);
*pcarrier = imap->io->_imap_stream;
return 0;
}
......
......@@ -24,18 +24,23 @@
#include <sys/select.h>
#include <sys/time.h>
#include <mailutils/errno.h>
#include <mailutils/wordsplit.h>
#include <mailutils/imapio.h>
#include <mailutils/sys/imap.h>
#include <mailutils/sys/imapio.h>
int
mu_imap_connect (mu_imap_t imap)
{
int status;
size_t wc;
char **wv;
char *bufptr;
size_t bufsize;
if (imap == NULL)
return EINVAL;
if (imap->carrier == NULL)
if (imap->io == NULL)
return EINVAL;
switch (imap->state)
{
......@@ -54,66 +59,48 @@ mu_imap_connect (mu_imap_t imap)
case MU_IMAP_CONNECT:
/* Establish the connection. */
if (!mu_stream_is_open (imap->carrier))
if (!mu_stream_is_open (imap->io->_imap_stream))
{
status = mu_stream_open (imap->carrier);
status = mu_stream_open (imap->io->_imap_stream);
MU_IMAP_CHECK_EAGAIN (imap, status);
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
}
imap->state = MU_IMAP_GREETINGS;
case MU_IMAP_GREETINGS:
status = mu_stream_getline (imap->carrier, &imap->rdbuf,
&imap->rdsize, NULL);
status = mu_imapio_getline (imap->io);
MU_IMAP_CHECK_EAGAIN (imap, status);
if (imap->rdsize < 2 ||
!(imap->rdbuf[0] == '*' && imap->rdbuf[1] == ' '))
mu_imapio_get_words (imap->io, &wc, &wv);
if (wc < 2 || strcmp (wv[0], "*"))
{
mu_imapio_getbuf (imap->io, &bufptr, &bufsize);
mu_error ("mu_imap_connect: invalid server response: %s",
imap->rdbuf);
bufptr);
imap->state = MU_IMAP_ERROR;
return MU_ERR_BADREPLY;
}
else if (strcmp (wv[1], "BYE") == 0)
{
status = EACCES;
mu_imapio_getbuf (imap->io, &bufptr, &bufsize);
_mu_imap_seterrstr (imap, bufptr + 2, bufsize - 2);
}
else if (strcmp (wv[1], "PREAUTH") == 0)
{
status = 0;
imap->state = MU_IMAP_CONNECTED;
imap->imap_state = MU_IMAP_STATE_AUTH;
}
else if (strcmp (wv[1], "OK") == 0)
{
status = 0;
imap->state = MU_IMAP_CONNECTED;
imap->imap_state = MU_IMAP_STATE_NONAUTH;
}
else
{
struct mu_wordsplit ws;
if (mu_wordsplit (imap->rdbuf, &ws,
MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
MU_WRDSF_SQUEEZE_DELIMS))
{
int ec = errno;
mu_error ("mu_imap_connect: cannot split line: %s",
mu_wordsplit_strerror (&ws));
imap->state = MU_IMAP_ERROR;
return ec;
}
if (ws.ws_wordc < 2)
status = MU_ERR_BADREPLY;
else if (strcmp (ws.ws_wordv[1], "BYE") == 0)
{
status = EACCES;
_mu_imap_seterrstr (imap, imap->rdbuf + 2,
strlen (imap->rdbuf + 2));
}
else if (strcmp (ws.ws_wordv[1], "PREAUTH") == 0)
{
status = 0;
imap->state = MU_IMAP_CONNECTED;
imap->imap_state = MU_IMAP_STATE_AUTH;
}
else if (strcmp (ws.ws_wordv[1], "OK") == 0)
{
status = 0;
imap->state = MU_IMAP_CONNECTED;
imap->imap_state = MU_IMAP_STATE_NONAUTH;
}
else
{
status = MU_ERR_BADREPLY;
imap->state = MU_IMAP_ERROR;
}
mu_wordsplit_free (&ws);
status = MU_ERR_BADREPLY;
imap->state = MU_IMAP_ERROR;
}
}
......
......@@ -49,7 +49,7 @@ _mu_imap_init (mu_imap_t imap)
{
if (imap == NULL)
return EINVAL;
if (imap->carrier == 0)
if (!imap->io)
{
int rc;
......
......@@ -31,13 +31,6 @@ mu_imap_destroy (mu_imap_t *pimap)
{
mu_imap_t imap = *pimap;
/* Free the response buffer. */
if (imap->tagbuf)
free (imap->tagbuf);
/* Free the read buffer. */
if (imap->rdbuf)
free (imap->rdbuf);
if (imap->errstr)
free (imap->errstr);
......@@ -49,7 +42,7 @@ mu_imap_destroy (mu_imap_t *pimap)
mu_list_destroy (&imap->untagged_resp);
mu_list_destroy (&imap->capa);
mu_stream_destroy (&imap->carrier);
mu_imapio_destroy (&imap->io);
free (imap);
......
......@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mailutils/imapio.h>
#include <mailutils/sys/imap.h>
int
......@@ -34,14 +35,11 @@ mu_imap_disconnect (mu_imap_t imap)
imap->state = MU_IMAP_NO_STATE;
MU_IMAP_FCLR (imap, MU_IMAP_RESP);
if (imap->rdbuf)
imap->rdbuf[0] = 0;
mu_list_clear (imap->untagged_resp);
mu_list_clear (imap->capa);
/* Close the stream. */
if (mu_stream_is_open (imap->carrier))
return mu_stream_close (imap->carrier);
mu_imapio_destroy (&imap->io);
return 0;
}
......
......@@ -22,93 +22,109 @@
#include <stdlib.h>
#include <string.h>
#include <mailutils/errno.h>
#include <mailutils/cstr.h>
#include <mailutils/wordsplit.h>
#include <mailutils/assoc.h>
#include <mailutils/stream.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
static int
id_comp (const void *item, const void *value)
void
_id_free (void *data)
{
const char *id = item;
const char *needle = value;
return mu_c_strcasecmp (id, needle);
char *s = *(char**)data;
free (s);
}
struct id_convert_state
{
int item;
mu_assoc_t assoc;
int ret;
};
static int
parse_id_reply (mu_imap_t imap, mu_list_t *plist)
_id_convert (void *item, void *data)
{
struct imap_list_element *elt = item;
struct id_convert_state *stp = data;
switch (stp->item)
{
case 0:
if (!(elt->type == imap_eltype_string &&
strcmp (elt->v.string, "ID") == 0))
{
stp->ret = MU_ERR_PARSE;
return 1;
}
stp->item++;
return 0;
case 1:
if (elt->type == imap_eltype_list)
{
mu_iterator_t itr;
mu_list_get_iterator (elt->v.list, &itr);
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
char *key, *val;
mu_iterator_current (itr, (void **) &elt);
if (elt->type != imap_eltype_string)
break;
key = elt->v.string;
elt->v.string = NULL;
mu_iterator_next (itr);
if (mu_iterator_is_done (itr))
break;
mu_iterator_current (itr, (void **) &elt);
if (elt->type != imap_eltype_string)
break;
val = elt->v.string;
elt->v.string = NULL;
mu_assoc_install (stp->assoc, key, &val);
}
}
}
return 1;
}
static int
parse_id_reply (mu_imap_t imap, mu_assoc_t *passoc)
{
mu_list_t list;
int rc;
const char *response;
struct mu_wordsplit ws;
size_t i;
rc = mu_list_create (&list);
struct imap_list_element const *response;
struct id_convert_state st;
mu_assoc_t assoc;
rc = mu_assoc_create (&assoc, sizeof (char**), MU_ASSOC_ICASE);
if (rc)
return rc;
mu_list_set_comparator (list, id_comp);
mu_list_set_destroy_item (list, mu_list_free_item);
mu_assoc_set_free (assoc, _id_free);
rc = mu_list_get (imap->untagged_resp, 0, (void*) &response);
*passoc = assoc;
if (rc == MU_ERR_NOENT)
{
*plist = list;
return 0;
}
else if (rc)
{
mu_list_destroy (&list);
return rc;
}
ws.ws_delim = "() \t";
if (mu_wordsplit (response, &ws,
MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
MU_WRDSF_QUOTE | MU_WRDSF_DELIM |
MU_WRDSF_SQUEEZE_DELIMS |
MU_WRDSF_WS))
{
int ec = errno;
mu_error ("mu_imap_id: cannot split line: %s",
mu_wordsplit_strerror (&ws));
mu_list_destroy (&list);
return ec;
}
return 0;
for (i = 1; i < ws.ws_wordc; i += 2)
{
size_t len, l1, l2;
char *elt;
if (i + 1 == ws.ws_wordc)
break;
l1 = strlen (ws.ws_wordv[i]);
l2 = strlen (ws.ws_wordv[i+1]);
len = l1 + l2 + 1;
elt = malloc (len + 1);
if (!elt)
break;
memcpy (elt, ws.ws_wordv[i], l1);
elt[l1] = 0;
memcpy (elt + l1 + 1, ws.ws_wordv[i+1], l2);
elt[len] = 0;
mu_list_append (list, elt);
}
mu_wordsplit_free (&ws);
*plist = list;
return 0;
st.item = 0;
st.assoc = assoc;
st.ret = 0;
mu_list_do (response->v.list, _id_convert, &st);
return st.ret;
}
int
mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc)
{
int status;
if (imap == NULL)
return EINVAL;
if (!imap->carrier)
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
return MU_ERR_SEQ;
......@@ -118,11 +134,10 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
case MU_IMAP_CONNECTED:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_stream_printf (imap->carrier, "%s ID ",
imap->tag_str);
status = mu_imapio_printf (imap->io, "%s ID ", imap->tag_str);
MU_IMAP_CHECK_ERROR (imap, status);
if (!idenv)
status = mu_stream_printf (imap->carrier, "NIL");
status = mu_imapio_printf (imap->io, "NIL");
else
{
if (idenv[0])
......@@ -131,7 +146,7 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
char *delim = "(";
for (i = 0; idenv[i]; i++)
{
status = mu_stream_printf (imap->carrier, "%s\"%s\"",
status = mu_imapio_printf (imap->io, "%s\"%s\"",
delim, idenv[i]);
MU_IMAP_CHECK_ERROR (imap, status);
......@@ -139,13 +154,13 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
if (status)
break;
}
status = mu_stream_printf (imap->carrier, ")");
status = mu_imapio_printf (imap->io, ")");
}
else
status = mu_stream_printf (imap->carrier, "()");
status = mu_imapio_printf (imap->io, "()");
}
MU_IMAP_CHECK_ERROR (imap, status);
status = mu_stream_printf (imap->carrier, "\r\n");
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;
......@@ -157,8 +172,8 @@ mu_imap_id (mu_imap_t imap, char **idenv, mu_list_t *plist)
{
case MU_IMAP_OK:
imap->imap_state = MU_IMAP_STATE_AUTH;
if (plist)
status = parse_id_reply (imap, plist);
if (passoc)
status = parse_id_reply (imap, passoc);
break;
case MU_IMAP_NO:
......
......@@ -30,7 +30,7 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
if (imap == NULL)
return EINVAL;
if (!imap->carrier)
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
return MU_ERR_SEQ;
......@@ -44,7 +44,7 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
_mu_imap_xscript_level (imap, MU_XSCRIPT_SECURE);
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_stream_printf (imap->carrier, "%s LOGIN \"%s\" \"%s\"\r\n",
status = mu_imapio_printf (imap->io, "%s LOGIN \"%s\" \"%s\"\r\n",
imap->tag_str, user, pass);
_mu_imap_xscript_level (imap, MU_XSCRIPT_NORMAL);
/* FIXME: how to obscure the passwd in the stream buffer? */
......
......@@ -30,7 +30,7 @@ mu_imap_logout (mu_imap_t imap)
if (imap == NULL)
return EINVAL;
if (!imap->carrier)
if (!imap->io)
return MU_ERR_NO_TRANSPORT;
if (imap->state != MU_IMAP_CONNECTED)
return MU_ERR_SEQ;
......@@ -40,7 +40,7 @@ mu_imap_logout (mu_imap_t imap)
case MU_IMAP_CONNECTED:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_stream_printf (imap->carrier, "%s LOGOUT\r\n",
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);
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010, 2011 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mailutils/cctype.h>
#include <mailutils/cstr.h>
#include <mailutils/stream.h>
#include <mailutils/errno.h>
#include <mailutils/sys/imap.h>
static void
_imap_list_free (void *ptr)
{
struct imap_list_element *elt = ptr;
switch (elt->type)
{
case imap_eltype_string:
free (elt->v.string);
break;
case imap_eltype_list:
mu_list_destroy (&elt->v.list);
}
free (ptr);
}
static int
_mu_imap_response_list_create (mu_imap_t imap, mu_list_t *plist)
{
mu_list_t list;
int status = mu_list_create (&list);
MU_IMAP_CHECK_ERROR (imap, status);
mu_list_set_destroy_item (list, _imap_list_free);
*plist = list;
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] == ')')
static struct imap_list_element *
_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;
}
else
elt->type = type;
return elt;
}
struct parsebuf
{
mu_imap_t pb_imap;
size_t pb_count;
char **pb_arr;
int pb_err;
int pb_inlist;
};
static void
parsebuf_init (struct parsebuf *pb, mu_imap_t imap)
{
memset (pb, 0, sizeof *pb);
pb->pb_imap = imap;
}
static int
parsebuf_advance (struct parsebuf *pb)
{
if (pb->pb_count == 0)
return MU_ERR_NOENT;
pb->pb_count--;
pb->pb_arr++;
return 0;
}
static char *
parsebuf_gettok (struct parsebuf *pb)
{
char *p;
if (pb->pb_count == 0)
return NULL;
p = *pb->pb_arr;
parsebuf_advance (pb);
return p;
}
static char *
parsebuf_peek (struct parsebuf *pb)
{
if (pb->pb_count == 0)
return NULL;
return *pb->pb_arr;
}
static void
parsebuf_seterr (struct parsebuf *pb, int err)
{
pb->pb_err = err;
}
static struct imap_list_element *_parse_element (struct parsebuf *pb);
static struct imap_list_element *
_parse_list (struct parsebuf *pb)
{
int rc;
struct imap_list_element *elt, *list_elt;
elt = _new_imap_list_element (pb->pb_imap, imap_eltype_list);
if (!elt)
{
parsebuf_seterr (pb, ENOMEM);
return NULL;
}
rc = _mu_imap_response_list_create (pb->pb_imap, &elt->v.list);
if (rc)
{
free (elt);
parsebuf_seterr (pb, rc);
return NULL;
}
while ((list_elt = _parse_element (pb)))
mu_list_append (elt->v.list, list_elt);
return elt;
}
static struct imap_list_element *
_parse_element (struct parsebuf *pb)
{
struct imap_list_element *elt;
char *tok;
if (pb->pb_err)
return NULL;
tok = parsebuf_gettok (pb);
if (!tok)
{
if (pb->pb_inlist)
parsebuf_seterr (pb, MU_ERR_PARSE);
return NULL;
}
if (IS_LBRACE (tok))
{
tok = parsebuf_peek (pb);
if (!tok)
{
parsebuf_seterr (pb, MU_ERR_PARSE);
return NULL;
}
if (IS_RBRACE (tok))
{
elt = _new_imap_list_element (pb->pb_imap, imap_eltype_list);
if (!elt)
{
parsebuf_seterr (pb, ENOMEM);
return NULL;
}
elt->v.list = NULL;
}
else
{
pb->pb_inlist++;
elt = _parse_list (pb);
}
}
else if (IS_RBRACE (tok))
{
if (pb->pb_inlist)
pb->pb_inlist--;
else
parsebuf_seterr (pb, MU_ERR_PARSE);
return NULL;
}
else
{
char *s;
elt = _new_imap_list_element (pb->pb_imap, imap_eltype_string);
if (!elt)
{
parsebuf_seterr (pb, ENOMEM);
return NULL;
}
s = strdup (tok);
if (!s)
{
free (elt);
parsebuf_seterr (pb, ENOMEM);
return NULL;
}
elt->v.string = s;
}
return elt;
}
int
_mu_imap_untagged_response_add (mu_imap_t imap)
{
struct imap_list_element *elt;
struct parsebuf pb;
parsebuf_init (&pb, imap);
mu_imapio_get_words (imap->io, &pb.pb_count, &pb.pb_arr);
parsebuf_advance (&pb); /* Skip initial '*' */
elt = _parse_list (&pb);
if (pb.pb_err)
{
if (elt)
_imap_list_free (elt);
imap->state = MU_IMAP_ERROR;
return pb.pb_err;
}
mu_list_append (imap->untagged_resp, elt);
return 0;
}
......@@ -27,15 +27,9 @@
#include <mailutils/errno.h>
#include <mailutils/sys/imap.h>
#define IS_PREFIX(s, len, pfx) \
((len) >= sizeof (pfx) - 1 && \
memcmp ((s), (pfx), sizeof (pfx) - 1) == 0 && \
s[sizeof (pfx) - 1] == ' ')
int
_mu_imap_response (mu_imap_t imap)
{
size_t n = 0;
int status = 0;
if (imap == NULL)
......@@ -45,81 +39,74 @@ _mu_imap_response (mu_imap_t imap)
return 0;
_mu_imap_clrerrstr (imap);
if (imap->untagged_resp)
mu_list_clear (imap->untagged_resp);
else
{
status = mu_list_create (&imap->untagged_resp);
MU_IMAP_CHECK_ERROR (imap, status);
mu_list_set_destroy_item (imap->untagged_resp, mu_list_free_item);
}
status = _mu_imap_untagged_response_clear (imap);
if (status)
return status;
while (1)
{
status = mu_stream_getline (imap->carrier, &imap->rdbuf,
&imap->rdsize, NULL);
status = mu_imapio_getline (imap->io);
if (status == 0)
{
n = mu_rtrim_class (imap->rdbuf, MU_CTYPE_SPACE);
if (imap->rdbuf[0] == '*' && imap->rdbuf[1] == ' ')
char **wv;
size_t wc;
char *p;
mu_imapio_get_words (imap->io, &wc, &wv);
if (strcmp (wv[0], "*") == 0)
{
char *p = mu_str_skip_cset (imap->rdbuf + 2, " ");
mu_list_append (imap->untagged_resp, strdup (p));
_mu_imap_untagged_response_add (imap);/* FIXME: error checking */
continue;
}
else if (n > imap->tag_len + 3 &&
memcmp (imap->rdbuf, imap->tag_str, imap->tag_len) == 0
&& imap->rdbuf[imap->tag_len] == ' ')
else if (strlen (wv[0]) == imap->tag_len &&
memcmp (wv[0], imap->tag_str, imap->tag_len) == 0)
{
char *p = mu_str_skip_cset (imap->rdbuf + imap->tag_len, " ");
size_t len = strlen (p);
if (len >= imap->tagsize)
/* Handle the tagged response */
if (wc < 2)
{
char *np = realloc (imap->tagbuf, len + 1);
if (!np)
{
imap->state = MU_IMAP_ERROR;
return ENOMEM;
}
imap->tagsize = len + 1;
imap->tagbuf = np;
/*imap->state = MU_IMAP_ERROR;*/
status = MU_ERR_BADREPLY;
}
strcpy (imap->tagbuf, p);
if (IS_PREFIX (p, len, "OK"))
else if (strcmp (wv[1], "OK") == 0)
{
imap->resp_code = MU_IMAP_OK;
p = mu_str_skip_cset (p + 2, " ");
_mu_imap_seterrstr (imap, p, strlen (p));
if (mu_imapio_reply_string (imap->io, 2, &p) == 0)
{
_mu_imap_seterrstr (imap, p, strlen (p));
free (p);
}
}
else if (IS_PREFIX (p, len, "NO"))
else if (strcmp (wv[1], "NO") == 0)
{
imap->resp_code = MU_IMAP_NO;
p = mu_str_skip_cset (p + 2, " ");
_mu_imap_seterrstr (imap, p, strlen (p));
if (mu_imapio_reply_string (imap->io, 2, &p) == 0)
{
_mu_imap_seterrstr (imap, p, strlen (p));
free (p);
}
}
else if (IS_PREFIX (p, len, "BAD"))
else if (strcmp (wv[1], "BAD") == 0)
{
imap->resp_code = MU_IMAP_BAD;
p = mu_str_skip_cset (p + 2, " ");
_mu_imap_seterrstr (imap, p, strlen (p));
if (mu_imapio_reply_string (imap->io, 2, &p) == 0)
{
_mu_imap_seterrstr (imap, p, strlen (p));
free (p);
}
}
else
status = MU_ERR_BADREPLY;
MU_IMAP_FSET (imap, MU_IMAP_RESP);
break;
}
else
{
imap->state = MU_IMAP_ERROR;
return MU_ERR_BADREPLY;
status = MU_ERR_BADREPLY;
}
}
else
{
imap->state = MU_IMAP_ERROR;
return status;
}
imap->state = MU_IMAP_ERROR;
break;
}
return status;
}
......
......@@ -19,78 +19,50 @@
# include <config.h>
#endif
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
#include <mailutils/stream.h>
#include <mailutils/imapio.h>
#include <mailutils/sys/imap.h>
static const char *imap_prefix[] = {
"S: ", "C: "
};
int
_mu_imap_trace_enable (mu_imap_t imap)
{
int rc = 0;
mu_stream_t dstr, xstr;
if (!imap->carrier)
int rc;
if (!imap->io)
return 0;
rc = mu_imapio_trace_enable (imap->io);
switch (rc)
{
case 0:
case MU_ERR_OPEN:
MU_IMAP_FSET (imap, MU_IMAP_TRACE);
return 0;
}
rc = mu_dbgstream_create (&dstr, MU_DIAG_DEBUG);
if (rc)
mu_error (_("cannot create debug stream; transcript disabled: %s"),
mu_strerror (rc));
else
{
rc = mu_xscript_stream_create (&xstr, imap->carrier, dstr,
imap_prefix);
if (rc)
mu_error (_("cannot create transcript stream: %s"),
mu_strerror (rc));
else
{
mu_stream_unref (imap->carrier);
imap->carrier = xstr;
MU_IMAP_FSET (imap, MU_IMAP_TRACE);
}
break;
}
return rc;
}
int
_mu_imap_trace_disable (mu_imap_t imap)
{
mu_stream_t xstr = imap->carrier;
mu_stream_t stream[2];
int rc;
if (!xstr)
if (!imap->io)
return 0;
rc = mu_stream_ioctl (xstr, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, stream);
if (rc)
return rc;
rc = mu_imapio_trace_disable (imap->io);
switch (rc)
{
case 0:
case MU_ERR_NOT_OPEN:
MU_IMAP_FCLR (imap, MU_IMAP_TRACE);
break;
}
return rc;
imap->carrier = stream[0];
mu_stream_destroy (&xstr);
MU_IMAP_FCLR (imap, MU_IMAP_TRACE);
return 0;
}
int
mu_imap_trace (mu_imap_t imap, int op)
{
int trace_on = MU_IMAP_FISSET (imap, MU_IMAP_TRACE);
int trace_on = mu_imapio_get_trace (imap->io);
switch (op)
{
case MU_IMAP_TRACE_SET:
......@@ -117,15 +89,15 @@ mu_imap_trace_mask (mu_imap_t imap, int op, int lev)
switch (op)
{
case MU_IMAP_TRACE_SET:
imap->flags |= MU_IMAP_XSCRIPT_MASK(lev);
imap->flags |= MU_IMAP_XSCRIPT_MASK (lev);
break;
case MU_IMAP_TRACE_CLR:
imap->flags &= ~MU_IMAP_XSCRIPT_MASK(lev);
imap->flags &= ~MU_IMAP_XSCRIPT_MASK (lev);
break;
case MU_IMAP_TRACE_QRY:
if (imap->flags & MU_IMAP_XSCRIPT_MASK(lev))
if (imap->flags & MU_IMAP_XSCRIPT_MASK (lev))
break;
return MU_ERR_NOENT;
......@@ -138,8 +110,5 @@ mu_imap_trace_mask (mu_imap_t imap, int op, int lev)
int
_mu_imap_xscript_level (mu_imap_t imap, int xlev)
{
if (mu_stream_ioctl (imap->carrier, MU_IOCTL_XSCRIPTSTREAM,
MU_IOCTL_XSCRIPTSTREAM_LEVEL, &xlev) == 0)
return xlev;
return MU_XSCRIPT_NORMAL;
return mu_imapio_set_xscript_level (imap->io, xlev);
}
......
......@@ -364,6 +364,12 @@ com_login (int argc, char **argv)
int status;
char *pwd, *passbuf = NULL;
if (!imap)
{
mu_error (_("you need to connect first"));
return 0;
}
if (argc == 2)
{
if (!mutool_shell_interactive)
......@@ -395,22 +401,13 @@ com_login (int argc, char **argv)
return 0;
}
static int
_print_id (void *item, void *data)
{
const char *id = item;
mu_printf ("ID: %s %s\n", id, id + strlen (id) + 1);
return 0;
}
static int
com_id (int argc, char **argv)
{
mu_list_t list;
mu_assoc_t assoc;
char *test = NULL;
int status;
argv++;
if (argv[0] && strcmp (argv[0], "-test") == 0)
{
......@@ -424,31 +421,36 @@ com_id (int argc, char **argv)
argv++;
}
status = mu_imap_id (imap, argv + 1, &list);
status = mu_imap_id (imap, argv + 1, &assoc);
if (status == 0)
{
if (test)
{
const char *res;
int rc = mu_list_locate (list, test, (void*)&res);
switch (rc)
void *res = mu_assoc_ref (assoc, test);
if (res)
{
case 0:
mu_printf ("%s: %s\n", test, res + strlen (res) + 1);
break;
case MU_ERR_NOENT:
mu_printf ("%s is not set\n", test);
break;
default:
return rc;
mu_printf ("%s: %s\n", test, *(char **)res);
}
else
mu_printf ("%s is not set\n", test);
}
else
mu_list_do (list, _print_id, NULL);
mu_list_destroy (&list);
{
mu_iterator_t itr;
mu_assoc_get_iterator (assoc, &itr);
for (mu_iterator_first (itr);
!mu_iterator_is_done (itr); mu_iterator_next (itr))
{
char *key;
void *val;
mu_iterator_current_kv (itr, (const void**)&key, &val);
mu_printf ("ID: %s %s\n", key, *(char**)val);
}
mu_iterator_destroy (&itr);
}
mu_assoc_destroy (&assoc);
}
return status;
}
......