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 |
bdc0d8cc | 9 | static char sccsid[] = "@(#)list.c 8.3 (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': | |
f7b5b524 EW |
392 | *cp2++ = '\\'; |
393 | cp--; | |
433e5791 EW |
394 | break; |
395 | case '0': case '1': case '2': case '3': | |
396 | case '4': case '5': case '6': case '7': | |
397 | c -= '0'; | |
398 | if (*cp >= '0' && *cp <= '7') | |
399 | c = c * 8 + *cp++ - '0'; | |
400 | if (*cp >= '0' && *cp <= '7') | |
401 | c = c * 8 + *cp++ - '0'; | |
402 | *cp2++ = c; | |
403 | break; | |
404 | case 'b': | |
405 | *cp2++ = '\b'; | |
406 | break; | |
407 | case 'f': | |
408 | *cp2++ = '\f'; | |
409 | break; | |
410 | case 'n': | |
411 | *cp2++ = '\n'; | |
412 | break; | |
413 | case 'r': | |
414 | *cp2++ = '\r'; | |
415 | break; | |
416 | case 't': | |
417 | *cp2++ = '\t'; | |
418 | break; | |
419 | case 'v': | |
420 | *cp2++ = '\v'; | |
421 | break; | |
f7b5b524 EW |
422 | default: |
423 | *cp2++ = c; | |
433e5791 EW |
424 | } |
425 | else if (c == '^') { | |
426 | c = *cp++; | |
427 | if (c == '?') | |
428 | *cp2++ = '\177'; | |
429 | /* null doesn't show up anyway */ | |
430 | else if (c >= 'A' && c <= '_' || | |
431 | c >= 'a' && c <= 'z') | |
f7b5b524 EW |
432 | *cp2++ = c & 037; |
433 | else { | |
434 | *cp2++ = '^'; | |
435 | cp--; | |
436 | } | |
433e5791 EW |
437 | } else |
438 | *cp2++ = c; | |
439 | } else if (c == '"' || c == '\'') | |
440 | quotec = c; | |
441 | else if (c == ' ' || c == '\t') | |
442 | break; | |
443 | else | |
444 | *cp2++ = c; | |
445 | } | |
446 | *cp2 = '\0'; | |
447 | argv[argn++] = savestr(linebuf); | |
b3149556 | 448 | } |
433e5791 EW |
449 | argv[argn] = NOSTR; |
450 | return argn; | |
b3149556 KS |
451 | } |
452 | ||
453 | /* | |
454 | * scan out a single lexical item and return its token number, | |
455 | * updating the string pointer passed **p. Also, store the value | |
456 | * of the number or string scanned in lexnumber or lexstring as | |
457 | * appropriate. In any event, store the scanned `thing' in lexstring. | |
458 | */ | |
459 | ||
460 | struct lex { | |
461 | char l_char; | |
462 | char l_token; | |
463 | } singles[] = { | |
464 | '$', TDOLLAR, | |
465 | '.', TDOT, | |
466 | '^', TUP, | |
467 | '*', TSTAR, | |
468 | '-', TDASH, | |
469 | '+', TPLUS, | |
470 | '(', TOPEN, | |
471 | ')', TCLOSE, | |
472 | 0, 0 | |
473 | }; | |
474 | ||
a0d23834 | 475 | int |
b3149556 KS |
476 | scan(sp) |
477 | char **sp; | |
478 | { | |
479 | register char *cp, *cp2; | |
480 | register int c; | |
481 | register struct lex *lp; | |
482 | int quotec; | |
483 | ||
484 | if (regretp >= 0) { | |
85d5837f | 485 | strcpy(lexstring, string_stack[regretp]); |
b3149556 KS |
486 | lexnumber = numberstack[regretp]; |
487 | return(regretstack[regretp--]); | |
488 | } | |
489 | cp = *sp; | |
490 | cp2 = lexstring; | |
491 | c = *cp++; | |
492 | ||
493 | /* | |
494 | * strip away leading white space. | |
495 | */ | |
496 | ||
470c33f3 | 497 | while (c == ' ' || c == '\t') |
b3149556 KS |
498 | c = *cp++; |
499 | ||
500 | /* | |
501 | * If no characters remain, we are at end of line, | |
502 | * so report that. | |
503 | */ | |
504 | ||
505 | if (c == '\0') { | |
506 | *sp = --cp; | |
507 | return(TEOL); | |
508 | } | |
509 | ||
510 | /* | |
511 | * If the leading character is a digit, scan | |
512 | * the number and convert it on the fly. | |
513 | * Return TNUMBER when done. | |
514 | */ | |
515 | ||
516 | if (isdigit(c)) { | |
517 | lexnumber = 0; | |
518 | while (isdigit(c)) { | |
519 | lexnumber = lexnumber*10 + c - '0'; | |
520 | *cp2++ = c; | |
521 | c = *cp++; | |
522 | } | |
523 | *cp2 = '\0'; | |
524 | *sp = --cp; | |
525 | return(TNUMBER); | |
526 | } | |
527 | ||
528 | /* | |
529 | * Check for single character tokens; return such | |
530 | * if found. | |
531 | */ | |
532 | ||
533 | for (lp = &singles[0]; lp->l_char != 0; lp++) | |
534 | if (c == lp->l_char) { | |
535 | lexstring[0] = c; | |
536 | lexstring[1] = '\0'; | |
537 | *sp = cp; | |
538 | return(lp->l_token); | |
539 | } | |
540 | ||
541 | /* | |
542 | * We've got a string! Copy all the characters | |
543 | * of the string into lexstring, until we see | |
544 | * a null, space, or tab. | |
545 | * If the lead character is a " or ', save it | |
546 | * and scan until you get another. | |
547 | */ | |
548 | ||
549 | quotec = 0; | |
470c33f3 | 550 | if (c == '\'' || c == '"') { |
b3149556 KS |
551 | quotec = c; |
552 | c = *cp++; | |
553 | } | |
554 | while (c != '\0') { | |
a8a981d5 EW |
555 | if (c == quotec) { |
556 | cp++; | |
b3149556 | 557 | break; |
a8a981d5 | 558 | } |
470c33f3 | 559 | if (quotec == 0 && (c == ' ' || c == '\t')) |
b3149556 KS |
560 | break; |
561 | if (cp2 - lexstring < STRINGLEN-1) | |
562 | *cp2++ = c; | |
563 | c = *cp++; | |
564 | } | |
a8a981d5 | 565 | if (quotec && c == 0) { |
b3149556 | 566 | fprintf(stderr, "Missing %c\n", quotec); |
a8a981d5 EW |
567 | return TERROR; |
568 | } | |
b3149556 KS |
569 | *sp = --cp; |
570 | *cp2 = '\0'; | |
571 | return(TSTRING); | |
572 | } | |
573 | ||
574 | /* | |
575 | * Unscan the named token by pushing it onto the regret stack. | |
576 | */ | |
a0d23834 | 577 | void |
b3149556 | 578 | regret(token) |
a0d23834 | 579 | int token; |
b3149556 KS |
580 | { |
581 | if (++regretp >= REGDEP) | |
582 | panic("Too many regrets"); | |
583 | regretstack[regretp] = token; | |
584 | lexstring[STRINGLEN-1] = '\0'; | |
85d5837f | 585 | string_stack[regretp] = savestr(lexstring); |
b3149556 KS |
586 | numberstack[regretp] = lexnumber; |
587 | } | |
588 | ||
589 | /* | |
590 | * Reset all the scanner global variables. | |
591 | */ | |
a0d23834 | 592 | void |
b3149556 KS |
593 | scaninit() |
594 | { | |
595 | regretp = -1; | |
596 | } | |
597 | ||
598 | /* | |
599 | * Find the first message whose flags & m == f and return | |
600 | * its message number. | |
601 | */ | |
a0d23834 | 602 | int |
b3149556 | 603 | first(f, m) |
a0d23834 | 604 | int f, m; |
b3149556 | 605 | { |
b3149556 KS |
606 | register struct message *mp; |
607 | ||
c1241556 EW |
608 | if (msgCount == 0) |
609 | return 0; | |
b3149556 KS |
610 | f &= MDELETED; |
611 | m &= MDELETED; | |
c1241556 | 612 | for (mp = dot; mp < &message[msgCount]; mp++) |
b3149556 | 613 | if ((mp->m_flag & m) == f) |
c1241556 EW |
614 | return mp - message + 1; |
615 | for (mp = dot-1; mp >= &message[0]; mp--) | |
b3149556 | 616 | if ((mp->m_flag & m) == f) |
c1241556 EW |
617 | return mp - message + 1; |
618 | return 0; | |
b3149556 KS |
619 | } |
620 | ||
621 | /* | |
622 | * See if the passed name sent the passed message number. Return true | |
623 | * if so. | |
624 | */ | |
a0d23834 | 625 | int |
a8a981d5 | 626 | matchsender(str, mesg) |
b3149556 | 627 | char *str; |
a0d23834 | 628 | int mesg; |
b3149556 | 629 | { |
9745f5e0 | 630 | register char *cp, *cp2, *backup; |
b3149556 | 631 | |
a8a981d5 EW |
632 | if (!*str) /* null string matches nothing instead of everything */ |
633 | return 0; | |
634 | backup = cp2 = nameof(&message[mesg - 1], 0); | |
9745f5e0 S |
635 | cp = str; |
636 | while (*cp2) { | |
637 | if (*cp == 0) | |
638 | return(1); | |
639 | if (raise(*cp++) != raise(*cp2++)) { | |
640 | cp2 = ++backup; | |
641 | cp = str; | |
642 | } | |
643 | } | |
644 | return(*cp == 0); | |
b3149556 KS |
645 | } |
646 | ||
bdc0d8cc DB |
647 | /* |
648 | * See if the passed name received the passed message number. Return true | |
649 | * if so. | |
650 | */ | |
651 | ||
652 | static char *to_fields[] = { "to", "cc", "bcc", 0 }; | |
653 | ||
654 | matchto(str, mesg) | |
655 | char *str; | |
656 | { | |
657 | register struct message *mp; | |
658 | register char *cp, *cp2, *backup, **to; | |
659 | ||
660 | str++; | |
661 | ||
662 | if (*str == 0) /* null string matches nothing instead of everything */ | |
663 | return(0); | |
664 | ||
665 | mp = &message[mesg-1]; | |
666 | ||
667 | for (to = to_fields; *to; to++) { | |
668 | cp = str; | |
669 | cp2 = hfield(*to, mp); | |
670 | if (cp2 != NOSTR) { | |
671 | backup = cp2; | |
672 | while (*cp2) { | |
673 | if (*cp == 0) | |
674 | return(1); | |
675 | if (raise(*cp++) != raise(*cp2++)) { | |
676 | cp2 = ++backup; | |
677 | cp = str; | |
678 | } | |
679 | } | |
680 | if (*cp == 0) | |
681 | return(1); | |
682 | } | |
683 | } | |
684 | return(0); | |
685 | } | |
686 | ||
f7a4f91c KS |
687 | /* |
688 | * See if the given string matches inside the subject field of the | |
689 | * given message. For the purpose of the scan, we ignore case differences. | |
690 | * If it does, return true. The string search argument is assumed to | |
691 | * have the form "/search-string." If it is of the form "/," we use the | |
692 | * previous search string. | |
693 | */ | |
694 | ||
695 | char lastscan[128]; | |
a0d23834 | 696 | int |
f7a4f91c KS |
697 | matchsubj(str, mesg) |
698 | char *str; | |
a0d23834 | 699 | int mesg; |
f7a4f91c KS |
700 | { |
701 | register struct message *mp; | |
312bdff6 | 702 | register char *cp, *cp2, *backup; |
f7a4f91c KS |
703 | |
704 | str++; | |
705 | if (strlen(str) == 0) | |
706 | str = lastscan; | |
707 | else | |
708 | strcpy(lastscan, str); | |
709 | mp = &message[mesg-1]; | |
710 | ||
711 | /* | |
712 | * Now look, ignoring case, for the word in the string. | |
713 | */ | |
714 | ||
c2e1b7e6 | 715 | if (value("searchheaders") && (cp = index(str, ':'))) { |
bdc0d8cc DB |
716 | /* Check for special case "/To:" */ |
717 | if (raise(str[0]) == 'T' && raise(str[1]) == 'O' && | |
718 | str[2] == ':') | |
719 | return(matchto(cp, mesg)); | |
c2e1b7e6 EW |
720 | *cp++ = '\0'; |
721 | cp2 = hfield(str, mp); | |
722 | cp[-1] = ':'; | |
723 | str = cp; | |
724 | } else { | |
725 | cp = str; | |
726 | cp2 = hfield("subject", mp); | |
727 | } | |
f7a4f91c KS |
728 | if (cp2 == NOSTR) |
729 | return(0); | |
312bdff6 | 730 | backup = cp2; |
f7a4f91c KS |
731 | while (*cp2) { |
732 | if (*cp == 0) | |
733 | return(1); | |
312bdff6 KS |
734 | if (raise(*cp++) != raise(*cp2++)) { |
735 | cp2 = ++backup; | |
f7a4f91c | 736 | cp = str; |
312bdff6 | 737 | } |
f7a4f91c KS |
738 | } |
739 | return(*cp == 0); | |
740 | } | |
741 | ||
b3149556 KS |
742 | /* |
743 | * Mark the named message by setting its mark bit. | |
744 | */ | |
a0d23834 | 745 | void |
b3149556 | 746 | mark(mesg) |
a0d23834 | 747 | int mesg; |
b3149556 KS |
748 | { |
749 | register int i; | |
750 | ||
751 | i = mesg; | |
752 | if (i < 1 || i > msgCount) | |
753 | panic("Bad message number to mark"); | |
754 | message[i-1].m_flag |= MMARK; | |
755 | } | |
756 | ||
757 | /* | |
758 | * Unmark the named message. | |
759 | */ | |
a0d23834 | 760 | void |
b3149556 | 761 | unmark(mesg) |
a0d23834 | 762 | int mesg; |
b3149556 KS |
763 | { |
764 | register int i; | |
765 | ||
766 | i = mesg; | |
767 | if (i < 1 || i > msgCount) | |
768 | panic("Bad message number to unmark"); | |
769 | message[i-1].m_flag &= ~MMARK; | |
770 | } | |
771 | ||
772 | /* | |
773 | * Return the message number corresponding to the passed meta character. | |
774 | */ | |
a0d23834 | 775 | int |
b3149556 | 776 | metamess(meta, f) |
a0d23834 | 777 | int meta, f; |
b3149556 KS |
778 | { |
779 | register int c, m; | |
780 | register struct message *mp; | |
781 | ||
782 | c = meta; | |
783 | switch (c) { | |
784 | case '^': | |
785 | /* | |
786 | * First 'good' message left. | |
787 | */ | |
788 | for (mp = &message[0]; mp < &message[msgCount]; mp++) | |
789 | if ((mp->m_flag & MDELETED) == f) | |
790 | return(mp - &message[0] + 1); | |
791 | printf("No applicable messages\n"); | |
792 | return(-1); | |
793 | ||
794 | case '$': | |
795 | /* | |
796 | * Last 'good message left. | |
797 | */ | |
798 | for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) | |
799 | if ((mp->m_flag & MDELETED) == f) | |
800 | return(mp - &message[0] + 1); | |
801 | printf("No applicable messages\n"); | |
802 | return(-1); | |
803 | ||
804 | case '.': | |
805 | /* | |
806 | * Current message. | |
807 | */ | |
808 | m = dot - &message[0] + 1; | |
809 | if ((dot->m_flag & MDELETED) != f) { | |
810 | printf("%d: Inappropriate message\n", m); | |
811 | return(-1); | |
812 | } | |
813 | return(m); | |
814 | ||
815 | default: | |
816 | printf("Unknown metachar (%c)\n", c); | |
817 | return(-1); | |
818 | } | |
819 | } |