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.
Showing
27 changed files
with
1510 additions
and
2 deletions
... | @@ -1479,6 +1479,7 @@ AC_CONFIG_FILES([ | ... | @@ -1479,6 +1479,7 @@ AC_CONFIG_FILES([ |
1479 | libmailutils/mailbox/Makefile | 1479 | libmailutils/mailbox/Makefile |
1480 | libmailutils/mailer/Makefile | 1480 | libmailutils/mailer/Makefile |
1481 | libmailutils/mime/Makefile | 1481 | libmailutils/mime/Makefile |
1482 | libmailutils/msgset/Makefile | ||
1482 | libmailutils/property/Makefile | 1483 | libmailutils/property/Makefile |
1483 | libmailutils/server/Makefile | 1484 | libmailutils/server/Makefile |
1484 | libmailutils/string/Makefile | 1485 | libmailutils/string/Makefile | ... | ... |
... | @@ -18,6 +18,10 @@ | ... | @@ -18,6 +18,10 @@ |
18 | #ifndef _MAILUTILS_DATETIME_H | 18 | #ifndef _MAILUTILS_DATETIME_H |
19 | #define _MAILUTILS_DATETIME_H | 19 | #define _MAILUTILS_DATETIME_H |
20 | 20 | ||
21 | #ifdef __cplusplus | ||
22 | extern "C" { | ||
23 | #endif | ||
24 | |||
21 | #include <time.h> | 25 | #include <time.h> |
22 | #include <mailutils/types.h> | 26 | #include <mailutils/types.h> |
23 | 27 | ||
... | @@ -83,4 +87,8 @@ int mu_scan_datetime (const char *input, const char *fmt, struct tm *tm, | ... | @@ -83,4 +87,8 @@ int mu_scan_datetime (const char *input, const char *fmt, struct tm *tm, |
83 | #define MU_DATETIME_FORM_RFC822 "%a, %e %b %Y %H:%M:%S %z" | 87 | #define MU_DATETIME_FORM_RFC822 "%a, %e %b %Y %H:%M:%S %z" |
84 | #define MU_DATETIME_SCAN_RFC822 "%[%a, %]%e %b %Y %H:%M%[:%S%] %z" | 88 | #define MU_DATETIME_SCAN_RFC822 "%[%a, %]%e %b %Y %H:%M%[:%S%] %z" |
85 | 89 | ||
90 | #ifdef __cplusplus | ||
91 | } | ||
92 | #endif | ||
93 | |||
86 | #endif | 94 | #endif | ... | ... |
... | @@ -70,5 +70,6 @@ | ... | @@ -70,5 +70,6 @@ |
70 | #include <mailutils/prog.h> | 70 | #include <mailutils/prog.h> |
71 | #include <mailutils/sockaddr.h> | 71 | #include <mailutils/sockaddr.h> |
72 | #include <mailutils/cidr.h> | 72 | #include <mailutils/cidr.h> |
73 | #include <mailutils/msgset.h> | ||
73 | 74 | ||
74 | /* EOF */ | 75 | /* EOF */ | ... | ... |
include/mailutils/msgset.h
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Lesser General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 3 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General | ||
15 | Public License along with this library. If not, see | ||
16 | <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | #ifndef _MAILUTILS_MSGSET_H | ||
19 | #define _MAILUTILS_MSGSET_H | ||
20 | |||
21 | #ifdef __cplusplus | ||
22 | extern "C" { | ||
23 | #endif | ||
24 | |||
25 | struct mu_msgrange | ||
26 | { | ||
27 | size_t msg_beg; | ||
28 | size_t msg_end; | ||
29 | }; | ||
30 | |||
31 | /* Message numbers start with 1. MU_MSGNO_LAST denotes the last | ||
32 | message. */ | ||
33 | #define MU_MSGNO_LAST 0 | ||
34 | |||
35 | #define MU_MSGSET_UID 0x01 /* Message set operates on UIDs */ | ||
36 | |||
37 | int mu_msgset_create (mu_msgset_t *pmsgset, mu_mailbox_t mbox, int flags); | ||
38 | int mu_msgset_get_list (mu_msgset_t msgset, mu_list_t *plist); | ||
39 | int mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr); | ||
40 | |||
41 | int mu_msgset_add_range (mu_msgset_t list, size_t beg, size_t end); | ||
42 | int mu_msgset_sub_range (mu_msgset_t list, size_t beg, size_t end); | ||
43 | /*int mu_msgset_add_set (mu_msgset_t a, mu_msgset_t b);*/ | ||
44 | /*int mu_msgset_sub_set (mu_msgset_t a, mu_msgset_t b);*/ | ||
45 | int mu_msgset_aggregate (mu_msgset_t set); | ||
46 | int mu_msgset_clear (mu_msgset_t set); | ||
47 | void mu_msgset_free (mu_msgset_t set); | ||
48 | void mu_msgset_destroy (mu_msgset_t *set); | ||
49 | |||
50 | int mu_msgset_parse_imap (mu_msgset_t set, char *s, char **end); | ||
51 | |||
52 | int mu_msgset_print (mu_stream_t str, mu_msgset_t msgset); | ||
53 | |||
54 | int mu_msgset_locate (mu_msgset_t msgset, size_t n, | ||
55 | struct mu_msgrange const **prange); | ||
56 | |||
57 | #ifdef __cplusplus | ||
58 | } | ||
59 | #endif | ||
60 | |||
61 | #endif |
include/mailutils/sys/msgset.h
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Lesser General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 3 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General | ||
15 | Public License along with this library. If not, see | ||
16 | <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | #ifndef _MAILUTILS_SYS_MSGSET_H | ||
19 | # define _MAILUTILS_SYS_MSGSET_H | ||
20 | |||
21 | #define _MU_MSGSET_AGGREGATED 0x10 | ||
22 | #define _MU_MSGSET_USERFLAG_MASK 0x0f | ||
23 | |||
24 | struct _mu_msgset | ||
25 | { | ||
26 | mu_list_t list; /* List of mu_msgrange structures */ | ||
27 | mu_mailbox_t mbox; /* Associated mailbox */ | ||
28 | int flags; /* Message set flags */ | ||
29 | }; | ||
30 | |||
31 | #endif |
... | @@ -77,7 +77,8 @@ struct _mu_server; | ... | @@ -77,7 +77,8 @@ struct _mu_server; |
77 | struct _mu_tcp_server; | 77 | struct _mu_tcp_server; |
78 | struct _mu_dbm_file; | 78 | struct _mu_dbm_file; |
79 | struct _mu_imapio; | 79 | struct _mu_imapio; |
80 | 80 | struct _mu_msgset; | |
81 | |||
81 | struct mu_sockaddr; /* defined in mailutils/sockaddr.h */ | 82 | struct mu_sockaddr; /* defined in mailutils/sockaddr.h */ |
82 | struct mu_cidr; /* defined in mailutils/cidr.h */ | 83 | struct mu_cidr; /* defined in mailutils/cidr.h */ |
83 | 84 | ||
... | @@ -125,6 +126,7 @@ typedef struct _mu_secret *mu_secret_t; | ... | @@ -125,6 +126,7 @@ typedef struct _mu_secret *mu_secret_t; |
125 | typedef struct _mu_mime_io_buffer *mu_mime_io_buffer_t; | 126 | typedef struct _mu_mime_io_buffer *mu_mime_io_buffer_t; |
126 | typedef struct _mu_dbm_file *mu_dbm_file_t; | 127 | typedef struct _mu_dbm_file *mu_dbm_file_t; |
127 | typedef struct _mu_imapio *mu_imapio_t; | 128 | typedef struct _mu_imapio *mu_imapio_t; |
129 | typedef struct _mu_msgset *mu_msgset_t; | ||
128 | 130 | ||
129 | typedef void (*mu_onexit_t) (void*); | 131 | typedef void (*mu_onexit_t) (void*); |
130 | typedef unsigned int mu_debug_handle_t; | 132 | typedef unsigned int mu_debug_handle_t; | ... | ... |
... | @@ -18,7 +18,7 @@ | ... | @@ -18,7 +18,7 @@ |
18 | 18 | ||
19 | SUBDIRS = \ | 19 | SUBDIRS = \ |
20 | auth base address list sockaddr cidr cfg diag\ | 20 | auth base address list sockaddr cidr cfg diag\ |
21 | filter mailbox mailer mime server string stream stdstream\ | 21 | filter mailbox mailer mime msgset server string stream stdstream\ |
22 | property url imapio datetime . tests | 22 | property url imapio datetime . tests |
23 | 23 | ||
24 | lib_LTLIBRARIES = libmailutils.la | 24 | lib_LTLIBRARIES = libmailutils.la |
... | @@ -41,6 +41,7 @@ libmailutils_la_LIBADD = \ | ... | @@ -41,6 +41,7 @@ libmailutils_la_LIBADD = \ |
41 | mailbox/libmailbox.la\ | 41 | mailbox/libmailbox.la\ |
42 | mailer/libmailer.la\ | 42 | mailer/libmailer.la\ |
43 | mime/libmime.la\ | 43 | mime/libmime.la\ |
44 | msgset/libmsgset.la\ | ||
44 | property/libproperty.la\ | 45 | property/libproperty.la\ |
45 | server/libserver.la\ | 46 | server/libserver.la\ |
46 | string/libstring.la\ | 47 | string/libstring.la\ | ... | ... |
libmailutils/msgset/Makefile.am
0 → 100644
1 | # GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | # Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | # | ||
4 | # This library is free software; you can redistribute it and/or | ||
5 | # modify it under the terms of the GNU Lesser General Public | ||
6 | # License as published by the Free Software Foundation; either | ||
7 | # version 3 of the License, or (at your option) any later version. | ||
8 | # | ||
9 | # This library is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | # Lesser General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU Lesser General | ||
15 | # Public License along with this library. If not, see | ||
16 | # <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | noinst_LTLIBRARIES = libmsgset.la | ||
19 | |||
20 | libmsgset_la_SOURCES = \ | ||
21 | add.c\ | ||
22 | aggr.c\ | ||
23 | clear.c\ | ||
24 | create.c\ | ||
25 | getitr.c\ | ||
26 | getlist.c\ | ||
27 | free.c\ | ||
28 | locate.c\ | ||
29 | parse.c\ | ||
30 | print.c\ | ||
31 | sub.c | ||
32 | |||
33 | INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils | ||
34 |
libmailutils/msgset/add.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/types.h> | ||
20 | #include <mailutils/errno.h> | ||
21 | #include <mailutils/list.h> | ||
22 | #include <mailutils/msgset.h> | ||
23 | #include <mailutils/sys/msgset.h> | ||
24 | |||
25 | int | ||
26 | mu_msgset_add_range (mu_msgset_t mset, size_t beg, size_t end) | ||
27 | { | ||
28 | int rc; | ||
29 | struct mu_msgrange *range; | ||
30 | |||
31 | if (!mset || beg == 0) | ||
32 | return EINVAL; | ||
33 | range = calloc (1, sizeof (*range)); | ||
34 | if (!range) | ||
35 | return ENOMEM; | ||
36 | range->msg_beg = beg; | ||
37 | range->msg_end = end; | ||
38 | rc = mu_list_append (mset->list, range); | ||
39 | if (rc) | ||
40 | free (range); | ||
41 | mset->flags &= ~_MU_MSGSET_AGGREGATED; | ||
42 | return rc; | ||
43 | } |
libmailutils/msgset/aggr.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/types.h> | ||
20 | #include <mailutils/errno.h> | ||
21 | #include <mailutils/list.h> | ||
22 | #include <mailutils/iterator.h> | ||
23 | #include <mailutils/msgset.h> | ||
24 | #include <mailutils/sys/msgset.h> | ||
25 | |||
26 | /* Comparator function for sorting the message set list. */ | ||
27 | static int | ||
28 | compare_msgrange (const void *a, const void *b) | ||
29 | { | ||
30 | struct mu_msgrange const *sa = a; | ||
31 | struct mu_msgrange const *sb = b; | ||
32 | |||
33 | if (sa->msg_end != sb->msg_end) | ||
34 | { | ||
35 | if (sa->msg_end == MU_MSGNO_LAST) | ||
36 | return 1; | ||
37 | if (sb->msg_end == MU_MSGNO_LAST) | ||
38 | return -1; | ||
39 | } | ||
40 | |||
41 | if (sa->msg_beg < sb->msg_beg) | ||
42 | return -1; | ||
43 | if (sa->msg_beg > sb->msg_beg) | ||
44 | return 1; | ||
45 | |||
46 | if (sa->msg_end == sb->msg_end) | ||
47 | return 0; | ||
48 | |||
49 | if (sa->msg_end < sb->msg_end) | ||
50 | return -1; | ||
51 | return 1; | ||
52 | } | ||
53 | |||
54 | int | ||
55 | mu_msgset_aggregate (mu_msgset_t mset) | ||
56 | { | ||
57 | int rc; | ||
58 | mu_iterator_t itr; | ||
59 | size_t count; | ||
60 | struct mu_msgrange *prev = NULL, *mr; | ||
61 | int dir; | ||
62 | |||
63 | if (!mset) | ||
64 | return EINVAL; | ||
65 | |||
66 | if (mset->flags & _MU_MSGSET_AGGREGATED) | ||
67 | return 0; /* nothing to do */ | ||
68 | |||
69 | rc = mu_list_count (mset->list, &count); | ||
70 | if (rc) | ||
71 | return rc; | ||
72 | if (count < 2) | ||
73 | return 0; | ||
74 | |||
75 | mu_list_sort (mset->list, compare_msgrange); | ||
76 | |||
77 | rc = mu_list_get_iterator (mset->list, &itr); | ||
78 | if (rc) | ||
79 | return rc; | ||
80 | /* Set backward direction */ | ||
81 | dir = 1; | ||
82 | rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &dir); | ||
83 | if (rc) | ||
84 | { | ||
85 | mu_iterator_destroy (&itr); | ||
86 | return rc; | ||
87 | } | ||
88 | |||
89 | mu_iterator_first (itr); | ||
90 | mu_iterator_current (itr, (void **)&mr); | ||
91 | |||
92 | if (mr->msg_end == MU_MSGNO_LAST) | ||
93 | { | ||
94 | struct mu_msgrange *last = mr; | ||
95 | |||
96 | for (mu_iterator_next (itr); | ||
97 | rc == 0 && !mu_iterator_is_done (itr); mu_iterator_next (itr)) | ||
98 | { | ||
99 | mu_iterator_current (itr, (void **)&mr); | ||
100 | if (mr->msg_end == MU_MSGNO_LAST) | ||
101 | { | ||
102 | last->msg_beg = mr->msg_beg; | ||
103 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
104 | } | ||
105 | else if (mr->msg_beg >= last->msg_beg) | ||
106 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
107 | else if (mr->msg_end + 1 >= last->msg_beg) | ||
108 | { | ||
109 | last->msg_beg = mr->msg_beg; | ||
110 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
111 | } | ||
112 | else | ||
113 | break; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | if (rc == 0) | ||
118 | { | ||
119 | dir = 0; | ||
120 | rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &dir); | ||
121 | if (rc) | ||
122 | { | ||
123 | mu_iterator_destroy (&itr); | ||
124 | return rc; | ||
125 | } | ||
126 | |||
127 | for (mu_iterator_first (itr); !mu_iterator_is_done (itr); | ||
128 | mu_iterator_next (itr)) | ||
129 | { | ||
130 | mu_iterator_current (itr, (void **)&mr); | ||
131 | if (mr->msg_end == MU_MSGNO_LAST) | ||
132 | break; | ||
133 | if (prev) | ||
134 | { | ||
135 | if (prev->msg_beg <= mr->msg_beg && mr->msg_beg <= prev->msg_end) | ||
136 | { | ||
137 | /* Possible cases: | ||
138 | 1. mr lies fully within prev: | ||
139 | mr->msg_end <= prev->msg_end | ||
140 | Action: mr deleted | ||
141 | 2. mr overlaps with prev: | ||
142 | mr->msg_end > prev->msg_end | ||
143 | Action: prev->msg_end is set to mr->msg_end; mr deleted | ||
144 | */ | ||
145 | if (mr->msg_end > prev->msg_end) | ||
146 | prev->msg_end = mr->msg_end; | ||
147 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
148 | if (rc) | ||
149 | break; | ||
150 | continue; | ||
151 | } | ||
152 | else if (prev->msg_end + 1 == mr->msg_beg) | ||
153 | { | ||
154 | prev->msg_end = mr->msg_end; | ||
155 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
156 | if (rc) | ||
157 | break; | ||
158 | continue; | ||
159 | } | ||
160 | } | ||
161 | prev = mr; | ||
162 | } | ||
163 | } | ||
164 | mu_iterator_destroy (&itr); | ||
165 | |||
166 | if (rc == 0) | ||
167 | mset->flags |= _MU_MSGSET_AGGREGATED; | ||
168 | return rc; | ||
169 | } |
libmailutils/msgset/clear.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <mailutils/types.h> | ||
19 | #include <mailutils/errno.h> | ||
20 | #include <mailutils/list.h> | ||
21 | #include <mailutils/msgset.h> | ||
22 | #include <mailutils/sys/msgset.h> | ||
23 | |||
24 | int | ||
25 | mu_msgset_clear (mu_msgset_t mset) | ||
26 | { | ||
27 | if (!mset) | ||
28 | return EINVAL; | ||
29 | mu_list_clear (mset->list); | ||
30 | return 0; | ||
31 | } | ||
32 |
libmailutils/msgset/create.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/types.h> | ||
20 | #include <mailutils/errno.h> | ||
21 | #include <mailutils/list.h> | ||
22 | #include <mailutils/msgset.h> | ||
23 | #include <mailutils/sys/msgset.h> | ||
24 | |||
25 | /* Comparator function used to locate a message in the list. Second argument | ||
26 | (b) is a pointer to the message number. */ | ||
27 | static int | ||
28 | compare_msgnum (const void *a, const void *b) | ||
29 | { | ||
30 | struct mu_msgrange const *range = a; | ||
31 | size_t msgno = *(size_t*)b; | ||
32 | |||
33 | if (range->msg_beg <= msgno && msgno <= range->msg_end) | ||
34 | return 0; | ||
35 | return 1; | ||
36 | } | ||
37 | |||
38 | int | ||
39 | mu_msgset_create (mu_msgset_t *pres, mu_mailbox_t mbox, int flags) | ||
40 | { | ||
41 | mu_msgset_t msgset; | ||
42 | int rc; | ||
43 | |||
44 | msgset = calloc (1, sizeof (*msgset)); | ||
45 | if (!msgset) | ||
46 | return ENOMEM; | ||
47 | |||
48 | rc = mu_list_create (&msgset->list); | ||
49 | if (rc) | ||
50 | { | ||
51 | free (msgset); | ||
52 | return rc; | ||
53 | } | ||
54 | mu_list_set_destroy_item (msgset->list, mu_list_free_item); | ||
55 | mu_list_set_comparator (msgset->list, compare_msgnum); | ||
56 | msgset->mbox = mbox; | ||
57 | msgset->flags = flags & _MU_MSGSET_USERFLAG_MASK; | ||
58 | *pres = msgset; | ||
59 | return 0; | ||
60 | } |
libmailutils/msgset/free.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/list.h> | ||
20 | #include <mailutils/msgset.h> | ||
21 | #include <mailutils/sys/msgset.h> | ||
22 | |||
23 | void | ||
24 | mu_msgset_free (mu_msgset_t mset) | ||
25 | { | ||
26 | if (mset) | ||
27 | { | ||
28 | mu_list_destroy (&mset->list); | ||
29 | free (mset); | ||
30 | } | ||
31 | } | ||
32 | |||
33 | void | ||
34 | mu_msgset_destroy (mu_msgset_t *pset) | ||
35 | { | ||
36 | if (pset) | ||
37 | { | ||
38 | mu_msgset_free (*pset); | ||
39 | *pset = NULL; | ||
40 | } | ||
41 | } | ||
42 |
libmailutils/msgset/getitr.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <mailutils/types.h> | ||
19 | #include <mailutils/errno.h> | ||
20 | #include <mailutils/list.h> | ||
21 | #include <mailutils/msgset.h> | ||
22 | #include <mailutils/sys/msgset.h> | ||
23 | |||
24 | int | ||
25 | mu_msgset_get_iterator (mu_msgset_t msgset, mu_iterator_t *pitr) | ||
26 | { | ||
27 | if (!msgset) | ||
28 | return EINVAL; | ||
29 | return mu_list_get_iterator (msgset->list, pitr); | ||
30 | } |
libmailutils/msgset/getlist.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <mailutils/types.h> | ||
19 | #include <mailutils/errno.h> | ||
20 | #include <mailutils/list.h> | ||
21 | #include <mailutils/msgset.h> | ||
22 | #include <mailutils/sys/msgset.h> | ||
23 | |||
24 | int | ||
25 | mu_msgset_get_list (mu_msgset_t msgset, mu_list_t *plist) | ||
26 | { | ||
27 | if (!msgset) | ||
28 | return EINVAL; | ||
29 | if (!plist) | ||
30 | return MU_ERR_OUT_PTR_NULL; | ||
31 | *plist = msgset->list; | ||
32 | return 0; | ||
33 | } |
libmailutils/msgset/locate.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/types.h> | ||
20 | #include <mailutils/errno.h> | ||
21 | #include <mailutils/list.h> | ||
22 | #include <mailutils/msgset.h> | ||
23 | #include <mailutils/sys/msgset.h> | ||
24 | |||
25 | int | ||
26 | mu_msgset_locate (mu_msgset_t msgset, size_t n, | ||
27 | struct mu_msgrange const **prange) | ||
28 | { | ||
29 | if (!msgset || n == 0) | ||
30 | return EINVAL; | ||
31 | return mu_list_locate (msgset->list, &n, (void**)prange); | ||
32 | } |
libmailutils/msgset/parse.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <limits.h> | ||
21 | #include <mailutils/types.h> | ||
22 | #include <mailutils/errno.h> | ||
23 | #include <mailutils/list.h> | ||
24 | #include <mailutils/iterator.h> | ||
25 | #include <mailutils/mailbox.h> | ||
26 | #include <mailutils/msgset.h> | ||
27 | #include <mailutils/sys/msgset.h> | ||
28 | |||
29 | /* This structure keeps parser state while parsing message set. */ | ||
30 | struct parse_msgnum_env | ||
31 | { | ||
32 | char *s; /* Current position in string */ | ||
33 | size_t minval; /* Min. sequence number or UID */ | ||
34 | size_t maxval; /* Max. sequence number or UID */ | ||
35 | mu_msgset_t msgset; /* Message set being built. */ | ||
36 | }; | ||
37 | |||
38 | /* Get a single message number/UID from env->s and store it into *PN. | ||
39 | Return 0 on success and error code on error. | ||
40 | |||
41 | Advance env->s to the point past the parsed message number. | ||
42 | */ | ||
43 | static int | ||
44 | get_msgnum (struct parse_msgnum_env *env, size_t *pn) | ||
45 | { | ||
46 | size_t msgnum; | ||
47 | char *p; | ||
48 | |||
49 | errno = 0; | ||
50 | msgnum = strtoul (env->s, &p, 10); | ||
51 | if (msgnum == ULONG_MAX && errno == ERANGE) | ||
52 | return MU_ERR_PARSE; | ||
53 | env->s = p; | ||
54 | if (env->msgset->mbox && env->maxval && msgnum > env->maxval) | ||
55 | msgnum = env->maxval; | ||
56 | *pn = msgnum; | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /* Parse a single message range (A:B). Treat '*' as the largest number/UID | ||
61 | in use. */ | ||
62 | static int | ||
63 | parse_msgrange (struct parse_msgnum_env *env) | ||
64 | { | ||
65 | int rc; | ||
66 | struct mu_msgrange msgrange; | ||
67 | |||
68 | if (*env->s == '*') | ||
69 | { | ||
70 | msgrange.msg_beg = env->maxval; | ||
71 | env->s++; | ||
72 | } | ||
73 | else if ((rc = get_msgnum (env, &msgrange.msg_beg))) | ||
74 | return rc; | ||
75 | |||
76 | if (*env->s == ':') | ||
77 | { | ||
78 | if (*++env->s == '*') | ||
79 | { | ||
80 | msgrange.msg_end = env->maxval; | ||
81 | ++env->s; | ||
82 | } | ||
83 | else if (*env->s == 0) | ||
84 | return MU_ERR_PARSE; | ||
85 | else if ((rc = get_msgnum (env, &msgrange.msg_end))) | ||
86 | return rc; | ||
87 | } | ||
88 | else | ||
89 | msgrange.msg_end = msgrange.msg_beg; | ||
90 | |||
91 | if (msgrange.msg_end && msgrange.msg_end < msgrange.msg_beg) | ||
92 | { | ||
93 | size_t tmp = msgrange.msg_end; | ||
94 | msgrange.msg_end = msgrange.msg_beg; | ||
95 | msgrange.msg_beg = tmp; | ||
96 | } | ||
97 | |||
98 | if ((env->msgset->flags & MU_MSGSET_UID) && env->msgset->mbox) | ||
99 | { | ||
100 | int rc; | ||
101 | |||
102 | rc = mu_mailbox_translate (env->msgset->mbox, | ||
103 | MU_MAILBOX_UID_TO_MSGNO, | ||
104 | msgrange.msg_beg, &msgrange.msg_beg); | ||
105 | if (rc == MU_ERR_NOENT) | ||
106 | msgrange.msg_beg = env->minval; | ||
107 | else if (rc) | ||
108 | return rc; | ||
109 | |||
110 | rc = mu_mailbox_translate (env->msgset->mbox, | ||
111 | MU_MAILBOX_UID_TO_MSGNO, | ||
112 | msgrange.msg_end, &msgrange.msg_end); | ||
113 | if (rc == MU_ERR_NOENT) | ||
114 | msgrange.msg_end = env->maxval; | ||
115 | else if (rc) | ||
116 | return rc; | ||
117 | } | ||
118 | |||
119 | return mu_msgset_add_range (env->msgset, msgrange.msg_beg, msgrange.msg_end); | ||
120 | } | ||
121 | |||
122 | /* Parse IMAP-style message set specification S. | ||
123 | |||
124 | On success, return 0 and populate MSET with the resulting message ranges. | ||
125 | On error, return error code and point END to the position in the input | ||
126 | string where parsing has failed. */ | ||
127 | int | ||
128 | mu_msgset_parse_imap (mu_msgset_t mset, char *s, char **end) | ||
129 | { | ||
130 | int rc; | ||
131 | struct parse_msgnum_env env; | ||
132 | |||
133 | if (!s || !mset) | ||
134 | return EINVAL; | ||
135 | if (!*s) | ||
136 | return MU_ERR_PARSE; | ||
137 | |||
138 | memset (&env, 0, sizeof (env)); | ||
139 | env.s = s; | ||
140 | env.msgset = mset; | ||
141 | env.minval = 1; | ||
142 | |||
143 | if (end) | ||
144 | *end = s; | ||
145 | if (mset->mbox) | ||
146 | { | ||
147 | size_t lastmsgno; /* Max. sequence number. */ | ||
148 | |||
149 | rc = mu_mailbox_messages_count (mset->mbox, &lastmsgno); | ||
150 | if (rc == 0) | ||
151 | { | ||
152 | if (mset->flags & MU_MSGSET_UID) | ||
153 | { | ||
154 | rc = mu_mailbox_translate (mset->mbox, MU_MAILBOX_MSGNO_TO_UID, | ||
155 | lastmsgno, &env.maxval); | ||
156 | if (rc == 0) | ||
157 | rc = mu_mailbox_translate (mset->mbox, MU_MAILBOX_MSGNO_TO_UID, | ||
158 | 1, &env.minval); | ||
159 | } | ||
160 | else | ||
161 | env.maxval = lastmsgno; | ||
162 | } | ||
163 | if (rc) | ||
164 | return rc; | ||
165 | } | ||
166 | |||
167 | while ((rc = parse_msgrange (&env)) == 0 && *env.s) | ||
168 | { | ||
169 | if (*env.s != ',' || *++env.s == 0) | ||
170 | { | ||
171 | rc = MU_ERR_PARSE; | ||
172 | break; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | if (end) | ||
177 | *end = env.s; | ||
178 | return rc; | ||
179 | } |
libmailutils/msgset/print.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/types.h> | ||
20 | #include <mailutils/errno.h> | ||
21 | #include <mailutils/list.h> | ||
22 | #include <mailutils/stream.h> | ||
23 | #include <mailutils/io.h> | ||
24 | #include <mailutils/msgset.h> | ||
25 | #include <mailutils/sys/msgset.h> | ||
26 | |||
27 | struct print_env | ||
28 | { | ||
29 | mu_stream_t stream; | ||
30 | int cont; | ||
31 | }; | ||
32 | |||
33 | static int | ||
34 | _msgrange_printer (void *item, void *data) | ||
35 | { | ||
36 | int rc; | ||
37 | struct mu_msgrange *range = item; | ||
38 | struct print_env *env = data; | ||
39 | |||
40 | if (env->cont) | ||
41 | { | ||
42 | rc = mu_stream_write (env->stream, ",", 1, NULL); | ||
43 | if (rc) | ||
44 | return rc; | ||
45 | } | ||
46 | else | ||
47 | env->cont = 1; | ||
48 | if (range->msg_beg == range->msg_end) | ||
49 | rc = mu_stream_printf (env->stream, "%lu", (unsigned long) range->msg_beg); | ||
50 | else if (range->msg_end == 0) | ||
51 | rc = mu_stream_printf (env->stream, "%lu:*", | ||
52 | (unsigned long) range->msg_beg); | ||
53 | else | ||
54 | rc = mu_stream_printf (env->stream, "%lu:%lu", | ||
55 | (unsigned long) range->msg_beg, | ||
56 | (unsigned long) range->msg_end); | ||
57 | return rc; | ||
58 | } | ||
59 | |||
60 | int | ||
61 | mu_msgset_print (mu_stream_t str, mu_msgset_t mset) | ||
62 | { | ||
63 | struct print_env env; | ||
64 | int rc; | ||
65 | |||
66 | if (mu_list_is_empty (mset->list)) | ||
67 | return MU_ERR_NOENT; | ||
68 | rc = mu_msgset_aggregate (mset); | ||
69 | if (rc) | ||
70 | return rc; | ||
71 | env.stream = str; | ||
72 | env.cont = 0; | ||
73 | return mu_list_foreach (mset->list, _msgrange_printer, &env); | ||
74 | } |
libmailutils/msgset/sub.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/types.h> | ||
20 | #include <mailutils/errno.h> | ||
21 | #include <mailutils/list.h> | ||
22 | #include <mailutils/iterator.h> | ||
23 | #include <mailutils/msgset.h> | ||
24 | #include <mailutils/sys/msgset.h> | ||
25 | |||
26 | /* Remove range R from the set S. | ||
27 | |||
28 | There are following basic cases: | ||
29 | |||
30 | 1. S does not contain R. | ||
31 | |||
32 | Return imeediately, there is nothing to do here. | ||
33 | |||
34 | 2. S contains a range X that matches exactly R. | ||
35 | |||
36 | Action: Remove X entirely and return. | ||
37 | |||
38 | 3. There is a range X in S such that R falls entirely within it. | ||
39 | |||
40 | Action: Split X into two ranges: | ||
41 | |||
42 | X.msg_beg : R.msg_beg-1 | ||
43 | R.msg_end+1 : X.msg_end | ||
44 | |||
45 | and return. | ||
46 | In border cases one of the new ranges may be empty. | ||
47 | |||
48 | 4. There is a range X which contains an initial subrange of R. | ||
49 | |||
50 | Action: Remove the subrange from X. If the resulting range is | ||
51 | empty, remove it. Continue iteration with X.msg_end:R.msg_end | ||
52 | in place of R. | ||
53 | |||
54 | 5. There is a range X such that its initial subrange is contained | ||
55 | in R. | ||
56 | |||
57 | Action: Remove X.msg_beg:R.msg_end and return. | ||
58 | |||
59 | 6. There is a range X that is contained within R. | ||
60 | |||
61 | Action: Remove X and continue. | ||
62 | |||
63 | There are two special cases. First is when R.msg_end is 0, meaning the last | ||
64 | available message number in the mailbox. In this case the problem is reduced | ||
65 | to either 2 or a combination of 4 and zero or more 6. It is handled by the | ||
66 | sub_msgno_last function below. | ||
67 | |||
68 | Yet another special case is when the last element of S has msg_end == 0. If | ||
69 | so, the problem is reduced to either 2 or 4. | ||
70 | */ | ||
71 | |||
72 | static int | ||
73 | sub_msgno_last (mu_msgset_t mset, size_t beg) | ||
74 | { | ||
75 | int rc; | ||
76 | struct mu_msgrange *range; | ||
77 | |||
78 | if (beg == 1) | ||
79 | mu_list_clear (mset->list); | ||
80 | else | ||
81 | { | ||
82 | mu_iterator_t itr; | ||
83 | |||
84 | rc = mu_list_get_iterator (mset->list, &itr); | ||
85 | if (rc) | ||
86 | return rc; | ||
87 | rc = 1; | ||
88 | rc = mu_iterator_ctl (itr, mu_itrctl_set_direction, &rc); | ||
89 | if (rc) | ||
90 | { | ||
91 | mu_iterator_destroy (&itr); | ||
92 | return rc; | ||
93 | } | ||
94 | |||
95 | for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr); | ||
96 | mu_iterator_next (itr)) | ||
97 | { | ||
98 | mu_iterator_current (itr, (void **)&range); | ||
99 | if (range->msg_beg > beg) | ||
100 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
101 | else if (range->msg_beg == beg) | ||
102 | { | ||
103 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
104 | break; | ||
105 | } | ||
106 | else | ||
107 | break; | ||
108 | } | ||
109 | mu_iterator_destroy (&itr); | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | int | ||
115 | mu_msgset_sub_range (mu_msgset_t mset, size_t beg, size_t end) | ||
116 | { | ||
117 | int rc; | ||
118 | mu_iterator_t itr; | ||
119 | struct mu_msgrange *mr; | ||
120 | |||
121 | if (!mset) | ||
122 | return EINVAL; | ||
123 | if (mu_list_is_empty (mset->list)) | ||
124 | return MU_ERR_NOENT; | ||
125 | rc = mu_msgset_aggregate (mset); | ||
126 | if (rc) | ||
127 | return rc; | ||
128 | |||
129 | if (end == MU_MSGNO_LAST) | ||
130 | return sub_msgno_last (mset, beg); | ||
131 | |||
132 | /* Test border cases */ | ||
133 | rc = mu_list_head (mset->list, (void**)&mr); | ||
134 | if (rc) | ||
135 | return rc; | ||
136 | if (end < mr->msg_beg) | ||
137 | return 0; | ||
138 | if (beg < mr->msg_beg) | ||
139 | beg = mr->msg_beg; | ||
140 | |||
141 | if (rc) | ||
142 | return rc; | ||
143 | rc = mu_list_tail (mset->list, (void**) &mr); | ||
144 | if (mr->msg_end != MU_MSGNO_LAST) | ||
145 | { | ||
146 | if (beg > mr->msg_end) | ||
147 | return 0; | ||
148 | if (end > mr->msg_end) | ||
149 | end = mr->msg_end; | ||
150 | } | ||
151 | |||
152 | rc = mu_list_get_iterator (mset->list, &itr); | ||
153 | if (rc) | ||
154 | return rc; | ||
155 | for (mu_iterator_first (itr); rc == 0 && !mu_iterator_is_done (itr); | ||
156 | mu_iterator_next (itr)) | ||
157 | { | ||
158 | mu_iterator_current (itr, (void **)&mr); | ||
159 | |||
160 | if (mr->msg_end == MU_MSGNO_LAST) | ||
161 | { | ||
162 | /* This is the last element in list. */ | ||
163 | if (mr->msg_beg == beg) | ||
164 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
165 | else if (mr->msg_beg > beg) | ||
166 | mr->msg_beg = end + 1; | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | if (mr->msg_beg == beg && mr->msg_end == end) /* See case 2 above */ | ||
171 | { | ||
172 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
173 | break; | ||
174 | } | ||
175 | else if (mr->msg_beg <= beg && beg <= mr->msg_end) | ||
176 | { | ||
177 | if (mr->msg_beg <= end && end <= mr->msg_end) /* Case 3 */ | ||
178 | { | ||
179 | /* Split the range */ | ||
180 | if (end != mr->msg_end) | ||
181 | { | ||
182 | struct mu_msgrange *newrange = calloc (1, | ||
183 | sizeof (*newrange)); | ||
184 | if (!newrange) | ||
185 | { | ||
186 | rc = ENOMEM; | ||
187 | break; | ||
188 | } | ||
189 | newrange->msg_beg = end + 1; | ||
190 | newrange->msg_end = mr->msg_end; | ||
191 | rc = mu_iterator_ctl (itr, mu_itrctl_insert, newrange); | ||
192 | if (rc) | ||
193 | { | ||
194 | free (newrange); | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | if (mr->msg_beg == beg) | ||
200 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
201 | else | ||
202 | mr->msg_end = beg - 1; | ||
203 | break; | ||
204 | } | ||
205 | else if (mr->msg_beg == beg) /* Case 4 */ | ||
206 | { | ||
207 | beg = mr->msg_end; | ||
208 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
209 | } | ||
210 | else | ||
211 | { | ||
212 | size_t n = mr->msg_end; | ||
213 | mr->msg_end = beg - 1; | ||
214 | beg = n; | ||
215 | } | ||
216 | } | ||
217 | else if (mr->msg_beg <= end && end <= mr->msg_end) /* Case 5 */ | ||
218 | { | ||
219 | mr->msg_beg = end + 1; | ||
220 | if (mr->msg_beg >= mr->msg_end) | ||
221 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
222 | break; | ||
223 | } | ||
224 | else if (beg <= mr->msg_beg && mr->msg_beg <= end) | ||
225 | { | ||
226 | rc = mu_iterator_ctl (itr, mu_itrctl_delete, NULL); | ||
227 | } | ||
228 | } | ||
229 | mu_iterator_destroy (&itr); | ||
230 | |||
231 | return rc; | ||
232 | } | ||
233 |
... | @@ -52,6 +52,7 @@ noinst_PROGRAMS = \ | ... | @@ -52,6 +52,7 @@ noinst_PROGRAMS = \ |
52 | listop\ | 52 | listop\ |
53 | mailcap\ | 53 | mailcap\ |
54 | mimehdr\ | 54 | mimehdr\ |
55 | msgset\ | ||
55 | prop\ | 56 | prop\ |
56 | scantime\ | 57 | scantime\ |
57 | strftime\ | 58 | strftime\ |
... | @@ -90,6 +91,7 @@ TESTSUITE_AT = \ | ... | @@ -90,6 +91,7 @@ TESTSUITE_AT = \ |
90 | list.at\ | 91 | list.at\ |
91 | mailcap.at\ | 92 | mailcap.at\ |
92 | mimehdr.at\ | 93 | mimehdr.at\ |
94 | msgset.at\ | ||
93 | prop.at\ | 95 | prop.at\ |
94 | scantime.at\ | 96 | scantime.at\ |
95 | strftime.at\ | 97 | strftime.at\ | ... | ... |
libmailutils/tests/msgset.at
0 → 100644
1 | # This file is part of GNU Mailutils. -*- Autotest -*- | ||
2 | # Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | # | ||
4 | # GNU Mailutils is free software; you can redistribute it and/or | ||
5 | # modify it under the terms of the GNU General Public License as | ||
6 | # published by the Free Software Foundation; either version 3, or (at | ||
7 | # your option) any later version. | ||
8 | # | ||
9 | # GNU Mailutils is distributed in the hope that it will be useful, but | ||
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | # General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. | ||
16 | |||
17 | AT_BANNER([Message sets]) | ||
18 | |||
19 | dnl ------------------------------------------------------------------ | ||
20 | dnl MSGSET([NAME], [KW = `'], [OP], [STDOUT = `'], [STDERR = `']) | ||
21 | dnl | ||
22 | m4_pushdef([MSGSET],[ | ||
23 | AT_SETUP([$1]) | ||
24 | AT_KEYWORDS([msgset $2]) | ||
25 | AT_CHECK([msgset $3],[0],[$4],[$5]) | ||
26 | AT_CLEANUP | ||
27 | ]) | ||
28 | dnl ------------------------------------------------------------------ | ||
29 | |||
30 | MSGSET([Aggregation: simple],[msgset-aggr-simple msgset-aggr], | ||
31 | [-msgset='1,5:11,20:24,80:90,22:30,50:60,4:12,41:50,70:81'], | ||
32 | [1,4:12,20:30,41:60,70:90 | ||
33 | ]) | ||
34 | |||
35 | MSGSET([Aggregation: open range (1)], | ||
36 | [msgset-aggr-open-1 msgset-aggr-open msgset-aggr], | ||
37 | [-msgset='12:*,1'], | ||
38 | [1,12:* | ||
39 | ]) | ||
40 | |||
41 | MSGSET([Aggregation: coalescing open ranges], | ||
42 | [msgset-aggr-open-2 msgset-aggr-open msgset-aggr], | ||
43 | [-msgset='12:*,1,15:*,8:*'], | ||
44 | [1,8:* | ||
45 | ]) | ||
46 | |||
47 | MSGSET([Aggregation: open range (3)], | ||
48 | [msgset-aggr-open-3 msgset-aggr-open msgset-aggr], | ||
49 | [-msgset='1,12:*,12:13'], | ||
50 | [1,12:* | ||
51 | ]) | ||
52 | |||
53 | MSGSET([Aggregation: open range (4)], | ||
54 | [msgset-aggr-open-4 msgset-aggr-open msgset-aggr], | ||
55 | [-msgset='1,12:*,13:40'], | ||
56 | [1,12:* | ||
57 | ]) | ||
58 | |||
59 | MSGSET([Aggregation: open range (5)], | ||
60 | [msgset-aggr-open-5 msgset-aggr-open msgset-aggr], | ||
61 | [-msgset='10:*,3,5:9'], | ||
62 | [3,5:* | ||
63 | ]) | ||
64 | |||
65 | MSGSET([Create simple set],[msgset-simple msgset-add], | ||
66 | [-add=1:10], | ||
67 | [1:10 | ||
68 | ]) | ||
69 | |||
70 | MSGSET([Create complex set],[msgset-complex msgset-add], | ||
71 | [-add=1 -add=2 -add=3 -add=4 -add=10:20 -add=15:35 -add=36:40], | ||
72 | [1:4,10:40 | ||
73 | ]) | ||
74 | |||
75 | MSGSET([Subtract: no match],[msgset-sub msgset-sub-1], | ||
76 | [-msgset=20:40 -sub=1:10], | ||
77 | [20:40 | ||
78 | ]) | ||
79 | |||
80 | MSGSET([Subtract: exact match],[msgset-sub msgset-sub-2], | ||
81 | [-msgset=1,4:9,11 -sub=4:9], | ||
82 | [1,11 | ||
83 | ]) | ||
84 | |||
85 | MSGSET([Subtract: contained range],[msgset-sub msgset-sub-3], | ||
86 | [-msgset=1:40 -sub=5:15 | ||
87 | ], | ||
88 | [1:4,16:40 | ||
89 | ]) | ||
90 | |||
91 | MSGSET([Subtract: contained range (left border case)], | ||
92 | [msgset-sub msgset-sub-3 msgset-sub-3-0], | ||
93 | [-msgset=1:40 -sub=1:20], | ||
94 | [21:40 | ||
95 | ]) | ||
96 | |||
97 | MSGSET([Subtract: contained range (right border case)], | ||
98 | [msgset-sub msgset-sub-3 msgset-sub-3-1], | ||
99 | [-msgset=1:40 -sub=30:40], | ||
100 | [1:29 | ||
101 | ]) | ||
102 | |||
103 | MSGSET([Subtract: initial subrange],[msgset-sub msgset-sub-4], | ||
104 | [-msgset=1:40,50:60,80:200 -sub=55:65], | ||
105 | [1:40,50:54,80:200 | ||
106 | ]) | ||
107 | |||
108 | MSGSET([Subtract: trailing subrange],[msgset-sub msgset-sub-5], | ||
109 | [-msgset=1:40,50:60,80:200 -sub=45:55], | ||
110 | [1:40,56:60,80:200 | ||
111 | ]) | ||
112 | |||
113 | MSGSET([Subtract: overlapping subrange],[msgset-sub msgset-sub-6], | ||
114 | [-msgset=1:40,50:60,80:200 -sub=41:70], | ||
115 | [1:40,80:200 | ||
116 | ]) | ||
117 | |||
118 | MSGSET([Subtract: 4, 5 and 6 combined], | ||
119 | [msgset-sub msgset-sub-4 msgset-sub-5 msgset-sub-6 msgset-sub-456], | ||
120 | [-msgset=1:40,50:60,80:200 -sub=30:100], | ||
121 | [1:29,101:200 | ||
122 | ]) | ||
123 | |||
124 | MSGSET([open range],[msgset-inf], | ||
125 | [-msgset='1:*'], | ||
126 | [1:* | ||
127 | ]) | ||
128 | |||
129 | MSGSET([add to open range],[msgset-inf-add msgset-add], | ||
130 | [-msgset='10:*' -add=3 -add=5:9], | ||
131 | [3,5:* | ||
132 | ]) | ||
133 | |||
134 | MSGSET([subtract from open range],[msgset-inf-sub msgset-sub], | ||
135 | [-msgset='3,10:*' -sub=5:11], | ||
136 | [3,12:* | ||
137 | ]) | ||
138 | |||
139 | MSGSET([subtract from open range an equal range],[msgset-inf-sub-1 msgset-sub], | ||
140 | [-msgset='3,10:*' -sub=10:*], | ||
141 | [3 | ||
142 | ]) | ||
143 | |||
144 | MSGSET([subtract from open range a broader range], | ||
145 | [msgset-inf-sub-2 msgset-sub], | ||
146 | [-msgset='3,10:*' -sub=20:*], | ||
147 | [3,10:* | ||
148 | ]) | ||
149 | |||
150 | MSGSET([subtract from open range a narrower range], | ||
151 | [msgset-inf-sub-3 msgset-sub], | ||
152 | [-msgset='3,10:*' -sub=5:*], | ||
153 | [3 | ||
154 | ]) | ||
155 | |||
156 | MSGSET([subtract an open range with matching left boundary], | ||
157 | [msgset-inf-sub-4 msgset-sub], | ||
158 | [-msgset='3,10:20' -sub=10:*], | ||
159 | [3 | ||
160 | ]) | ||
161 | |||
162 | MSGSET([subtract an open range with greater left boundary], | ||
163 | [msgset-inf-sub-4 msgset-sub], | ||
164 | [-msgset='3,10:20' -sub=11:*], | ||
165 | [3,10:20 | ||
166 | ]) | ||
167 | |||
168 | MSGSET([subtract an open range with smaller left boundary], | ||
169 | [msgset-inf-sub-4 msgset-sub], | ||
170 | [-msgset='3,10:20' -sub=8:*], | ||
171 | [3 | ||
172 | ]) | ||
173 | |||
174 | dnl ------------------------------------------------------------------ | ||
175 | m4_popdef([MSGSET]) | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
libmailutils/tests/msgset.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/mailutils.h> | ||
20 | |||
21 | static void | ||
22 | parse_msgset (char *arg, struct mu_msgrange *range) | ||
23 | { | ||
24 | size_t msgnum; | ||
25 | char *p; | ||
26 | |||
27 | errno = 0; | ||
28 | msgnum = strtoul (arg, &p, 10); | ||
29 | range->msg_beg = msgnum; | ||
30 | if (*p == ':') | ||
31 | { | ||
32 | if (*++p == '*') | ||
33 | msgnum = 0; | ||
34 | else | ||
35 | { | ||
36 | msgnum = strtoul (p, &p, 10); | ||
37 | if (*p) | ||
38 | { | ||
39 | mu_error ("error in message range near %s", p); | ||
40 | exit (1); | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | else if (*p == '*') | ||
45 | msgnum = 0; | ||
46 | else if (*p) | ||
47 | { | ||
48 | mu_error ("error in message range near %s", p); | ||
49 | exit (1); | ||
50 | } | ||
51 | |||
52 | range->msg_end = msgnum; | ||
53 | } | ||
54 | |||
55 | int | ||
56 | main (int argc, char **argv) | ||
57 | { | ||
58 | int i; | ||
59 | char *msgset_string = NULL; | ||
60 | mu_msgset_t msgset; | ||
61 | int rc; | ||
62 | |||
63 | mu_set_program_name (argv[0]); | ||
64 | for (i = 1; i < argc; i++) | ||
65 | { | ||
66 | char *arg = argv[i]; | ||
67 | |||
68 | if (strcmp (arg, "-h") == 0 || strcmp (arg, "-help") == 0) | ||
69 | { | ||
70 | mu_printf ("usage: %s [-msgset=SET] [-add X[:Y]] [-del X:[Y]]...\n", | ||
71 | mu_program_name); | ||
72 | return 0; | ||
73 | } | ||
74 | else if (strncmp (arg, "-msgset=", 8) == 0) | ||
75 | msgset_string = arg + 8; | ||
76 | else | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | MU_ASSERT (mu_msgset_create (&msgset, NULL, 0)); | ||
81 | if (msgset_string) | ||
82 | { | ||
83 | char *end; | ||
84 | rc = mu_msgset_parse_imap (msgset, msgset_string, &end); | ||
85 | if (rc) | ||
86 | { | ||
87 | mu_error ("mu_msgset_parse_imap: %s near %s", | ||
88 | mu_strerror (rc), end); | ||
89 | return 1; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | for (; i < argc; i++) | ||
94 | { | ||
95 | char *arg = argv[i]; | ||
96 | struct mu_msgrange range; | ||
97 | |||
98 | if (strncmp (arg, "-add=", 5) == 0) | ||
99 | { | ||
100 | parse_msgset (arg + 5, &range); | ||
101 | MU_ASSERT (mu_msgset_add_range (msgset, range.msg_beg, | ||
102 | range.msg_end)); | ||
103 | } | ||
104 | else if (strncmp (arg, "-sub=", 5) == 0) | ||
105 | { | ||
106 | parse_msgset (arg + 5, &range); | ||
107 | MU_ASSERT (mu_msgset_sub_range (msgset, range.msg_beg, | ||
108 | range.msg_end)); | ||
109 | } | ||
110 | else | ||
111 | { | ||
112 | mu_error ("unknown option %s", arg); | ||
113 | return 1; | ||
114 | } | ||
115 | } | ||
116 | MU_ASSERT (mu_msgset_print (mu_strout, msgset)); | ||
117 | mu_printf ("\n"); | ||
118 | mu_msgset_free (msgset); | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | |||
124 | |||
125 |
testsuite/msgset.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <mailutils/mailutils.h> | ||
20 | |||
21 | static void | ||
22 | parse_msgset (char *arg, struct mu_msgrange *range) | ||
23 | { | ||
24 | size_t msgnum; | ||
25 | char *p; | ||
26 | |||
27 | errno = 0; | ||
28 | msgnum = strtoul (arg, &p, 10); | ||
29 | range->msg_beg = msgnum; | ||
30 | if (*p == ':') | ||
31 | { | ||
32 | if (*++p == '*') | ||
33 | msgnum = 0; | ||
34 | else | ||
35 | { | ||
36 | msgnum = strtoul (p, &p, 10); | ||
37 | if (*p) | ||
38 | { | ||
39 | mu_error ("error in message range near %s", p); | ||
40 | exit (1); | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | else if (*p == '*') | ||
45 | msgnum = 0; | ||
46 | else if (*p) | ||
47 | { | ||
48 | mu_error ("error in message range near %s", p); | ||
49 | exit (1); | ||
50 | } | ||
51 | |||
52 | range->msg_end = msgnum; | ||
53 | } | ||
54 | |||
55 | int | ||
56 | main (int argc, char **argv) | ||
57 | { | ||
58 | int i; | ||
59 | char *msgset_string = NULL; | ||
60 | mu_msgset_t msgset; | ||
61 | int rc; | ||
62 | int flags = 0; | ||
63 | mu_mailbox_t mbox = NULL; | ||
64 | |||
65 | mu_set_program_name (argv[0]); | ||
66 | mu_registrar_record (mu_mbox_record); | ||
67 | for (i = 1; i < argc; i++) | ||
68 | { | ||
69 | char *arg = argv[i]; | ||
70 | |||
71 | if (strcmp (arg, "-h") == 0 || strcmp (arg, "-help") == 0) | ||
72 | { | ||
73 | mu_printf ("usage: %s [-msgset=SET] [-add X[:Y]] [-del X:[Y]]...\n", | ||
74 | mu_program_name); | ||
75 | return 0; | ||
76 | } | ||
77 | else if (strncmp (arg, "-msgset=", 8) == 0) | ||
78 | msgset_string = arg + 8; | ||
79 | else if (strcmp (arg, "-uid") == 0) | ||
80 | flags |= MU_MSGSET_UID; | ||
81 | else if (strncmp (arg, "-mailbox=", 9) == 0) | ||
82 | { | ||
83 | MU_ASSERT (mu_mailbox_create (&mbox, arg + 9)); | ||
84 | MU_ASSERT (mu_mailbox_open (mbox, MU_STREAM_READ)); | ||
85 | } | ||
86 | else | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | MU_ASSERT (mu_msgset_create (&msgset, mbox, flags)); | ||
91 | if (msgset_string) | ||
92 | { | ||
93 | char *end; | ||
94 | rc = mu_msgset_parse_imap (msgset, msgset_string, &end); | ||
95 | if (rc) | ||
96 | { | ||
97 | mu_error ("mu_msgset_parse_imap: %s near %s", | ||
98 | mu_strerror (rc), end); | ||
99 | return 1; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | for (; i < argc; i++) | ||
104 | { | ||
105 | char *arg = argv[i]; | ||
106 | struct mu_msgrange range; | ||
107 | |||
108 | if (strncmp (arg, "-add=", 5) == 0) | ||
109 | { | ||
110 | parse_msgset (arg + 5, &range); | ||
111 | MU_ASSERT (mu_msgset_add_range (msgset, range.msg_beg, | ||
112 | range.msg_end)); | ||
113 | } | ||
114 | else if (strncmp (arg, "-sub=", 5) == 0) | ||
115 | { | ||
116 | parse_msgset (arg + 5, &range); | ||
117 | MU_ASSERT (mu_msgset_sub_range (msgset, range.msg_beg, | ||
118 | range.msg_end)); | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | mu_error ("unknown option %s", arg); | ||
123 | return 1; | ||
124 | } | ||
125 | } | ||
126 | MU_ASSERT (mu_msgset_print (mu_strout, msgset)); | ||
127 | mu_printf ("\n"); | ||
128 | mu_msgset_free (msgset); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | |||
134 | |||
135 |
-
Please register or sign in to post a comment