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; +} + + + + |