Commit c96bc2c0 c96bc2c092dda2d3c9fe3f1498857c7d4afb56dc by Sergey Poznyakoff

imap client: implement status command

* include/mailutils/imap.h (mu_imap_status): New proto.
(_mu_imap_status_name_table): New declaration.
* include/mailutils/sys/imap.h (mu_imap_client_state)
<MU_IMAP_STATUS_RX>: New state.
* libproto/imap/status.c: New file.
* libproto/imap/Makefile.am (libmu_imap_la_SOURCES): Add status.c
* mu/imap.c: Implement "status"
1 parent ebbbc397
......@@ -21,6 +21,7 @@
#include <mailutils/iterator.h>
#include <mailutils/debug.h>
#include <mailutils/stream.h>
#include <mailutils/kwd.h>
#ifdef __cplusplus
extern "C" {
......@@ -95,6 +96,10 @@ struct mu_imap_stat
int mu_imap_select (mu_imap_t imap, const char *mbox, int writable,
struct mu_imap_stat *ps);
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[];
#ifdef __cplusplus
}
#endif
......
......@@ -44,7 +44,8 @@ enum mu_imap_client_state
MU_IMAP_LOGIN_RX,
MU_IMAP_LOGOUT_RX,
MU_IMAP_ID_RX,
MU_IMAP_SELECT_RX
MU_IMAP_SELECT_RX,
MU_IMAP_STATUS_RX
};
enum mu_imap_response
......
......@@ -43,6 +43,7 @@ libmu_imap_la_SOURCES = \
response.c\
select.c\
state.c\
status.c\
tag.c\
trace.c
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 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 <mailutils/errno.h>
#include <mailutils/assoc.h>
#include <mailutils/stream.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
#define STATUS_FLAG_MASK \
(MU_IMAP_STAT_MESSAGE_COUNT| \
MU_IMAP_STAT_RECENT_COUNT| \
MU_IMAP_STAT_UIDNEXT| \
MU_IMAP_STAT_UIDVALIDITY| \
MU_IMAP_STAT_FIRST_UNSEEN)
struct mu_kwd _mu_imap_status_name_table[] = {
{ "MESSAGES", MU_IMAP_STAT_MESSAGE_COUNT },
{ "RECENT", MU_IMAP_STAT_RECENT_COUNT },
{ "UIDNEXT", MU_IMAP_STAT_UIDNEXT },
{ "UIDVALIDITY", MU_IMAP_STAT_UIDVALIDITY },
{ "UNSEEN", MU_IMAP_STAT_FIRST_UNSEEN },
{ NULL }
};
static int
_status_mapper (void **itmv, size_t itmc, void *call_data)
{
struct mu_imap_stat *ps = call_data;
struct imap_list_element *kw = itmv[0], *val = itmv[1];
size_t value;
char *p;
int flag;
if (kw->type != imap_eltype_string || val->type != imap_eltype_string)
return MU_ERR_PARSE;
if (mu_kwd_xlat_name_ci (_mu_imap_status_name_table, kw->v.string, &flag))
return MU_ERR_PARSE;
value = strtoul (val->v.string, &p, 10);
if (*p)
return MU_ERR_PARSE;
ps->flags |= flag;
switch (flag)
{
case MU_IMAP_STAT_MESSAGE_COUNT:
ps->message_count = value;
break;
case MU_IMAP_STAT_RECENT_COUNT:
ps->recent_count = value;
break;
case MU_IMAP_STAT_UIDNEXT:
ps->uidnext = value;
break;
case MU_IMAP_STAT_UIDVALIDITY:
ps->uidvalidity = value;
break;
case MU_IMAP_STAT_FIRST_UNSEEN:
ps->first_unseen = value;
}
return 0;
}
static int
_parse_status_response (mu_imap_t imap, const char *mboxname,
struct mu_imap_stat *ps)
{
struct imap_list_element *response, *elt;
size_t count;
int rc;
rc = mu_list_get (imap->untagged_resp, 0, (void*) &response);
if (rc)
return rc;
mu_list_count (response->v.list, &count);
if (count != 3)
return MU_ERR_PARSE;
rc = mu_list_get (response->v.list, 0, (void*) &elt);
if (rc)
return rc;
if (!_mu_imap_list_element_is_string (elt, "STATUS"))
return MU_ERR_NOENT;
rc = mu_list_get (response->v.list, 1, (void*) &elt);
if (rc)
return rc;
if (!_mu_imap_list_element_is_string (elt, mboxname))
return MU_ERR_NOENT;
rc = mu_list_get (response->v.list, 2, (void*) &elt);
if (rc)
return rc;
if (elt->type != imap_eltype_list)
return MU_ERR_PARSE;
ps->flags = 0;
return mu_list_gmap (elt->v.list, _status_mapper, 2, ps);
}
int
mu_imap_status (mu_imap_t imap, const char *mboxname, struct mu_imap_stat *ps)
{
int status;
char *p;
int delim = 0;
int i;
if (imap == NULL)
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)
return MU_ERR_SEQ;
if (!ps)
return MU_ERR_OUT_PTR_NULL;
if ((ps->flags & STATUS_FLAG_MASK) == 0)
return EINVAL;
if (!mboxname)
{
if (imap->imap_state == MU_IMAP_STATE_SELECTED)
{
if (ps)
*ps = imap->mbox_stat;
return 0;
}
return EINVAL;
}
if (imap->mbox_name && strcmp (imap->mbox_name, mboxname) == 0)
{
if (ps)
*ps = imap->mbox_stat;
return 0;
}
switch (imap->state)
{
case MU_IMAP_CONNECTED:
status = _mu_imap_tag_next (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
status = mu_imapio_printf (imap->io, "%s STATUS %s (",
imap->tag_str, mboxname);
MU_IMAP_CHECK_ERROR (imap, status);
delim = 0;
for (i = 0; status == 0 && _mu_imap_status_name_table[i].name; i++)
{
if (ps->flags & _mu_imap_status_name_table[i].tok)
{
if (delim)
status = mu_imapio_send (imap->io, " ", 1);
if (status == 0)
status = mu_imapio_printf (imap->io, "%s",
_mu_imap_status_name_table[i].name);
}
delim = 1;
}
if (status == 0)
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;
case MU_IMAP_STATUS_RX:
status = _mu_imap_response (imap);
MU_IMAP_CHECK_EAGAIN (imap, status);
switch (imap->resp_code)
{
case MU_IMAP_OK:
memset (&imap->mbox_stat, 0, sizeof (imap->mbox_stat));
status = _parse_status_response (imap, mboxname, ps);
break;
case MU_IMAP_NO:
status = EACCES;
break;
case MU_IMAP_BAD:
status = MU_ERR_BADREPLY;
if (mu_imapio_reply_string (imap->io, 2, &p) == 0)
{
_mu_imap_seterrstr (imap, p, strlen (p));
free (p);
}
break;
}
imap->state = MU_IMAP_CONNECTED;
break;
default:
status = EINPROGRESS;
}
return status;
}
......@@ -520,6 +520,40 @@ com_examine (int argc, char **argv)
{
return select_mbox (argc, argv, 0);
}
static int
com_status (int argc, char **argv)
{
struct mu_imap_stat st;
int i, flag;
int status;
st.flags = 0;
for (i = 2; i < argc; i++)
{
if (mu_kwd_xlat_name_ci (_mu_imap_status_name_table, argv[i], &flag))
{
mu_error (_("unknown data item: %s"), argv[i]);
return 0;
}
st.flags |= flag;
}
status = mu_imap_status (imap, argv[1], &st);
if (status == 0)
{
print_imap_stats (&st);
}
else
{
const char *str;
mu_error ("status failed: %s", mu_strerror (status));
if (mu_imap_strerror (imap, &str) == 0)
mu_error ("server reply: %s", str);
}
return 0;
}
struct mutool_command imap_comtab[] = {
......@@ -548,11 +582,14 @@ struct mutool_command imap_comtab[] = {
N_("[-test KW] [ARG [ARG...]]"),
N_("send ID command") },
{ "select", 1, 2, com_select,
N_("MBOX"),
N_("[MBOX]"),
N_("select a mailbox") },
{ "examine", 1, 2, com_examine,
N_("MBOX"),
N_("examine a mailbox") },
{ "examine", 1, 2, com_examine,
N_("[MBOX]"),
N_("examine a mailbox") },
{ "status", 3, -1, com_status,
N_("MBOX KW [KW...]"),
N_("get mailbox status") },
{ "quit", 1, 1, com_logout,
NULL,
N_("same as `logout'") },
......