Commit 7e78c6af 7e78c6af4aa397ff422db07489850d40a9360a8c by Sergey Poznyakoff

Imap client: implement list.

* libmailutils/stdstream/basestr.c (mu_strout): Bugfix: initialize
destroy function.
* include/mailutils/imap.h (imap_command)
(mu_imap_gencom): Move to sys/imap.h
(mu_imap_list,mu_imap_list_new): New protos.
* include/mailutils/sys/imap.h (imap_command): New struct (from ../imap.h).
<handler>: Rename to tagged_handler.
(untagged_handler,untagged_handler_data): New members. All uses changed.
(mu_imap_gencom): New proto.

* libproto/imap/list.c: New file.
* libproto/imap/Makefile.am: Add list.c
* libproto/imap/gencom.c: Use supplied untagged_handler to
analize untagged response.

* mu/imap.c: Implement list command.
1 parent 85c5f9a8
......@@ -44,19 +44,6 @@ enum mu_imap_session_state
int mu_imap_create (mu_imap_t *pimap);
void mu_imap_destroy (mu_imap_t *pimap);
struct imap_command
{
int session_state;
char *capa;
int rx_state;
int uid;
int argc;
char const **argv;
void (*handler) (mu_imap_t);
};
int mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd);
int mu_imap_connect (mu_imap_t imap);
int mu_imap_disconnect (mu_imap_t imap);
......@@ -100,6 +87,11 @@ int mu_imap_append_message (mu_imap_t imap, const char *mailbox, int flags,
struct tm *tm, struct mu_timezone *tz,
mu_message_t msg);
int mu_imap_list (mu_imap_t imap, const char *refname, const char *mboxname,
mu_list_t retlist);
int mu_imap_list_new (mu_imap_t imap, const char *refname, const char *mboxname,
mu_list_t *plist);
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);
......
......@@ -66,6 +66,7 @@ enum mu_imap_client_state
MU_IMAP_CLIENT_COPY_RX,
MU_IMAP_CLIENT_EXPUNGE_RX,
MU_IMAP_CLIENT_APPEND_RX,
MU_IMAP_CLIENT_LIST_RX,
MU_IMAP_CLIENT_CLOSING
};
......@@ -135,6 +136,24 @@ int _mu_imap_trace_enable (mu_imap_t imap);
int _mu_imap_trace_disable (mu_imap_t imap);
int _mu_imap_xscript_level (mu_imap_t imap, int xlev);
typedef void (*mu_imap_response_action_t) (mu_imap_t imap, mu_list_t resp,
void *data);
struct imap_command
{
int session_state;
char *capa;
int rx_state;
int uid;
int argc;
char const **argv;
void (*tagged_handler) (mu_imap_t);
mu_imap_response_action_t untagged_handler;
void *untagged_handler_data;
};
int mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd);
/* If status indicates an error, return.
*/
#define MU_IMAP_CHECK_ERROR(imap, status) \
......@@ -182,9 +201,6 @@ int _mu_imap_tag_next (mu_imap_t imap);
int _mu_imap_tag_clr (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,
......
......@@ -128,6 +128,7 @@ static struct _mu_file_stream stdstream[2] = {
{ { ref_count: 1,
buftype: mu_buffer_none,
flags: MU_STREAM_WRITE,
destroy: bootstrap_destroy,
event_cb: std_bootstrap,
event_mask: _MU_STR_EVMASK (_MU_STR_EVENT_BOOTSTRAP)
}, fd: MU_STDOUT_FD, filename: "<stdout>",
......
......@@ -48,6 +48,7 @@ libmu_imap_la_SOURCES = \
err.c\
expunge.c\
id.c\
list.c\
login.c\
logout.c\
mbcreate.c\
......
......@@ -39,7 +39,8 @@ mu_imap_copy (mu_imap_t imap, int uid, const char *msgset, const char *mailbox)
com.uid = 0;
com.argc = 3;
com.argv = argv;
com.handler = NULL;
com.tagged_handler = NULL;
com.untagged_handler = NULL;
return mu_imap_gencom (imap, &com);
}
......
......@@ -40,7 +40,8 @@ mu_imap_delete (mu_imap_t imap, const char *mailbox)
com.uid = 0;
com.argc = 2;
com.argv = argv;
com.handler = NULL;
com.tagged_handler = NULL;
com.untagged_handler = NULL;
return mu_imap_gencom (imap, &com);
}
......
......@@ -44,7 +44,8 @@ mu_imap_fetch (mu_imap_t imap, int uid, const char *msgset, const char *items)
com.uid = uid;
com.argc = 3;
com.argv = argv;
com.handler = NULL;
com.tagged_handler = NULL;
com.untagged_handler = NULL;
return mu_imap_gencom (imap, &com);
}
......
......@@ -74,10 +74,11 @@ mu_imap_gencom (mu_imap_t imap, struct imap_command *cmd)
if (imap->client_state == cmd->rx_state)
{
status = _mu_imap_response (imap, NULL, NULL);
status = _mu_imap_response (imap, cmd->untagged_handler,
cmd->untagged_handler_data);
MU_IMAP_CHECK_EAGAIN (imap, status);
if (cmd->handler)
cmd->handler (imap);
if (cmd->tagged_handler)
cmd->tagged_handler (imap);
switch (imap->resp_code)
{
case MU_IMAP_OK:
......
/* 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/address.h>
#include <mailutils/cstr.h>
#include <mailutils/cctype.h>
#include <mailutils/list.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
struct list_closure
{
int error_code;
mu_list_t retlist;
};
static int
count_level (const char *name, int delim)
{
int level = 0;
while (*name)
if (*name++ == delim)
level++;
return level;
}
static int
list_attr_conv (void *item, void *data)
{
struct imap_list_element *elt = item;
struct mu_list_response *rp = data;
if (elt->type != imap_eltype_string)
return 0;
if (mu_c_strcasecmp (elt->v.string, "\\Noinferiors"))
rp->type |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
if (mu_c_strcasecmp (elt->v.string, "\\Noselect"))
rp->type |= MU_FOLDER_ATTRIBUTE_FILE;
/* FIXME: \Marked nad \Unmarked have no correspondence in flags. */
return 0;
}
static void
list_untagged_handler (mu_imap_t imap, mu_list_t resp, void *data)
{
struct list_closure *clos = data;
struct imap_list_element *elt;
size_t count;
if (clos->error_code)
return;
mu_list_count (resp, &count);
if (count == 4 &&
_mu_imap_list_nth_element_is_string (resp, 0, "LIST"))
{
struct mu_list_response *rp;
rp = calloc (1, sizeof (*rp));
if (!rp)
{
clos->error_code = ENOMEM;
return;
}
elt = _mu_imap_list_at (resp, 1);
if (!(elt && elt->type == imap_eltype_list))
return;
rp->type = 0;
mu_list_foreach (elt->v.list, list_attr_conv, rp);
elt = _mu_imap_list_at (resp, 3);
if (!(elt && elt->type == imap_eltype_string))
return;
rp->name = strdup (elt->v.string);
if (!rp->name)
{
free (rp);
clos->error_code = ENOMEM;
return;
}
elt = _mu_imap_list_at (resp, 2);
if (!(elt && elt->type == imap_eltype_string))
return;
if (mu_c_strcasecmp (elt->v.string, "NIL") == 0)
{
rp->separator = 0;
rp->level = 0;
}
else
{
rp->separator = elt->v.string[0];
rp->level = count_level (rp->name, rp->separator);
}
if ((clos->error_code = mu_list_append (clos->retlist, rp)))
mu_list_response_free (rp);
}
}
int
mu_imap_list (mu_imap_t imap, const char *refname, const char *mboxname,
mu_list_t retlist)
{
char const *argv[3];
static struct imap_command com;
struct list_closure clos;
int rc;
argv[0] = "LIST";
argv[1] = refname;
argv[2] = mboxname;
clos.error_code = 0;
clos.retlist = retlist;
com.session_state = MU_IMAP_SESSION_AUTH;
com.capa = NULL;
com.rx_state = MU_IMAP_CLIENT_LIST_RX;
com.uid = 0;
com.argc = 3;
com.argv = argv;
com.tagged_handler = NULL;
com.untagged_handler = list_untagged_handler;
com.untagged_handler_data = &clos;
rc = mu_imap_gencom (imap, &com);
if (rc == 0)
rc = clos.error_code;
return rc;
}
int
mu_imap_list_new (mu_imap_t imap, const char *refname, const char *mboxname,
mu_list_t *plist)
{
mu_list_t list;
int rc = mu_list_create (&list);
if (rc == 0)
{
mu_list_set_destroy_item (list, mu_list_response_free);
rc = mu_imap_list (imap, refname, mboxname, list);
if (rc)
mu_list_destroy (&list);
else
*plist = list;
}
return rc;
}
......@@ -40,7 +40,8 @@ mu_imap_mailbox_create (mu_imap_t imap, const char *mailbox)
com.uid = 0;
com.argc = 2;
com.argv = argv;
com.handler = NULL;
com.tagged_handler = NULL;
com.untagged_handler = NULL;
return mu_imap_gencom (imap, &com);
}
......
......@@ -39,7 +39,8 @@ mu_imap_rename (mu_imap_t imap, const char *mailbox, const char *new_mailbox)
com.uid = 0;
com.argc = 3;
com.argv = argv;
com.handler = NULL;
com.tagged_handler = NULL;
com.untagged_handler = NULL;
return mu_imap_gencom (imap, &com);
}
......
......@@ -41,7 +41,8 @@ mu_imap_store (mu_imap_t imap, int uid, const char *msgset, const char *items)
com.uid = uid;
com.argc = 3;
com.argv = argv;
com.handler = NULL;
com.tagged_handler = NULL;
com.untagged_handler = NULL;
return mu_imap_gencom (imap, &com);
}
......
......@@ -895,6 +895,43 @@ com_append (int argc, char **argv)
return 0;
}
static int
print_list_item (void *item, void *data)
{
struct mu_list_response *resp = item;
mu_stream_t out = data;
mu_stream_printf (out,
"%c%c %c %4d %s\n",
(resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
(resp->type & MU_FOLDER_ATTRIBUTE_FILE) ? 'f' : '-',
resp->separator,
resp->level,
resp->name);
return 0;
}
static int
com_list (int argc, char **argv)
{
mu_list_t list;
int rc;
mu_stream_t out;
rc = mu_imap_list_new (imap, argv[1], argv[2], &list);
if (rc)
{
report_failure ("list", rc);
return 0;
}
out = mutool_open_pager ();
mu_list_foreach (list, print_list_item, out);
mu_stream_unref (out);
return 0;
}
struct mutool_command imap_comtab[] = {
{ "capability", 1, -1, 0,
com_capability,
......@@ -982,6 +1019,10 @@ struct mutool_command imap_comtab[] = {
com_append,
N_("[-time DATETIME] [-flag FLAG] MAILBOX FILE"),
N_("append message text from FILE to MAILBOX") },
{ "list", 3, 3, 0,
com_list,
N_("REF MBOX"),
N_("List matching mailboxes") },
{ "quit", 1, 1, 0,
com_logout,
NULL,
......