Commit fa42589c fa42589cef090379bda4ea4e0838474520f9f4f6 by Sergey Poznyakoff

imap client: implement folder API.

* libmailutils/list/listlist.c (mu_list_append_list): Do nothing if the
source list is empty.

* include/mailutils/sys/imap.h (_mu_imap_url_init)
(_mu_imaps_url_init): New protos.
* libproto/imap/Makefile.am (libmu_imap_la_SOURCES): Restore url.c
* libproto/imap/mbox.c: Deleted
* libproto/imap/url.c: Rewrite.
* libproto/imap/folder.c: Rewrite from scratch.
* configure.ac: Build libproto/imap/tests/Makefile
* include/mailutils/imap.h (mu_imap_session_state)
(mu_imap_iserror, mu_imap_clearerr)
(mu_imap_login_secret): New protos.
* include/mailutils/sys/imap.h (_mu_imap_list_element_is_nil): New proto.

* libmailutils/mailbox/folder.c (mu_folder_list): Pass
MU_FOLDER_ATTRIBUTE_ALL.
* libproto/imap/fake-folder.c: Remove.
* libproto/imap/Makefile.am (libmu_imap_la_SOURCES): Remove fake-folder.c
Add url.c and folder.c
* libproto/imap/create.c (mu_imap_session_state)
(mu_imap_iserror, mu_imap_clearerr): New functions.
* libproto/imap/delete.c: Check input parameters.

* libproto/imap/fetch.c: Use _mu_imap_list_element_is_nil to check for
empty lists.
* libproto/imap/genlist.c: Likewise.
* libproto/imap/rename.c: Likewise.
* libproto/imap/subscribe.c: Likewise.
* libproto/imap/unsubscribe.c: Likewise.

* libproto/imap/resplist.c: Treat NIL and () equally.
* libproto/imap/login.c (mu_imap_login_secret): New function.

