]> diplodocus.org Git - nmh/blob - sbr/m_convert.c
Cope with sasl_decode64() returning SASL_CONTINUE as well as SASL_OK.
[nmh] / sbr / m_convert.c
1
2 /*
3 * m_convert.c -- parse a message range or sequence and set SELECTED
4 *
5 * $Id$
6 *
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
10 */
11
12 #include <h/mh.h>
13
14 /*
15 * error codes for sequence
16 * and message range processing
17 */
18 #define BADMSG (-2)
19 #define BADRNG (-3)
20 #define BADNEW (-4)
21 #define BADNUM (-5)
22 #define BADLST (-6)
23
24 #define FIRST 1
25 #define LAST 2
26
27 #define getnew(mp) (mp->hghmsg + 1)
28
29 static int convdir; /* convert direction */
30 static char *delimp;
31
32 /*
33 * static prototypes
34 */
35 static int m_conv (struct msgs *, char *, int);
36 static int attr (struct msgs *, char *);
37
38
39 int
40 m_convert (struct msgs *mp, char *name)
41 {
42 int first, last, found, range, err;
43 unsigned char *bp;
44 char *cp;
45
46 /* check if user defined sequence */
47 err = attr (mp, cp = name);
48
49 if (err == -1)
50 return 0;
51 else if (err < 0)
52 goto badmsg;
53 else if (err > 0)
54 return 1;
55 /*
56 * else err == 0, so continue
57 */
58
59 found = 0;
60
61 /*
62 * Check for special "new" sequence, which
63 * is valid only if ALLOW_NEW is set.
64 */
65 if ((mp->msgflags & ALLOW_NEW) && !strcmp (cp, "new")) {
66 if ((err = first = getnew (mp)) <= 0)
67 goto badmsg;
68 else
69 goto single;
70 }
71
72 if (!strcmp (cp, "all"))
73 cp = "first-last";
74
75 if ((err = first = m_conv (mp, cp, FIRST)) <= 0)
76 goto badmsg;
77
78 cp = delimp;
79 if (*cp != '\0' && *cp != '-' && *cp != ':') {
80 badelim:
81 advise (NULL, "illegal argument delimiter: `%c'(0%o)", *delimp, *delimp);
82 return 0;
83 }
84
85 if (*cp == '-') {
86 cp++;
87 if ((err = last = m_conv (mp, cp, LAST)) <= 0) {
88 badmsg:
89 switch (err) {
90 case BADMSG:
91 advise (NULL, "no %s message", cp);
92 break;
93
94 case BADNUM:
95 advise (NULL, "message %s doesn't exist", cp);
96 break;
97
98 case BADRNG:
99 advise (NULL, "message %s out of range 1-%d", cp, mp->hghmsg);
100 break;
101
102 case BADLST:
103 badlist:
104 advise (NULL, "bad message list %s", name);
105 break;
106
107 case BADNEW:
108 advise (NULL, "folder full, no %s message", name);
109 break;
110
111 default:
112 advise (NULL, "no messages match specification");
113 }
114 return 0;
115 }
116
117 if (last < first)
118 goto badlist;
119 if (*delimp)
120 goto badelim;
121 if (first > mp->hghmsg || last < mp->lowmsg) {
122 rangerr:
123 advise (NULL, "no messages in range %s", name);
124 return 0;
125 }
126
127 /* tighten the range to search */
128 if (last > mp->hghmsg)
129 last = mp->hghmsg;
130 if (first < mp->lowmsg)
131 first = mp->lowmsg;
132
133 } else if (*cp == ':') {
134 cp++;
135 if (*cp == '-') {
136 convdir = -1;
137 cp++;
138 } else {
139 if (*cp == '+') {
140 convdir = 1;
141 cp++;
142 }
143 }
144 if ((range = atoi (bp = cp)) == 0)
145 goto badlist;
146 while (isdigit (*bp))
147 bp++;
148 if (*bp)
149 goto badelim;
150 if ((convdir > 0 && first > mp->hghmsg)
151 || (convdir < 0 && first < mp->lowmsg))
152 goto rangerr;
153
154 /* tighten the range to search */
155 if (first < mp->lowmsg)
156 first = mp->lowmsg;
157 if (first > mp->hghmsg)
158 first = mp->hghmsg;
159
160 for (last = first;
161 last >= mp->lowmsg && last <= mp->hghmsg;
162 last += convdir)
163 if (does_exist (mp, last))
164 if (--range <= 0)
165 break;
166 if (last < mp->lowmsg)
167 last = mp->lowmsg;
168 if (last > mp->hghmsg)
169 last = mp->hghmsg;
170 if (last < first) {
171 range = last;
172 last = first;
173 first = range;
174 }
175 } else {
176
177 single:
178 /*
179 * Single Message
180 *
181 * If ALLOW_NEW is set, then allow selecting of an
182 * empty slot. If ALLOW_NEW is not set, then we
183 * check if message is in-range and exists.
184 */
185 if (mp->msgflags & ALLOW_NEW) {
186 set_select_empty (mp, first);
187 } else {
188 if (first > mp->hghmsg
189 || first < mp->lowmsg
190 || !(does_exist (mp, first))) {
191 if (!strcmp (name, "cur") || !strcmp (name, "."))
192 advise (NULL, "no %s message", name);
193 else
194 advise (NULL, "message %d doesn't exist", first);
195 return 0;
196 }
197 }
198 last = first; /* range of 1 */
199 }
200
201 /*
202 * Cycle through the range and select the messages
203 * that exist. If ALLOW_NEW is set, then we also check
204 * if we are selecting an empty slot.
205 */
206 for (; first <= last; first++) {
207 if (does_exist (mp, first) ||
208 ((mp->msgflags & ALLOW_NEW) && is_select_empty (mp, first))) {
209 if (!is_selected (mp, first)) {
210 set_selected (mp, first);
211 mp->numsel++;
212 if (mp->lowsel == 0 || first < mp->lowsel)
213 mp->lowsel = first;
214 if (first > mp->hghsel)
215 mp->hghsel = first;
216 }
217 found++;
218 }
219 }
220
221 if (!found)
222 goto rangerr;
223
224 return 1;
225 }
226
227 /*
228 * Convert the various message names to
229 * their numeric values.
230 *
231 * n (integer)
232 * prev
233 * next
234 * first
235 * last
236 * cur
237 * . (same as cur)
238 */
239
240 static int
241 m_conv (struct msgs *mp, char *str, int call)
242 {
243 register int i;
244 register unsigned char *cp, *bp;
245 unsigned char buf[16];
246
247 convdir = 1;
248 cp = bp = str;
249 if (isdigit (*cp)) {
250 while (isdigit (*bp))
251 bp++;
252 delimp = bp;
253 i = atoi (cp);
254
255 if (i <= mp->hghmsg)
256 return i;
257 else if (*delimp || call == LAST)
258 return mp->hghmsg + 1;
259 else if (mp->msgflags & ALLOW_NEW)
260 return BADRNG;
261 else
262 return BADNUM;
263 }
264
265 #ifdef LOCALE
266 /* doesn't enforce lower case */
267 for (bp = buf; (isalpha(*cp) || *cp == '.')
268 && (bp - buf < sizeof(buf) - 1); )
269 #else
270 for (bp = buf; ((*cp >= 'a' && *cp <= 'z') || *cp == '.')
271 && (bp - buf < sizeof(buf) - 1); )
272 #endif /* LOCALE */
273 {
274 *bp++ = *cp++;
275 }
276 *bp++ = '\0';
277 delimp = cp;
278
279 if (!strcmp (buf, "first"))
280 return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW)
281 ? mp->lowmsg : BADMSG);
282
283 if (!strcmp (buf, "last")) {
284 convdir = -1;
285 return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW) ? mp->hghmsg : BADMSG);
286 }
287
288 if (!strcmp (buf, "cur") || !strcmp (buf, "."))
289 return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
290
291 if (!strcmp (buf, "prev")) {
292 convdir = -1;
293 for (i = (mp->curmsg <= mp->hghmsg) ? mp->curmsg - 1 : mp->hghmsg;
294 i >= mp->lowmsg; i--) {
295 if (does_exist (mp, i))
296 return i;
297 }
298 return BADMSG;
299 }
300
301 if (!strcmp (buf, "next")) {
302 for (i = (mp->curmsg >= mp->lowmsg) ? mp->curmsg + 1 : mp->lowmsg;
303 i <= mp->hghmsg; i++) {
304 if (does_exist (mp, i))
305 return i;
306 }
307 return BADMSG;
308 }
309
310 return BADLST;
311 }
312
313 /*
314 * Handle user defined sequences.
315 * They can take the following forms:
316 *
317 * seq
318 * seq:prev
319 * seq:next
320 * seq:first
321 * seq:last
322 * seq:+n
323 * seq:-n
324 * seq:n
325 */
326
327 static int
328 attr (struct msgs *mp, char *cp)
329 {
330 register unsigned char *dp;
331 char *bp = NULL;
332 register int i, j;
333 int found,
334 inverted = 0,
335 range = 0, /* no range */
336 first = 0;
337
338 /* hack for "cur-name", "cur-n", etc. */
339 if (!strcmp (cp, "cur"))
340 return 0;
341 if (ssequal ("cur:", cp)) /* this code need to be rewritten... */
342 return 0;
343
344 /* Check for sequence negation */
345 if ((dp = context_find (nsequence)) && *dp != '\0' && ssequal (dp, cp)) {
346 inverted = 1;
347 cp += strlen (dp);
348 }
349
350 convdir = 1; /* convert direction */
351
352 for (dp = cp; *dp && isalnum(*dp); dp++)
353 continue;
354
355 if (*dp == ':') {
356 bp = dp++;
357 range = 1;
358
359 /*
360 * seq:prev (or)
361 * seq:next (or)
362 * seq:first (or)
363 * seq:last
364 */
365 if (isalpha (*dp)) {
366 if (!strcmp (dp, "prev")) {
367 convdir = -1;
368 first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
369 ? mp->curmsg - 1
370 : mp->hghmsg;
371 }
372 else if (!strcmp (dp, "next")) {
373 convdir = 1;
374 first = (mp->curmsg >= mp->lowmsg)
375 ? mp->curmsg + 1
376 : mp->lowmsg;
377 }
378 else if (!strcmp (dp, "first")) {
379 convdir = 1;
380 }
381 else if (!strcmp (dp, "last")) {
382 convdir = -1;
383 }
384 else
385 return BADLST;
386 } else {
387 /*
388 * seq:n (or)
389 * seq:+n (or)
390 * seq:-n
391 */
392 if (*dp == '+')
393 dp++;
394 else if (*dp == '-') {
395 dp++;
396 convdir = -1;
397 }
398 if ((range = atoi(dp)) == 0)
399 return BADLST;
400 while (isdigit (*dp))
401 dp++;
402 if (*dp)
403 return BADLST;
404 }
405
406 *bp = '\0'; /* temporarily terminate sequence name */
407 }
408
409 i = seq_getnum (mp, cp); /* get index of sequence */
410
411 if (bp)
412 *bp = ':'; /* restore sequence name */
413 if (i == -1)
414 return 0;
415
416 found = 0; /* count the number we select for this argument */
417
418 for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg;
419 j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) {
420 if (does_exist (mp, j)
421 && inverted ? !in_sequence (mp, i, j) : in_sequence (mp, i, j)) {
422 if (!is_selected (mp, j)) {
423 set_selected (mp, j);
424 mp->numsel++;
425 if (mp->lowsel == 0 || j < mp->lowsel)
426 mp->lowsel = j;
427 if (j > mp->hghsel)
428 mp->hghsel = j;
429 }
430 found++;
431
432 /*
433 * If we have a range, then break out
434 * once we've found enough.
435 */
436 if (range && found >= range)
437 break;
438 }
439 }
440
441 if (found > 0)
442 return found;
443
444 if (first)
445 return BADMSG;
446 advise (NULL, "sequence %s %s", cp, inverted ? "full" : "empty");
447 return -1;
448 }