Commit | Line | Data |
---|---|---|
9552e6b8 | 1 | /* |
a12ff486 KB |
2 | * Copyright (c) 1980, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
0c5f72fb | 4 | * |
f15db449 | 5 | * %sccs.include.redist.c% |
9552e6b8 DF |
6 | */ |
7 | ||
acfc7e9b | 8 | #ifndef lint |
a12ff486 | 9 | static char sccsid[] = "@(#)list.c 8.1 (Berkeley) %G%"; |
acfc7e9b | 10 | #endif /* not lint */ |
b3149556 KS |
11 | |
12 | #include "rcv.h" | |
13 | #include <ctype.h> | |
a0d23834 | 14 | #include "extern.h" |
b3149556 KS |
15 | |
16 | /* | |
17 | * Mail -- a mail program | |
18 | * | |
19 | * Message list handling. | |
20 | */ | |
21 | ||
b3149556 KS |
22 | /* |
23 | * Convert the user string of message numbers and | |
24 | * store the numbers into vector. | |
25 | * | |
26 | * Returns the count of messages picked up or -1 on error. | |
27 | */ | |
a0d23834 | 28 | int |
b3149556 KS |
29 | getmsglist(buf, vector, flags) |
30 | char *buf; | |
a0d23834 | 31 | int *vector, flags; |
b3149556 KS |
32 | { |
33 | register int *ip; | |
34 | register struct message *mp; | |
35 | ||
c1241556 EW |
36 | if (msgCount == 0) { |
37 | *vector = 0; | |
38 | return 0; | |
39 | } | |
b3149556 KS |
40 | if (markall(buf, flags) < 0) |
41 | return(-1); | |
42 | ip = vector; | |
43 | for (mp = &message[0]; mp < &message[msgCount]; mp++) | |
44 | if (mp->m_flag & MMARK) | |
45 | *ip++ = mp - &message[0] + 1; | |
c1241556 | 46 | *ip = 0; |
b3149556 KS |
47 | return(ip - vector); |
48 | } | |
49 | ||
50 | /* | |
51 | * Mark all messages that the user wanted from the command | |
52 | * line in the message structure. Return 0 on success, -1 | |
53 | * on error. | |
54 | */ | |
55 | ||
2919b83d KS |
56 | /* |
57 | * Bit values for colon modifiers. | |
58 | */ | |
59 | ||
60 | #define CMNEW 01 /* New messages */ | |
61 | #define CMOLD 02 /* Old messages */ | |
62 | #define CMUNREAD 04 /* Unread messages */ | |
63 | #define CMDELETED 010 /* Deleted messages */ | |
64 | #define CMREAD 020 /* Read messages */ | |
65 | ||
66 | /* | |
67 | * The following table describes the letters which can follow | |
68 | * the colon and gives the corresponding modifier bit. | |
69 | */ | |
70 | ||
71 | struct coltab { | |
72 | char co_char; /* What to find past : */ | |
73 | int co_bit; /* Associated modifier bit */ | |
74 | int co_mask; /* m_status bits to mask */ | |
75 | int co_equal; /* ... must equal this */ | |
76 | } coltab[] = { | |
77 | 'n', CMNEW, MNEW, MNEW, | |
78 | 'o', CMOLD, MNEW, 0, | |
79 | 'u', CMUNREAD, MREAD, 0, | |
80 | 'd', CMDELETED, MDELETED, MDELETED, | |
81 | 'r', CMREAD, MREAD, MREAD, | |
82 | 0, 0, 0, 0 | |
83 | }; | |
84 | ||
85 | static int lastcolmod; | |
86 | ||
a0d23834 | 87 | int |
b3149556 KS |
88 | markall(buf, f) |
89 | char buf[]; | |
a0d23834 | 90 | int f; |
b3149556 KS |
91 | { |
92 | register char **np; | |
93 | register int i; | |
2919b83d | 94 | register struct message *mp; |
b3149556 | 95 | char *namelist[NMLSIZE], *bufp; |
2919b83d | 96 | int tok, beg, mc, star, other, valdot, colmod, colresult; |
b3149556 KS |
97 | |
98 | valdot = dot - &message[0] + 1; | |
2919b83d | 99 | colmod = 0; |
b3149556 KS |
100 | for (i = 1; i <= msgCount; i++) |
101 | unmark(i); | |
102 | bufp = buf; | |
103 | mc = 0; | |
104 | np = &namelist[0]; | |
105 | scaninit(); | |
106 | tok = scan(&bufp); | |
107 | star = 0; | |
108 | other = 0; | |
109 | beg = 0; | |
110 | while (tok != TEOL) { | |
111 | switch (tok) { | |
112 | case TNUMBER: | |
113 | number: | |
114 | if (star) { | |
115 | printf("No numbers mixed with *\n"); | |
116 | return(-1); | |
117 | } | |
118 | mc++; | |
119 | other++; | |
120 | if (beg != 0) { | |
121 | if (check(lexnumber, f)) | |
122 | return(-1); | |
123 | for (i = beg; i <= lexnumber; i++) | |
20878753 | 124 | if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0) |
c9c93837 | 125 | mark(i); |
b3149556 KS |
126 | beg = 0; |
127 | break; | |
128 | } | |
129 | beg = lexnumber; | |
130 | if (check(beg, f)) | |
131 | return(-1); | |
132 | tok = scan(&bufp); | |
133 | regret(tok); | |
134 | if (tok != TDASH) { | |
135 | mark(beg); | |
136 | beg = 0; | |
137 | } | |
138 | break; | |
139 | ||
140 | case TPLUS: | |
141 | if (beg != 0) { | |
142 | printf("Non-numeric second argument\n"); | |
143 | return(-1); | |
144 | } | |
9745f5e0 S |
145 | i = valdot; |
146 | do { | |
147 | i++; | |
148 | if (i > msgCount) { | |
149 | printf("Referencing beyond EOF\n"); | |
150 | return(-1); | |
151 | } | |
152 | } while ((message[i - 1].m_flag & MDELETED) != f); | |
153 | mark(i); | |
b3149556 KS |
154 | break; |
155 | ||
156 | case TDASH: | |
157 | if (beg == 0) { | |
9745f5e0 S |
158 | i = valdot; |
159 | do { | |
160 | i--; | |
161 | if (i <= 0) { | |
162 | printf("Referencing before 1\n"); | |
163 | return(-1); | |
164 | } | |
165 | } while ((message[i - 1].m_flag & MDELETED) != f); | |
166 | mark(i); | |
b3149556 KS |
167 | } |
168 | break; | |
169 | ||
170 | case TSTRING: | |
171 | if (beg != 0) { | |
172 | printf("Non-numeric second argument\n"); | |
173 | return(-1); | |
174 | } | |
175 | other++; | |
2919b83d KS |
176 | if (lexstring[0] == ':') { |
177 | colresult = evalcol(lexstring[1]); | |
178 | if (colresult == 0) { | |
179 | printf("Unknown colon modifier \"%s\"\n", | |
180 | lexstring); | |
181 | return(-1); | |
182 | } | |
183 | colmod |= colresult; | |
184 | } | |
185 | else | |
186 | *np++ = savestr(lexstring); | |
b3149556 KS |
187 | break; |
188 | ||
189 | case TDOLLAR: | |
190 | case TUP: | |
191 | case TDOT: | |
192 | lexnumber = metamess(lexstring[0], f); | |
193 | if (lexnumber == -1) | |
194 | return(-1); | |
195 | goto number; | |
196 | ||
197 | case TSTAR: | |
198 | if (other) { | |
199 | printf("Can't mix \"*\" with anything\n"); | |
200 | return(-1); | |
201 | } | |
202 | star++; | |
203 | break; | |
a8a981d5 EW |
204 | |
205 | case TERROR: | |
206 | return -1; | |
b3149556 KS |
207 | } |
208 | tok = scan(&bufp); | |
209 | } | |
2919b83d | 210 | lastcolmod = colmod; |
b3149556 KS |
211 | *np = NOSTR; |
212 | mc = 0; | |
213 | if (star) { | |
214 | for (i = 0; i < msgCount; i++) | |
215 | if ((message[i].m_flag & MDELETED) == f) { | |
216 | mark(i+1); | |
217 | mc++; | |
218 | } | |
219 | if (mc == 0) { | |
220 | printf("No applicable messages.\n"); | |
221 | return(-1); | |
222 | } | |
223 | return(0); | |
224 | } | |
225 | ||
226 | /* | |
227 | * If no numbers were given, mark all of the messages, | |
228 | * so that we can unmark any whose sender was not selected | |
229 | * if any user names were given. | |
230 | */ | |
231 | ||
2919b83d | 232 | if ((np > namelist || colmod != 0) && mc == 0) |
b3149556 | 233 | for (i = 1; i <= msgCount; i++) |
9745f5e0 | 234 | if ((message[i-1].m_flag & MDELETED) == f) |
b3149556 KS |
235 | mark(i); |
236 | ||
237 | /* | |
238 | * If any names were given, go through and eliminate any | |
239 | * messages whose senders were not requested. | |
240 | */ | |
241 | ||
242 | if (np > namelist) { | |
243 | for (i = 1; i <= msgCount; i++) { | |
244 | for (mc = 0, np = &namelist[0]; *np != NOSTR; np++) | |
f7a4f91c KS |
245 | if (**np == '/') { |
246 | if (matchsubj(*np, i)) { | |
247 | mc++; | |
248 | break; | |
249 | } | |
250 | } | |
251 | else { | |
a8a981d5 | 252 | if (matchsender(*np, i)) { |
f7a4f91c KS |
253 | mc++; |
254 | break; | |
255 | } | |
b3149556 KS |
256 | } |
257 | if (mc == 0) | |
258 | unmark(i); | |
259 | } | |
260 | ||
261 | /* | |
262 | * Make sure we got some decent messages. | |
263 | */ | |
264 | ||
265 | mc = 0; | |
266 | for (i = 1; i <= msgCount; i++) | |
267 | if (message[i-1].m_flag & MMARK) { | |
268 | mc++; | |
269 | break; | |
270 | } | |
271 | if (mc == 0) { | |
272 | printf("No applicable messages from {%s", | |
273 | namelist[0]); | |
274 | for (np = &namelist[1]; *np != NOSTR; np++) | |
275 | printf(", %s", *np); | |
276 | printf("}\n"); | |
277 | return(-1); | |
278 | } | |
279 | } | |
2919b83d KS |
280 | |
281 | /* | |
282 | * If any colon modifiers were given, go through and | |
283 | * unmark any messages which do not satisfy the modifiers. | |
284 | */ | |
285 | ||
286 | if (colmod != 0) { | |
287 | for (i = 1; i <= msgCount; i++) { | |
288 | register struct coltab *colp; | |
289 | ||
290 | mp = &message[i - 1]; | |
291 | for (colp = &coltab[0]; colp->co_char; colp++) | |
292 | if (colp->co_bit & colmod) | |
293 | if ((mp->m_flag & colp->co_mask) | |
294 | != colp->co_equal) | |
295 | unmark(i); | |
296 | ||
297 | } | |
298 | for (mp = &message[0]; mp < &message[msgCount]; mp++) | |
299 | if (mp->m_flag & MMARK) | |
300 | break; | |
301 | if (mp >= &message[msgCount]) { | |
302 | register struct coltab *colp; | |
303 | ||
304 | printf("No messages satisfy"); | |
305 | for (colp = &coltab[0]; colp->co_char; colp++) | |
306 | if (colp->co_bit & colmod) | |
307 | printf(" :%c", colp->co_char); | |
308 | printf("\n"); | |
309 | return(-1); | |
310 | } | |
311 | } | |
312 | return(0); | |
313 | } | |
314 | ||
315 | /* | |
316 | * Turn the character after a colon modifier into a bit | |
317 | * value. | |
318 | */ | |
a0d23834 | 319 | int |
2919b83d | 320 | evalcol(col) |
a0d23834 | 321 | int col; |
2919b83d KS |
322 | { |
323 | register struct coltab *colp; | |
324 | ||
325 | if (col == 0) | |
326 | return(lastcolmod); | |
327 | for (colp = &coltab[0]; colp->co_char; colp++) | |
328 | if (colp->co_char == col) | |
329 | return(colp->co_bit); | |
b3149556 KS |
330 | return(0); |
331 | } | |
332 | ||
333 | /* | |
334 | * Check the passed message number for legality and proper flags. | |
20878753 EW |
335 | * If f is MDELETED, then either kind will do. Otherwise, the message |
336 | * has to be undeleted. | |
b3149556 | 337 | */ |
a0d23834 | 338 | int |
b3149556 | 339 | check(mesg, f) |
a0d23834 | 340 | int mesg, f; |
b3149556 KS |
341 | { |
342 | register struct message *mp; | |
343 | ||
344 | if (mesg < 1 || mesg > msgCount) { | |
345 | printf("%d: Invalid message number\n", mesg); | |
346 | return(-1); | |
347 | } | |
348 | mp = &message[mesg-1]; | |
20878753 | 349 | if (f != MDELETED && (mp->m_flag & MDELETED) != 0) { |
b3149556 KS |
350 | printf("%d: Inappropriate message\n", mesg); |
351 | return(-1); | |
352 | } | |
353 | return(0); | |
354 | } | |
355 | ||
356 | /* | |
357 | * Scan out the list of string arguments, shell style | |
358 | * for a RAWLIST. | |
359 | */ | |
a0d23834 | 360 | int |
fee4667a | 361 | getrawlist(line, argv, argc) |
b3149556 KS |
362 | char line[]; |
363 | char **argv; | |
fee4667a | 364 | int argc; |
b3149556 | 365 | { |
433e5791 EW |
366 | register char c, *cp, *cp2, quotec; |
367 | int argn; | |
368 | char linebuf[BUFSIZ]; | |
b3149556 | 369 | |
433e5791 | 370 | argn = 0; |
b3149556 | 371 | cp = line; |
433e5791 EW |
372 | for (;;) { |
373 | for (; *cp == ' ' || *cp == '\t'; cp++) | |
374 | ; | |
375 | if (*cp == '\0') | |
b3149556 | 376 | break; |
433e5791 EW |
377 | if (argn >= argc - 1) { |
378 | printf( | |
379 | "Too many elements in the list; excess discarded.\n"); | |
fee4667a S |
380 | break; |
381 | } | |
433e5791 EW |
382 | cp2 = linebuf; |
383 | quotec = '\0'; | |
384 | while ((c = *cp) != '\0') { | |
385 | cp++; | |
386 | if (quotec != '\0') { | |
387 | if (c == quotec) | |
388 | quotec = '\0'; | |
389 | else if (c == '\\') | |
390 | switch (c = *cp++) { | |
391 | case '\0': | |
392 | *cp2++ = *--cp; | |
393 | break; | |
394 | case '0': case '1': case '2': case '3': | |
395 | case '4': case '5': case '6': case '7': | |
396 | c -= '0'; | |
397 | if (*cp >= '0' && *cp <= '7') | |
398 | c = c * 8 + *cp++ - '0'; | |
399 | if (*cp >= '0' && *cp <= '7') | |
400 | c = c * 8 + *cp++ - '0'; | |
401 | *cp2++ = c; | |
402 | break; | |
403 | case 'b': | |
404 | *cp2++ = '\b'; | |
405 | break; | |
406 | case 'f': | |
407 | *cp2++ = '\f'; | |
408 | break; | |
409 | case 'n': | |
410 | *cp2++ = '\n'; | |
411 | break; | |
412 | case 'r': | |
413 | *cp2++ = '\r'; | |
414 | break; | |
415 | case 't': | |
416 | *cp2++ = '\t'; | |
417 | break; | |
418 | case 'v': | |
419 | *cp2++ = '\v'; | |
420 | break; | |
421 | } | |
422 | else if (c == '^') { | |
423 | c = *cp++; | |
424 | if (c == '?') | |
425 | *cp2++ = '\177'; | |
426 | /* null doesn't show up anyway */ | |
427 | else if (c >= 'A' && c <= '_' || | |
428 | c >= 'a' && c <= 'z') | |
429 | *cp2++ &= 037; | |
430 | else | |
431 | *cp2++ = *--cp; | |
432 | } else | |
433 | *cp2++ = c; | |
434 | } else if (c == '"' || c == '\'') | |
435 | quotec = c; | |
436 | else if (c == ' ' || c == '\t') | |
437 | break; | |
438 | else | |
439 | *cp2++ = c; | |
440 | } | |
441 | *cp2 = '\0'; | |
442 | argv[argn++] = savestr(linebuf); | |
b3149556 | 443 | } |
433e5791 EW |
444 | argv[argn] = NOSTR; |
445 | return argn; | |
b3149556 KS |
446 | } |
447 | ||
448 | /* | |
449 | * scan out a single lexical item and return its token number, | |
450 | * updating the string pointer passed **p. Also, store the value | |
451 | * of the number or string scanned in lexnumber or lexstring as | |
452 | * appropriate. In any event, store the scanned `thing' in lexstring. | |
453 | */ | |
454 | ||
455 | struct lex { | |
456 | char l_char; | |
457 | char l_token; | |
458 | } singles[] = { | |
459 | '$', TDOLLAR, | |
460 | '.', TDOT, | |
461 | '^', TUP, | |
462 | '*', TSTAR, | |
463 | '-', TDASH, | |
464 | '+', TPLUS, | |
465 | '(', TOPEN, | |
466 | ')', TCLOSE, | |
467 | 0, 0 | |
468 | }; | |
469 | ||
a0d23834 | 470 | int |
b3149556 KS |
471 | scan(sp) |
472 | char **sp; | |
473 | { | |
474 | register char *cp, *cp2; | |
475 | register int c; | |
476 | register struct lex *lp; | |
477 | int quotec; | |
478 | ||
479 | if (regretp >= 0) { | |
85d5837f | 480 | strcpy(lexstring, string_stack[regretp]); |
b3149556 KS |
481 | lexnumber = numberstack[regretp]; |
482 | return(regretstack[regretp--]); | |
483 | } | |
484 | cp = *sp; | |
485 | cp2 = lexstring; | |
486 | c = *cp++; | |
487 | ||
488 | /* | |
489 | * strip away leading white space. | |
490 | */ | |
491 | ||
470c33f3 | 492 | while (c == ' ' || c == '\t') |
b3149556 KS |
493 | c = *cp++; |
494 | ||
495 | /* | |
496 | * If no characters remain, we are at end of line, | |
497 | * so report that. | |
498 | */ | |
499 | ||
500 | if (c == '\0') { | |
501 | *sp = --cp; | |
502 | return(TEOL); | |
503 | } | |
504 | ||
505 | /* | |
506 | * If the leading character is a digit, scan | |
507 | * the number and convert it on the fly. | |
508 | * Return TNUMBER when done. | |
509 | */ | |
510 | ||
511 | if (isdigit(c)) { | |
512 | lexnumber = 0; | |
513 | while (isdigit(c)) { | |
514 | lexnumber = lexnumber*10 + c - '0'; | |
515 | *cp2++ = c; | |
516 | c = *cp++; | |
517 | } | |
518 | *cp2 = '\0'; | |
519 | *sp = --cp; | |
520 | return(TNUMBER); | |
521 | } | |
522 | ||
523 | /* | |
524 | * Check for single character tokens; return such | |
525 | * if found. | |
526 | */ | |
527 | ||
528 | for (lp = &singles[0]; lp->l_char != 0; lp++) | |
529 | if (c == lp->l_char) { | |
530 | lexstring[0] = c; | |
531 | lexstring[1] = '\0'; | |
532 | *sp = cp; | |
533 | return(lp->l_token); | |
534 | } | |
535 | ||
536 | /* | |
537 | * We've got a string! Copy all the characters | |
538 | * of the string into lexstring, until we see | |
539 | * a null, space, or tab. | |
540 | * If the lead character is a " or ', save it | |
541 | * and scan until you get another. | |
542 | */ | |
543 | ||
544 | quotec = 0; | |
470c33f3 | 545 | if (c == '\'' || c == '"') { |
b3149556 KS |
546 | quotec = c; |
547 | c = *cp++; | |
548 | } | |
549 | while (c != '\0') { | |
a8a981d5 EW |
550 | if (c == quotec) { |
551 | cp++; | |
b3149556 | 552 | break; |
a8a981d5 | 553 | } |
470c33f3 | 554 | if (quotec == 0 && (c == ' ' || c == '\t')) |
b3149556 KS |
555 | break; |
556 | if (cp2 - lexstring < STRINGLEN-1) | |
557 | *cp2++ = c; | |
558 | c = *cp++; | |
559 | } | |
a8a981d5 | 560 | if (quotec && c == 0) { |
b3149556 | 561 | fprintf(stderr, "Missing %c\n", quotec); |
a8a981d5 EW |
562 | return TERROR; |
563 | } | |
b3149556 KS |
564 | *sp = --cp; |
565 | *cp2 = '\0'; | |
566 | return(TSTRING); | |
567 | } | |
568 | ||
569 | /* | |
570 | * Unscan the named token by pushing it onto the regret stack. | |
571 | */ | |
a0d23834 | 572 | void |
b3149556 | 573 | regret(token) |
a0d23834 | 574 | int token; |
b3149556 KS |
575 | { |
576 | if (++regretp >= REGDEP) | |
577 | panic("Too many regrets"); | |
578 | regretstack[regretp] = token; | |
579 | lexstring[STRINGLEN-1] = '\0'; | |
85d5837f | 580 | string_stack[regretp] = savestr(lexstring); |
b3149556 KS |
581 | numberstack[regretp] = lexnumber; |
582 | } | |
583 | ||
584 | /* | |
585 | * Reset all the scanner global variables. | |
586 | */ | |
a0d23834 | 587 | void |
b3149556 KS |
588 | scaninit() |
589 | { | |
590 | regretp = -1; | |
591 | } | |
592 | ||
593 | /* | |
594 | * Find the first message whose flags & m == f and return | |
595 | * its message number. | |
596 | */ | |
a0d23834 | 597 | int |
b3149556 | 598 | first(f, m) |
a0d23834 | 599 | int f, m; |
b3149556 | 600 | { |
b3149556 KS |
601 | register struct message *mp; |
602 | ||
c1241556 EW |
603 | if (msgCount == 0) |
604 | return 0; | |
b3149556 KS |
605 | f &= MDELETED; |
606 | m &= MDELETED; | |
c1241556 | 607 | for (mp = dot; mp < &message[msgCount]; mp++) |
b3149556 | 608 | if ((mp->m_flag & m) == f) |
c1241556 EW |
609 | return mp - message + 1; |
610 | for (mp = dot-1; mp >= &message[0]; mp--) | |
b3149556 | 611 | if ((mp->m_flag & m) == f) |
c1241556 EW |
612 | return mp - message + 1; |
613 | return 0; | |
b3149556 KS |
614 | } |
615 | ||
616 | /* | |
617 | * See if the passed name sent the passed message number. Return true | |
618 | * if so. | |
619 | */ | |
a0d23834 | 620 | int |
a8a981d5 | 621 | matchsender(str, mesg) |
b3149556 | 622 | char *str; |
a0d23834 | 623 | int mesg; |
b3149556 | 624 | { |
9745f5e0 | 625 | register char *cp, *cp2, *backup; |
b3149556 | 626 | |
a8a981d5 EW |
627 | if (!*str) /* null string matches nothing instead of everything */ |
628 | return 0; | |
629 | backup = cp2 = nameof(&message[mesg - 1], 0); | |
9745f5e0 S |
630 | cp = str; |
631 | while (*cp2) { | |
632 | if (*cp == 0) | |
633 | return(1); | |
634 | if (raise(*cp++) != raise(*cp2++)) { | |
635 | cp2 = ++backup; | |
636 | cp = str; | |
637 | } | |
638 | } | |
639 | return(*cp == 0); | |
b3149556 KS |
640 | } |
641 | ||
f7a4f91c KS |
642 | /* |
643 | * See if the given string matches inside the subject field of the | |
644 | * given message. For the purpose of the scan, we ignore case differences. | |
645 | * If it does, return true. The string search argument is assumed to | |
646 | * have the form "/search-string." If it is of the form "/," we use the | |
647 | * previous search string. | |
648 | */ | |
649 | ||
650 | char lastscan[128]; | |
a0d23834 | 651 | int |
f7a4f91c KS |
652 | matchsubj(str, mesg) |
653 | char *str; | |
a0d23834 | 654 | int mesg; |
f7a4f91c KS |
655 | { |
656 | register struct message *mp; | |
312bdff6 | 657 | register char *cp, *cp2, *backup; |
f7a4f91c KS |
658 | |
659 | str++; | |
660 | if (strlen(str) == 0) | |
661 | str = lastscan; | |
662 | else | |
663 | strcpy(lastscan, str); | |
664 | mp = &message[mesg-1]; | |
665 | ||
666 | /* | |
667 | * Now look, ignoring case, for the word in the string. | |
668 | */ | |
669 | ||
c2e1b7e6 EW |
670 | if (value("searchheaders") && (cp = index(str, ':'))) { |
671 | *cp++ = '\0'; | |
672 | cp2 = hfield(str, mp); | |
673 | cp[-1] = ':'; | |
674 | str = cp; | |
675 | } else { | |
676 | cp = str; | |
677 | cp2 = hfield("subject", mp); | |
678 | } | |
f7a4f91c KS |
679 | if (cp2 == NOSTR) |
680 | return(0); | |
312bdff6 | 681 | backup = cp2; |
f7a4f91c KS |
682 | while (*cp2) { |
683 | if (*cp == 0) | |
684 | return(1); | |
312bdff6 KS |
685 | if (raise(*cp++) != raise(*cp2++)) { |
686 | cp2 = ++backup; | |
f7a4f91c | 687 | cp = str; |
312bdff6 | 688 | } |
f7a4f91c KS |
689 | } |
690 | return(*cp == 0); | |
691 | } | |
692 | ||
b3149556 KS |
693 | /* |
694 | * Mark the named message by setting its mark bit. | |
695 | */ | |
a0d23834 | 696 | void |
b3149556 | 697 | mark(mesg) |
a0d23834 | 698 | int mesg; |
b3149556 KS |
699 | { |
700 | register int i; | |
701 | ||
702 | i = mesg; | |
703 | if (i < 1 || i > msgCount) | |
704 | panic("Bad message number to mark"); | |
705 | message[i-1].m_flag |= MMARK; | |
706 | } | |
707 | ||
708 | /* | |
709 | * Unmark the named message. | |
710 | */ | |
a0d23834 | 711 | void |
b3149556 | 712 | unmark(mesg) |
a0d23834 | 713 | int mesg; |
b3149556 KS |
714 | { |
715 | register int i; | |
716 | ||
717 | i = mesg; | |
718 | if (i < 1 || i > msgCount) | |
719 | panic("Bad message number to unmark"); | |
720 | message[i-1].m_flag &= ~MMARK; | |
721 | } | |
722 | ||
723 | /* | |
724 | * Return the message number corresponding to the passed meta character. | |
725 | */ | |
a0d23834 | 726 | int |
b3149556 | 727 | metamess(meta, f) |
a0d23834 | 728 | int meta, f; |
b3149556 KS |
729 | { |
730 | register int c, m; | |
731 | register struct message *mp; | |
732 | ||
733 | c = meta; | |
734 | switch (c) { | |
735 | case '^': | |
736 | /* | |
737 | * First 'good' message left. | |
738 | */ | |
739 | for (mp = &message[0]; mp < &message[msgCount]; mp++) | |
740 | if ((mp->m_flag & MDELETED) == f) | |
741 | return(mp - &message[0] + 1); | |
742 | printf("No applicable messages\n"); | |
743 | return(-1); | |
744 | ||
745 | case '$': | |
746 | /* | |
747 | * Last 'good message left. | |
748 | */ | |
749 | for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) | |
750 | if ((mp->m_flag & MDELETED) == f) | |
751 | return(mp - &message[0] + 1); | |
752 | printf("No applicable messages\n"); | |
753 | return(-1); | |
754 | ||
755 | case '.': | |
756 | /* | |
757 | * Current message. | |
758 | */ | |
759 | m = dot - &message[0] + 1; | |
760 | if ((dot->m_flag & MDELETED) != f) { | |
761 | printf("%d: Inappropriate message\n", m); | |
762 | return(-1); | |
763 | } | |
764 | return(m); | |
765 | ||
766 | default: | |
767 | printf("Unknown metachar (%c)\n", c); | |
768 | return(-1); | |
769 | } | |
770 | } |