* mu/imap.c: Fix a typo.
1 parent 0e8ae1c3
......@@ -1460,6 +1460,7 @@ AC_CONFIG_FILES([
libproto/pop/Makefile
libproto/nntp/Makefile
libproto/imap/Makefile
libproto/imap/tests/Makefile
libmu_compat/Makefile
maidag/Makefile
mail/Makefile
......
......@@ -47,6 +47,10 @@ void mu_imap_destroy (mu_imap_t *pimap);
int mu_imap_connect (mu_imap_t imap);
int mu_imap_disconnect (mu_imap_t imap);
int mu_imap_session_state (mu_imap_t imap);
int mu_imap_iserror (mu_imap_t imap);
void mu_imap_clearerr (mu_imap_t imap);
int mu_imap_capability (mu_imap_t imap, int reread, mu_iterator_t *piter);
int mu_imap_capability_test (mu_imap_t imap, const char *name,
const char **pret);
......@@ -54,6 +58,8 @@ int mu_imap_capability_test (mu_imap_t imap, const char *name,
int mu_imap_starttls (mu_imap_t imap);
int mu_imap_login (mu_imap_t imap, const char *user, const char *pass);
int mu_imap_login_secret (mu_imap_t imap, const char *user,
mu_secret_t secret);
int mu_imap_logout (mu_imap_t imap);
int mu_imap_id (mu_imap_t imap, char **idenv, mu_assoc_t *passoc);
......
......@@ -215,6 +215,8 @@ int _mu_imap_response (mu_imap_t imap, mu_imap_response_action_t fun,
int _mu_imap_list_element_is_string (struct imap_list_element *elt,
const char *str);
int _mu_imap_list_element_is_nil (struct imap_list_element *elt);
int _mu_imap_list_nth_element_is_string (mu_list_t list, size_t n,
const char *str);
......@@ -225,7 +227,18 @@ struct imap_list_element *_mu_imap_list_at (mu_list_t list, int idx);
int _mu_imap_parse_fetch_response (mu_list_t resp, mu_list_t *result_list);
void _mu_close_handler (mu_imap_t imap);
/* ----------------------------- */
/* URL Auxiliaries */
/* ----------------------------- */
int _mu_imap_url_init (mu_url_t url);
int _mu_imaps_url_init (mu_url_t url);
/* ----------------------------- */
/* Folder interface */
/* ----------------------------- */
# ifdef __cplusplus
}
# endif
......
......@@ -99,7 +99,9 @@ mu_list_insert_list (mu_list_t list, void *item, mu_list_t new_list,
void
mu_list_append_list (mu_list_t list, mu_list_t new_list)
{
if (list->count == 0)
if (new_list->count == 0)
return;
else if (list->count == 0)
{
list->head = new_list->head;
list->head.next->prev = list->head.prev->next = &list->head;
......
......@@ -368,7 +368,8 @@ mu_folder_list (mu_folder_t folder, const char *dirname, void *pattern,
size_t max_level,
mu_list_t *pflist)
{
return mu_folder_enumerate (folder, dirname, pattern, 0, max_level,
return mu_folder_enumerate (folder, dirname, pattern,
MU_FOLDER_ATTRIBUTE_ALL, max_level,
pflist, NULL, NULL);
}
......
......@@ -21,16 +21,14 @@ lib_LTLIBRARIES = libmu_imap.la
libmu_imap_la_LDFLAGS=-version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
libmu_imap_la_LIBADD = ${MU_LIB_AUTH} ${MU_LIB_MAILUTILS} @INTLLIBS@
# FIXME: Put these back when ready
SUBDIRS = . tests
# folder.c\
# mbox.c\
# url.c
# FIXME: Put this back when ready
# mbox.c
libmu_imap_la_SOURCES = \
appmsg.c\
appstr.c\
appstrsiz.c\
fake-folder.c\
fetch.c\
gencom.c\
genlist.c\
......@@ -68,5 +66,6 @@ libmu_imap_la_SOURCES = \
tag.c\
trace.c\
unselect.c\
unsubscribe.c
unsubscribe.c\
folder.c\
url.c
......
......@@ -64,3 +64,30 @@ _mu_imap_init (mu_imap_t imap)
imap->session_state = MU_IMAP_SESSION_INIT;
return 0;
}
int
mu_imap_session_state (mu_imap_t imap)
{
if (!imap)
return -1;
return imap->session_state;
}
int
mu_imap_iserror (mu_imap_t imap)
{
if (!imap)
return -1;
return imap->client_state == MU_IMAP_CLIENT_ERROR;
}
void
mu_imap_clearerr (mu_imap_t imap)
{
if (imap)
{
imap->client_state = MU_IMAP_CLIENT_READY;
if (imap->io)
mu_imapio_clearerr (imap->io);
}
}
......
......@@ -31,6 +31,9 @@ mu_imap_delete (mu_imap_t imap, const char *mailbox)
char const *argv[2];
static struct imap_command com;
if (!mailbox)
return EINVAL;
argv[0] = "DELETE";
argv[1] = mailbox;
......
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <mailutils/mailutils.h>
mu_record_t mu_imap_record = NULL;
mu_record_t mu_imaps_record = NULL;
......@@ -354,11 +354,11 @@ static int
elt_to_string (struct imap_list_element *elt, char **pstr)
{
char *p;
if (elt->type != imap_eltype_string)
return EINVAL;
if (mu_c_strcasecmp (elt->v.string, "NIL") == 0)
if (_mu_imap_list_element_is_nil (elt))
p = NULL;
else if (elt->type != imap_eltype_string)
return EINVAL;
else
{
p = strdup (elt->v.string);
......@@ -386,13 +386,13 @@ _fill_subaddr (void *item, void *data)
return 0;
arg = _mu_imap_list_at (elt->v.list, 0);
if (arg && arg->type == imap_eltype_string && strcmp (arg->v.string, "NIL"))
if (arg && arg->type == imap_eltype_string)
personal = arg->v.string;
arg = _mu_imap_list_at (elt->v.list, 2);
if (arg && arg->type == imap_eltype_string && strcmp (arg->v.string, "NIL"))
if (arg && arg->type == imap_eltype_string)
local = arg->v.string;
arg = _mu_imap_list_at (elt->v.list, 3);
if (arg && arg->type == imap_eltype_string && strcmp (arg->v.string, "NIL"))
if (arg && arg->type == imap_eltype_string)
domain = arg->v.string;
if (domain && local)
......@@ -414,13 +414,10 @@ _fill_subaddr (void *item, void *data)
static int
elt_to_address (struct imap_list_element *elt, mu_address_t *paddr)
{
if (elt->type != imap_eltype_list)
{
if (mu_c_strcasecmp (elt->v.string, "NIL") == 0)
*paddr = NULL;
else
return EINVAL;
}
if (_mu_imap_list_element_is_nil (elt))
*paddr = NULL;
else if (elt->type != imap_eltype_list)
return EINVAL;
else
{
struct addr_env addr_env;
......
......@@ -104,13 +104,15 @@ list_untagged_handler (mu_imap_t imap, mu_list_t resp, void *data)
}
elt = _mu_imap_list_at (resp, 2);
if (!(elt && elt->type == imap_eltype_string))
if (!elt)
return;
if (mu_c_strcasecmp (elt->v.string, "NIL") == 0)
if (_mu_imap_list_element_is_nil (elt))
{
rp->separator = 0;
rp->level = 0;
}
else if (elt->type != imap_eltype_string)
return;
else
{
rp->separator = elt->v.string[0];
......@@ -131,6 +133,9 @@ mu_imap_genlist (mu_imap_t imap, int lsub,
struct list_closure clos;
int rc;
if (!refname || !mboxname)
return EINVAL;
argv[0] = lsub ? "LSUB" : "LIST";
argv[1] = refname;
argv[2] = mboxname;
......
......@@ -22,6 +22,7 @@
#include <string.h>
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/secret.h>
#include <mailutils/sys/imap.h>
int
......@@ -77,3 +78,12 @@ mu_imap_login (mu_imap_t imap, const char *user, const char *pass)
return status;
}
int
mu_imap_login_secret (mu_imap_t imap, const char *user, mu_secret_t secret)
{
int rc = mu_imap_login (imap, user, mu_secret_password (secret));
mu_secret_password_unref (secret);
return rc;
}
......
......@@ -29,6 +29,9 @@ mu_imap_rename (mu_imap_t imap, const char *mailbox, const char *new_mailbox)
char const *argv[3];
static struct imap_command com;
if (!mailbox || !new_mailbox)
return EINVAL;
argv[0] = "RENAME";
argv[1] = mailbox;
argv[2] = new_mailbox;
......
......@@ -57,6 +57,7 @@ _mu_imap_response_list_create (mu_imap_t imap, mu_list_t *plist)
#define IS_LBRACE(p) ((p)[0] == '(')
#define IS_RBRACE(p) ((p)[0] == ')')
#define IS_NIL(p) (strcmp (p, "NIL") == 0)
static struct imap_list_element *
_new_imap_list_element (mu_imap_t imap, enum imap_eltype type)
......@@ -181,6 +182,7 @@ _parse_element (struct parsebuf *pb)
if (IS_RBRACE (tok))
{
parsebuf_gettok (pb);
elt = _new_imap_list_element (pb->pb_imap, imap_eltype_list);
if (!elt)
{
......@@ -203,6 +205,16 @@ _parse_element (struct parsebuf *pb)
parsebuf_seterr (pb, MU_ERR_PARSE);
return NULL;
}
else if (IS_NIL (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
{
char *s;
......@@ -255,6 +267,12 @@ _mu_imap_list_element_is_string (struct imap_list_element *elt,
return strcmp (elt->v.string, str) == 0;
}
int
_mu_imap_list_element_is_nil (struct imap_list_element *elt)
{
return elt->type == imap_eltype_list && mu_list_is_empty (elt->v.list);
}
struct imap_list_element *
_mu_imap_list_at (mu_list_t list, int idx)
{
......
......@@ -19,6 +19,7 @@
# include <config.h>
#endif
#include <errno.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
......@@ -28,6 +29,9 @@ mu_imap_subscribe (mu_imap_t imap, const char *mailbox)
char const *argv[2];
static struct imap_command com;
if (!mailbox)
return EINVAL;
argv[0] = "SUBSCRIBE";
argv[1] = mailbox;
......
## This file is part of GNU Mailutils.
## Copyright (C) 2003, 2005, 2006, 2007, 2010, 2011 Free Software
## Foundation, Inc.
##
## GNU Mailutils is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 3, or (at
## your option) any later version.
##
## GNU Mailutils 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
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
noinst_PROGRAMS = \
imapfolder
INCLUDES = @MU_LIB_COMMON_INCLUDES@
LDADD = \
@MU_LIB_IMAP@\
@MU_LIB_AUTH@\
@MU_AUTHLIBS@\
@MU_LIB_MAILUTILS@
/* 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 <mailutils/mailutils.h>
struct command
{
char *verb;
int nargs;
char *args;
void (*handler) (mu_folder_t folder, char **argv);
};
static int
_print_list_entry (void *item, void *data)
{
struct mu_list_response *resp = item;
mu_printf ("%c%c %c %4d %s\n",
(resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
(resp->type & MU_FOLDER_ATTRIBUTE_FILE) ? 'f' : '-',
resp->separator ? resp->separator : ' ',
resp->level,
resp->name);
return 0;
}
static void
com_list (mu_folder_t folder, char **argv)
{
int rc;
mu_list_t list;
mu_printf ("listing %s %s\n", argv[0], argv[1]);
rc = mu_folder_list (folder, argv[0], argv[1], 0, &list);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_list", argv[0], rc);
else
{
mu_list_foreach (list, _print_list_entry, NULL);
mu_list_destroy (&list);
}
}
static void
com_lsub (mu_folder_t folder, char **argv)
{
int rc;
mu_list_t list;
mu_printf ("listing subscriptions for '%s' '%s'\n", argv[0], argv[1]);
rc = mu_folder_lsub (folder, argv[0], argv[1], &list);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_lsub", argv[0], rc);
else
{
mu_list_foreach (list, _print_list_entry, NULL);
mu_list_destroy (&list);
}
}
static void
com_delete (mu_folder_t folder, char **argv)
{
int rc;
mu_printf ("deleting %s\n", argv[0]);
rc = mu_folder_delete (folder, argv[0]);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_lsub", argv[0], rc);
else
mu_printf ("delete successful\n");
}
static void
com_rename (mu_folder_t folder, char **argv)
{
int rc;
mu_printf ("renaming %s to %s\n", argv[0], argv[1]);
rc = mu_folder_rename (folder, argv[0], argv[1]);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_rename", argv[0], rc);
else
mu_printf ("rename successful\n");
}
static void
com_subscribe (mu_folder_t folder, char **argv)
{
int rc;
mu_printf ("subscribing %s\n", argv[0]);
rc = mu_folder_subscribe (folder, argv[0]);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_subscribe", argv[0], rc);
else
mu_printf ("subscribe successful\n");
}
static void
com_unsubscribe (mu_folder_t folder, char **argv)
{
int rc;
mu_printf ("unsubscribing %s\n", argv[0]);
rc = mu_folder_unsubscribe (folder, argv[0]);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_unsubscribe", argv[0], rc);
else
mu_printf ("unsubscribe successful\n");
}
static struct command comtab[] = {
{ "list", 2, "REF MBX", com_list },
{ "lsub", 2, "REF MBX", com_lsub },
{ "delete", 1, "MBX", com_delete },
{ "rename", 2, "OLD NEW", com_rename },
{ "delete", 1, "MBOX", com_delete },
{ "subscribe", 1, "MBX", com_subscribe },
{ "unsubscribe", 1, "MBX", com_unsubscribe },
{ NULL }
};
static struct command *
find_command (const char *name)
{
struct command *cp;
for (cp = comtab; cp->verb; cp++)
if (strcmp (cp->verb, name) == 0)
return cp;
return NULL;
}
static void
usage ()
{
struct command *cp;
mu_printf (
"usage: %s [debug=SPEC] url=URL OP ARG [ARG...] [OP ARG [ARG...]...]\n",
mu_program_name);
mu_printf ("OPerations and corresponding ARGuments are:\n");
for (cp = comtab; cp->verb; cp++)
mu_printf (" %s %s\n", cp->verb, cp->args);
}
int
main (int argc, char **argv)
{
int i;
int rc;
mu_folder_t folder;
char *fname = NULL;
mu_set_program_name (argv[0]);
mu_registrar_record (mu_imap_record);
mu_registrar_record (mu_imaps_record);
if (argc == 1)
{
usage ();
exit (0);
}
for (i = 1; i < argc; i++)
{
if (strncmp (argv[i], "debug=", 6) == 0)
mu_debug_parse_spec (argv[i] + 6);
else if (strncmp (argv[i], "url=", 4) == 0)
fname = argv[i] + 4;
else
break;
}
if (!fname)
{
mu_error ("URL not specified");
exit (1);
}
rc = mu_folder_create (&folder, fname);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", fname, rc);
return 1;
}
rc = mu_folder_open (folder, MU_STREAM_READ);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_open", fname, rc);
return 1;
}
while (i < argc)
{
char *comargs[2];
struct command *cmd;
cmd = find_command (argv[i]);
if (!cmd)
{
mu_error ("unknown command %s\n", argv[i]);
break;
}
i++;
if (i + cmd->nargs > argc)
{
mu_error ("not enough arguments for %s", cmd->verb);
break;
}
memcpy (comargs, argv + i, cmd->nargs * sizeof (comargs[0]));
i += cmd->nargs;
cmd->handler (folder, comargs);
}
mu_folder_close (folder);
mu_folder_destroy (&folder);
return 0;
}
......@@ -19,6 +19,7 @@
# include <config.h>
#endif
#include <errno.h>
#include <mailutils/imap.h>
#include <mailutils/sys/imap.h>
......@@ -28,6 +29,9 @@ mu_imap_unsubscribe (mu_imap_t imap, const char *mailbox)
char const *argv[2];
static struct imap_command com;
if (!mailbox)
return EINVAL;
argv[0] = "UNSUBSCRIBE";
argv[1] = mailbox;
......
......@@ -20,18 +20,15 @@
# include <config.h>
#endif
#ifdef ENABLE_IMAP
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <string.h>
#include <mailutils/sys/registrar.h>
#include <mailutils/sys/url.h>
#include <mailutils/sys/imap.h>
static void url_imap_destroy (mu_url_t url);
......@@ -47,7 +44,7 @@ url_imap_destroy (mu_url_t url MU_ARG_UNUSED)
*/
int
_url_imap_init (mu_url_t url)
_mu_imap_url_init (mu_url_t url)
{
if (url->port == 0)
url->port = MU_IMAP_PORT;
......@@ -78,7 +75,7 @@ _url_imap_init (mu_url_t url)
*/
int
_url_imaps_init (mu_url_t url)
_mu_imaps_url_init (mu_url_t url)
{
if (url->port == 0)
url->port = MU_IMAPS_PORT;
......@@ -102,4 +99,3 @@ _url_imaps_init (mu_url_t url)
return 0;
}
#endif /* ENABLE_IMAP */
......
......@@ -160,7 +160,7 @@ imap_prompt_env ()
/* Callbacks */
static void
imap_popauth_callback (void *data, int code, size_t sdat, void *pdat)
imap_preauth_callback (void *data, int code, size_t sdat, void *pdat)
{
const char *text = pdat;
if (text)
......@@ -425,7 +425,7 @@ com_connect (int argc, char **argv)
/* Set callbacks */
mu_imap_register_callback_function (imap, MU_IMAP_CB_PREAUTH,
imap_popauth_callback,
imap_preauth_callback,
NULL);
mu_imap_register_callback_function (imap, MU_IMAP_CB_BYE,
imap_bye_callback,
......