summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2011-12-26 12:06:57 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2011-12-26 18:34:13 (GMT)
commite072a2734eaf1bffdacfc20fcb598d79a50d11e7 (patch) (side-by-side diff)
tree62b91a5c1e240aee855bc87431ad75b73ca32367
parentd16a3de50d8c43f7b45f18db1704fa784ee4cb7b (diff)
downloadmailutils-e072a2734eaf1bffdacfc20fcb598d79a50d11e7.tar.gz
mailutils-e072a2734eaf1bffdacfc20fcb598d79a50d11e7.tar.bz2
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.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--configure.ac1
-rw-r--r--include/mailutils/Makefile.am1
-rw-r--r--include/mailutils/datetime.h8
-rw-r--r--include/mailutils/mailutils.h1
-rw-r--r--include/mailutils/msgset.h61
-rw-r--r--include/mailutils/sys/Makefile.am1
-rw-r--r--include/mailutils/sys/msgset.h31
-rw-r--r--include/mailutils/types.hin4
-rw-r--r--libmailutils/Makefile.am3
-rw-r--r--libmailutils/msgset/Makefile.am34
-rw-r--r--libmailutils/msgset/add.c43
-rw-r--r--libmailutils/msgset/aggr.c169
-rw-r--r--libmailutils/msgset/clear.c32
-rw-r--r--libmailutils/msgset/create.c60
-rw-r--r--libmailutils/msgset/free.c42
-rw-r--r--libmailutils/msgset/getitr.c30
-rw-r--r--libmailutils/msgset/getlist.c33
-rw-r--r--libmailutils/msgset/locate.c32
-rw-r--r--libmailutils/msgset/parse.c179
-rw-r--r--libmailutils/msgset/print.c74
-rw-r--r--libmailutils/msgset/sub.c233
-rw-r--r--libmailutils/tests/Makefile.am2
-rw-r--r--libmailutils/tests/msgset.at175
-rw-r--r--libmailutils/tests/msgset.c125
-rw-r--r--libmailutils/tests/testsuite.at2
-rw-r--r--testsuite/Makefile.am1
-rw-r--r--testsuite/msgset.c135
27 files changed, 1510 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index 9472fb7..8f1cbeb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am
index 53ea5e4..d8e46ac 100644
--- a/include/mailutils/Makefile.am
+++ b/include/mailutils/Makefile.am
@@ -73,6 +73,7 @@ pkginclude_HEADERS = \
mh.h\
mime.h\
monitor.h\
+ msgset.h\
mu_auth.h\
util.h\
nls.h\
diff --git a/include/mailutils/datetime.h b/include/mailutils/datetime.h
index bc1aa98..dbf1447 100644
--- a/include/mailutils/datetime.h
+++ b/include/mailutils/datetime.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
diff --git a/include/mailutils/mailutils.h b/include/mailutils/mailutils.h
index eb2a616..b562136 100644
--- a/include/mailutils/mailutils.h
+++ b/include/mailutils/mailutils.h
@@ -70,5 +70,6 @@
#include <mailutils/prog.h>
#include <mailutils/sockaddr.h>
#include <mailutils/cidr.h>
+#include <mailutils/msgset.h>
/* EOF */
diff --git a/include/mailutils/msgset.h b/include/mailutils/msgset.h
new file mode 100644
index 0000000..901ea79
--- a/dev/null
+++ b/include/mailutils/msgset.h
@@ -0,0 +1,61 @@
+/* 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
diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am
index 86412d0..27e2fe4 100644
--- a/include/mailutils/sys/Makefile.am
+++ b/include/mailutils/sys/Makefile.am
@@ -44,6 +44,7 @@ sysinclude_HEADERS = \
message.h\
mime.h\
monitor.h\
+ msgset.h\
nntp.h\
nullstream.h\
observer.h\
diff --git a/include/mailutils/sys/msgset.h b/include/mailutils/sys/msgset.h
new file mode 100644
index 0000000..9ecb053
--- a/dev/null
+++ b/include/mailutils/sys/msgset.h
@@ -0,0 +1,31 @@
+/* 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
diff --git a/include/mailutils/types.hin b/include/mailutils/types.hin
index b98d617..bda2c37 100644
--- a/include/mailutils/types.hin
+++ b/include/mailutils/types.hin
@@ -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;
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index c01b321..bbc8447 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -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\
diff --git a/libmailutils/msgset/Makefile.am b/libmailutils/msgset/Makefile.am
new file mode 100644
index 0000000..398806d
--- a/dev/null
+++ b/libmailutils/msgset/Makefile.am
@@ -0,0 +1,34 @@
+# 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
+
diff --git a/libmailutils/msgset/add.c b/libmailutils/msgset/add.c
new file mode 100644
index 0000000..9d97707
--- a/dev/null
+++ b/libmailutils/msgset/add.c
@@ -0,0 +1,43 @@
+/* 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;
+}
diff --git a/libmailutils/msgset/aggr.c b/libmailutils/msgset/aggr.c
new file mode 100644
index 0000000..a6fe7aa
--- a/dev/null
+++ b/libmailutils/msgset/aggr.c
@@ -0,0 +1,169 @@
+/* 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;
+}
diff --git a/libmailutils/msgset/clear.c b/libmailutils/msgset/clear.c
new file mode 100644
index 0000000..f3f7ef8
--- a/dev/null
+++ b/libmailutils/msgset/clear.c
@@ -0,0 +1,32 @@
+/* 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;
+}
+
diff --git a/libmailutils/msgset/create.c b/libmailutils/msgset/create.c
new file mode 100644
index 0000000..0f70ab2
--- a/dev/null
+++ b/libmailutils/msgset/create.c
@@ -0,0 +1,60 @@
+/* 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;
+}
diff --git a/libmailutils/msgset/free.c b/libmailutils/msgset/free.c
new file mode 100644
index 0000000..77a348e
--- a/dev/null
+++ b/libmailutils/msgset/free.c
@@ -0,0 +1,42 @@
+/* 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;
+ }
+}
+
diff --git a/libmailutils/msgset/getitr.c b/libmailutils/msgset/getitr.c
new file mode 100644
index 0000000..75cfb3d
--- a/dev/null
+++ b/libmailutils/msgset/getitr.c
@@ -0,0 +1,30 @@
+/* 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);
+}
diff --git a/libmailutils/msgset/getlist.c b/libmailutils/msgset/getlist.c
new file mode 100644
index 0000000..5f7370d
--- a/dev/null
+++ b/libmailutils/msgset/getlist.c
@@ -0,0 +1,33 @@
+/* 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;
+}
diff --git a/libmailutils/msgset/locate.c b/libmailutils/msgset/locate.c
new file mode 100644
index 0000000..7b94ece
--- a/dev/null
+++ b/libmailutils/msgset/locate.c
@@ -0,0 +1,32 @@
+/* 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);
+}
diff --git a/libmailutils/msgset/parse.c b/libmailutils/msgset/parse.c
new file mode 100644
index 0000000..6e139fc
--- a/dev/null
+++ b/libmailutils/msgset/parse.c
@@ -0,0 +1,179 @@
+/* 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;
+}
diff --git a/libmailutils/msgset/print.c b/libmailutils/msgset/print.c
new file mode 100644
index 0000000..e7f990e
--- a/dev/null
+++ b/libmailutils/msgset/print.c
@@ -0,0 +1,74 @@
+/* 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);
+}
diff --git a/libmailutils/msgset/sub.c b/libmailutils/msgset/sub.c
new file mode 100644
index 0000000..2840781
--- a/dev/null
+++ b/libmailutils/msgset/sub.c
@@ -0,0 +1,233 @@
+/* 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;
+}
+
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 8b97c86..aa1661d 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -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\
diff --git a/libmailutils/tests/msgset.at b/libmailutils/tests/msgset.at
new file mode 100644
index 0000000..a591afd
--- a/dev/null
+++ b/libmailutils/tests/msgset.at
@@ -0,0 +1,175 @@
+# 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
diff --git a/libmailutils/tests/msgset.c b/libmailutils/tests/msgset.c
new file mode 100644
index 0000000..91db029
--- a/dev/null
+++ b/libmailutils/tests/msgset.c
@@ -0,0 +1,125 @@
+/* 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;
+}
+
+
+
+
diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at
index b9b889c..15226c6 100644
--- a/libmailutils/tests/testsuite.at
+++ b/libmailutils/tests/testsuite.at
@@ -99,3 +99,5 @@ m4_include([strftime.at])
m4_include([fsaf.at])
m4_include([mimehdr.at])
+
+m4_include([msgset.at])
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 2a9f4ea..f115a86 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -54,6 +54,7 @@ noinst_PROGRAMS = \
fldel\
lstuid\
mbdel\
+ msgset\
mimetest\
smtpsend\
ufms
diff --git a/testsuite/msgset.c b/testsuite/msgset.c
new file mode 100644
index 0000000..ae2a099
--- a/dev/null
+++ b/testsuite/msgset.c
@@ -0,0 +1,135 @@
+/* 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;
+}
+
+
+
+

Return to:

Send suggestions and report system problems to the System administrator.