Commit 26cfa219 26cfa2197d5a2866f1a08c48f94d65504fdef7b1 by Sergey Poznyakoff

msgset: implement "foreach" calls.

* imap4d/copy.c (copy_env) <src>: Remove. Not needed now.
(size_sum,do_copy): Change to a mu_msgset_message_action_t.
(try_copy,safe_copy): Change signature; use mu_msgset_foreach_message.
* imap4d/fetch.c (_fetch_from_message): Change to a
mu_msgset_message_action_t.
(imap4d_fetch0): Use mu_msgset_foreach_message.
* imap4d/imap4d.h (imap4d_message_action_t): Remove typedef.
(util_foreach_message): Remove. Use mu_msgset_foreach_message.
* imap4d/store.c (_do_store): Change to a mu_msgset_message_action_t.
(imap4d_store0): Use mu_msgset_foreach_message.
* imap4d/util.c (util_foreach_message): Remove.
* include/mailutils/list.h (mu_list_foreach_dir): New proto.
* include/mailutils/msgset.h (mu_msgset_msgno_action_t)
(mu_msgset_message_action_t): New typedefs.
(mu_msgset_negate,mu_msgset_foreach_dir_msgno)
(mu_msgset_foreach_msgno,mu_msgset_foreach_dir_message)
(mu_msgset_foreach_message): New protos.
* libmailutils/list/foreachdir.c: New file.
* libmailutils/list/Makefile.am (liblist_la_SOURCES): Add foreachdir.c.
* libmailutils/list/head.c (mu_list_head): Fix conditional.
* libmailutils/list/tail.c (mu_list_tail): Likewise.
* libmailutils/msgset/foreachmsg.c: New file.
* libmailutils/msgset/foreachnum.c: New file.
* libmailutils/msgset/negate.c: New file.
* libmailutils/msgset/Makefile.am (libmsgset_la_SOURCES): Add
new files.
* libmailutils/msgset/getitr.c (mu_msgset_get_iterator): Call
mu_msgset_aggregate before doing anything.
* libmailutils/msgset/getlist.c (mu_msgset_get_list): Likewise.
* libmailutils/msgset/locate.c (mu_msgset_locate): Likewise.
* libmailutils/msgset/parse.c (parse_msgrange): Remove duplicated
code.
* testsuite/msgset.c: Implement -neg option.
1 parent e7ab6892
......@@ -58,57 +58,35 @@ imap4d_copy (struct imap4d_command *command, imap4d_tokbuf_t tok)
struct copy_env
{
mu_mailbox_t dst;
mu_mailbox_t src;
mu_off_t total;
int ret;
char **err_text;
};
static int
size_sum (size_t msgno, void *data)
size_sum (size_t msgno, mu_message_t msg, void *data)
{
struct copy_env *env = data;
mu_message_t msg = NULL;
int rc;
rc = mu_mailbox_get_message (env->src, msgno, &msg);
size_t size;
rc = mu_message_size (msg, &size);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
env->ret = RESP_NO;
mu_diag_funcall (MU_DIAG_ERROR, "mu_message_size", NULL, rc);
env->ret = RESP_BAD;
return MU_ERR_FAILURE;
}
else
{
size_t size;
rc = mu_message_size (msg, &size);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_message_size", NULL, rc);
env->ret = RESP_BAD;
return MU_ERR_FAILURE;
}
env->total += size;
}
env->total += size;
return 0;
}
static int
do_copy (size_t msgno, void *data)
do_copy (size_t msgno, mu_message_t msg, void *data)
{
struct copy_env *env = data;
mu_message_t msg = NULL;
int status;
status = mu_mailbox_get_message (env->src, msgno, &msg);
if (status)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL,
status);
env->ret = RESP_BAD;
return MU_ERR_FAILURE;
}
imap4d_enter_critical ();
status = mu_mailbox_append_message (env->dst, msg);
imap4d_leave_critical ();
......@@ -124,14 +102,12 @@ do_copy (size_t msgno, void *data)
}
static int
try_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t msgset,
char **err_text)
try_copy (mu_mailbox_t dst, mu_msgset_t msgset, char **err_text)
{
int rc;
struct copy_env env;
env.dst = dst;
env.src = src;
env.total = 0;
env.ret = RESP_OK;
env.err_text = err_text;
......@@ -139,7 +115,7 @@ try_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t msgset,
*env.err_text = "Operation failed";
/* Check size */
rc = util_foreach_message (msgset, size_sum, &env);
rc = mu_msgset_foreach_message (msgset, size_sum, &env);
if (rc)
return RESP_NO;
if (env.ret != RESP_OK)
......@@ -151,7 +127,7 @@ try_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t msgset,
return RESP_NO;
}
env.total = 0;
rc = util_foreach_message (msgset, do_copy, &env);
rc = mu_msgset_foreach_message (msgset, do_copy, &env);
quota_update (env.total);
if (rc)
return RESP_NO;
......@@ -159,8 +135,7 @@ try_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t msgset,
}
static int
safe_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t msgset,
char **err_text)
safe_copy (mu_mailbox_t dst, mu_msgset_t msgset, char **err_text)
{
size_t nmesg;
int status;
......@@ -174,7 +149,7 @@ safe_copy (mu_mailbox_t dst, mu_mailbox_t src, mu_msgset_t msgset,
return RESP_NO;
}
status = try_copy (dst, src, msgset, err_text);
status = try_copy (dst, msgset, err_text);
if (status != RESP_OK)
{
size_t maxmesg;
......@@ -283,7 +258,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
mu_list_t msglist;
mu_msgset_get_list (msgset, &msglist);
if (!mu_list_is_empty (msglist))
status = safe_copy (cmbox, mbox, msgset, err_text);
status = safe_copy (cmbox, msgset, err_text);
mu_mailbox_close (cmbox);
}
mu_mailbox_destroy (&cmbox);
......
......@@ -1783,19 +1783,19 @@ fetch_thunk (imap4d_parsebuf_t pb)
}
int
_fetch_from_message (size_t msgno, void *data)
_fetch_from_message (size_t msgno, mu_message_t msg, void *data)
{
int rc = 0;
struct fetch_runtime_closure *frc = data;
frc->msgno = msgno;
if (mu_mailbox_get_message (mbox, msgno, &frc->msg) == 0)
{
io_sendf ("* %lu FETCH (", (unsigned long) msgno);
frc->eltno = 0;
rc = mu_list_foreach (frc->fnlist, _do_fetch, frc);
io_sendf (")\n");
}
frc->msg = msg;
io_sendf ("* %lu FETCH (", (unsigned long) msgno);
frc->eltno = 0;
rc = mu_list_foreach (frc->fnlist, _do_fetch, frc);
io_sendf (")\n");
return rc;
}
......@@ -1833,7 +1833,7 @@ imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
loop below */
frc.err_text = "Completed";
util_foreach_message (pclos.msgset, _fetch_from_message, &frc);
mu_msgset_foreach_message (pclos.msgset, _fetch_from_message, &frc);
mu_list_destroy (&frc.msglist);
}
......
......@@ -372,11 +372,6 @@ extern char *util_getfullpath (const char *);
extern struct imap4d_command *util_getcommand (char *,
struct imap4d_command []);
typedef int (*imap4d_message_action_t) (size_t, void *);
int util_foreach_message (mu_msgset_t list, imap4d_message_action_t action,
void *data);
enum datetime_parse_mode /* how to parse date/time strings */
{
datetime_default, /* default mode */
......
......@@ -91,13 +91,11 @@ store_thunk (imap4d_parsebuf_t p)
}
static int
_do_store (size_t msgno, void *data)
_do_store (size_t msgno, mu_message_t msg, void *data)
{
struct store_parse_closure *pclos = data;
mu_message_t msg = NULL;
mu_attribute_t attr = NULL;
mu_mailbox_get_message (mbox, msgno, &msg);
mu_message_get_attribute (msg, &attr);
switch (pclos->how)
......@@ -154,7 +152,7 @@ imap4d_store0 (imap4d_tokbuf_t tok, int isuid, char **ptext)
ptext);
if (rc == RESP_OK)
{
util_foreach_message (pclos.msgset, _do_store, &pclos);
mu_msgset_foreach_message (pclos.msgset, _do_store, &pclos);
*ptext = "Completed";
}
......
......@@ -39,42 +39,6 @@ util_getfullpath (const char *name)
return mu_normalize_path (exp);
}
struct action_closure
{
imap4d_message_action_t action;
void *data;
};
static int
procrange (void *item, void *data)
{
struct mu_msgrange *mp = item;
struct action_closure *clos = data;
size_t i;
for (i = mp->msg_beg; i <= mp->msg_end; i++)
{
int rc = clos->action (i, clos->data);
if (rc)
return rc;
}
return 0;
}
/* Apply ACTION to each message number from LIST. */
int
util_foreach_message (mu_msgset_t msgset, imap4d_message_action_t action,
void *data)
{
mu_list_t list;
struct action_closure clos;
clos.action = action;
clos.data = data;
mu_msgset_get_list (msgset, &list);
return mu_list_foreach (list, procrange, &clos);
}
int
util_do_command (imap4d_tokbuf_t tok)
{
......
......@@ -144,10 +144,15 @@ int mu_list_get_iterator (mu_list_t _list, mu_iterator_t *_pitr);
typedef int (*mu_list_action_t) (void *_item, void *_data);
/* Execute _action for each element in _list. Use _data as the call-specific
data. */
data. If _dir is 0, traverse the list from head to tail. If it is 1,
traverse it in the reverse direction */
int mu_list_foreach_dir (mu_list_t _list, int _dir, mu_list_action_t _action,
void *_cbdata);
/* Same as mu_list_foreach_dir with _dir==0. */
int mu_list_foreach (mu_list_t _list, mu_list_action_t _action, void *_data);
/* A historical alias to the above. */
int mu_list_do (mu_list_t, mu_list_action_t, void *) MU_DEPRECATED;
/* ************************************************* */
/* Functions for combining two lists. */
......
......@@ -33,7 +33,7 @@ struct mu_msgrange
#define MU_MSGNO_LAST 0
#define MU_MSGSET_UID 0x01 /* Message set operates on UIDs */
int mu_msgset_create (mu_msgset_t *pmsgset, mu_mailbox_t mbox, int flags);
int mu_msgset_get_list (mu_msgset_t msgset, mu_list_t *plist);
int mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr);
......@@ -53,6 +53,26 @@ int mu_msgset_print (mu_stream_t str, mu_msgset_t msgset);
int mu_msgset_locate (mu_msgset_t msgset, size_t n,
struct mu_msgrange const **prange);
int mu_msgset_negate (mu_msgset_t msgset, mu_msgset_t *pnset);
typedef int (*mu_msgset_msgno_action_t) (size_t _n, void *_call_data);
typedef int (*mu_msgset_message_action_t) (size_t _n, mu_message_t _msg,
void *_call_data);
int mu_msgset_foreach_dir_msgno (mu_msgset_t _msgset, int _dir,
mu_msgset_msgno_action_t _action,
void *_data);
int mu_msgset_foreach_msgno (mu_msgset_t _msgset,
mu_msgset_msgno_action_t _action,
void *_call_data);
int mu_msgset_foreach_dir_message (mu_msgset_t _msgset, int _dir,
mu_msgset_message_action_t _action,
void *_call_data);
int mu_msgset_foreach_message (mu_msgset_t _msgset,
mu_msgset_message_action_t _action,
void *_call_data);
#ifdef __cplusplus
}
......
......@@ -29,6 +29,7 @@ liblist_la_SOURCES = \
foreach.c\
get.c\
getcomp.c\
foreachdir.c\
gmap.c\
head.c\
insert.c\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2004, 2005, 2007, 2008, 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 <mailutils/sys/list.h>
#include <mailutils/errno.h>
int
mu_list_foreach_dir (mu_list_t list, int dir,
mu_list_action_t action, void *cbdata)
{
mu_iterator_t itr;
int status = 0;
if (list == NULL || action == NULL)
return EINVAL;
status = mu_list_get_iterator (list, &itr);
if (status)
return status;
status = mu_iterator_ctl (itr, mu_itrctl_set_direction, &dir);
if (status == 0)
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
void *item;
mu_iterator_current (itr, &item);
if ((status = action (item, cbdata)))
break;
}
mu_iterator_destroy (&itr);
return status;
}
......@@ -29,7 +29,7 @@ mu_list_head (mu_list_t list, void **pitem)
return EINVAL;
if (pitem == NULL)
return MU_ERR_OUT_PTR_NULL;
if (!list->head.next)
if (list->head.next == &list->head)
return MU_ERR_NOENT;
*pitem = list->head.next->item;
return 0;
......
......@@ -29,7 +29,7 @@ mu_list_tail (mu_list_t list, void **pitem)
return EINVAL;
if (pitem == NULL)
return MU_ERR_OUT_PTR_NULL;
if (!list->head.prev)
if (list->head.prev == &list->head)
return MU_ERR_NOENT;
*pitem = list->head.prev->item;
return 0;
......
......@@ -24,8 +24,11 @@ libmsgset_la_SOURCES = \
create.c\
getitr.c\
getlist.c\
foreachnum.c\
foreachmsg.c\
free.c\
locate.c\
negate.c\
parse.c\
print.c\
sub.c
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/errno.h>
#include <mailutils/list.h>
#include <mailutils/msgset.h>
#include <mailutils/mailbox.h>
#include <mailutils/sys/msgset.h>
struct action_closure
{
mu_msgset_message_action_t action;
void *data;
mu_msgset_t msgset;
int dir;
};
static int
procrange (void *item, void *data)
{
struct mu_msgrange *mp = item;
struct action_closure *clos = data;
size_t i;
if (clos->dir)
for (i = mp->msg_end; i >= mp->msg_beg; i--)
{
int rc;
mu_message_t msg = NULL;
if (clos->msgset->mbox)
{
rc = mu_mailbox_get_message (clos->msgset->mbox, i, &msg);
if (rc == MU_ERR_NOENT)
continue;
else if (rc)
return rc;
}
rc = clos->action (i, msg, clos->data);
if (rc)
return rc;
}
else
for (i = mp->msg_beg; i <= mp->msg_end; i++)
{
int rc;
mu_message_t msg = NULL;
if (clos->msgset->mbox)
{
rc = mu_mailbox_get_message (clos->msgset->mbox, i, &msg);
if (rc == MU_ERR_NOENT)
continue;
else if (rc)
return rc;
}
rc = clos->action (i, msg, clos->data);
if (rc)
return rc;
}
return 0;
}
/* Apply ACTION to each message number from MSGSET. */
int
mu_msgset_foreach_dir_message (mu_msgset_t msgset, int dir,
mu_msgset_message_action_t action,
void *data)
{
int rc;
struct action_closure clos;
rc = mu_msgset_aggregate (msgset);
if (rc)
return rc;
clos.action = action;
clos.data = data;
clos.msgset = msgset;
clos.dir = dir;
return mu_list_foreach_dir (msgset->list, dir, procrange, &clos);
}
int
mu_msgset_foreach_message (mu_msgset_t msgset,
mu_msgset_message_action_t action,
void *data)
{
return mu_msgset_foreach_dir_message (msgset, 0, action, data);
}
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/errno.h>
#include <mailutils/list.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
struct action_closure
{
mu_msgset_msgno_action_t action;
void *data;
mu_msgset_t msgset;
int dir;
};
static int
procrange (void *item, void *data)
{
struct mu_msgrange *mp = item;
struct action_closure *clos = data;
size_t i;
if (clos->dir)
for (i = mp->msg_end; i >= mp->msg_beg; i--)
{
int rc = clos->action (i, clos->data);
if (rc)
return rc;
}
else
for (i = mp->msg_beg; i <= mp->msg_end; i++)
{
int rc = clos->action (i, clos->data);
if (rc)
return rc;
}
return 0;
}
/* Apply ACTION to each message number from MSGSET. */
int
mu_msgset_foreach_dir_msgno (mu_msgset_t msgset, int dir,
mu_msgset_msgno_action_t action,
void *data)
{
int rc;
struct action_closure clos;
rc = mu_msgset_aggregate (msgset);
if (rc)
return rc;
clos.action = action;
clos.data = data;
clos.dir = dir;
return mu_list_foreach_dir (msgset->list, dir, procrange, &clos);
}
int
mu_msgset_foreach_msgno (mu_msgset_t msgset,
mu_msgset_msgno_action_t action,
void *data)
{
return mu_msgset_foreach_dir_msgno (msgset, 0, action, data);
}
......@@ -24,7 +24,11 @@
int
mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr)
{
int rc;
if (!msgset)
return EINVAL;
rc = mu_msgset_aggregate (msgset);
if (rc)
return rc;
return mu_list_get_iterator (msgset->list, pitr);
}
......
......@@ -24,10 +24,14 @@
int
mu_msgset_get_list (mu_msgset_t msgset, mu_list_t *plist)
{
int rc;
if (!msgset)
return EINVAL;
if (!plist)
return MU_ERR_OUT_PTR_NULL;
rc = mu_msgset_aggregate (msgset);
if (rc)
return rc;
*plist = msgset->list;
return 0;
}
......
......@@ -26,7 +26,11 @@ int
mu_msgset_locate (mu_msgset_t msgset, size_t n,
struct mu_msgrange const **prange)
{
int rc;
if (!msgset || n == 0)
return EINVAL;
rc = mu_msgset_aggregate (msgset);
if (rc)
return rc;
return mu_list_locate (msgset->list, &n, (void**)prange);
}
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 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/>. */
#include <config.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/errno.h>
#include <mailutils/list.h>
#include <mailutils/mailbox.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
struct invert_closure
{
mu_msgset_t nset;
size_t next_num;
};
static int
_invert_range (void *item, void *data)
{
struct mu_msgrange *range = item;
struct invert_closure *clos = data;
int rc;
if (clos->next_num < range->msg_beg - 1)
{
rc = mu_msgset_add_range (clos->nset, clos->next_num, range->msg_beg - 1);
if (rc)
return rc;
}
clos->next_num = range->msg_end + 1;
return 0;
}
/* Negate the message set: on return PNSET consists of the messages
_not contained_ in the input message set. */
int
mu_msgset_negate (mu_msgset_t msgset, mu_msgset_t *pnset)
{
int rc;
struct invert_closure clos;
size_t total;
if (!msgset)
return EINVAL;
if (!msgset->mbox)
return MU_ERR_NOT_OPEN;
rc = mu_msgset_aggregate (msgset);
if (rc)
return rc;
rc = mu_mailbox_messages_count (msgset->mbox, &total);
if (rc)
return rc;
rc = mu_msgset_create (&clos.nset, NULL, 0);
if (rc)
return rc;
clos.next_num = 1;
rc = mu_list_foreach (msgset->list, _invert_range, &clos);
if (rc == 0)
{
if (clos.next_num < total)
rc = mu_msgset_add_range (clos.nset, clos.next_num, total);
}
if (rc)
mu_msgset_free (clos.nset);
else
{
clos.nset->mbox = msgset->mbox;
*pnset = clos.nset;
}
return 0;
}
......@@ -101,14 +101,6 @@ parse_msgrange (struct parse_msgnum_env *env)
rc = mu_mailbox_translate (env->msgset->mbox,
MU_MAILBOX_UID_TO_MSGNO,
msgrange.msg_beg, &msgrange.msg_beg);
if (rc == MU_ERR_NOENT)
msgrange.msg_beg = env->minval;
else if (rc)
return rc;
rc = mu_mailbox_translate (env->msgset->mbox,
MU_MAILBOX_UID_TO_MSGNO,
msgrange.msg_end, &msgrange.msg_end);
if (rc == MU_ERR_NOENT)
msgrange.msg_end = env->maxval;
......
......@@ -117,6 +117,13 @@ main (int argc, char **argv)
MU_ASSERT (mu_msgset_sub_range (msgset, range.msg_beg,
range.msg_end));
}
else if (strcmp (arg, "-neg") == 0)
{
mu_msgset_t negated_set;
MU_ASSERT (mu_msgset_negate (msgset, &negated_set));
mu_msgset_free (msgset);
msgset = negated_set;
}
else
{
mu_error ("unknown option %s", arg);
......