mh: fix msgset parser and some more comp compatibility issues; provide testsuite for comp.
* mh/Makefile.am (bin_PROGRAMS): Add mhseq. * mh/comp.c (main): Rewrite to fix compatibility issues. * mh/mh.h (MH_MSGSET_UID): New define. (mh_msgset_t) <flags,size>: New members. * mh/mh_init.c (mh_draft_message): Bugfix: convert msgset to UIDs. * mh/mh_msgset.c: Rewrite from scratch. * mh/tests/comp.at: New file. * mh/tests/mhseq.at: New file. * mh/tests/Makefile.am (TESTSUITE_AT): Add comp.at, mhseq.at. * mh/tests/testsuite.at: Include comp.at and mhseq.at. * libmailutils/property/mhprop.c (_mh_prop_read_stream): Minor fix. Do remove empty lines. * mh/mh_whatnow.c (_whatnow): Detect EOF. (call_send): Quit after successful send.
Showing
14 changed files
with
1227 additions
and
471 deletions
... | @@ -113,7 +113,7 @@ _mh_prop_read_stream (mu_header_t *phdr, mu_stream_t stream) | ... | @@ -113,7 +113,7 @@ _mh_prop_read_stream (mu_header_t *phdr, mu_stream_t stream) |
113 | argv[1] = "#"; | 113 | argv[1] = "#"; |
114 | argv[2] = "-r"; | 114 | argv[2] = "-r"; |
115 | argv[3] = NULL; | 115 | argv[3] = NULL; |
116 | rc = mu_filter_create_args (&flt, stream, argv[0], 2, argv, | 116 | rc = mu_filter_create_args (&flt, stream, argv[0], 3, argv, |
117 | MU_FILTER_DECODE, MU_STREAM_READ); | 117 | MU_FILTER_DECODE, MU_STREAM_READ); |
118 | if (rc) | 118 | if (rc) |
119 | { | 119 | { | ... | ... |
... | @@ -80,6 +80,7 @@ static int build_only = 0; /* --build flag */ | ... | @@ -80,6 +80,7 @@ static int build_only = 0; /* --build flag */ |
80 | static int use_draft = 0; /* --use flag */ | 80 | static int use_draft = 0; /* --use flag */ |
81 | static char *draftmessage = "new"; | 81 | static char *draftmessage = "new"; |
82 | static const char *draftfolder = NULL; | 82 | static const char *draftfolder = NULL; |
83 | static int folder_set; /* Folder is set on the command line */ | ||
83 | 84 | ||
84 | static error_t | 85 | static error_t |
85 | opt_handler (int key, char *arg, struct argp_state *state) | 86 | opt_handler (int key, char *arg, struct argp_state *state) |
... | @@ -87,8 +88,7 @@ opt_handler (int key, char *arg, struct argp_state *state) | ... | @@ -87,8 +88,7 @@ opt_handler (int key, char *arg, struct argp_state *state) |
87 | switch (key) | 88 | switch (key) |
88 | { | 89 | { |
89 | case ARGP_KEY_INIT: | 90 | case ARGP_KEY_INIT: |
90 | draftfolder = mh_global_profile_get ("Draft-Folder", | 91 | draftfolder = mh_global_profile_get ("Draft-Folder", NULL); |
91 | mu_folder_directory ()); | ||
92 | whatnowproc = mh_global_profile_get ("whatnowproc", NULL); | 92 | whatnowproc = mh_global_profile_get ("whatnowproc", NULL); |
93 | break; | 93 | break; |
94 | 94 | ||
... | @@ -106,6 +106,7 @@ opt_handler (int key, char *arg, struct argp_state *state) | ... | @@ -106,6 +106,7 @@ opt_handler (int key, char *arg, struct argp_state *state) |
106 | 106 | ||
107 | case ARG_FOLDER: | 107 | case ARG_FOLDER: |
108 | mh_set_current_folder (arg); | 108 | mh_set_current_folder (arg); |
109 | folder_set = 1; | ||
109 | break; | 110 | break; |
110 | 111 | ||
111 | case ARG_FORM: | 112 | case ARG_FORM: |
... | @@ -126,7 +127,7 @@ opt_handler (int key, char *arg, struct argp_state *state) | ... | @@ -126,7 +127,7 @@ opt_handler (int key, char *arg, struct argp_state *state) |
126 | break; | 127 | break; |
127 | 128 | ||
128 | case ARG_FILE: | 129 | case ARG_FILE: |
129 | wh_env.draftfile = mh_expand_name (NULL, arg, 0); | 130 | wh_env.file = mh_expand_name (NULL, arg, 0); |
130 | break; | 131 | break; |
131 | 132 | ||
132 | case ARG_NODRAFTFOLDER: | 133 | case ARG_NODRAFTFOLDER: |
... | @@ -197,7 +198,7 @@ main (int argc, char **argv) | ... | @@ -197,7 +198,7 @@ main (int argc, char **argv) |
197 | mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, | 198 | mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, |
198 | opt_handler, NULL, &index); | 199 | opt_handler, NULL, &index); |
199 | 200 | ||
200 | if (wh_env.draftfile) | 201 | if (wh_env.file) |
201 | { | 202 | { |
202 | if (build_only) | 203 | if (build_only) |
203 | { | 204 | { |
... | @@ -205,51 +206,60 @@ main (int argc, char **argv) | ... | @@ -205,51 +206,60 @@ main (int argc, char **argv) |
205 | exit (1); | 206 | exit (1); |
206 | } | 207 | } |
207 | } | 208 | } |
209 | else if (folder_set) | ||
210 | { | ||
211 | wh_env.file = mh_expand_name (NULL, "draft", 0); | ||
212 | } | ||
208 | else | 213 | else |
209 | { | 214 | { |
210 | if (build_only || !draftfolder) | 215 | if (build_only || !draftfolder) |
216 | { | ||
217 | switch (argc - index) | ||
218 | { | ||
219 | case 0: | ||
211 | wh_env.file = mh_expand_name (NULL, "draft", 0); | 220 | wh_env.file = mh_expand_name (NULL, "draft", 0); |
221 | break; | ||
222 | |||
223 | case 1: | ||
224 | wh_env.file = mh_expand_name (NULL, argv[index], 0); | ||
225 | break; | ||
226 | |||
227 | default: | ||
228 | mu_error (_("only one message at a time!")); | ||
229 | return 1; | ||
230 | } | ||
231 | } | ||
212 | else if (draftfolder) | 232 | else if (draftfolder) |
213 | { | 233 | { |
214 | /* Comp accepts a `file', and it will, if given | 234 | /* Comp accepts a `file', and it will, if given |
215 | `-draftfolder +folder' treat this arguments as `msg'. */ | 235 | `-draftfolder +folder' treat this arguments as `msg'. */ |
216 | if (index < argc) | 236 | if (use_draft || index < argc) |
217 | { | 237 | { |
218 | mh_msgset_t msgset; | 238 | mh_msgset_t msgset; |
219 | mu_mailbox_t mbox; | 239 | mu_mailbox_t mbox; |
220 | 240 | ||
221 | mbox = mh_open_folder (draftfolder, 1); | 241 | mbox = mh_open_folder (draftfolder, 1); |
222 | mh_msgset_parse (mbox, &msgset, argc - index, argv + index, | 242 | mh_msgset_parse (mbox, &msgset, |
223 | "new"); | 243 | argc - index, argv + index, |
244 | use_draft ? "cur" : "new"); | ||
224 | mu_mailbox_destroy (&mbox); | 245 | mu_mailbox_destroy (&mbox); |
225 | if (msgset.count != 1) | 246 | if (msgset.count != 1) |
226 | { | 247 | { |
227 | mu_error (_("only one message at a time!")); | 248 | mu_error (_("only one message at a time!")); |
228 | return 1; | 249 | return 1; |
229 | } | 250 | } |
251 | mh_msgset_uids (mbox, &msgset); | ||
230 | draftmessage = mu_umaxtostr (0, msgset.list[0]); | 252 | draftmessage = mu_umaxtostr (0, msgset.list[0]); |
231 | mh_msgset_free (&msgset); | 253 | mh_msgset_free (&msgset); |
232 | index = argc; | ||
233 | } | 254 | } |
234 | if (mh_draft_message (draftfolder, draftmessage, | 255 | if (mh_draft_message (draftfolder, draftmessage, |
235 | &wh_env.file)) | 256 | &wh_env.file)) |
236 | return 1; | 257 | return 1; |
237 | } | 258 | } |
238 | wh_env.draftfile = wh_env.file; | ||
239 | } | 259 | } |
260 | wh_env.draftfile = wh_env.file; | ||
240 | 261 | ||
241 | switch (check_draft_disposition (&wh_env, use_draft)) | 262 | if (folder_set && index < argc) |
242 | { | ||
243 | case DISP_QUIT: | ||
244 | exit (0); | ||
245 | |||
246 | case DISP_USE: | ||
247 | break; | ||
248 | |||
249 | case DISP_REPLACE: | ||
250 | unlink (wh_env.draftfile); | ||
251 | |||
252 | if (index < argc) | ||
253 | { | 263 | { |
254 | mh_msgset_t msgset; | 264 | mh_msgset_t msgset; |
255 | mu_mailbox_t mbox; | 265 | mu_mailbox_t mbox; |
... | @@ -261,13 +271,26 @@ main (int argc, char **argv) | ... | @@ -261,13 +271,26 @@ main (int argc, char **argv) |
261 | mu_error (_("only one message at a time!")); | 271 | mu_error (_("only one message at a time!")); |
262 | return 1; | 272 | return 1; |
263 | } | 273 | } |
274 | unlink (wh_env.file); | ||
264 | copy_message (mbox, msgset.list[0], wh_env.file); | 275 | copy_message (mbox, msgset.list[0], wh_env.file); |
265 | mu_mailbox_destroy (&mbox); | 276 | mu_mailbox_destroy (&mbox); |
266 | mh_msgset_free (&msgset); | 277 | mh_msgset_free (&msgset); |
267 | } | 278 | } |
268 | else | 279 | else |
280 | { | ||
281 | switch (check_draft_disposition (&wh_env, use_draft)) | ||
282 | { | ||
283 | case DISP_QUIT: | ||
284 | exit (0); | ||
285 | |||
286 | case DISP_USE: | ||
287 | break; | ||
288 | |||
289 | case DISP_REPLACE: | ||
290 | unlink (wh_env.draftfile); | ||
269 | mh_comp_draft (formfile, "components", wh_env.file); | 291 | mh_comp_draft (formfile, "components", wh_env.file); |
270 | } | 292 | } |
293 | } | ||
271 | 294 | ||
272 | /* Exit immediately if --build is given */ | 295 | /* Exit immediately if --build is given */ |
273 | if (build_only) | 296 | if (build_only) | ... | ... |
... | @@ -195,10 +195,14 @@ typedef struct | ... | @@ -195,10 +195,14 @@ typedef struct |
195 | mu_header_t header; | 195 | mu_header_t header; |
196 | } mh_context_t; | 196 | } mh_context_t; |
197 | 197 | ||
198 | #define MH_MSGSET_UID 0x01 | ||
199 | |||
198 | typedef struct | 200 | typedef struct |
199 | { | 201 | { |
200 | size_t count; | 202 | int flags; |
201 | size_t *list; | 203 | size_t *list; |
204 | size_t count; | ||
205 | size_t size; | ||
202 | } mh_msgset_t; | 206 | } mh_msgset_t; |
203 | 207 | ||
204 | typedef void (*mh_iterator_fp) (mu_mailbox_t mbox, mu_message_t msg, | 208 | typedef void (*mh_iterator_fp) (mu_mailbox_t mbox, mu_message_t msg, |
... | @@ -300,7 +304,7 @@ int mh_message_number (mu_message_t msg, size_t *pnum); | ... | @@ -300,7 +304,7 @@ int mh_message_number (mu_message_t msg, size_t *pnum); |
300 | 304 | ||
301 | mu_mailbox_t mh_open_folder (const char *folder, int create); | 305 | mu_mailbox_t mh_open_folder (const char *folder, int create); |
302 | 306 | ||
303 | int mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, | 307 | void mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, |
304 | int argc, char **argv, char *def); | 308 | int argc, char **argv, char *def); |
305 | int mh_msgset_member (mh_msgset_t *msgset, size_t num); | 309 | int mh_msgset_member (mh_msgset_t *msgset, size_t num); |
306 | void mh_msgset_reverse (mh_msgset_t *msgset); | 310 | void mh_msgset_reverse (mh_msgset_t *msgset); | ... | ... |
... | @@ -998,14 +998,14 @@ mh_draft_message (const char *name, const char *msgspec, char **pname) | ... | @@ -998,14 +998,14 @@ mh_draft_message (const char *name, const char *msgspec, char **pname) |
998 | 998 | ||
999 | argv[0] = (char*) msgspec; | 999 | argv[0] = (char*) msgspec; |
1000 | argv[1] = NULL; | 1000 | argv[1] = NULL; |
1001 | rc = mh_msgset_parse (mbox, &msgset, 1, argv, "cur"); | 1001 | mh_msgset_parse (mbox, &msgset, 1, argv, "cur"); |
1002 | if (rc) | 1002 | if (msgset.count > 1) |
1003 | mu_error (_("invalid message number: %s"), msgspec); | ||
1004 | else if (msgset.count > 1) | ||
1005 | mu_error (_("only one message at a time!")); | 1003 | mu_error (_("only one message at a time!")); |
1006 | else | 1004 | else |
1005 | { | ||
1006 | mh_msgset_uids (mbox, &msgset); | ||
1007 | uid = msgset.list[0]; | 1007 | uid = msgset.list[0]; |
1008 | 1008 | } | |
1009 | mh_msgset_free (&msgset); | 1009 | mh_msgset_free (&msgset); |
1010 | } | 1010 | } |
1011 | 1011 | ... | ... |
... | @@ -19,234 +19,316 @@ | ... | @@ -19,234 +19,316 @@ |
19 | 19 | ||
20 | #include <mh.h> | 20 | #include <mh.h> |
21 | 21 | ||
22 | /* Expand a message set (msgcnt;msglist) to accomodate `inc' more | 22 | int |
23 | elements */ | 23 | mh_uid_to_msgno (mu_mailbox_t mbox, size_t uid, size_t *msgno) |
24 | static void | ||
25 | _expand (size_t *msgcnt, size_t **msglist, size_t inc) | ||
26 | { | 24 | { |
27 | if (!inc) | 25 | size_t num = mh_get_message (mbox, uid, NULL); |
28 | return; | 26 | if (num == 0) |
29 | 27 | return MU_ERR_NOENT; | |
30 | *msgcnt += inc; | 28 | *msgno = num; |
31 | *msglist = realloc (*msglist, (*msgcnt)*sizeof(**msglist)); | 29 | return 0; |
32 | if (!*msglist) | ||
33 | mh_err_memory (1); | ||
34 | } | 30 | } |
35 | 31 | ||
36 | /* Fatal error handler */ | 32 | int |
37 | static void | 33 | mh_msgno_to_uid (mu_mailbox_t mbox, size_t msgno, size_t *uid) |
38 | msgset_abort (const char *arg) | ||
39 | { | 34 | { |
40 | mu_error (_("bad message list `%s'"), arg); | 35 | mu_message_t msg; |
41 | exit (1); | 36 | int rc = mu_mailbox_get_message (mbox, msgno, &msg); |
37 | if (rc) | ||
38 | return rc; | ||
39 | return mu_message_get_uid (msg, uid); | ||
42 | } | 40 | } |
43 | 41 | ||
44 | /* Handlers for expansion of the reserved message names */ | ||
45 | 42 | ||
46 | static int | 43 | void |
47 | msgset_first (mu_mailbox_t mbox, size_t *pnum) | 44 | mh_msgset_init (mh_msgset_t *msgset) |
48 | { | 45 | { |
49 | *pnum = 1; | 46 | memset (msgset, 0, sizeof (*msgset)); |
50 | return 0; | ||
51 | } | 47 | } |
52 | 48 | ||
53 | static int | 49 | void |
54 | msgset_last (mu_mailbox_t mbox, size_t *pnum) | 50 | mh_msgset_expand (mh_msgset_t *msgset, size_t count) |
55 | { | 51 | { |
56 | int rc; | 52 | size_t rest = msgset->size - msgset->count; |
57 | size_t count = 0; | ||
58 | 53 | ||
59 | rc = mu_mailbox_messages_count (mbox, &count); | 54 | if (rest < count) |
60 | if (rc) | ||
61 | { | 55 | { |
62 | mu_error (_("cannot get last message: %s"), mu_strerror (rc)); | 56 | msgset->size += count; |
63 | exit (1); | 57 | msgset->list = xrealloc (msgset->list, |
58 | msgset->size * sizeof (msgset->list[0])); | ||
64 | } | 59 | } |
65 | *pnum = count; | 60 | } |
66 | return 0; | 61 | |
62 | void | ||
63 | mh_msgset_add (mh_msgset_t *msgset, size_t n) | ||
64 | { | ||
65 | mh_msgset_expand (msgset, 1); | ||
66 | msgset->list[msgset->count++] = n; | ||
67 | } | 67 | } |
68 | 68 | ||
69 | static int | 69 | static int |
70 | msgset_cur (mu_mailbox_t mbox, size_t *pnum) | 70 | comp_mesg (const void *a, const void *b) |
71 | { | 71 | { |
72 | size_t i, count = 0; | 72 | size_t an = *(size_t*)a; |
73 | static int cached_n = 0; | 73 | size_t bn = *(size_t*)b; |
74 | size_t cur; | 74 | if (an > bn) |
75 | return 1; | ||
76 | else if (an < bn) | ||
77 | return -1; | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | void | ||
82 | mh_msgset_optimize (mh_msgset_t *msgset) | ||
83 | { | ||
84 | size_t i, msgno; | ||
85 | size_t msgcnt = msgset->count; | ||
86 | size_t *msglist = msgset->list; | ||
75 | 87 | ||
76 | mh_mailbox_get_cur (mbox, &cur); | 88 | /* Sort the resulting message set */ |
89 | qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg); | ||
77 | 90 | ||
78 | if (cached_n) | 91 | /* Remove duplicates. */ |
79 | { | 92 | for (i = 0, msgno = 1; i < msgset->count; i++) |
80 | *pnum = cached_n; | 93 | if (msglist[msgno-1] != msglist[i]) |
94 | msglist[msgno++] = msglist[i]; | ||
95 | msgset->count = msgno; | ||
96 | } | ||
97 | |||
98 | /* Check if message with ordinal number `num' is contained in the | ||
99 | message set. */ | ||
100 | int | ||
101 | mh_msgset_member (mh_msgset_t *msgset, size_t num) | ||
102 | { | ||
103 | size_t i; | ||
104 | |||
105 | for (i = 0; i < msgset->count; i++) | ||
106 | if (msgset->list[i] == num) | ||
107 | return i + 1; | ||
81 | return 0; | 108 | return 0; |
82 | } | 109 | } |
83 | 110 | ||
84 | mu_mailbox_messages_count (mbox, &count); | 111 | /* Reverse the order of messages in the message set */ |
85 | for (i = 1; i <= count; i++) | 112 | void |
86 | { | 113 | mh_msgset_reverse (mh_msgset_t *msgset) |
87 | mu_message_t msg = NULL; | 114 | { |
88 | size_t uid = 0; | 115 | int head, tail; |
89 | 116 | ||
90 | mu_mailbox_get_message (mbox, i, &msg); | 117 | for (head = 0, tail = msgset->count-1; head < tail; head++, tail--) |
91 | mh_message_number (msg, &uid); | ||
92 | if (uid == cur) | ||
93 | { | 118 | { |
94 | *pnum = cached_n = i; | 119 | size_t val = msgset->list[head]; |
95 | return 0; | 120 | msgset->list[head] = msgset->list[tail]; |
96 | } | 121 | msgset->list[tail] = val; |
97 | } | 122 | } |
98 | mu_error (_("no cur message")); | ||
99 | exit (1); | ||
100 | } | 123 | } |
101 | 124 | ||
102 | static int | 125 | /* Set the current message to that contained at position `index' |
103 | msgset_prev (mu_mailbox_t mbox, size_t *pnum) | 126 | in the given message set */ |
127 | void | ||
128 | mh_msgset_current (mu_mailbox_t mbox, mh_msgset_t *msgset, int index) | ||
104 | { | 129 | { |
105 | size_t cur_n = 0; | 130 | mu_message_t msg = NULL; |
106 | msgset_cur (mbox, &cur_n); | 131 | int rc; |
107 | if (cur_n < 1) | 132 | size_t cur; |
133 | |||
134 | rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg); | ||
135 | if (rc) | ||
108 | { | 136 | { |
109 | mu_error (_("no prev message")); | 137 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc); |
110 | exit (1); | 138 | exit (1); |
111 | } | 139 | } |
112 | *pnum = cur_n - 1; | 140 | mh_message_number (msg, &cur); |
113 | return 0; | 141 | mh_mailbox_set_cur (mbox, cur); |
114 | } | 142 | } |
115 | 143 | ||
116 | static int | 144 | /* Free memory allocated for the message set. Note, that the msgset |
117 | msgset_next (mu_mailbox_t mbox, size_t *pnum) | 145 | itself is supposed to reside in the statically allocated memory and |
146 | therefore is not freed */ | ||
147 | void | ||
148 | mh_msgset_free (mh_msgset_t *msgset) | ||
118 | { | 149 | { |
119 | size_t cur_n = 0, total = 0; | 150 | if (msgset->count) |
120 | msgset_cur (mbox, &cur_n); | 151 | free (msgset->list); |
152 | } | ||
153 | |||
154 | /* Negate the message set: on return `msgset' consists of the messages | ||
155 | _not contained_ in the input message set. Any memory associated with | ||
156 | the input message set is freed */ | ||
157 | void | ||
158 | mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset) | ||
159 | { | ||
160 | size_t i, total = 0, msgno; | ||
161 | size_t *list; | ||
162 | |||
121 | mu_mailbox_messages_count (mbox, &total); | 163 | mu_mailbox_messages_count (mbox, &total); |
122 | if (cur_n + 1 > total) | 164 | list = calloc (total, sizeof (list[0])); |
165 | if (!list) | ||
166 | mh_err_memory (1); | ||
167 | for (i = 1, msgno = 0; i <= total; i++) | ||
123 | { | 168 | { |
124 | mu_error (_("no next message")); | 169 | if (!mh_msgset_member (msgset, i)) |
125 | exit (1); | 170 | list[msgno++] = i; |
126 | } | 171 | } |
127 | *pnum = cur_n + 1; | ||
128 | return 0; | ||
129 | } | ||
130 | 172 | ||
131 | static struct msgset_keyword { | 173 | list = realloc (list, sizeof (list[0]) * msgno); |
132 | char *name; | 174 | if (!list) |
133 | int (*handler) (mu_mailbox_t mbox, size_t *pnum); | 175 | { |
134 | } keywords[] = { | 176 | mu_error (_("not enough memory")); |
135 | { "first", msgset_first }, | 177 | abort (); |
136 | { "last", msgset_last }, | 178 | } |
137 | { "prev", msgset_prev }, | 179 | mh_msgset_free (msgset); |
138 | { "next", msgset_next }, | 180 | msgset->count = msgno; |
139 | { "cur", msgset_cur }, | 181 | msgset->list = list; |
140 | { NULL }, | 182 | } |
141 | }; | ||
142 | 183 | ||
143 | /* Preprocess a part of a complex message designation. Returns | 184 | void |
144 | a pointer to the allocated memory containing expanded part of | 185 | mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset) |
145 | the designation. Pointer to the beginning of the not expanded | ||
146 | part (in arg) is placed into *rest */ | ||
147 | static char * | ||
148 | msgset_preproc_part (mu_mailbox_t mbox, char *arg, char **rest) | ||
149 | { | 186 | { |
150 | struct msgset_keyword *p; | 187 | size_t i; |
151 | char *cp; | ||
152 | 188 | ||
153 | for (p = keywords; p->name; p++) | 189 | if (msgset->flags & MH_MSGSET_UID) |
154 | if (strncmp (arg, p->name, strlen (p->name)) == 0) | 190 | return; |
191 | for (i = 0; i < msgset->count; i++) | ||
155 | { | 192 | { |
156 | int rc; | ||
157 | size_t uid, num; | ||
158 | mu_message_t msg; | 193 | mu_message_t msg; |
194 | mu_mailbox_get_message (mbox, msgset->list[i], &msg); | ||
195 | mh_message_number (msg, &msgset->list[i]); | ||
196 | } | ||
197 | msgset->flags |= MH_MSGSET_UID; | ||
198 | } | ||
159 | 199 | ||
160 | if (p->handler (mbox, &num)) | 200 | /* Auxiliary function. Performs binary search for a message with the |
161 | msgset_abort (arg); | 201 | given sequence number */ |
162 | rc = mu_mailbox_get_message (mbox, num, &msg); | 202 | static size_t |
163 | if (rc) | 203 | mh_search_message (mu_mailbox_t mbox, size_t start, size_t stop, |
204 | size_t seqno, mu_message_t *mesg) | ||
205 | { | ||
206 | mu_message_t mid_msg = NULL; | ||
207 | size_t num = 0, middle; | ||
208 | |||
209 | middle = (start + stop) / 2; | ||
210 | if (mu_mailbox_get_message (mbox, middle, &mid_msg) | ||
211 | || mh_message_number (mid_msg, &num)) | ||
212 | return 0; | ||
213 | |||
214 | if (num == seqno) | ||
164 | { | 215 | { |
165 | mu_error (_("cannot get message %lu: %s"), | 216 | if (mesg) |
166 | (unsigned long) num, mu_strerror (rc)); | 217 | *mesg = mid_msg; |
167 | exit (1); | 218 | return middle; |
168 | } | ||
169 | *rest = arg + strlen (p->name); | ||
170 | mu_message_get_uid (msg, &uid); | ||
171 | return xstrdup (mu_umaxtostr (0, uid)); | ||
172 | } | 219 | } |
173 | cp = strchr (arg, '-'); | ||
174 | if (cp) | ||
175 | { | ||
176 | char *ret; | ||
177 | 220 | ||
178 | *rest = cp; | 221 | if (start >= stop) |
179 | ret = xmalloc (cp - arg + 1); | 222 | return 0; |
180 | memcpy (ret, arg, cp - arg); | ||
181 | ret[cp - arg] = 0; | ||
182 | return ret; | ||
183 | } | ||
184 | 223 | ||
185 | *rest = arg + strlen (arg); | 224 | if (num > seqno) |
186 | return strdup (arg); | 225 | return mh_search_message (mbox, start, middle-1, seqno, mesg); |
226 | else /*if (num < seqno)*/ | ||
227 | return mh_search_message (mbox, middle+1, stop, seqno, mesg); | ||
187 | } | 228 | } |
188 | 229 | ||
189 | /* Preprocess (expand) a single message designation */ | 230 | /* Retrieve the message with the given sequence number. |
190 | static char * | 231 | Returns ordinal number of the message in the mailbox if found, |
191 | msgset_preproc (mu_mailbox_t mbox, char *arg) | 232 | zero otherwise. The retrieved message is stored in the location |
233 | pointed to by mesg, unless it is NULL. */ | ||
234 | |||
235 | size_t | ||
236 | mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg) | ||
192 | { | 237 | { |
193 | char *buf, *tail; | 238 | size_t num, count; |
239 | mu_message_t msg; | ||
194 | 240 | ||
195 | if (strcmp (arg, "all") == 0 || strcmp (arg, ".") == 0) | 241 | if (mu_mailbox_get_message (mbox, 1, &msg) |
242 | || mh_message_number (msg, &num)) | ||
243 | return 0; | ||
244 | if (seqno < num) | ||
245 | return 0; | ||
246 | else if (seqno == num) | ||
196 | { | 247 | { |
197 | /* Special case */ | 248 | if (mesg) |
198 | arg = "first-last"; | 249 | *mesg = msg; |
250 | return 1; | ||
199 | } | 251 | } |
200 | 252 | ||
201 | buf = msgset_preproc_part (mbox, arg, &tail); | 253 | if (mu_mailbox_messages_count (mbox, &count) |
202 | if (tail[0] == '-') | 254 | || mu_mailbox_get_message (mbox, count, &msg) |
255 | || mh_message_number (msg, &num)) | ||
256 | return 0; | ||
257 | if (seqno > num) | ||
258 | return 0; | ||
259 | else if (seqno == num) | ||
203 | { | 260 | { |
204 | char *rest = msgset_preproc_part (mbox, tail+1, &tail); | 261 | if (mesg) |
205 | char *p = NULL; | 262 | *mesg = msg; |
206 | mu_asprintf (&p, "%s-%s", buf, rest); | 263 | return count; |
207 | free (rest); | ||
208 | free (buf); | ||
209 | buf = p; | ||
210 | } | 264 | } |
211 | 265 | ||
212 | if (tail[0]) | 266 | return mh_search_message (mbox, 1, count, seqno, mesg); |
213 | { | 267 | } |
214 | char *p = NULL; | 268 | |
215 | mu_asprintf (&p, "%s%s", buf, tail); | 269 | |
216 | free (buf); | 270 | struct msgset_parser |
217 | buf = p; | 271 | { |
218 | } | 272 | mu_mailbox_t mbox; |
219 | return buf; | 273 | mh_msgset_t *msgset; |
274 | char *curp; | ||
275 | int argc; | ||
276 | char **argv; | ||
277 | |||
278 | int sign; | ||
279 | size_t number; | ||
280 | int validuid; | ||
281 | }; | ||
282 | |||
283 | static void | ||
284 | msgset_parser_init (struct msgset_parser *parser, mu_mailbox_t mbox, | ||
285 | mh_msgset_t *msgset, int argc, char **argv) | ||
286 | { | ||
287 | parser->mbox = mbox; | ||
288 | parser->msgset = msgset; | ||
289 | parser->argc = argc; | ||
290 | parser->argv = argv; | ||
291 | parser->curp = ""; | ||
292 | |||
293 | parser->sign = 0; | ||
294 | parser->number = 0; | ||
295 | } | ||
296 | |||
297 | static void | ||
298 | msgset_abort (const char *arg) | ||
299 | { | ||
300 | mu_error (_("bad message list `%s'"), arg); | ||
301 | exit (1); | ||
302 | } | ||
303 | |||
304 | static void | ||
305 | emptyrange_abort (const char *range) | ||
306 | { | ||
307 | mu_error (_("no messages in range %s"), range); | ||
308 | exit (1); | ||
220 | } | 309 | } |
221 | 310 | ||
311 | /* Advance parser to the next argument */ | ||
222 | static int | 312 | static int |
223 | comp_mesg (const void *a, const void *b) | 313 | nextarg (struct msgset_parser *parser) |
224 | { | 314 | { |
225 | if (*(size_t*)a > *(size_t*)b) | 315 | if (parser->argc == 0) |
226 | return 1; | ||
227 | else if (*(size_t*)a < *(size_t*)b) | ||
228 | return -1; | ||
229 | return 0; | 316 | return 0; |
317 | parser->argc--; | ||
318 | parser->curp = *parser->argv++; | ||
319 | return 1; | ||
230 | } | 320 | } |
231 | 321 | ||
232 | static int _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, | 322 | static void msgset_parser_run (struct msgset_parser *parser); |
233 | int argc, char **argv); | ||
234 | 323 | ||
235 | /* Treat arg as a name of user-defined sequence and attempt to | 324 | static int |
236 | expand it. Return 0 if succeeded, non-zero otherwise. */ | 325 | _expand_sequence (struct msgset_parser *parser, char *term) |
237 | int | ||
238 | expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg) | ||
239 | { | 326 | { |
240 | struct mu_wordsplit ws; | 327 | struct mu_wordsplit ws; |
241 | char *p; | ||
242 | const char *listp; | 328 | const char *listp; |
243 | int rc = 1; | ||
244 | int negate = 0; | 329 | int negate = 0; |
245 | 330 | ||
246 | p = strchr (arg, ':'); | 331 | listp = mh_global_sequences_get (parser->mbox, term, NULL); |
247 | if (p) | ||
248 | *p++ = 0; | ||
249 | listp = mh_global_sequences_get (mbox, arg, NULL); | ||
250 | if (!listp) | 332 | if (!listp) |
251 | { | 333 | { |
252 | int len; | 334 | int len; |
... | @@ -254,10 +336,10 @@ expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg) | ... | @@ -254,10 +336,10 @@ expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg) |
254 | if (!neg) | 336 | if (!neg) |
255 | return 1; | 337 | return 1; |
256 | len = strlen (neg); | 338 | len = strlen (neg); |
257 | if (strncmp (arg, neg, len)) | 339 | if (strncmp (term, neg, len)) |
258 | return 1; | 340 | return 1; |
259 | negate = 1; | 341 | negate = 1; |
260 | listp = mh_global_sequences_get (mbox, arg + len, NULL); | 342 | listp = mh_global_sequences_get (parser->mbox, term + len, NULL); |
261 | if (!listp) | 343 | if (!listp) |
262 | return 1; | 344 | return 1; |
263 | } | 345 | } |
... | @@ -266,376 +348,375 @@ expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg) | ... | @@ -266,376 +348,375 @@ expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg) |
266 | { | 348 | { |
267 | mu_error (_("cannot split line `%s': %s"), listp, | 349 | mu_error (_("cannot split line `%s': %s"), listp, |
268 | mu_wordsplit_strerror (&ws)); | 350 | mu_wordsplit_strerror (&ws)); |
351 | exit (1); | ||
269 | } | 352 | } |
270 | else | 353 | else |
271 | { | 354 | { |
272 | rc = _mh_msgset_parse (mbox, msgset, ws.ws_wordc, ws.ws_wordv); | 355 | struct msgset_parser clone; |
356 | |||
357 | msgset_parser_init (&clone, parser->mbox, parser->msgset, | ||
358 | ws.ws_wordc, ws.ws_wordv); | ||
359 | msgset_parser_run (&clone); | ||
273 | mu_wordsplit_free (&ws); | 360 | mu_wordsplit_free (&ws); |
274 | } | 361 | } |
275 | 362 | ||
276 | if (rc) | ||
277 | return rc; | ||
278 | |||
279 | if (negate) | 363 | if (negate) |
280 | mh_msgset_negate (mbox, msgset); | 364 | mh_msgset_negate (parser->mbox, parser->msgset); |
365 | return 0; | ||
366 | } | ||
281 | 367 | ||
282 | if (p) | 368 | static int |
369 | parse_count (struct msgset_parser *parser) | ||
370 | { | ||
371 | char *endp; | ||
372 | if (!*parser->curp && nextarg (parser) == 0) | ||
373 | return 0; | ||
374 | if (*parser->curp == '-') | ||
283 | { | 375 | { |
284 | int first, num; | 376 | parser->sign = 1; |
285 | 377 | parser->curp++; | |
286 | num = strtoul (p, &p, 0); | ||
287 | if (*p) | ||
288 | { | ||
289 | mh_msgset_free (msgset); | ||
290 | return 1; | ||
291 | } | 378 | } |
292 | if (num < 0) | 379 | else if (*parser->curp == '+') |
293 | { | 380 | { |
294 | first = num + msgset->count; | 381 | parser->sign = 0; |
295 | num = - num; | 382 | parser->curp++; |
296 | } | 383 | } |
297 | else | 384 | parser->number = strtoul (parser->curp, &endp, 10); |
298 | first = 0; | 385 | if (*endp) |
299 | if (num > msgset->count) | 386 | msgset_abort (parser->curp); |
300 | { | 387 | parser->curp = endp; |
301 | mh_msgset_free (msgset); | ||
302 | return 1; | 388 | return 1; |
303 | } | 389 | } |
304 | 390 | ||
305 | if (first > 0) | ||
306 | memmove (msgset->list, &msgset->list[first], | ||
307 | sizeof (msgset->list[0]) * num); | ||
308 | msgset->count = num; | ||
309 | } | ||
310 | 391 | ||
311 | return rc; | 392 | static int |
393 | msgset_first (mu_mailbox_t mbox, size_t *pnum) | ||
394 | { | ||
395 | *pnum = 1; | ||
396 | return 0; | ||
312 | } | 397 | } |
313 | 398 | ||
314 | /* Parse a message specification from (argc;argv). Returned msgset is | 399 | static int |
315 | not sorted nor optimised */ | 400 | msgset_last (mu_mailbox_t mbox, size_t *pnum) |
316 | int | ||
317 | _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) | ||
318 | { | 401 | { |
319 | size_t msgcnt; | 402 | int rc; |
320 | size_t *msglist; | ||
321 | size_t i, msgno; | ||
322 | |||
323 | if (argc == 0) | ||
324 | return 1; | ||
325 | 403 | ||
326 | msgcnt = argc; | 404 | rc = mu_mailbox_messages_count (mbox, pnum); |
327 | msglist = calloc (msgcnt, sizeof(*msglist)); | 405 | if (rc) |
328 | for (i = 0, msgno = 0; i < argc; i++) | ||
329 | { | 406 | { |
330 | char *p = NULL, *q; | 407 | mu_error (_("cannot get last message: %s"), mu_strerror (rc)); |
331 | size_t start, end; | 408 | exit (1); |
332 | size_t msg_first, n; | 409 | } |
333 | long num; | 410 | return 0; |
334 | char *arg = msgset_preproc (mbox, argv[i]); | 411 | } |
335 | 412 | ||
336 | if (!mu_isdigit (arg[0])) | 413 | static int |
337 | { | 414 | msgset_cur (mu_mailbox_t mbox, size_t *pnum) |
338 | int j; | 415 | { |
339 | mh_msgset_t m; | 416 | size_t num; |
417 | mh_mailbox_get_cur (mbox, &num); | ||
418 | return mh_uid_to_msgno (mbox, num, pnum); | ||
419 | } | ||
340 | 420 | ||
341 | if (expand_user_seq (mbox, &m, arg)) | 421 | static int |
422 | msgset_prev (mu_mailbox_t mbox, size_t *pnum) | ||
423 | { | ||
424 | size_t cur_n = 0; | ||
425 | msgset_cur (mbox, &cur_n); | ||
426 | if (cur_n < 1) | ||
342 | { | 427 | { |
343 | mu_error (_("message set %s does not exist"), arg); | 428 | mu_error (_("no prev message")); |
344 | exit (1); | 429 | exit (1); |
345 | } | 430 | } |
346 | _expand (&msgcnt, &msglist, m.count); | 431 | *pnum = cur_n - 1; |
347 | for (j = 0; j < m.count; j++) | 432 | return 0; |
348 | msglist[msgno++] = m.list[j]; | 433 | } |
349 | mh_msgset_free (&m); | 434 | |
350 | } | 435 | static int |
351 | else | 436 | msgset_next (mu_mailbox_t mbox, size_t *pnum) |
352 | { | 437 | { |
353 | start = strtoul (arg, &p, 0); | 438 | size_t cur_n = 0, total = 0; |
354 | switch (*p) | 439 | msgset_cur (mbox, &cur_n); |
355 | { | 440 | mu_mailbox_messages_count (mbox, &total); |
356 | case 0: | 441 | if (cur_n + 1 > total) |
357 | n = mh_get_message (mbox, start, NULL); | ||
358 | if (!n) | ||
359 | { | 442 | { |
360 | mu_error (_("message %lu does not exist"), | 443 | mu_error (_("no next message")); |
361 | (unsigned long) start); | ||
362 | exit (1); | 444 | exit (1); |
363 | } | 445 | } |
364 | msglist[msgno++] = n; | 446 | *pnum = cur_n + 1; |
365 | break; | 447 | return 0; |
448 | } | ||
366 | 449 | ||
367 | case '-': | 450 | struct msgset_keyword |
368 | end = strtoul (p+1, &p, 0); | 451 | { |
369 | if (*p) | 452 | char *name; |
370 | msgset_abort (argv[i]); | 453 | size_t len; |
371 | if (end < start) | 454 | int (*handler) (mu_mailbox_t mbox, size_t *pnum); |
372 | { | 455 | int sign; |
373 | size_t t = start; | 456 | }; |
374 | start = end; | 457 | |
375 | end = t; | 458 | static struct msgset_keyword keywords[] = { |
376 | } | 459 | #define S(s) #s, sizeof (#s) - 1 |
377 | _expand (&msgcnt, &msglist, end - start); | 460 | { S(first), msgset_first, 0 }, |
378 | msg_first = msgno; | 461 | { S(last), msgset_last, 1 }, |
379 | for (; start <= end; start++) | 462 | { S(prev), msgset_prev, 1 }, |
380 | { | 463 | { S(next), msgset_next, 0 }, |
381 | n = mh_get_message (mbox, start, NULL); | 464 | { S(cur), msgset_cur, 0 }, |
382 | if (n) | 465 | { NULL } |
383 | msglist[msgno++] = n; | 466 | }; |
384 | } | 467 | |
385 | if (msgno == msg_first) | 468 | #define PARSE_EOF 0 |
469 | #define PARSE_MORE 1 | ||
470 | #define PARSE_SUCCESS 2 | ||
471 | |||
472 | /* term : NUMBER | ||
473 | | "first" | ||
474 | | "last" | ||
475 | | "cur" | ||
476 | | "prev" | ||
477 | | "next" | ||
478 | ; | ||
479 | */ | ||
480 | static int | ||
481 | parse_term (struct msgset_parser *parser, int seq) | ||
482 | { | ||
483 | size_t tlen; | ||
484 | char *term; | ||
485 | |||
486 | if (!*parser->curp && nextarg (parser) == 0) | ||
487 | return PARSE_EOF; | ||
488 | |||
489 | term = parser->curp; | ||
490 | parser->curp = mu_str_skip_class (term, MU_CTYPE_ALPHA|MU_CTYPE_DIGIT); | ||
491 | tlen = parser->curp - term; | ||
492 | if (mu_isalpha (*term)) | ||
386 | { | 493 | { |
387 | mu_error (_("no messages in range %s"), argv[i]); | 494 | struct msgset_keyword *p; |
388 | exit (1); | ||
389 | } | ||
390 | break; | ||
391 | 495 | ||
392 | case ':': | 496 | for (p = keywords; p->name; p++) |
393 | num = strtoul (p+1, &q, 0); | 497 | if (tlen == p->len && memcmp (p->name, term, tlen) == 0) |
394 | if (*q) | ||
395 | msgset_abort (argv[i]); | ||
396 | if (p[1] != '+' && p[1] != '-') | ||
397 | { | 498 | { |
398 | if (strncmp (argv[i], "last:", 5) == 0 | 499 | if (p->handler (parser->mbox, &parser->number)) |
399 | || strncmp (argv[i], "prev:", 5) == 0) | 500 | msgset_abort (term); |
400 | num = -num; | 501 | parser->sign = p->sign; |
502 | parser->validuid = 1; | ||
503 | return PARSE_MORE; | ||
401 | } | 504 | } |
402 | end = start + num; | 505 | |
403 | if (end < start) | 506 | if (*parser->curp == 0 && seq) |
404 | { | 507 | { |
405 | size_t t = start; | 508 | /* See if it is a user-defined sequence */ |
406 | start = end + 1; | 509 | if (_expand_sequence (parser, term) == 0) |
407 | end = t; | 510 | return PARSE_SUCCESS; |
408 | } | 511 | } |
409 | else | 512 | msgset_abort (term); |
410 | end--; | ||
411 | _expand (&msgcnt, &msglist, end - start); | ||
412 | msg_first = msgno; | ||
413 | for (; start <= end; start++) | ||
414 | { | ||
415 | n = mh_get_message (mbox, start, NULL); | ||
416 | if (n) | ||
417 | msglist[msgno++] = n; | ||
418 | } | 513 | } |
419 | if (msgno == msg_first) | 514 | else if (mu_isdigit (*term)) |
420 | { | 515 | { |
421 | mu_error (_("no messages in range %s"), argv[i]); | 516 | char *endp; |
422 | exit (1); | 517 | size_t num = strtoul (term, &endp, 10); |
423 | } | 518 | if (endp != parser->curp) |
424 | break; | 519 | msgset_abort (term); |
425 | 520 | ||
426 | default: | 521 | if (mh_uid_to_msgno (parser->mbox, num, &parser->number)) |
427 | msgset_abort (argv[i]); | 522 | { |
428 | } | 523 | parser->validuid = 0; |
524 | parser->number = num; | ||
429 | } | 525 | } |
430 | free (arg); | 526 | else |
527 | parser->validuid = 1; | ||
528 | parser->sign = 0; | ||
431 | } | 529 | } |
432 | 530 | else | |
433 | msgset->count = msgno; | 531 | msgset_abort (term); |
434 | msgset->list = msglist; | 532 | return PARSE_MORE; |
435 | return 0; | ||
436 | } | 533 | } |
437 | 534 | ||
438 | /* Parse a message specification from (argc;argv). Returned msgset is | 535 | static void |
439 | sorted and optimised (i.e. it does not contain duplicate message | 536 | add_messages (struct msgset_parser *parser, size_t start, size_t count, |
440 | numbers) */ | 537 | int sign) |
441 | int | ||
442 | mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, | ||
443 | int argc, char **argv, char *def) | ||
444 | { | 538 | { |
445 | char *xargv[2]; | 539 | size_t i; |
446 | int rc; | ||
447 | 540 | ||
448 | if (argc == 0) | 541 | if (start == 0) |
542 | start = 1; | ||
543 | mh_msgset_expand (parser->msgset, count); | ||
544 | if (sign) | ||
449 | { | 545 | { |
450 | argc = 1; | 546 | if (count > start) |
451 | argv = xargv; | 547 | count = start; |
452 | argv[0] = def ? def : "cur"; | 548 | for (i = 0; i < count; i++, start--) |
453 | argv[1] = NULL; | 549 | parser->msgset->list[parser->msgset->count++] = start; |
454 | } | 550 | } |
455 | 551 | else | |
456 | rc = _mh_msgset_parse (mbox, msgset, argc, argv); | ||
457 | |||
458 | if (rc == 0) | ||
459 | { | 552 | { |
460 | size_t i, msgno; | 553 | size_t total; |
461 | size_t msgcnt = msgset->count; | ||
462 | size_t *msglist = msgset->list; | ||
463 | 554 | ||
464 | /* Sort the resulting message set */ | 555 | mu_mailbox_messages_count (parser->mbox, &total); |
465 | qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg); | 556 | if (start + count > total) |
466 | 557 | count = total - start + 1; | |
467 | /* Remove duplicates. */ | 558 | for (i = 0; i < count; i++, start++) |
468 | for (i = 0, msgno = 1; i < msgset->count; i++) | 559 | parser->msgset->list[parser->msgset->count++] = start; |
469 | if (msglist[msgno-1] != msglist[i]) | ||
470 | msglist[msgno++] = msglist[i]; | ||
471 | msgset->count = msgno; | ||
472 | } | 560 | } |
473 | return rc; | 561 | if (count == 0) |
562 | emptyrange_abort (parser->argv[-1]); | ||
474 | } | 563 | } |
475 | 564 | ||
476 | /* Check if message with ordinal number `num' is contained in the | 565 | static void |
477 | message set. */ | 566 | add_message_range (struct msgset_parser *parser, size_t start, size_t end) |
478 | int | ||
479 | mh_msgset_member (mh_msgset_t *msgset, size_t num) | ||
480 | { | 567 | { |
481 | size_t i; | 568 | if (end == start) |
569 | emptyrange_abort (parser->argv[-1]); | ||
482 | 570 | ||
483 | for (i = 0; i < msgset->count; i++) | 571 | if (end < start) |
484 | if (msgset->list[i] == num) | 572 | { |
485 | return i + 1; | 573 | size_t t = start; |
486 | return 0; | 574 | start = end; |
575 | end = t; | ||
576 | } | ||
577 | mh_msgset_expand (parser->msgset, end - start + 1); | ||
578 | |||
579 | for (; start <= end; start++) | ||
580 | parser->msgset->list[parser->msgset->count++] = start; | ||
487 | } | 581 | } |
488 | 582 | ||
489 | /* Auxiliary function. Performs binary search for a message with the | 583 | /* range: term '-' term |
490 | given sequence number */ | 584 | | term ':' count |
491 | static size_t | 585 | ; |
492 | mh_search_message (mu_mailbox_t mbox, size_t start, size_t stop, | 586 | count: NUMBER |
493 | size_t seqno, mu_message_t *mesg) | 587 | | '+' NUMBER |
588 | | '-' NUMBER | ||
589 | ; | ||
590 | */ | ||
591 | static int | ||
592 | parse_range (struct msgset_parser *parser) | ||
494 | { | 593 | { |
495 | mu_message_t mid_msg = NULL; | 594 | size_t start; |
496 | size_t num = 0, middle; | ||
497 | |||
498 | middle = (start + stop) / 2; | ||
499 | if (mu_mailbox_get_message (mbox, middle, &mid_msg) | ||
500 | || mh_message_number (mid_msg, &num)) | ||
501 | return 0; | ||
502 | 595 | ||
503 | if (num == seqno) | 596 | switch (parse_term (parser, 1)) |
504 | { | 597 | { |
505 | if (mesg) | 598 | case PARSE_EOF: |
506 | *mesg = mid_msg; | ||
507 | return middle; | ||
508 | } | ||
509 | |||
510 | if (start >= stop) | ||
511 | return 0; | 599 | return 0; |
512 | 600 | ||
513 | if (num > seqno) | 601 | case PARSE_SUCCESS: |
514 | return mh_search_message (mbox, start, middle-1, seqno, mesg); | 602 | return 1; |
515 | else /*if (num < seqno)*/ | ||
516 | return mh_search_message (mbox, middle+1, stop, seqno, mesg); | ||
517 | } | ||
518 | 603 | ||
519 | /* Retrieve the message with the given sequence number. | 604 | case PARSE_MORE: |
520 | Returns ordinal number of the message in the mailbox if found, | 605 | break; |
521 | zero otherwise. The retrieved message is stored in the location | 606 | } |
522 | pointed to by mesg, unless it is NULL. */ | ||
523 | 607 | ||
524 | size_t | 608 | start = parser->number; |
525 | mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg) | ||
526 | { | ||
527 | size_t num, count; | ||
528 | mu_message_t msg; | ||
529 | 609 | ||
530 | if (mu_mailbox_get_message (mbox, 1, &msg) | 610 | if (*parser->curp == ':') |
531 | || mh_message_number (msg, &num)) | 611 | { |
532 | return 0; | 612 | int validuid = parser->validuid; |
533 | if (seqno < num) | 613 | parser->curp++; |
614 | if (parse_count (parser) == 0) | ||
534 | return 0; | 615 | return 0; |
535 | else if (seqno == num) | 616 | if (!validuid) |
536 | { | 617 | { |
537 | if (mesg) | 618 | size_t total, lastuid; |
538 | *mesg = msg; | 619 | msgset_last (parser->mbox, &total); |
620 | mh_msgno_to_uid (parser->mbox, total, &lastuid); | ||
621 | if (start > lastuid) | ||
622 | { | ||
623 | if (!parser->sign) | ||
624 | emptyrange_abort (parser->argv[-1]); | ||
625 | start = total; | ||
626 | } | ||
627 | else | ||
628 | { | ||
629 | if (parser->sign) | ||
630 | emptyrange_abort (parser->argv[-1]); | ||
631 | start = 1; | ||
632 | } | ||
633 | } | ||
634 | add_messages (parser, start, parser->number, parser->sign); | ||
539 | return 1; | 635 | return 1; |
540 | } | 636 | } |
637 | else if (*parser->curp == '-') | ||
638 | { | ||
639 | size_t lastuid = 0; | ||
640 | int validuid = parser->validuid; | ||
541 | 641 | ||
542 | if (mu_mailbox_messages_count (mbox, &count) | 642 | parser->curp++; |
543 | || mu_mailbox_get_message (mbox, count, &msg) | 643 | if (parse_term (parser, 0) == PARSE_EOF) |
544 | || mh_message_number (msg, &num)) | ||
545 | return 0; | ||
546 | if (seqno > num) | ||
547 | return 0; | 644 | return 0; |
548 | else if (seqno == num) | 645 | if (!parser->validuid) |
549 | { | 646 | { |
550 | if (mesg) | 647 | size_t total; |
551 | *mesg = msg; | ||
552 | return count; | ||
553 | } | ||
554 | |||
555 | return mh_search_message (mbox, 1, count, seqno, mesg); | ||
556 | } | ||
557 | 648 | ||
558 | /* Reverse the order of messages in the message set */ | 649 | msgset_last (parser->mbox, &total); |
559 | void | 650 | mh_msgno_to_uid (parser->mbox, total, &lastuid); |
560 | mh_msgset_reverse (mh_msgset_t *msgset) | 651 | if (parser->number > lastuid) |
561 | { | 652 | parser->number = total; |
562 | int head, tail; | 653 | else if (!validuid) |
563 | 654 | emptyrange_abort (parser->argv[-1]); | |
564 | for (head = 0, tail = msgset->count-1; head < tail; head++, tail--) | 655 | } |
656 | if (!validuid) | ||
565 | { | 657 | { |
566 | size_t val = msgset->list[head]; | 658 | if (!lastuid) |
567 | msgset->list[head] = msgset->list[tail]; | 659 | { |
568 | msgset->list[tail] = val; | 660 | size_t total; |
661 | msgset_last (parser->mbox, &total); | ||
662 | mh_msgno_to_uid (parser->mbox, total, &lastuid); | ||
569 | } | 663 | } |
570 | } | 664 | if (start > lastuid && !parser->validuid) |
571 | 665 | emptyrange_abort (parser->argv[-1]); | |
572 | /* Set the current message to that contained at position `index' | 666 | start = 1; |
573 | in the given message set */ | 667 | } |
574 | void | 668 | add_message_range (parser, start, parser->number); |
575 | mh_msgset_current (mu_mailbox_t mbox, mh_msgset_t *msgset, int index) | 669 | } |
576 | { | 670 | else if (!parser->validuid) |
577 | mu_message_t msg = NULL; | ||
578 | int rc; | ||
579 | size_t cur; | ||
580 | |||
581 | rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg); | ||
582 | if (rc) | ||
583 | { | 671 | { |
584 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc); | 672 | mu_error (_("message %s does not exist"), parser->argv[-1]); |
585 | exit (1); | 673 | exit (1); |
586 | } | 674 | } |
587 | mh_message_number (msg, &cur); | 675 | else |
588 | mh_mailbox_set_cur (mbox, cur); | 676 | mh_msgset_add (parser->msgset, start); |
677 | return 1; | ||
589 | } | 678 | } |
590 | 679 | ||
591 | /* Free memory allocated for the message set. Note, that the msgset | 680 | |
592 | itself is supposed to reside in the statically allocated memory and | 681 | /* Parse a message specification. The composed msgset is |
593 | therefore is not freed */ | 682 | not sorted nor optimised */ |
594 | void | 683 | static void |
595 | mh_msgset_free (mh_msgset_t *msgset) | 684 | msgset_parser_run (struct msgset_parser *parser) |
596 | { | 685 | { |
597 | if (msgset->count) | 686 | while (parse_range (parser)) |
598 | free (msgset->list); | 687 | ; |
599 | } | 688 | } |
600 | 689 | ||
601 | /* Negate the message set: on return `msgset' consists of the messages | 690 | /* Parse a message specification from (argc;argv). Returned msgset is |
602 | _not contained_ in the input message set. Any memory associated with | 691 | sorted and optimised (i.e. it does not contain duplicate message |
603 | the input message set is freed */ | 692 | numbers) */ |
604 | void | 693 | void |
605 | mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset) | 694 | mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, |
695 | int argc, char **argv, char *def) | ||
606 | { | 696 | { |
607 | size_t i, total = 0, msgno; | 697 | struct msgset_parser parser; |
608 | size_t *list; | 698 | char *xargv[2]; |
609 | 699 | ||
610 | mu_mailbox_messages_count (mbox, &total); | 700 | if (argc == 0) |
611 | list = calloc (total, sizeof (list[0])); | ||
612 | if (!list) | ||
613 | mh_err_memory (1); | ||
614 | for (i = 1, msgno = 0; i <= total; i++) | ||
615 | { | 701 | { |
616 | if (!mh_msgset_member (msgset, i)) | 702 | argc = 1; |
617 | list[msgno++] = i; | 703 | argv = xargv; |
704 | argv[0] = def ? def : "cur"; | ||
705 | argv[1] = NULL; | ||
618 | } | 706 | } |
619 | 707 | ||
620 | list = realloc (list, sizeof (list[0]) * msgno); | 708 | if (argc == 1 && |
621 | if (!list) | 709 | (strcmp (argv[0], "all") == 0 || strcmp (argv[0], ".") == 0)) |
622 | { | 710 | { |
623 | mu_error (_("not enough memory")); | 711 | argc = 1; |
624 | abort (); | 712 | argv = xargv; |
713 | argv[0] = "first-last"; | ||
714 | argv[1] = NULL; | ||
625 | } | 715 | } |
626 | mh_msgset_free (msgset); | ||
627 | msgset->count = msgno; | ||
628 | msgset->list = list; | ||
629 | } | ||
630 | 716 | ||
631 | void | 717 | mh_msgset_init (msgset); |
632 | mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset) | 718 | msgset_parser_init (&parser, mbox, msgset, argc, argv); |
633 | { | 719 | msgset_parser_run (&parser); |
634 | size_t i; | 720 | |
635 | for (i = 0; i < msgset->count; i++) | 721 | mh_msgset_optimize (msgset); |
636 | { | ||
637 | mu_message_t msg; | ||
638 | mu_mailbox_get_message (mbox, msgset->list[i], &msg); | ||
639 | mh_message_number (msg, &msgset->list[i]); | ||
640 | } | ||
641 | } | 722 | } | ... | ... |
... | @@ -346,17 +346,20 @@ _whatnow (struct mh_whatnow_env *wh, struct action_tab *tab) | ... | @@ -346,17 +346,20 @@ _whatnow (struct mh_whatnow_env *wh, struct action_tab *tab) |
346 | 346 | ||
347 | do | 347 | do |
348 | { | 348 | { |
349 | size_t n; | ||
349 | handler_fp fun; | 350 | handler_fp fun; |
350 | 351 | ||
351 | printf ("%s ", wh->prompt); | 352 | printf ("%s ", wh->prompt); |
352 | fflush (stdout); | 353 | fflush (stdout); |
353 | rc = mu_stream_getline (in, &line, &size, NULL); | 354 | rc = mu_stream_getline (in, &line, &size, &n); |
354 | if (rc) | 355 | if (rc) |
355 | { | 356 | { |
356 | mu_error (_("cannot read input stream: %s"), mu_strerror (rc)); | 357 | mu_error (_("cannot read input stream: %s"), mu_strerror (rc)); |
357 | status = 1; | 358 | status = 1; |
358 | break; | 359 | break; |
359 | } | 360 | } |
361 | if (n == 0) | ||
362 | break; | ||
360 | 363 | ||
361 | ws.ws_comment = "#"; | 364 | ws.ws_comment = "#"; |
362 | rc = mu_wordsplit (line, &ws, wsflags); | 365 | rc = mu_wordsplit (line, &ws, wsflags); |
... | @@ -462,7 +465,10 @@ static int | ... | @@ -462,7 +465,10 @@ static int |
462 | call_send (struct mh_whatnow_env *wh, int argc, char **argv, int *status) | 465 | call_send (struct mh_whatnow_env *wh, int argc, char **argv, int *status) |
463 | { | 466 | { |
464 | if (invoke ("sendproc", MHBINDIR "/send", argc, argv, wh->file, NULL) == 0) | 467 | if (invoke ("sendproc", MHBINDIR "/send", argc, argv, wh->file, NULL) == 0) |
468 | { | ||
465 | annotate (wh); | 469 | annotate (wh); |
470 | return 1; | ||
471 | } | ||
466 | return 0; | 472 | return 0; |
467 | } | 473 | } |
468 | 474 | ... | ... |
mh/mhseq.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2010 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 | /* MH mhparam command */ | ||
18 | |||
19 | #include <mh.h> | ||
20 | |||
21 | static char doc[] = N_("GNU MH mhseq")"\v" | ||
22 | N_("Use -help to obtain the list of traditional MH options."); | ||
23 | static char args_doc[] = N_("[SEQUENCE]"); | ||
24 | |||
25 | static struct argp_option options[] = { | ||
26 | {"folder", ARG_FOLDER, N_("FOLDER"), 0, | ||
27 | N_("specify the folder to use")}, | ||
28 | { "uids", 'u', NULL, 0, | ||
29 | N_("show message UIDs (default)")}, | ||
30 | { "numbers", 'n', NULL, 0, | ||
31 | N_("show message numbers") }, | ||
32 | { NULL } | ||
33 | }; | ||
34 | |||
35 | /* Traditional MH options */ | ||
36 | struct mh_option mh_option[] = { | ||
37 | { "uid" }, | ||
38 | { NULL } | ||
39 | }; | ||
40 | |||
41 | static int uid_option = 1; | ||
42 | |||
43 | static error_t | ||
44 | opt_handler (int key, char *arg, struct argp_state *state) | ||
45 | { | ||
46 | switch (key) | ||
47 | { | ||
48 | case ARG_FOLDER: | ||
49 | mh_set_current_folder (arg); | ||
50 | break; | ||
51 | |||
52 | case 'n': | ||
53 | uid_option = 0; | ||
54 | break; | ||
55 | |||
56 | case 'u': | ||
57 | uid_option = 1; | ||
58 | break; | ||
59 | |||
60 | default: | ||
61 | return ARGP_ERR_UNKNOWN; | ||
62 | } | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | int | ||
67 | main (int argc, char **argv) | ||
68 | { | ||
69 | int index; | ||
70 | mu_mailbox_t mbox; | ||
71 | mh_msgset_t msgset; | ||
72 | size_t i; | ||
73 | |||
74 | /* Native Language Support */ | ||
75 | MU_APP_INIT_NLS (); | ||
76 | |||
77 | mh_argp_init (); | ||
78 | mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc, | ||
79 | opt_handler, NULL, &index); | ||
80 | |||
81 | argc -= index; | ||
82 | argv += index; | ||
83 | mbox = mh_open_folder (mh_current_folder (), 0); | ||
84 | |||
85 | mh_msgset_parse (mbox, &msgset, argc, argv, "cur"); | ||
86 | if (uid_option) | ||
87 | mh_msgset_uids (mbox, &msgset); | ||
88 | |||
89 | for (i = 0; i < msgset.count; i++) | ||
90 | printf ("%lu\n", (unsigned long) msgset.list[i]); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 |
... | @@ -42,6 +42,7 @@ TESTSUITE_AT = \ | ... | @@ -42,6 +42,7 @@ TESTSUITE_AT = \ |
42 | ali.at\ | 42 | ali.at\ |
43 | anno.at\ | 43 | anno.at\ |
44 | burst.at\ | 44 | burst.at\ |
45 | comp.at\ | ||
45 | folder.at\ | 46 | folder.at\ |
46 | inc.at\ | 47 | inc.at\ |
47 | install-mh.at\ | 48 | install-mh.at\ |
... | @@ -49,6 +50,7 @@ TESTSUITE_AT = \ | ... | @@ -49,6 +50,7 @@ TESTSUITE_AT = \ |
49 | mhl.at\ | 50 | mhl.at\ |
50 | mhparam.at\ | 51 | mhparam.at\ |
51 | mhpath.at\ | 52 | mhpath.at\ |
53 | mhseq.at\ | ||
52 | pick.at\ | 54 | pick.at\ |
53 | scan.at\ | 55 | scan.at\ |
54 | refile.at\ | 56 | refile.at\ | ... | ... |
mh/tests/comp.at
0 → 100644
1 | # This file is part of GNU Mailutils. -*- Autotest -*- | ||
2 | # Copyright (C) 2010 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 | m4_pushdef([MH_KEYWORDS],[comp]) | ||
18 | m4_pushdef([compcmd],[comp dnl | ||
19 | -form $abs_top_srcdir/mh/components dnl | ||
20 | -editor $abs_top_srcdir/mh/tests/mhed]) | ||
21 | |||
22 | MH_CHECK([comp -file],[comp00 comp-file],[ | ||
23 | dir=`pwd` | ||
24 | echo quit | compcmd -file ./infile | sed "s|$dir/*||;s| *$||" | ||
25 | cat infile | ||
26 | ], | ||
27 | [0], | ||
28 | [-- Editor invocation: ./infile | ||
29 | -- Input file: | ||
30 | To: | ||
31 | cc: | ||
32 | Subject: | ||
33 | -------- | ||
34 | -- Input file end | ||
35 | What now? draft left on "./infile". | ||
36 | To: | ||
37 | cc: | ||
38 | Subject: | ||
39 | -------- | ||
40 | Seen by mhed | ||
41 | ]) | ||
42 | |||
43 | MH_CHECK([comp -file (del)],[comp01 comp-file_del],[ | ||
44 | dir=`pwd` | ||
45 | echo 'quit -delete' | compcmd -file ./infile | sed "s|$dir/*||;s| *$||" | ||
46 | ], | ||
47 | [0], | ||
48 | [-- Editor invocation: ./infile | ||
49 | -- Input file: | ||
50 | To: | ||
51 | cc: | ||
52 | Subject: | ||
53 | -------- | ||
54 | -- Input file end | ||
55 | What now?]) | ||
56 | |||
57 | MH_CHECK([comp file],[comp02 comp_file],[ | ||
58 | echo 'quit' | compcmd file | sed "s|$dir/*||;s| *$||" | ||
59 | cat Mail/file | ||
60 | ], | ||
61 | [0], | ||
62 | [-- Editor invocation: Mail/file | ||
63 | -- Input file: | ||
64 | To: | ||
65 | cc: | ||
66 | Subject: | ||
67 | -------- | ||
68 | -- Input file end | ||
69 | What now? draft left on "Mail/file". | ||
70 | To: | ||
71 | cc: | ||
72 | Subject: | ||
73 | -------- | ||
74 | Seen by mhed | ||
75 | ]) | ||
76 | |||
77 | MH_CHECK([comp -use file],[comp03 comp-use_file],[ | ||
78 | AT_DATA([Mail/file],[From: gray | ||
79 | To: root | ||
80 | Subject: test input | ||
81 | |||
82 | message body | ||
83 | ]) | ||
84 | |||
85 | echo 'quit' | compcmd -use file | sed "s|$dir/*||;s| *$||" | ||
86 | cat Mail/file | ||
87 | ], | ||
88 | [0], | ||
89 | [-- Editor invocation: Mail/file | ||
90 | -- Input file: | ||
91 | From: gray | ||
92 | To: root | ||
93 | Subject: test input | ||
94 | |||
95 | message body | ||
96 | -- Input file end | ||
97 | What now? draft left on "Mail/file". | ||
98 | From: gray | ||
99 | To: root | ||
100 | Subject: test input | ||
101 | |||
102 | message body | ||
103 | Seen by mhed | ||
104 | ]) | ||
105 | |||
106 | MH_CHECK([comp +folder msg],[comp04 comp+folder_msg],[ | ||
107 | mkdir Mail/inbox | ||
108 | AT_DATA([Mail/inbox/1],[From: gray | ||
109 | To: root | ||
110 | Subject: test input | ||
111 | |||
112 | message body | ||
113 | ]) | ||
114 | |||
115 | echo 'quit' | compcmd +inbox 1 | sed "s|$dir/*||;s| *$||" | ||
116 | echo Mail/draft | ||
117 | cat Mail/draft | ||
118 | echo Message | ||
119 | cat Mail/inbox/1 | ||
120 | ], | ||
121 | [0], | ||
122 | [-- Editor invocation: Mail/draft | ||
123 | -- Input file: | ||
124 | From: gray | ||
125 | To: root | ||
126 | Subject: test input | ||
127 | |||
128 | message body | ||
129 | -- Input file end | ||
130 | What now? draft left on "Mail/draft". | ||
131 | Mail/draft | ||
132 | From: gray | ||
133 | To: root | ||
134 | Subject: test input | ||
135 | |||
136 | message body | ||
137 | Seen by mhed | ||
138 | Message | ||
139 | From: gray | ||
140 | To: root | ||
141 | Subject: test input | ||
142 | |||
143 | message body | ||
144 | ]) | ||
145 | |||
146 | m4_popdef([compcmd]) | ||
147 | m4_popdef([MH_KEYWORDS]) | ||
148 |
mh/tests/mhed
0 → 100755
mh/tests/mhseq.at
0 → 100644
1 | # This file is part of GNU Mailutils. -*- Autotest -*- | ||
2 | # Copyright (C) 2010 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 | m4_pushdef([MH_KEYWORDS],[mhseq mh-sequences]) | ||
18 | |||
19 | dnl --------------------------------------------------------------- | ||
20 | |||
21 | MH_CHECK([mhseq: existing message number],[mhseq00],[ | ||
22 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
23 | mhseq 1 | ||
24 | ], | ||
25 | [0], | ||
26 | [1 | ||
27 | ]) | ||
28 | |||
29 | MH_CHECK([mhseq: not existing message number],[mhseq01],[ | ||
30 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
31 | mhseq 100 | ||
32 | ], | ||
33 | [1], | ||
34 | [], | ||
35 | dnl FIXME: See FIXME 3 in mhpath.at | ||
36 | [mhseq: message 100 does not exist | ||
37 | ]) | ||
38 | |||
39 | MH_CHECK([mhseq: contiguous message range],[mhseq02],[ | ||
40 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
41 | mhseq 2-5 | ||
42 | ], | ||
43 | [0], | ||
44 | [2 | ||
45 | 3 | ||
46 | 4 | ||
47 | 5 | ||
48 | ]) | ||
49 | |||
50 | MH_CHECK([mhseq: reversed contiguous message range],[mhseq03],[ | ||
51 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
52 | mhseq 5-2 | ||
53 | ], | ||
54 | [0], | ||
55 | [2 | ||
56 | 3 | ||
57 | 4 | ||
58 | 5 | ||
59 | ]) | ||
60 | |||
61 | MH_CHECK([mhseq: reversed non-contiguous message range],[mhseq04],[ | ||
62 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
63 | rm Mail/inbox/3 Mail/inbox/4 | ||
64 | mhseq 5-2 | ||
65 | ], | ||
66 | [0], | ||
67 | [2 | ||
68 | 5 | ||
69 | ]) | ||
70 | |||
71 | MH_CHECK([mhseq: message range (left fixup)],[mhseq05],[ | ||
72 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
73 | rm Mail/inbox/1 Mail/inbox/2 | ||
74 | mhseq 1-5 | ||
75 | ], | ||
76 | [0], | ||
77 | [3 | ||
78 | 4 | ||
79 | 5 | ||
80 | ]) | ||
81 | |||
82 | MH_CHECK([mhseq: message range (right fixup)],[mhseq06],[ | ||
83 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
84 | rm Mail/inbox/4 Mail/inbox/5 | ||
85 | mhseq 1-5 | ||
86 | ], | ||
87 | [0], | ||
88 | [1 | ||
89 | 2 | ||
90 | 3 | ||
91 | ]) | ||
92 | |||
93 | MH_CHECK([mhseq: message range (both fixups)],[mhseq07],[ | ||
94 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
95 | rm Mail/inbox/1 Mail/inbox/5 | ||
96 | mhseq 1-5 | ||
97 | ], | ||
98 | [0], | ||
99 | [2 | ||
100 | 3 | ||
101 | 4 | ||
102 | ]) | ||
103 | |||
104 | MH_CHECK([mhseq: non-existent message range (left)],[mhseq08],[ | ||
105 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
106 | rm Mail/inbox/1 Mail/inbox/2 Mail/inbox/3 | ||
107 | mhseq 1-2 | ||
108 | ], | ||
109 | [1], | ||
110 | [], | ||
111 | [mhseq: no messages in range 1-2 | ||
112 | ]) | ||
113 | |||
114 | MH_CHECK([mhseq: non-existent message range (right)],[mhseq09],[ | ||
115 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
116 | mhseq 6-10 | ||
117 | ], | ||
118 | [1], | ||
119 | [], | ||
120 | [mhseq: no messages in range 6-10 | ||
121 | ]) | ||
122 | |||
123 | MH_CHECK([mhseq: message set addition],[mhseq10],[ | ||
124 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox]) | ||
125 | mhseq 5 8-10 15-20 | ||
126 | ], | ||
127 | [0], | ||
128 | [5 | ||
129 | 8 | ||
130 | 9 | ||
131 | 10 | ||
132 | 15 | ||
133 | 16 | ||
134 | 17 | ||
135 | 18 | ||
136 | 19 | ||
137 | 20 | ||
138 | ]) | ||
139 | |||
140 | MH_CHECK([mhseq: message set optimization],[mhseq11],[ | ||
141 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox]) | ||
142 | rm Mail/inbox/17 Mail/inbox/19 | ||
143 | mhseq 5 1-10 15-20 | ||
144 | ], | ||
145 | [0], | ||
146 | [1 | ||
147 | 2 | ||
148 | 3 | ||
149 | 4 | ||
150 | 5 | ||
151 | 6 | ||
152 | 7 | ||
153 | 8 | ||
154 | 9 | ||
155 | 10 | ||
156 | 15 | ||
157 | 16 | ||
158 | 18 | ||
159 | 20 | ||
160 | ]) | ||
161 | |||
162 | MH_CHECK([mhseq: counted range (positive)],[mhseq12],[ | ||
163 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox]) | ||
164 | mhseq 10:4 | ||
165 | ], | ||
166 | [0], | ||
167 | [10 | ||
168 | 11 | ||
169 | 12 | ||
170 | 13 | ||
171 | ]) | ||
172 | |||
173 | MH_CHECK([mhseq: non-contiguous counted range (positive)],[mhseq13],[ | ||
174 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox]) | ||
175 | rm Mail/inbox/12 Mail/inbox/14 | ||
176 | mhseq 10:4 | ||
177 | ], | ||
178 | [0], | ||
179 | [10 | ||
180 | 11 | ||
181 | 13 | ||
182 | 15 | ||
183 | ]) | ||
184 | |||
185 | MH_CHECK([mhseq: counted range (positive, left fixup)],[mhseq14],[ | ||
186 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
187 | rm Mail/inbox/1 Mail/inbox/2 | ||
188 | mhseq 1:3 | ||
189 | ], | ||
190 | [0], | ||
191 | [3 | ||
192 | 4 | ||
193 | 5 | ||
194 | ]) | ||
195 | |||
196 | MH_CHECK([mhseq: counted range (positive, right fixup)],[mhseq15],[ | ||
197 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
198 | mhseq 2:10 | ||
199 | ], | ||
200 | [0], | ||
201 | [2 | ||
202 | 3 | ||
203 | 4 | ||
204 | 5 | ||
205 | ]) | ||
206 | |||
207 | MH_CHECK([mhseq: invalid counted range (negative)],[mhseq16],[ | ||
208 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
209 | rm Mail/inbox/1 Mail/inbox/2 | ||
210 | mhseq 10:2 | ||
211 | ], | ||
212 | [1], | ||
213 | [], | ||
214 | [mhseq: no messages in range 10:2 | ||
215 | ]) | ||
216 | |||
217 | MH_CHECK([mhseq: counted range (negative)],[mhseq17],[ | ||
218 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox]) | ||
219 | mhseq 10:-4 | ||
220 | ], | ||
221 | [0], | ||
222 | [7 | ||
223 | 8 | ||
224 | 9 | ||
225 | 10 | ||
226 | ]) | ||
227 | |||
228 | MH_CHECK([mhseq: non-contiguous counted range (negative)],[mhseq18],[ | ||
229 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/teaparty,[Mail/inbox]) | ||
230 | rm Mail/inbox/8 Mail/inbox/6 | ||
231 | mhseq 10:-4 | ||
232 | ], | ||
233 | [0], | ||
234 | [5 | ||
235 | 7 | ||
236 | 9 | ||
237 | 10 | ||
238 | ]) | ||
239 | |||
240 | MH_CHECK([mhseq: counted range (negative, left fixup)],[mhseq19],[ | ||
241 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
242 | rm Mail/inbox/1 Mail/inbox/2 | ||
243 | mhseq 4:-30 | ||
244 | ], | ||
245 | [0], | ||
246 | [3 | ||
247 | 4 | ||
248 | ]) | ||
249 | |||
250 | MH_CHECK([mhseq: counted range (negative, right fixup)],[mhseq20],[ | ||
251 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
252 | rm Mail/inbox/1 Mail/inbox/2 | ||
253 | mhseq 4:30 | ||
254 | ], | ||
255 | [0], | ||
256 | [4 | ||
257 | 5 | ||
258 | ]) | ||
259 | |||
260 | MH_CHECK([mhseq: invalid counted range (negative)],[mhseq21],[ | ||
261 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
262 | rm Mail/inbox/1 Mail/inbox/2 | ||
263 | mhseq 1:-30 | ||
264 | ], | ||
265 | [1], | ||
266 | [], | ||
267 | [mhseq: no messages in range 1:-30 | ||
268 | ]) | ||
269 | |||
270 | MH_CHECK([mhseq: cur],[mhseq22 cur],[ | ||
271 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
272 | echo "cur: 3" > Mail/inbox/.mh_sequences | ||
273 | mhseq cur | ||
274 | ], | ||
275 | [0], | ||
276 | [3 | ||
277 | ]) | ||
278 | |||
279 | MH_CHECK([mhseq: cur:n -- default direction],[mhseq23 cur:n],[ | ||
280 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
281 | echo "cur: 3" > Mail/inbox/.mh_sequences | ||
282 | mhseq cur:2 | ||
283 | ], | ||
284 | [0], | ||
285 | [3 | ||
286 | 4 | ||
287 | ]) | ||
288 | |||
289 | MH_CHECK([mhseq: cur:n -- explicit dir (negative)],[mhseq24 cur:n cur:n-],[ | ||
290 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
291 | echo "cur: 3" > Mail/inbox/.mh_sequences | ||
292 | mhseq cur:-2 | ||
293 | ], | ||
294 | [0], | ||
295 | [2 | ||
296 | 3 | ||
297 | ]) | ||
298 | |||
299 | MH_CHECK([mhseq: cur:n -- explicit dir (positive)],[mhseq25 cur:n cur:n+],[ | ||
300 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
301 | echo "cur: 3" > Mail/inbox/.mh_sequences | ||
302 | mhseq cur:+2 | ||
303 | ], | ||
304 | [0], | ||
305 | [3 | ||
306 | 4 | ||
307 | ]) | ||
308 | |||
309 | MH_CHECK([mhseq: next],[mhseq26 next],[ | ||
310 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
311 | echo "cur: 3" > Mail/inbox/.mh_sequences | ||
312 | rm Mail/inbox/4 | ||
313 | mhseq next | ||
314 | ], | ||
315 | [0], | ||
316 | [5 | ||
317 | ]) | ||
318 | |||
319 | MH_CHECK([mhseq: next:n -- default direction],[mhseq27 next:n],[ | ||
320 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
321 | echo "cur: 3" > Mail/inbox/.mh_sequences | ||
322 | mhseq next:2 | ||
323 | ], | ||
324 | [0], | ||
325 | [4 | ||
326 | 5 | ||
327 | ]) | ||
328 | |||
329 | MH_CHECK([mhseq: prev],[mhseq28 prev],[ | ||
330 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
331 | echo "cur: 3" > Mail/inbox/.mh_sequences | ||
332 | rm Mail/inbox/2 | ||
333 | mhseq prev | ||
334 | ], | ||
335 | [0], | ||
336 | [1 | ||
337 | ]) | ||
338 | |||
339 | MH_CHECK([mhseq: prev:n -- default direction],[mhseq29 prev:n],[ | ||
340 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
341 | echo "cur: 3" > Mail/inbox/.mh_sequences | ||
342 | mhseq prev:2 | ||
343 | ], | ||
344 | [0], | ||
345 | [1 | ||
346 | 2 | ||
347 | ]) | ||
348 | |||
349 | MH_CHECK([mhseq: first],[mhseq30 first],[ | ||
350 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
351 | rm Mail/inbox/1 | ||
352 | mhseq first | ||
353 | ], | ||
354 | [0], | ||
355 | [2 | ||
356 | ]) | ||
357 | |||
358 | MH_CHECK([mhseq: first:n -- default direction],[mhseq31 first:n],[ | ||
359 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
360 | rm Mail/inbox/1 | ||
361 | mhseq first:2 | ||
362 | ], | ||
363 | [0], | ||
364 | [2 | ||
365 | 3 | ||
366 | ]) | ||
367 | |||
368 | MH_CHECK([mhseq: last],[mhseq32 last],[ | ||
369 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
370 | mhseq last | ||
371 | ], | ||
372 | [0], | ||
373 | [5 | ||
374 | ]) | ||
375 | |||
376 | MH_CHECK([mhseq: last:n -- default direction],[mhseq33 last:n],[ | ||
377 | MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox]) | ||
378 | mhseq last:2 | ||
379 | ], | ||
380 | [0], | ||
381 | [4 | ||
382 | 5 | ||
383 | ]) | ||
384 | |||
385 | m4_popdef([MH_KEYWORDS]) | ||
386 | # End of mhseq.at | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -42,6 +42,7 @@ AT_CLEANUP | ... | @@ -42,6 +42,7 @@ AT_CLEANUP |
42 | AT_INIT | 42 | AT_INIT |
43 | 43 | ||
44 | m4_include([install-mh.at]) | 44 | m4_include([install-mh.at]) |
45 | m4_include([mhseq.at]) | ||
45 | m4_include([ali.at]) | 46 | m4_include([ali.at]) |
46 | m4_include([folder.at]) | 47 | m4_include([folder.at]) |
47 | m4_include([inc.at]) | 48 | m4_include([inc.at]) |
... | @@ -56,3 +57,4 @@ m4_include([mhl.at]) | ... | @@ -56,3 +57,4 @@ m4_include([mhl.at]) |
56 | m4_include([anno.at]) | 57 | m4_include([anno.at]) |
57 | m4_include([pick.at]) | 58 | m4_include([pick.at]) |
58 | m4_include([burst.at]) | 59 | m4_include([burst.at]) |
60 | m4_include([comp.at]) | ... | ... |
-
Please register or sign in to post a comment