Commit e072a273 e072a2734eaf1bffdacfc20fcb598d79a50d11e7 by Sergey Poznyakoff

Add functions for operations on message sets.

* configure.ac: Build libmailutils/msgset/Makefile
* include/mailutils/msgset.h: New file.
* include/mailutils/Makefile.am (pkginclude_HEADERS): Add msgset.h
* include/mailutils/mailutils.h: Include mailutils/msgset.h
* include/mailutils/sys/msgset.h: New file.
* include/mailutils/sys/Makefile.am (sysinclude_HEADERS): Add msgset.h
* include/mailutils/types.hin (mu_msgset_t): New type.
* libmailutils/Makefile.am (SUBDIRS): Add msgset.
(libmailutils_la_LIBADD): Add libmsgset.la
* libmailutils/msgset/Makefile.am: New file.
* libmailutils/msgset/add.c: New file.
* libmailutils/msgset/aggr.c: New file.
* libmailutils/msgset/clear.c: New file.
* libmailutils/msgset/create.c: New file.
* libmailutils/msgset/free.c: New file.
* libmailutils/msgset/getitr.c: New file.
* libmailutils/msgset/getlist.c: New file.
* libmailutils/msgset/locate.c: New file.
* libmailutils/msgset/parse.c: New file.
* libmailutils/msgset/print.c: New file.
* libmailutils/msgset/sub.c: New file.
* libmailutils/tests/msgset.at: New file.
* libmailutils/tests/msgset.c: New file.
* libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add msgset.
(TESTSUITE_AT): Add msgset.at.
* libmailutils/tests/testsuite.at: Include msgset.at.
* testsuite/msgset.c: New file.
* testsuite/Makefile.am (noinst_PROGRAMS): Add msgset.
1 parent d16a3de5
......@@ -1479,6 +1479,7 @@ AC_CONFIG_FILES([
libmailutils/mailbox/Makefile
libmailutils/mailer/Makefile
libmailutils/mime/Makefile
libmailutils/msgset/Makefile
libmailutils/property/Makefile
libmailutils/server/Makefile
libmailutils/string/Makefile
......
......@@ -73,6 +73,7 @@ pkginclude_HEADERS = \
mh.h\
mime.h\
monitor.h\
msgset.h\
mu_auth.h\
util.h\
nls.h\
......
......@@ -18,6 +18,10 @@
#ifndef _MAILUTILS_DATETIME_H
#define _MAILUTILS_DATETIME_H
#ifdef __cplusplus
extern "C" {
#endif
#include <time.h>
#include <mailutils/types.h>
......@@ -83,4 +87,8 @@ int mu_scan_datetime (const char *input, const char *fmt, struct tm *tm,
#define MU_DATETIME_FORM_RFC822 "%a, %e %b %Y %H:%M:%S %z"
#define MU_DATETIME_SCAN_RFC822 "%[%a, %]%e %b %Y %H:%M%[:%S%] %z"
#ifdef __cplusplus
}
#endif
#endif
......
......@@ -70,5 +70,6 @@
#include <mailutils/prog.h>
#include <mailutils/sockaddr.h>
#include <mailutils/cidr.h>
#include <mailutils/msgset.h>
/* EOF */
......
/* 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/>. */
#ifndef _MAILUTILS_MSGSET_H
#define _MAILUTILS_MSGSET_H
#ifdef __cplusplus
extern "C" {
#endif
struct mu_msgrange
{
size_t msg_beg;
size_t msg_end;
};
/* Message numbers start with 1. MU_MSGNO_LAST denotes the last
message. */
#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);
int mu_msgset_add_range (mu_msgset_t list, size_t beg, size_t end);
int mu_msgset_sub_range (mu_msgset_t list, size_t beg, size_t end);
/*int mu_msgset_add_set (mu_msgset_t a, mu_msgset_t b);*/
/*int mu_msgset_sub_set (mu_msgset_t a, mu_msgset_t b);*/
int mu_msgset_aggregate (mu_msgset_t set);
int mu_msgset_clear (mu_msgset_t set);
void mu_msgset_free (mu_msgset_t set);
void mu_msgset_destroy (mu_msgset_t *set);
int mu_msgset_parse_imap (mu_msgset_t set, char *s, char **end);
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);
#ifdef __cplusplus
}
#endif
#endif
......@@ -44,6 +44,7 @@ sysinclude_HEADERS = \
message.h\
mime.h\
monitor.h\
msgset.h\
nntp.h\
nullstream.h\
observer.h\
......
/* 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/>. */
#ifndef _MAILUTILS_SYS_MSGSET_H
# define _MAILUTILS_SYS_MSGSET_H
#define _MU_MSGSET_AGGREGATED 0x10
#define _MU_MSGSET_USERFLAG_MASK 0x0f
struct _mu_msgset
{
mu_list_t list; /* List of mu_msgrange structures */
mu_mailbox_t mbox; /* Associated mailbox */
int flags; /* Message set flags */
};
#endif
......@@ -77,7 +77,8 @@ struct _mu_server;
struct _mu_tcp_server;
struct _mu_dbm_file;
struct _mu_imapio;
struct _mu_msgset;
struct mu_sockaddr; /* defined in mailutils/sockaddr.h */
struct mu_cidr; /* defined in mailutils/cidr.h */
......@@ -125,6 +126,7 @@ typedef struct _mu_secret *mu_secret_t;
typedef struct _mu_mime_io_buffer *mu_mime_io_buffer_t;
typedef struct _mu_dbm_file *mu_dbm_file_t;
typedef struct _mu_imapio *mu_imapio_t;
typedef struct _mu_msgset *mu_msgset_t;
typedef void (*mu_onexit_t) (void*);
typedef unsigned int mu_debug_handle_t;
......
......@@ -18,7 +18,7 @@
SUBDIRS = \
auth base address list sockaddr cidr cfg diag\
filter mailbox mailer mime server string stream stdstream\
filter mailbox mailer mime msgset server string stream stdstream\
property url imapio datetime . tests
lib_LTLIBRARIES = libmailutils.la
......@@ -41,6 +41,7 @@ libmailutils_la_LIBADD = \
mailbox/libmailbox.la\
mailer/libmailer.la\
mime/libmime.la\
msgset/libmsgset.la\
property/libproperty.la\
server/libserver.la\
string/libstring.la\
......
# 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/>.
noinst_LTLIBRARIES = libmsgset.la
libmsgset_la_SOURCES = \
add.c\
aggr.c\
clear.c\
create.c\
getitr.c\
getlist.c\
free.c\
locate.c\
parse.c\
print.c\
sub.c
INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
/* 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>
int
mu_msgset_add_range (mu_msgset_t mset, size_t beg, size_t end)
{
int rc;
struct mu_msgrange *range;
if (!mset || beg == 0)
return EINVAL;
range = calloc (1, sizeof (*range));
if (!range)
return ENOMEM;
range->msg_beg = beg;
range->msg_end = end;
rc = mu_list_append (mset->list, range);
if (rc)
free (range);
mset->flags &= ~_MU_MSGSET_AGGREGATED;
return rc;
}
/* 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/iterator.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
/* Comparator function for sorting the message set list. */
static int
compare_msgrange (const void *a, const void *b)
{
struct mu_msgrange const *sa = a;
struct mu_msgrange const *sb = b;
if (sa->msg_end != sb->msg_end)
{
if (sa->msg_end == MU_MSGNO_LAST)
return 1;
if (sb->msg_end == MU_MSGNO_LAST)
return -1;
}
if (sa->msg_beg < sb->msg_beg)
return -1;
if (sa->msg_beg > sb->msg_beg)
return 1;
if (sa->msg_end == sb->msg_end)
return 0;
if (sa->msg_end < sb->msg_end)
return -1;
return 1;
}
int
mu_msgset_aggregate (mu_msgset_t mset)
{
int rc;
mu_iterator_t itr;
size_t count;
struct mu_msgrange *prev = NULL, *mr;
int dir;
if (!mset)
return EINVAL;
if (mset->flags & _MU_MSGSET_AGGREGATED)
return 0; /* nothing to do */
rc = mu_list_count (mset->list, &count);
if (rc)
return rc;
if (count < 2)
return 0;
mu_list_sort (mset->list, compare_msgrange);
rc = mu_list_get_iterator (mset->list, &itr);
if (rc)
return rc;
/* Set backward direction */
dir = 1;
rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &dir);
if (rc)
{
mu_iterator_destroy (&itr);
return rc;
}
mu_iterator_first (itr);
mu_iterator_current (itr, (void **)&mr);
if (mr->msg_end == MU_MSGNO_LAST)
{
struct mu_msgrange *last = mr;
for (mu_iterator_next (itr);
rc == 0 && !mu_iterator_is_done (itr); mu_iterator_next (itr))
{
mu_iterator_current (itr, (void **)&mr);
if (mr->msg_end == MU_MSGNO_LAST)
{
last->msg_beg = mr->msg_beg;
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
}
else if (mr->msg_beg >= last->msg_beg)
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
else if (mr->msg_end + 1 >= last->msg_beg)
{
last->msg_beg = mr->msg_beg;
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
}
else
break;
}
}
if (rc == 0)
{
dir = 0;
rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &dir);
if (rc)
{
mu_iterator_destroy (&itr);
return rc;
}
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
mu_iterator_current (itr, (void **)&mr);
if (mr->msg_end == MU_MSGNO_LAST)
break;
if (prev)
{
if (prev->msg_beg <= mr->msg_beg && mr->msg_beg <= prev->msg_end)
{
/* Possible cases:
1. mr lies fully within prev:
mr->msg_end <= prev->msg_end
Action: mr deleted
2. mr overlaps with prev:
mr->msg_end > prev->msg_end
Action: prev->msg_end is set to mr->msg_end; mr deleted
*/
if (mr->msg_end > prev->msg_end)
prev->msg_end = mr->msg_end;
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
if (rc)
break;
continue;
}
else if (prev->msg_end + 1 == mr->msg_beg)
{
prev->msg_end = mr->msg_end;
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
if (rc)
break;
continue;
}
}
prev = mr;
}
}
mu_iterator_destroy (&itr);
if (rc == 0)
mset->flags |= _MU_MSGSET_AGGREGATED;
return rc;
}
/* 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 <mailutils/types.h>
#include <mailutils/errno.h>
#include <mailutils/list.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
int
mu_msgset_clear (mu_msgset_t mset)
{
if (!mset)
return EINVAL;
mu_list_clear (mset->list);
return 0;
}
/* 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>
/* Comparator function used to locate a message in the list. Second argument
(b) is a pointer to the message number. */
static int
compare_msgnum (const void *a, const void *b)
{
struct mu_msgrange const *range = a;
size_t msgno = *(size_t*)b;
if (range->msg_beg <= msgno && msgno <= range->msg_end)
return 0;
return 1;
}
int
mu_msgset_create (mu_msgset_t *pres, mu_mailbox_t mbox, int flags)
{
mu_msgset_t msgset;
int rc;
msgset = calloc (1, sizeof (*msgset));
if (!msgset)
return ENOMEM;
rc = mu_list_create (&msgset->list);
if (rc)
{
free (msgset);
return rc;
}
mu_list_set_destroy_item (msgset->list, mu_list_free_item);
mu_list_set_comparator (msgset->list, compare_msgnum);
msgset->mbox = mbox;
msgset->flags = flags & _MU_MSGSET_USERFLAG_MASK;
*pres = msgset;
return 0;
}
/* 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/list.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
void
mu_msgset_free (mu_msgset_t mset)
{
if (mset)
{
mu_list_destroy (&mset->list);
free (mset);
}
}
void
mu_msgset_destroy (mu_msgset_t *pset)
{
if (pset)
{
mu_msgset_free (*pset);
*pset = NULL;
}
}
/* 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 <mailutils/types.h>
#include <mailutils/errno.h>
#include <mailutils/list.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
int
mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr)
{
if (!msgset)
return EINVAL;
return mu_list_get_iterator (msgset->list, pitr);
}
/* 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 <mailutils/types.h>
#include <mailutils/errno.h>
#include <mailutils/list.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
int
mu_msgset_get_list (mu_msgset_t msgset, mu_list_t *plist)
{
if (!msgset)
return EINVAL;
if (!plist)
return MU_ERR_OUT_PTR_NULL;
*plist = msgset->list;
return 0;
}
/* 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>
int
mu_msgset_locate (mu_msgset_t msgset, size_t n,
struct mu_msgrange const **prange)
{
if (!msgset || n == 0)
return EINVAL;
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 <string.h>
#include <limits.h>
#include <mailutils/types.h>
#include <mailutils/errno.h>
#include <mailutils/list.h>
#include <mailutils/iterator.h>
#include <mailutils/mailbox.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
/* This structure keeps parser state while parsing message set. */
struct parse_msgnum_env
{
char *s; /* Current position in string */
size_t minval; /* Min. sequence number or UID */
size_t maxval; /* Max. sequence number or UID */
mu_msgset_t msgset; /* Message set being built. */
};
/* Get a single message number/UID from env->s and store it into *PN.
Return 0 on success and error code on error.
Advance env->s to the point past the parsed message number.
*/
static int
get_msgnum (struct parse_msgnum_env *env, size_t *pn)
{
size_t msgnum;
char *p;
errno = 0;
msgnum = strtoul (env->s, &p, 10);
if (msgnum == ULONG_MAX && errno == ERANGE)
return MU_ERR_PARSE;
env->s = p;
if (env->msgset->mbox && env->maxval && msgnum > env->maxval)
msgnum = env->maxval;
*pn = msgnum;
return 0;
}
/* Parse a single message range (A:B). Treat '*' as the largest number/UID
in use. */
static int
parse_msgrange (struct parse_msgnum_env *env)
{
int rc;
struct mu_msgrange msgrange;
if (*env->s == '*')
{
msgrange.msg_beg = env->maxval;
env->s++;
}
else if ((rc = get_msgnum (env, &msgrange.msg_beg)))
return rc;
if (*env->s == ':')
{
if (*++env->s == '*')
{
msgrange.msg_end = env->maxval;
++env->s;
}
else if (*env->s == 0)
return MU_ERR_PARSE;
else if ((rc = get_msgnum (env, &msgrange.msg_end)))
return rc;
}
else
msgrange.msg_end = msgrange.msg_beg;
if (msgrange.msg_end && msgrange.msg_end < msgrange.msg_beg)
{
size_t tmp = msgrange.msg_end;
msgrange.msg_end = msgrange.msg_beg;
msgrange.msg_beg = tmp;
}
if ((env->msgset->flags & MU_MSGSET_UID) && env->msgset->mbox)
{
int rc;
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;
else if (rc)
return rc;
}
return mu_msgset_add_range (env->msgset, msgrange.msg_beg, msgrange.msg_end);
}
/* Parse IMAP-style message set specification S.
On success, return 0 and populate MSET with the resulting message ranges.
On error, return error code and point END to the position in the input
string where parsing has failed. */
int
mu_msgset_parse_imap (mu_msgset_t mset, char *s, char **end)
{
int rc;
struct parse_msgnum_env env;
if (!s || !mset)
return EINVAL;
if (!*s)
return MU_ERR_PARSE;
memset (&env, 0, sizeof (env));
env.s = s;
env.msgset = mset;
env.minval = 1;
if (end)
*end = s;
if (mset->mbox)
{
size_t lastmsgno; /* Max. sequence number. */
rc = mu_mailbox_messages_count (mset->mbox, &lastmsgno);
if (rc == 0)
{
if (mset->flags & MU_MSGSET_UID)
{
rc = mu_mailbox_translate (mset->mbox, MU_MAILBOX_MSGNO_TO_UID,
lastmsgno, &env.maxval);
if (rc == 0)
rc = mu_mailbox_translate (mset->mbox, MU_MAILBOX_MSGNO_TO_UID,
1, &env.minval);
}
else
env.maxval = lastmsgno;
}
if (rc)
return rc;
}
while ((rc = parse_msgrange (&env)) == 0 && *env.s)
{
if (*env.s != ',' || *++env.s == 0)
{
rc = MU_ERR_PARSE;
break;
}
}
if (end)
*end = env.s;
return rc;
}
/* 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/stream.h>
#include <mailutils/io.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
struct print_env
{
mu_stream_t stream;
int cont;
};
static int
_msgrange_printer (void *item, void *data)
{
int rc;
struct mu_msgrange *range = item;
struct print_env *env = data;
if (env->cont)
{
rc = mu_stream_write (env->stream, ",", 1, NULL);
if (rc)
return rc;
}
else
env->cont = 1;
if (range->msg_beg == range->msg_end)
rc = mu_stream_printf (env->stream, "%lu", (unsigned long) range->msg_beg);
else if (range->msg_end == 0)
rc = mu_stream_printf (env->stream, "%lu:*",
(unsigned long) range->msg_beg);
else
rc = mu_stream_printf (env->stream, "%lu:%lu",
(unsigned long) range->msg_beg,
(unsigned long) range->msg_end);
return rc;
}
int
mu_msgset_print (mu_stream_t str, mu_msgset_t mset)
{
struct print_env env;
int rc;
if (mu_list_is_empty (mset->list))
return MU_ERR_NOENT;
rc = mu_msgset_aggregate (mset);
if (rc)
return rc;
env.stream = str;
env.cont = 0;
return mu_list_foreach (mset->list, _msgrange_printer, &env);
}
/* 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/iterator.h>
#include <mailutils/msgset.h>
#include <mailutils/sys/msgset.h>
/* Remove range R from the set S.
There are following basic cases:
1. S does not contain R.
Return imeediately, there is nothing to do here.
2. S contains a range X that matches exactly R.
Action: Remove X entirely and return.
3. There is a range X in S such that R falls entirely within it.
Action: Split X into two ranges:
X.msg_beg : R.msg_beg-1
R.msg_end+1 : X.msg_end
and return.
In border cases one of the new ranges may be empty.
4. There is a range X which contains an initial subrange of R.
Action: Remove the subrange from X. If the resulting range is
empty, remove it. Continue iteration with X.msg_end:R.msg_end
in place of R.
5. There is a range X such that its initial subrange is contained
in R.
Action: Remove X.msg_beg:R.msg_end and return.
6. There is a range X that is contained within R.
Action: Remove X and continue.
There are two special cases. First is when R.msg_end is 0, meaning the last
available message number in the mailbox. In this case the problem is reduced
to either 2 or a combination of 4 and zero or more 6. It is handled by the
sub_msgno_last function below.
Yet another special case is when the last element of S has msg_end == 0. If
so, the problem is reduced to either 2 or 4.
*/
static int
sub_msgno_last (mu_msgset_t mset, size_t beg)
{
int rc;
struct mu_msgrange *range;
if (beg == 1)
mu_list_clear (mset->list);
else
{
mu_iterator_t itr;
rc = mu_list_get_iterator (mset->list, &itr);
if (rc)
return rc;
rc = 1;
rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &rc);
if (rc)
{
mu_iterator_destroy (&itr);
return rc;
}
for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
mu_iterator_current (itr, (void **)&range);
if (range->msg_beg > beg)
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
else if (range->msg_beg == beg)
{
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
break;
}
else
break;
}
mu_iterator_destroy (&itr);
}
return 0;
}
int
mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t end)
{
int rc;
mu_iterator_t itr;
struct mu_msgrange *mr;
if (!mset)
return EINVAL;
if (mu_list_is_empty (mset->list))
return MU_ERR_NOENT;
rc = mu_msgset_aggregate (mset);
if (rc)
return rc;
if (end == MU_MSGNO_LAST)
return sub_msgno_last (mset, beg);
/* Test border cases */
rc = mu_list_head (mset->list, (void**)&mr);
if (rc)
return rc;
if (end < mr->msg_beg)
return 0;
if (beg < mr->msg_beg)
beg = mr->msg_beg;
if (rc)
return rc;
rc = mu_list_tail (mset->list, (void**) &mr);
if (mr->msg_end != MU_MSGNO_LAST)
{
if (beg > mr->msg_end)
return 0;
if (end > mr->msg_end)
end = mr->msg_end;
}
rc = mu_list_get_iterator (mset->list, &itr);
if (rc)
return rc;
for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
mu_iterator_current (itr, (void **)&mr);
if (mr->msg_end == MU_MSGNO_LAST)
{
/* This is the last element in list. */
if (mr->msg_beg == beg)
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
else if (mr->msg_beg > beg)
mr->msg_beg = end + 1;
break;
}
if (mr->msg_beg == beg && mr->msg_end == end) /* See case 2 above */
{
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
break;
}
else if (mr->msg_beg <= beg && beg <= mr->msg_end)
{
if (mr->msg_beg <= end && end <= mr->msg_end) /* Case 3 */
{
/* Split the range */
if (end != mr->msg_end)
{
struct mu_msgrange *newrange = calloc (1,
sizeof (*newrange));
if (!newrange)
{
rc = ENOMEM;
break;
}
newrange->msg_beg = end + 1;
newrange->msg_end = mr->msg_end;
rc = mu_iterator_ctl (itr, mu_itrctl_insert, newrange);
if (rc)
{
free (newrange);
break;
}
}
if (mr->msg_beg == beg)
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
else
mr->msg_end = beg - 1;
break;
}
else if (mr->msg_beg == beg) /* Case 4 */
{
beg = mr->msg_end;
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
}
else
{
size_t n = mr->msg_end;
mr->msg_end = beg - 1;
beg = n;
}
}
else if (mr->msg_beg <= end && end <= mr->msg_end) /* Case 5 */
{
mr->msg_beg = end + 1;
if (mr->msg_beg >= mr->msg_end)
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
break;
}
else if (beg <= mr->msg_beg && mr->msg_beg <= end)
{
rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
}
}
mu_iterator_destroy (&itr);
return rc;
}
......@@ -52,6 +52,7 @@ noinst_PROGRAMS = \
listop\
mailcap\
mimehdr\
msgset\
prop\
scantime\
strftime\
......@@ -90,6 +91,7 @@ TESTSUITE_AT = \
list.at\
mailcap.at\
mimehdr.at\
msgset.at\
prop.at\
scantime.at\
strftime.at\
......
# This file is part of GNU Mailutils. -*- Autotest -*-
# 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/>.
AT_BANNER([Message sets])
dnl ------------------------------------------------------------------
dnl MSGSET([NAME], [KW = `'], [OP], [STDOUT = `'], [STDERR = `'])
dnl
m4_pushdef([MSGSET],[
AT_SETUP([$1])
AT_KEYWORDS([msgset $2])
AT_CHECK([msgset $3],[0],[$4],[$5])
AT_CLEANUP
])
dnl ------------------------------------------------------------------
MSGSET([Aggregation: simple],[msgset-aggr-simple msgset-aggr],
[-msgset='1,5:11,20:24,80:90,22:30,50:60,4:12,41:50,70:81'],
[1,4:12,20:30,41:60,70:90
])
MSGSET([Aggregation: open range (1)],
[msgset-aggr-open-1 msgset-aggr-open msgset-aggr],
[-msgset='12:*,1'],
[1,12:*
])
MSGSET([Aggregation: coalescing open ranges],
[msgset-aggr-open-2 msgset-aggr-open msgset-aggr],
[-msgset='12:*,1,15:*,8:*'],
[1,8:*
])
MSGSET([Aggregation: open range (3)],
[msgset-aggr-open-3 msgset-aggr-open msgset-aggr],
[-msgset='1,12:*,12:13'],
[1,12:*
])
MSGSET([Aggregation: open range (4)],
[msgset-aggr-open-4 msgset-aggr-open msgset-aggr],
[-msgset='1,12:*,13:40'],
[1,12:*
])
MSGSET([Aggregation: open range (5)],
[msgset-aggr-open-5 msgset-aggr-open msgset-aggr],
[-msgset='10:*,3,5:9'],
[3,5:*
])
MSGSET([Create simple set],[msgset-simple msgset-add],
[-add=1:10],
[1:10
])
MSGSET([Create complex set],[msgset-complex msgset-add],
[-add=1 -add=2 -add=3 -add=4 -add=10:20 -add=15:35 -add=36:40],
[1:4,10:40
])
MSGSET([Subtract: no match],[msgset-sub msgset-sub-1],
[-msgset=20:40 -sub=1:10],
[20:40
])
MSGSET([Subtract: exact match],[msgset-sub msgset-sub-2],
[-msgset=1,4:9,11 -sub=4:9],
[1,11
])
MSGSET([Subtract: contained range],[msgset-sub msgset-sub-3],
[-msgset=1:40 -sub=5:15
],
[1:4,16:40
])
MSGSET([Subtract: contained range (left border case)],
[msgset-sub msgset-sub-3 msgset-sub-3-0],
[-msgset=1:40 -sub=1:20],
[21:40
])
MSGSET([Subtract: contained range (right border case)],
[msgset-sub msgset-sub-3 msgset-sub-3-1],
[-msgset=1:40 -sub=30:40],
[1:29
])
MSGSET([Subtract: initial subrange],[msgset-sub msgset-sub-4],
[-msgset=1:40,50:60,80:200 -sub=55:65],
[1:40,50:54,80:200
])
MSGSET([Subtract: trailing subrange],[msgset-sub msgset-sub-5],
[-msgset=1:40,50:60,80:200 -sub=45:55],
[1:40,56:60,80:200
])
MSGSET([Subtract: overlapping subrange],[msgset-sub msgset-sub-6],
[-msgset=1:40,50:60,80:200 -sub=41:70],
[1:40,80:200
])
MSGSET([Subtract: 4, 5 and 6 combined],
[msgset-sub msgset-sub-4 msgset-sub-5 msgset-sub-6 msgset-sub-456],
[-msgset=1:40,50:60,80:200 -sub=30:100],
[1:29,101:200
])
MSGSET([open range],[msgset-inf],
[-msgset='1:*'],
[1:*
])
MSGSET([add to open range],[msgset-inf-add msgset-add],
[-msgset='10:*' -add=3 -add=5:9],
[3,5:*
])
MSGSET([subtract from open range],[msgset-inf-sub msgset-sub],
[-msgset='3,10:*' -sub=5:11],
[3,12:*
])
MSGSET([subtract from open range an equal range],[msgset-inf-sub-1 msgset-sub],
[-msgset='3,10:*' -sub=10:*],
[3
])
MSGSET([subtract from open range a broader range],
[msgset-inf-sub-2 msgset-sub],
[-msgset='3,10:*' -sub=20:*],
[3,10:*
])
MSGSET([subtract from open range a narrower range],
[msgset-inf-sub-3 msgset-sub],
[-msgset='3,10:*' -sub=5:*],
[3
])
MSGSET([subtract an open range with matching left boundary],
[msgset-inf-sub-4 msgset-sub],
[-msgset='3,10:20' -sub=10:*],
[3
])
MSGSET([subtract an open range with greater left boundary],
[msgset-inf-sub-4 msgset-sub],
[-msgset='3,10:20' -sub=11:*],
[3,10:20
])
MSGSET([subtract an open range with smaller left boundary],
[msgset-inf-sub-4 msgset-sub],
[-msgset='3,10:20' -sub=8:*],
[3
])
dnl ------------------------------------------------------------------
m4_popdef([MSGSET])
\ No newline at end of file
/* 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/mailutils.h>
static void
parse_msgset (char *arg, struct mu_msgrange *range)
{
size_t msgnum;
char *p;
errno = 0;
msgnum = strtoul (arg, &p, 10);
range->msg_beg = msgnum;
if (*p == ':')
{
if (*++p == '*')
msgnum = 0;
else
{
msgnum = strtoul (p, &p, 10);
if (*p)
{
mu_error ("error in message range near %s", p);
exit (1);
}
}
}
else if (*p == '*')
msgnum = 0;
else if (*p)
{
mu_error ("error in message range near %s", p);
exit (1);
}
range->msg_end = msgnum;
}
int
main (int argc, char **argv)
{
int i;
char *msgset_string = NULL;
mu_msgset_t msgset;
int rc;
mu_set_program_name (argv[0]);
for (i = 1; i < argc; i++)
{
char *arg = argv[i];
if (strcmp (arg, "-h") == 0 || strcmp (arg, "-help") == 0)
{
mu_printf ("usage: %s [-msgset=SET] [-add X[:Y]] [-del X:[Y]]...\n",
mu_program_name);
return 0;
}
else if (strncmp (arg, "-msgset=", 8) == 0)
msgset_string = arg + 8;
else
break;
}
MU_ASSERT (mu_msgset_create (&msgset, NULL, 0));
if (msgset_string)
{
char *end;
rc = mu_msgset_parse_imap (msgset, msgset_string, &end);
if (rc)
{
mu_error ("mu_msgset_parse_imap: %s near %s",
mu_strerror (rc), end);
return 1;
}
}
for (; i < argc; i++)
{
char *arg = argv[i];
struct mu_msgrange range;
if (strncmp (arg, "-add=", 5) == 0)
{
parse_msgset (arg + 5, &range);
MU_ASSERT (mu_msgset_add_range (msgset, range.msg_beg,
range.msg_end));
}
else if (strncmp (arg, "-sub=", 5) == 0)
{
parse_msgset (arg + 5, &range);
MU_ASSERT (mu_msgset_sub_range (msgset, range.msg_beg,
range.msg_end));
}
else
{
mu_error ("unknown option %s", arg);
return 1;
}
}
MU_ASSERT (mu_msgset_print (mu_strout, msgset));
mu_printf ("\n");
mu_msgset_free (msgset);
return 0;
}
......@@ -99,3 +99,5 @@ m4_include([strftime.at])
m4_include([fsaf.at])
m4_include([mimehdr.at])
m4_include([msgset.at])
......
......@@ -54,6 +54,7 @@ noinst_PROGRAMS = \
fldel\
lstuid\
mbdel\
msgset\
mimetest\
smtpsend\
ufms
......
/* 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/mailutils.h>
static void
parse_msgset (char *arg, struct mu_msgrange *range)
{
size_t msgnum;
char *p;
errno = 0;
msgnum = strtoul (arg, &p, 10);
range->msg_beg = msgnum;
if (*p == ':')
{
if (*++p == '*')
msgnum = 0;
else
{
msgnum = strtoul (p, &p, 10);
if (*p)
{
mu_error ("error in message range near %s", p);
exit (1);
}
}
}
else if (*p == '*')
msgnum = 0;
else if (*p)
{
mu_error ("error in message range near %s", p);
exit (1);
}
range->msg_end = msgnum;
}
int
main (int argc, char **argv)
{
int i;
char *msgset_string = NULL;
mu_msgset_t msgset;
int rc;
int flags = 0;
mu_mailbox_t mbox = NULL;
mu_set_program_name (argv[0]);
mu_registrar_record (mu_mbox_record);
for (i = 1; i < argc; i++)
{
char *arg = argv[i];
if (strcmp (arg, "-h") == 0 || strcmp (arg, "-help") == 0)
{
mu_printf ("usage: %s [-msgset=SET] [-add X[:Y]] [-del X:[Y]]...\n",
mu_program_name);
return 0;
}
else if (strncmp (arg, "-msgset=", 8) == 0)
msgset_string = arg + 8;
else if (strcmp (arg, "-uid") == 0)
flags |= MU_MSGSET_UID;
else if (strncmp (arg, "-mailbox=", 9) == 0)
{
MU_ASSERT (mu_mailbox_create (&mbox, arg + 9));
MU_ASSERT (mu_mailbox_open (mbox, MU_STREAM_READ));
}
else
break;
}
MU_ASSERT (mu_msgset_create (&msgset, mbox, flags));
if (msgset_string)
{
char *end;
rc = mu_msgset_parse_imap (msgset, msgset_string, &end);
if (rc)
{
mu_error ("mu_msgset_parse_imap: %s near %s",
mu_strerror (rc), end);
return 1;
}
}
for (; i < argc; i++)
{
char *arg = argv[i];
struct mu_msgrange range;
if (strncmp (arg, "-add=", 5) == 0)
{
parse_msgset (arg + 5, &range);
MU_ASSERT (mu_msgset_add_range (msgset, range.msg_beg,
range.msg_end));
}
else if (strncmp (arg, "-sub=", 5) == 0)
{
parse_msgset (arg + 5, &range);
MU_ASSERT (mu_msgset_sub_range (msgset, range.msg_beg,
range.msg_end));
}
else
{
mu_error ("unknown option %s", arg);
return 1;
}
}
MU_ASSERT (mu_msgset_print (mu_strout, msgset));
mu_printf ("\n");
mu_msgset_free (msgset);
return 0;
}