Commit e34d8c16 e34d8c168f9031dbfc2441006e0eb24182ef4389 by Sergey Poznyakoff

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.
1 parent e6927c46
...@@ -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 {
......
...@@ -23,6 +23,7 @@ mh_alias_lex.c ...@@ -23,6 +23,7 @@ mh_alias_lex.c
23 mh_fmtgram.c 23 mh_fmtgram.c
24 mhl 24 mhl
25 mhn 25 mhn
26 mhseq
26 mhparam 27 mhparam
27 mhpath 28 mhpath
28 pick 29 pick
......
...@@ -33,6 +33,7 @@ bin_PROGRAMS = \ ...@@ -33,6 +33,7 @@ bin_PROGRAMS = \
33 mhn\ 33 mhn\
34 mhparam\ 34 mhparam\
35 mhpath\ 35 mhpath\
36 mhseq\
36 pick\ 37 pick\
37 prompter\ 38 prompter\
38 refile\ 39 refile\
......
...@@ -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,68 +206,90 @@ main (int argc, char **argv) ...@@ -205,68 +206,90 @@ 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)
211 wh_env.file = mh_expand_name (NULL, "draft", 0); 216 {
217 switch (argc - index)
218 {
219 case 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 }
240 260 wh_env.draftfile = wh_env.file;
241 switch (check_draft_disposition (&wh_env, use_draft))
242 {
243 case DISP_QUIT:
244 exit (0);
245 261
246 case DISP_USE: 262 if (folder_set && index < argc)
247 break; 263 {
248 264 mh_msgset_t msgset;
249 case DISP_REPLACE: 265 mu_mailbox_t mbox;
250 unlink (wh_env.draftfile); 266
251 267 mbox = mh_open_folder (mh_current_folder (), 0);
252 if (index < argc) 268 mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur");
269 if (msgset.count != 1)
253 { 270 {
254 mh_msgset_t msgset; 271 mu_error (_("only one message at a time!"));
255 mu_mailbox_t mbox; 272 return 1;
273 }
274 unlink (wh_env.file);
275 copy_message (mbox, msgset.list[0], wh_env.file);
276 mu_mailbox_destroy (&mbox);
277 mh_msgset_free (&msgset);
278 }
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;
256 288
257 mbox = mh_open_folder (mh_current_folder (), 0); 289 case DISP_REPLACE:
258 mh_msgset_parse (mbox, &msgset, argc - index, argv + index, "cur"); 290 unlink (wh_env.draftfile);
259 if (msgset.count != 1) 291 mh_comp_draft (formfile, "components", wh_env.file);
260 {
261 mu_error (_("only one message at a time!"));
262 return 1;
263 }
264 copy_message (mbox, msgset.list[0], wh_env.file);
265 mu_mailbox_destroy (&mbox);
266 mh_msgset_free (&msgset);
267 } 292 }
268 else
269 mh_comp_draft (formfile, "components", wh_env.file);
270 } 293 }
271 294
272 /* Exit immediately if --build is given */ 295 /* Exit immediately if --build is given */
......
...@@ -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,8 +304,8 @@ int mh_message_number (mu_message_t msg, size_t *pnum); ...@@ -300,8 +304,8 @@ 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);
307 void mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset); 311 void mh_msgset_negate (mu_mailbox_t mbox, 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
1007 uid = msgset.list[0]; 1005 {
1008 1006 mh_msgset_uids (mbox, &msgset);
1007 uid = msgset.list[0];
1008 }
1009 mh_msgset_free (&msgset); 1009 mh_msgset_free (&msgset);
1010 } 1010 }
1011 1011
......
...@@ -19,473 +19,184 @@ ...@@ -19,473 +19,184 @@
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 */ 42
45 43 void
46 static int 44 mh_msgset_init (mh_msgset_t *msgset)
47 msgset_first (mu_mailbox_t mbox, size_t *pnum)
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;
66 return 0;
67 } 60 }
68 61
69 static int 62 void
70 msgset_cur (mu_mailbox_t mbox, size_t *pnum) 63 mh_msgset_add (mh_msgset_t *msgset, size_t n)
71 { 64 {
72 size_t i, count = 0; 65 mh_msgset_expand (msgset, 1);
73 static int cached_n = 0; 66 msgset->list[msgset->count++] = n;
74 size_t cur;
75
76 mh_mailbox_get_cur (mbox, &cur);
77
78 if (cached_n)
79 {
80 *pnum = cached_n;
81 return 0;
82 }
83
84 mu_mailbox_messages_count (mbox, &count);
85 for (i = 1; i <= count; i++)
86 {
87 mu_message_t msg = NULL;
88 size_t uid = 0;
89
90 mu_mailbox_get_message (mbox, i, &msg);
91 mh_message_number (msg, &uid);
92 if (uid == cur)
93 {
94 *pnum = cached_n = i;
95 return 0;
96 }
97 }
98 mu_error (_("no cur message"));
99 exit (1);
100 } 67 }
101 68
102 static int 69 static int
103 msgset_prev (mu_mailbox_t mbox, size_t *pnum) 70 comp_mesg (const void *a, const void *b)
104 { 71 {
105 size_t cur_n = 0; 72 size_t an = *(size_t*)a;
106 msgset_cur (mbox, &cur_n); 73 size_t bn = *(size_t*)b;
107 if (cur_n < 1) 74 if (an > bn)
108 { 75 return 1;
109 mu_error (_("no prev message")); 76 else if (an < bn)
110 exit (1); 77 return -1;
111 }
112 *pnum = cur_n - 1;
113 return 0; 78 return 0;
114 } 79 }
115 80
116 static int 81 void
117 msgset_next (mu_mailbox_t mbox, size_t *pnum) 82 mh_msgset_optimize (mh_msgset_t *msgset)
118 { 83 {
119 size_t cur_n = 0, total = 0; 84 size_t i, msgno;
120 msgset_cur (mbox, &cur_n); 85 size_t msgcnt = msgset->count;
121 mu_mailbox_messages_count (mbox, &total); 86 size_t *msglist = msgset->list;
122 if (cur_n + 1 > total) 87
123 { 88 /* Sort the resulting message set */
124 mu_error (_("no next message")); 89 qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
125 exit (1);
126 }
127 *pnum = cur_n + 1;
128 return 0;
129 }
130 90
131 static struct msgset_keyword { 91 /* Remove duplicates. */
132 char *name; 92 for (i = 0, msgno = 1; i < msgset->count; i++)
133 int (*handler) (mu_mailbox_t mbox, size_t *pnum); 93 if (msglist[msgno-1] != msglist[i])
134 } keywords[] = { 94 msglist[msgno++] = msglist[i];
135 { "first", msgset_first }, 95 msgset->count = msgno;
136 { "last", msgset_last }, 96 }
137 { "prev", msgset_prev },
138 { "next", msgset_next },
139 { "cur", msgset_cur },
140 { NULL },
141 };
142 97
143 /* Preprocess a part of a complex message designation. Returns 98 /* Check if message with ordinal number `num' is contained in the
144 a pointer to the allocated memory containing expanded part of 99 message set. */
145 the designation. Pointer to the beginning of the not expanded 100 int
146 part (in arg) is placed into *rest */ 101 mh_msgset_member (mh_msgset_t *msgset, size_t num)
147 static char *
148 msgset_preproc_part (mu_mailbox_t mbox, char *arg, char **rest)
149 { 102 {
150 struct msgset_keyword *p; 103 size_t i;
151 char *cp;
152
153 for (p = keywords; p->name; p++)
154 if (strncmp (arg, p->name, strlen (p->name)) == 0)
155 {
156 int rc;
157 size_t uid, num;
158 mu_message_t msg;
159
160 if (p->handler (mbox, &num))
161 msgset_abort (arg);
162 rc = mu_mailbox_get_message (mbox, num, &msg);
163 if (rc)
164 {
165 mu_error (_("cannot get message %lu: %s"),
166 (unsigned long) num, mu_strerror (rc));
167 exit (1);
168 }
169 *rest = arg + strlen (p->name);
170 mu_message_get_uid (msg, &uid);
171 return xstrdup (mu_umaxtostr (0, uid));
172 }
173 cp = strchr (arg, '-');
174 if (cp)
175 {
176 char *ret;
177
178 *rest = cp;
179 ret = xmalloc (cp - arg + 1);
180 memcpy (ret, arg, cp - arg);
181 ret[cp - arg] = 0;
182 return ret;
183 }
184 104
185 *rest = arg + strlen (arg); 105 for (i = 0; i < msgset->count; i++)
186 return strdup (arg); 106 if (msgset->list[i] == num)
107 return i + 1;
108 return 0;
187 } 109 }
188 110
189 /* Preprocess (expand) a single message designation */ 111 /* Reverse the order of messages in the message set */
190 static char * 112 void
191 msgset_preproc (mu_mailbox_t mbox, char *arg) 113 mh_msgset_reverse (mh_msgset_t *msgset)
192 { 114 {
193 char *buf, *tail; 115 int head, tail;
194
195 if (strcmp (arg, "all") == 0 || strcmp (arg, ".") == 0)
196 {
197 /* Special case */
198 arg = "first-last";
199 }
200 116
201 buf = msgset_preproc_part (mbox, arg, &tail); 117 for (head = 0, tail = msgset->count-1; head < tail; head++, tail--)
202 if (tail[0] == '-')
203 {
204 char *rest = msgset_preproc_part (mbox, tail+1, &tail);
205 char *p = NULL;
206 mu_asprintf (&p, "%s-%s", buf, rest);
207 free (rest);
208 free (buf);
209 buf = p;
210 }
211
212 if (tail[0])
213 { 118 {
214 char *p = NULL; 119 size_t val = msgset->list[head];
215 mu_asprintf (&p, "%s%s", buf, tail); 120 msgset->list[head] = msgset->list[tail];
216 free (buf); 121 msgset->list[tail] = val;
217 buf = p;
218 } 122 }
219 return buf;
220 } 123 }
221 124
222 static int 125 /* Set the current message to that contained at position `index'
223 comp_mesg (const void *a, const void *b) 126 in the given message set */
224 { 127 void
225 if (*(size_t*)a > *(size_t*)b) 128 mh_msgset_current (mu_mailbox_t mbox, mh_msgset_t *msgset, int index)
226 return 1;
227 else if (*(size_t*)a < *(size_t*)b)
228 return -1;
229 return 0;
230 }
231
232 static int _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
233 int argc, char **argv);
234
235 /* Treat arg as a name of user-defined sequence and attempt to
236 expand it. Return 0 if succeeded, non-zero otherwise. */
237 int
238 expand_user_seq (mu_mailbox_t mbox, mh_msgset_t *msgset, char *arg)
239 { 129 {
240 struct mu_wordsplit ws; 130 mu_message_t msg = NULL;
241 char *p; 131 int rc;
242 const char *listp; 132 size_t cur;
243 int rc = 1;
244 int negate = 0;
245
246 p = strchr (arg, ':');
247 if (p)
248 *p++ = 0;
249 listp = mh_global_sequences_get (mbox, arg, NULL);
250 if (!listp)
251 {
252 int len;
253 const char *neg = mh_global_profile_get ("Sequence-Negation", NULL);
254 if (!neg)
255 return 1;
256 len = strlen (neg);
257 if (strncmp (arg, neg, len))
258 return 1;
259 negate = 1;
260 listp = mh_global_sequences_get (mbox, arg + len, NULL);
261 if (!listp)
262 return 1;
263 }
264
265 if (mu_wordsplit (listp, &ws, MU_WRDSF_DEFFLAGS))
266 {
267 mu_error (_("cannot split line `%s': %s"), listp,
268 mu_wordsplit_strerror (&ws));
269 }
270 else
271 {
272 rc = _mh_msgset_parse (mbox, msgset, ws.ws_wordc, ws.ws_wordv);
273 mu_wordsplit_free (&ws);
274 }
275 133
134 rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
276 if (rc) 135 if (rc)
277 return rc;
278
279 if (negate)
280 mh_msgset_negate (mbox, msgset);
281
282 if (p)
283 { 136 {
284 int first, num; 137 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc);
285 138 exit (1);
286 num = strtoul (p, &p, 0);
287 if (*p)
288 {
289 mh_msgset_free (msgset);
290 return 1;
291 }
292 if (num < 0)
293 {
294 first = num + msgset->count;
295 num = - num;
296 }
297 else
298 first = 0;
299 if (num > msgset->count)
300 {
301 mh_msgset_free (msgset);
302 return 1;
303 }
304
305 if (first > 0)
306 memmove (msgset->list, &msgset->list[first],
307 sizeof (msgset->list[0]) * num);
308 msgset->count = num;
309 } 139 }
310 140 mh_message_number (msg, &cur);
311 return rc; 141 mh_mailbox_set_cur (mbox, cur);
312 } 142 }
313 143
314 /* Parse a message specification from (argc;argv). Returned msgset is 144 /* Free memory allocated for the message set. Note, that the msgset
315 not sorted nor optimised */ 145 itself is supposed to reside in the statically allocated memory and
316 int 146 therefore is not freed */
317 _mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, int argc, char **argv) 147 void
148 mh_msgset_free (mh_msgset_t *msgset)
318 { 149 {
319 size_t msgcnt; 150 if (msgset->count)
320 size_t *msglist; 151 free (msgset->list);
321 size_t i, msgno;
322
323 if (argc == 0)
324 return 1;
325
326 msgcnt = argc;
327 msglist = calloc (msgcnt, sizeof(*msglist));
328 for (i = 0, msgno = 0; i < argc; i++)
329 {
330 char *p = NULL, *q;
331 size_t start, end;
332 size_t msg_first, n;
333 long num;
334 char *arg = msgset_preproc (mbox, argv[i]);
335
336 if (!mu_isdigit (arg[0]))
337 {
338 int j;
339 mh_msgset_t m;
340
341 if (expand_user_seq (mbox, &m, arg))
342 {
343 mu_error (_("message set %s does not exist"), arg);
344 exit (1);
345 }
346 _expand (&msgcnt, &msglist, m.count);
347 for (j = 0; j < m.count; j++)
348 msglist[msgno++] = m.list[j];
349 mh_msgset_free (&m);
350 }
351 else
352 {
353 start = strtoul (arg, &p, 0);
354 switch (*p)
355 {
356 case 0:
357 n = mh_get_message (mbox, start, NULL);
358 if (!n)
359 {
360 mu_error (_("message %lu does not exist"),
361 (unsigned long) start);
362 exit (1);
363 }
364 msglist[msgno++] = n;
365 break;
366
367 case '-':
368 end = strtoul (p+1, &p, 0);
369 if (*p)
370 msgset_abort (argv[i]);
371 if (end < start)
372 {
373 size_t t = start;
374 start = end;
375 end = t;
376 }
377 _expand (&msgcnt, &msglist, end - start);
378 msg_first = msgno;
379 for (; start <= end; start++)
380 {
381 n = mh_get_message (mbox, start, NULL);
382 if (n)
383 msglist[msgno++] = n;
384 }
385 if (msgno == msg_first)
386 {
387 mu_error (_("no messages in range %s"), argv[i]);
388 exit (1);
389 }
390 break;
391
392 case ':':
393 num = strtoul (p+1, &q, 0);
394 if (*q)
395 msgset_abort (argv[i]);
396 if (p[1] != '+' && p[1] != '-')
397 {
398 if (strncmp (argv[i], "last:", 5) == 0
399 || strncmp (argv[i], "prev:", 5) == 0)
400 num = -num;
401 }
402 end = start + num;
403 if (end < start)
404 {
405 size_t t = start;
406 start = end + 1;
407 end = t;
408 }
409 else
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 }
419 if (msgno == msg_first)
420 {
421 mu_error (_("no messages in range %s"), argv[i]);
422 exit (1);
423 }
424 break;
425
426 default:
427 msgset_abort (argv[i]);
428 }
429 }
430 free (arg);
431 }
432
433 msgset->count = msgno;
434 msgset->list = msglist;
435 return 0;
436 } 152 }
437 153
438 /* Parse a message specification from (argc;argv). Returned msgset is 154 /* Negate the message set: on return `msgset' consists of the messages
439 sorted and optimised (i.e. it does not contain duplicate message 155 _not contained_ in the input message set. Any memory associated with
440 numbers) */ 156 the input message set is freed */
441 int 157 void
442 mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset, 158 mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset)
443 int argc, char **argv, char *def)
444 { 159 {
445 char *xargv[2]; 160 size_t i, total = 0, msgno;
446 int rc; 161 size_t *list;
447 162
448 if (argc == 0) 163 mu_mailbox_messages_count (mbox, &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++)
449 { 168 {
450 argc = 1; 169 if (!mh_msgset_member (msgset, i))
451 argv = xargv; 170 list[msgno++] = i;
452 argv[0] = def ? def : "cur";
453 argv[1] = NULL;
454 } 171 }
455
456 rc = _mh_msgset_parse (mbox, msgset, argc, argv);
457 172
458 if (rc == 0) 173 list = realloc (list, sizeof (list[0]) * msgno);
174 if (!list)
459 { 175 {
460 size_t i, msgno; 176 mu_error (_("not enough memory"));
461 size_t msgcnt = msgset->count; 177 abort ();
462 size_t *msglist = msgset->list;
463
464 /* Sort the resulting message set */
465 qsort (msglist, msgcnt, sizeof (*msgset->list), comp_mesg);
466
467 /* Remove duplicates. */
468 for (i = 0, msgno = 1; i < msgset->count; i++)
469 if (msglist[msgno-1] != msglist[i])
470 msglist[msgno++] = msglist[i];
471 msgset->count = msgno;
472 } 178 }
473 return rc; 179 mh_msgset_free (msgset);
180 msgset->count = msgno;
181 msgset->list = list;
474 } 182 }
475 183
476 /* Check if message with ordinal number `num' is contained in the 184 void
477 message set. */ 185 mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset)
478 int
479 mh_msgset_member (mh_msgset_t *msgset, size_t num)
480 { 186 {
481 size_t i; 187 size_t i;
482 188
189 if (msgset->flags & MH_MSGSET_UID)
190 return;
483 for (i = 0; i < msgset->count; i++) 191 for (i = 0; i < msgset->count; i++)
484 if (msgset->list[i] == num) 192 {
485 return i + 1; 193 mu_message_t msg;
486 return 0; 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;
487 } 198 }
488 199
489 /* Auxiliary function. Performs binary search for a message with the 200 /* Auxiliary function. Performs binary search for a message with the
490 given sequence number */ 201 given sequence number */
491 static size_t 202 static size_t
...@@ -555,87 +266,457 @@ mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg) ...@@ -555,87 +266,457 @@ mh_get_message (mu_mailbox_t mbox, size_t seqno, mu_message_t *mesg)
555 return mh_search_message (mbox, 1, count, seqno, mesg); 266 return mh_search_message (mbox, 1, count, seqno, mesg);
556 } 267 }
557 268
558 /* Reverse the order of messages in the message set */ 269
559 void 270 struct msgset_parser
560 mh_msgset_reverse (mh_msgset_t *msgset)
561 { 271 {
562 int head, tail; 272 mu_mailbox_t mbox;
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 };
563 282
564 for (head = 0, tail = msgset->count-1; head < tail; head++, tail--) 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);
309 }
310
311 /* Advance parser to the next argument */
312 static int
313 nextarg (struct msgset_parser *parser)
314 {
315 if (parser->argc == 0)
316 return 0;
317 parser->argc--;
318 parser->curp = *parser->argv++;
319 return 1;
320 }
321
322 static void msgset_parser_run (struct msgset_parser *parser);
323
324 static int
325 _expand_sequence (struct msgset_parser *parser, char *term)
326 {
327 struct mu_wordsplit ws;
328 const char *listp;
329 int negate = 0;
330
331 listp = mh_global_sequences_get (parser->mbox, term, NULL);
332 if (!listp)
565 { 333 {
566 size_t val = msgset->list[head]; 334 int len;
567 msgset->list[head] = msgset->list[tail]; 335 const char *neg = mh_global_profile_get ("Sequence-Negation", NULL);
568 msgset->list[tail] = val; 336 if (!neg)
337 return 1;
338 len = strlen (neg);
339 if (strncmp (term, neg, len))
340 return 1;
341 negate = 1;
342 listp = mh_global_sequences_get (parser->mbox, term + len, NULL);
343 if (!listp)
344 return 1;
345 }
346
347 if (mu_wordsplit (listp, &ws, MU_WRDSF_DEFFLAGS))
348 {
349 mu_error (_("cannot split line `%s': %s"), listp,
350 mu_wordsplit_strerror (&ws));
351 exit (1);
352 }
353 else
354 {
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);
360 mu_wordsplit_free (&ws);
569 } 361 }
362
363 if (negate)
364 mh_msgset_negate (parser->mbox, parser->msgset);
365 return 0;
570 } 366 }
571 367
572 /* Set the current message to that contained at position `index' 368 static int
573 in the given message set */ 369 parse_count (struct msgset_parser *parser)
574 void 370 {
575 mh_msgset_current (mu_mailbox_t mbox, mh_msgset_t *msgset, int index) 371 char *endp;
372 if (!*parser->curp && nextarg (parser) == 0)
373 return 0;
374 if (*parser->curp == '-')
375 {
376 parser->sign = 1;
377 parser->curp++;
378 }
379 else if (*parser->curp == '+')
380 {
381 parser->sign = 0;
382 parser->curp++;
383 }
384 parser->number = strtoul (parser->curp, &endp, 10);
385 if (*endp)
386 msgset_abort (parser->curp);
387 parser->curp = endp;
388 return 1;
389 }
390
391
392 static int
393 msgset_first (mu_mailbox_t mbox, size_t *pnum)
394 {
395 *pnum = 1;
396 return 0;
397 }
398
399 static int
400 msgset_last (mu_mailbox_t mbox, size_t *pnum)
576 { 401 {
577 mu_message_t msg = NULL;
578 int rc; 402 int rc;
579 size_t cur; 403
580 404 rc = mu_mailbox_messages_count (mbox, pnum);
581 rc = mu_mailbox_get_message (mbox, msgset->list[index], &msg);
582 if (rc) 405 if (rc)
583 { 406 {
584 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_message", NULL, rc); 407 mu_error (_("cannot get last message: %s"), mu_strerror (rc));
585 exit (1); 408 exit (1);
586 } 409 }
587 mh_message_number (msg, &cur); 410 return 0;
588 mh_mailbox_set_cur (mbox, cur);
589 } 411 }
590 412
591 /* Free memory allocated for the message set. Note, that the msgset 413 static int
592 itself is supposed to reside in the statically allocated memory and 414 msgset_cur (mu_mailbox_t mbox, size_t *pnum)
593 therefore is not freed */
594 void
595 mh_msgset_free (mh_msgset_t *msgset)
596 { 415 {
597 if (msgset->count) 416 size_t num;
598 free (msgset->list); 417 mh_mailbox_get_cur (mbox, &num);
418 return mh_uid_to_msgno (mbox, num, pnum);
599 } 419 }
600 420
601 /* Negate the message set: on return `msgset' consists of the messages 421 static int
602 _not contained_ in the input message set. Any memory associated with 422 msgset_prev (mu_mailbox_t mbox, size_t *pnum)
603 the input message set is freed */
604 void
605 mh_msgset_negate (mu_mailbox_t mbox, mh_msgset_t *msgset)
606 { 423 {
607 size_t i, total = 0, msgno; 424 size_t cur_n = 0;
608 size_t *list; 425 msgset_cur (mbox, &cur_n);
426 if (cur_n < 1)
427 {
428 mu_error (_("no prev message"));
429 exit (1);
430 }
431 *pnum = cur_n - 1;
432 return 0;
433 }
609 434
435 static int
436 msgset_next (mu_mailbox_t mbox, size_t *pnum)
437 {
438 size_t cur_n = 0, total = 0;
439 msgset_cur (mbox, &cur_n);
610 mu_mailbox_messages_count (mbox, &total); 440 mu_mailbox_messages_count (mbox, &total);
611 list = calloc (total, sizeof (list[0])); 441 if (cur_n + 1 > total)
612 if (!list)
613 mh_err_memory (1);
614 for (i = 1, msgno = 0; i <= total; i++)
615 { 442 {
616 if (!mh_msgset_member (msgset, i)) 443 mu_error (_("no next message"));
617 list[msgno++] = i; 444 exit (1);
618 } 445 }
446 *pnum = cur_n + 1;
447 return 0;
448 }
619 449
620 list = realloc (list, sizeof (list[0]) * msgno); 450 struct msgset_keyword
621 if (!list) 451 {
452 char *name;
453 size_t len;
454 int (*handler) (mu_mailbox_t mbox, size_t *pnum);
455 int sign;
456 };
457
458 static struct msgset_keyword keywords[] = {
459 #define S(s) #s, sizeof (#s) - 1
460 { S(first), msgset_first, 0 },
461 { S(last), msgset_last, 1 },
462 { S(prev), msgset_prev, 1 },
463 { S(next), msgset_next, 0 },
464 { S(cur), msgset_cur, 0 },
465 { NULL }
466 };
467
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))
622 { 493 {
623 mu_error (_("not enough memory")); 494 struct msgset_keyword *p;
624 abort (); 495
496 for (p = keywords; p->name; p++)
497 if (tlen == p->len && memcmp (p->name, term, tlen) == 0)
498 {
499 if (p->handler (parser->mbox, &parser->number))
500 msgset_abort (term);
501 parser->sign = p->sign;
502 parser->validuid = 1;
503 return PARSE_MORE;
504 }
505
506 if (*parser->curp == 0 && seq)
507 {
508 /* See if it is a user-defined sequence */
509 if (_expand_sequence (parser, term) == 0)
510 return PARSE_SUCCESS;
511 }
512 msgset_abort (term);
625 } 513 }
626 mh_msgset_free (msgset); 514 else if (mu_isdigit (*term))
627 msgset->count = msgno; 515 {
628 msgset->list = list; 516 char *endp;
517 size_t num = strtoul (term, &endp, 10);
518 if (endp != parser->curp)
519 msgset_abort (term);
520
521 if (mh_uid_to_msgno (parser->mbox, num, &parser->number))
522 {
523 parser->validuid = 0;
524 parser->number = num;
525 }
526 else
527 parser->validuid = 1;
528 parser->sign = 0;
529 }
530 else
531 msgset_abort (term);
532 return PARSE_MORE;
629 } 533 }
630 534
631 void 535 static void
632 mh_msgset_uids (mu_mailbox_t mbox, mh_msgset_t *msgset) 536 add_messages (struct msgset_parser *parser, size_t start, size_t count,
537 int sign)
633 { 538 {
634 size_t i; 539 size_t i;
635 for (i = 0; i < msgset->count; i++) 540
541 if (start == 0)
542 start = 1;
543 mh_msgset_expand (parser->msgset, count);
544 if (sign)
636 { 545 {
637 mu_message_t msg; 546 if (count > start)
638 mu_mailbox_get_message (mbox, msgset->list[i], &msg); 547 count = start;
639 mh_message_number (msg, &msgset->list[i]); 548 for (i = 0; i < count; i++, start--)
549 parser->msgset->list[parser->msgset->count++] = start;
550 }
551 else
552 {
553 size_t total;
554
555 mu_mailbox_messages_count (parser->mbox, &total);
556 if (start + count > total)
557 count = total - start + 1;
558 for (i = 0; i < count; i++, start++)
559 parser->msgset->list[parser->msgset->count++] = start;
560 }
561 if (count == 0)
562 emptyrange_abort (parser->argv[-1]);
563 }
564
565 static void
566 add_message_range (struct msgset_parser *parser, size_t start, size_t end)
567 {
568 if (end == start)
569 emptyrange_abort (parser->argv[-1]);
570
571 if (end < start)
572 {
573 size_t t = start;
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;
581 }
582
583 /* range: term '-' term
584 | term ':' count
585 ;
586 count: NUMBER
587 | '+' NUMBER
588 | '-' NUMBER
589 ;
590 */
591 static int
592 parse_range (struct msgset_parser *parser)
593 {
594 size_t start;
595
596 switch (parse_term (parser, 1))
597 {
598 case PARSE_EOF:
599 return 0;
600
601 case PARSE_SUCCESS:
602 return 1;
603
604 case PARSE_MORE:
605 break;
606 }
607
608 start = parser->number;
609
610 if (*parser->curp == ':')
611 {
612 int validuid = parser->validuid;
613 parser->curp++;
614 if (parse_count (parser) == 0)
615 return 0;
616 if (!validuid)
617 {
618 size_t total, lastuid;
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);
635 return 1;
636 }
637 else if (*parser->curp == '-')
638 {
639 size_t lastuid = 0;
640 int validuid = parser->validuid;
641
642 parser->curp++;
643 if (parse_term (parser, 0) == PARSE_EOF)
644 return 0;
645 if (!parser->validuid)
646 {
647 size_t total;
648
649 msgset_last (parser->mbox, &total);
650 mh_msgno_to_uid (parser->mbox, total, &lastuid);
651 if (parser->number > lastuid)
652 parser->number = total;
653 else if (!validuid)
654 emptyrange_abort (parser->argv[-1]);
655 }
656 if (!validuid)
657 {
658 if (!lastuid)
659 {
660 size_t total;
661 msgset_last (parser->mbox, &total);
662 mh_msgno_to_uid (parser->mbox, total, &lastuid);
663 }
664 if (start > lastuid && !parser->validuid)
665 emptyrange_abort (parser->argv[-1]);
666 start = 1;
667 }
668 add_message_range (parser, start, parser->number);
640 } 669 }
670 else if (!parser->validuid)
671 {
672 mu_error (_("message %s does not exist"), parser->argv[-1]);
673 exit (1);
674 }
675 else
676 mh_msgset_add (parser->msgset, start);
677 return 1;
678 }
679
680
681 /* Parse a message specification. The composed msgset is
682 not sorted nor optimised */
683 static void
684 msgset_parser_run (struct msgset_parser *parser)
685 {
686 while (parse_range (parser))
687 ;
688 }
689
690 /* Parse a message specification from (argc;argv). Returned msgset is
691 sorted and optimised (i.e. it does not contain duplicate message
692 numbers) */
693 void
694 mh_msgset_parse (mu_mailbox_t mbox, mh_msgset_t *msgset,
695 int argc, char **argv, char *def)
696 {
697 struct msgset_parser parser;
698 char *xargv[2];
699
700 if (argc == 0)
701 {
702 argc = 1;
703 argv = xargv;
704 argv[0] = def ? def : "cur";
705 argv[1] = NULL;
706 }
707
708 if (argc == 1 &&
709 (strcmp (argv[0], "all") == 0 || strcmp (argv[0], ".") == 0))
710 {
711 argc = 1;
712 argv = xargv;
713 argv[0] = "first-last";
714 argv[1] = NULL;
715 }
716
717 mh_msgset_init (msgset);
718 msgset_parser_init (&parser, mbox, msgset, argc, argv);
719 msgset_parser_run (&parser);
720
721 mh_msgset_optimize (msgset);
641 } 722 }
......
...@@ -346,18 +346,21 @@ _whatnow (struct mh_whatnow_env *wh, struct action_tab *tab) ...@@ -346,18 +346,21 @@ _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 }
360 361 if (n == 0)
362 break;
363
361 ws.ws_comment = "#"; 364 ws.ws_comment = "#";
362 rc = mu_wordsplit (line, &ws, wsflags); 365 rc = mu_wordsplit (line, &ws, wsflags);
363 if (rc) 366 if (rc)
...@@ -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)
465 annotate (wh); 468 {
469 annotate (wh);
470 return 1;
471 }
466 return 0; 472 return 0;
467 } 473 }
468 474
......
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\
......
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
1 #! /bin/sh
2
3 echo "-- Editor invocation:" $*
4 echo "-- Input file: "
5 cat $1
6 echo "-- Input file end"
7 echo "Seen by mhed" >> $1
8 exit 0
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])
......