Add support for tab-completion when selecting by rule
[alpine.git] / pith / msgno.c
blob3b27462fc10dddd12c4e995c6d4ef1203aba15ee
1 /*
2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2007 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include "../pith/headers.h"
16 #include "../pith/msgno.h"
17 #include "../pith/flag.h"
18 #include "../pith/mailindx.h"
19 #include "../pith/pineelt.h"
20 #include "../pith/icache.h"
23 /* internal prototypes */
24 void set_msg_score(MAILSTREAM *, long, long);
28 * * * * Message number management functions * * *
32 /*----------------------------------------------------------------------
33 Initialize a message manipulation structure for the given total
35 Accepts: msgs - pointer to pointer to message manipulation struct
36 tot - number of messages to initialize with
37 ----*/
38 void
39 msgno_init(MSGNO_S **msgs, long int tot, SortOrder def_sort, int def_sort_rev)
41 long slop = (tot + 1L) % 64;
42 size_t len;
44 if(!msgs)
45 return;
47 if(!(*msgs)){
48 (*msgs) = (MSGNO_S *)fs_get(sizeof(MSGNO_S));
49 memset((void *)(*msgs), 0, sizeof(MSGNO_S));
52 (*msgs)->sel_cur = 0L;
53 (*msgs)->sel_cnt = 1L;
54 (*msgs)->sel_size = 8L;
55 len = (size_t)(*msgs)->sel_size * sizeof(long);
56 if((*msgs)->select)
57 fs_resize((void **)&((*msgs)->select), len);
58 else
59 (*msgs)->select = (long *)fs_get(len);
61 (*msgs)->select[0] = (tot) ? 1L : 0L;
63 (*msgs)->sort_size = (tot + 1L) + (64 - slop);
64 len = (size_t)(*msgs)->sort_size * sizeof(long);
65 if((*msgs)->sort)
66 fs_resize((void **)&((*msgs)->sort), len);
67 else
68 (*msgs)->sort = (long *)fs_get(len);
70 memset((void *)(*msgs)->sort, 0, len);
71 for(slop = 1L ; slop <= tot; slop++) /* reusing "slop" */
72 (*msgs)->sort[slop] = slop;
75 * If there is filtering happening, isort will become larger than sort.
76 * Sort is a list of raw message numbers in their sorted order. There
77 * are missing raw numbers because some of the messages are excluded
78 * (MN_EXLD) from the view. Isort has one entry for every raw message
79 * number, which maps to the corresponding msgno (the row in the sort
80 * array). Some of the entries in isort are not used because those
81 * messages are excluded, but the entry is still there because we want
82 * to map from rawno to message number and the row number is the rawno.
84 (*msgs)->isort_size = (*msgs)->sort_size;
85 if((*msgs)->isort)
86 fs_resize((void **)&((*msgs)->isort), len);
87 else
88 (*msgs)->isort = (long *)fs_get(len);
90 (*msgs)->max_msgno = tot;
91 (*msgs)->nmsgs = tot;
93 /* set the inverse array */
94 msgno_reset_isort(*msgs);
96 (*msgs)->sort_order = def_sort;
97 (*msgs)->reverse_sort = def_sort_rev;
98 (*msgs)->flagged_hid = 0L;
99 (*msgs)->flagged_exld = 0L;
100 (*msgs)->flagged_chid = 0L;
101 (*msgs)->flagged_chid2= 0L;
102 (*msgs)->flagged_coll = 0L;
103 (*msgs)->flagged_usor = 0L;
104 (*msgs)->flagged_tmp = 0L;
105 (*msgs)->flagged_stmp = 0L;
108 * This one is the total number of messages which are flagged
109 * hid OR chid. It isn't the sum of those two because a
110 * message may be flagged both at the same time.
112 (*msgs)->flagged_invisible = 0L;
115 * And this keeps track of visible threads in the THRD_INDX. This is
116 * weird because a thread is visible if any of its messages are
117 * not hidden, including those that are CHID hidden. You can't just
118 * count up all the messages that are hid or chid because you would
119 * miss a thread that has its top-level message hidden but some chid
120 * message not hidden.
122 (*msgs)->visible_threads = -1L;
127 * Isort makes mn_raw2m fast. Alternatively, we could look through
128 * the sort array to do mn_raw2m.
130 void
131 msgno_reset_isort(MSGNO_S *msgs)
133 long i;
135 if(msgs){
137 * Zero isort so raw messages numbers which don't appear in the
138 * sort array show up as undefined.
140 memset((void *) msgs->isort, 0,
141 (size_t) msgs->isort_size * sizeof(long));
143 /* fill in all the defined entries */
144 for(i = 1L; i <= mn_get_total(msgs); i++)
145 msgs->isort[msgs->sort[i]] = i;
151 /*----------------------------------------------------------------------
152 Release resources of a message manipulation structure
154 Accepts: msgs - pointer to message manipulation struct
155 n - number to test
156 Returns: with specified structure and its members free'd
157 ----*/
158 void
159 msgno_give(MSGNO_S **msgs)
161 if(msgs && *msgs){
162 if((*msgs)->sort)
163 fs_give((void **) &((*msgs)->sort));
165 if((*msgs)->isort)
166 fs_give((void **) &((*msgs)->isort));
168 if((*msgs)->select)
169 fs_give((void **) &((*msgs)->select));
171 fs_give((void **) msgs);
177 /*----------------------------------------------------------------------
178 Release resources of a message part exception list
180 Accepts: parts -- list of parts to free
181 Returns: with specified structure and its members free'd
182 ----*/
183 void
184 msgno_free_exceptions(PARTEX_S **parts)
186 if(parts && *parts){
187 if((*parts)->next)
188 msgno_free_exceptions(&(*parts)->next);
190 fs_give((void **) &(*parts)->partno);
191 fs_give((void **) parts);
197 /*----------------------------------------------------------------------
198 Increment the current message number
200 Accepts: msgs - pointer to message manipulation struct
201 ----*/
202 void
203 msgno_inc(MAILSTREAM *stream, MSGNO_S *msgs, int flags)
205 long i;
207 if(!msgs || mn_get_total(msgs) < 1L)
208 return;
210 for(i = msgs->select[msgs->sel_cur] + 1; i <= mn_get_total(msgs); i++){
211 if(!msgline_hidden(stream, msgs, i, flags)){
212 (msgs)->select[((msgs)->sel_cur)] = i;
213 break;
220 /*----------------------------------------------------------------------
221 Decrement the current message number
223 Accepts: msgs - pointer to message manipulation struct
224 ----*/
225 void
226 msgno_dec(MAILSTREAM *stream, MSGNO_S *msgs, int flags)
228 long i;
230 if(!msgs || mn_get_total(msgs) < 1L)
231 return;
233 for(i = (msgs)->select[((msgs)->sel_cur)] - 1L; i >= 1L; i--){
234 if(!msgline_hidden(stream, msgs, i, flags)){
235 (msgs)->select[((msgs)->sel_cur)] = i;
236 break;
243 /*----------------------------------------------------------------------
244 Got thru the message mapping table, and remove messages with DELETED flag
246 Accepts: stream -- mail stream to removed message references from
247 msgs -- pointer to message manipulation struct
248 f -- flags to use a purge criteria
249 ----*/
250 void
251 msgno_exclude_deleted(MAILSTREAM *stream, MSGNO_S *msgs, char *sequence)
253 long i, rawno;
254 MESSAGECACHE *mc;
255 int need_isort_reset = 0;
257 if(!msgs || msgs->max_msgno < 1L)
258 return;
261 * With 3.91 we're using a new strategy for finding and operating
262 * on all the messages with deleted status. The idea is to do a
263 * mail_search for deleted messages so the elt's "searched" bit gets
264 * set, and then to scan the elt's for them and set our local bit
265 * to indicate they're excluded...
267 (void) count_flagged(stream, F_DEL);
269 if(sequence)
270 mail_sequence (stream,(unsigned char *) sequence);
273 * Start with the end of the folder and work backwards so that
274 * msgno_exclude doesn't have to shift the entire array each time when
275 * there are lots of deleteds. In fact, if everything is deleted (like
276 * might be the case in a huge newsgroup) then it never has to shift
277 * anything. It is always at the end of the array just eliminating the
278 * last one instead. So instead of an n**2 operation, it is n.
280 for(i = msgs->max_msgno; i >= 1L; i--)
281 if((rawno = mn_m2raw(msgs, i)) > 0L && stream && rawno <= stream->nmsgs
282 && (mc = mail_elt(stream, rawno))
283 && (sequence ? mc->sequence : 1)
284 && ((mc->valid && mc->deleted) || (!mc->valid && mc->searched))){
285 msgno_exclude(stream, msgs, i, 0);
286 need_isort_reset++;
289 if(need_isort_reset)
290 msgno_reset_isort(msgs);
293 * If we excluded away a zoomed display, unhide everything...
295 if(msgs->max_msgno > 0L && any_lflagged(msgs, MN_HIDE) >= msgs->max_msgno)
296 for(i = 1L; i <= msgs->max_msgno; i++)
297 set_lflag(stream, msgs, i, MN_HIDE, 0);
302 void
303 msgno_exclude(MAILSTREAM *stream, MSGNO_S *msgmap, long int msgno, int reset_isort)
305 long i;
307 /*--- clear all flags to keep our counts consistent ---*/
308 set_lflag(stream, msgmap, msgno, MN_HIDE | MN_CHID | MN_CHID2 | MN_SLCT, 0);
309 set_lflag(stream, msgmap, msgno, MN_EXLD, 1); /* mark excluded */
311 /* erase knowledge in sort array (shift array down) */
312 for(i = msgno + 1L; i <= msgmap->max_msgno; i++)
313 msgmap->sort[i-1L] = msgmap->sort[i];
315 msgmap->max_msgno = MAX(0L, msgmap->max_msgno - 1L);
316 if(reset_isort)
317 msgno_reset_isort(msgmap);
319 msgno_flush_selected(msgmap, msgno);
324 /*----------------------------------------------------------------------
325 Accepts: stream -- mail stream to removed message references from
326 msgs -- pointer to message manipulation struct
327 flags
328 MI_REFILTERING -- do includes appropriate for refiltering
329 MI_STATECHGONLY -- when refiltering, maybe only re-include
330 messages which have had state changes
331 since they were originally filtered
332 Returns 1 if any new messages are included (indicating that we need
333 to re-sort)
334 0 if no new messages are included
335 ----*/
337 msgno_include(MAILSTREAM *stream, MSGNO_S *msgs, int flags)
339 long i, slop, old_total, old_size;
340 int exbits, ret = 0;
341 size_t len;
342 MESSAGECACHE *mc;
344 if(!msgs)
345 return(ret);
347 for(i = 1L; i <= stream->nmsgs; i++){
348 if(!msgno_exceptions(stream, i, "0", &exbits, FALSE))
349 exbits = 0;
351 if((((flags & MI_REFILTERING) && (exbits & MSG_EX_FILTERED)
352 && !(exbits & MSG_EX_FILED)
353 && (!(flags & MI_STATECHGONLY) || (exbits & MSG_EX_STATECHG)))
354 || (!(flags & MI_REFILTERING) && !(exbits & MSG_EX_FILTERED)))
355 && get_lflag(stream, NULL, i, MN_EXLD)){
356 old_total = msgs->max_msgno;
357 old_size = msgs->sort_size;
358 slop = (msgs->max_msgno + 1L) % 64;
359 msgs->sort_size = (msgs->max_msgno + 1L) + (64 - slop);
360 len = (size_t) msgs->sort_size * sizeof(long);
361 if(msgs->sort){
362 if(old_size != msgs->sort_size)
363 fs_resize((void **)&(msgs->sort), len);
365 else
366 msgs->sort = (long *)fs_get(len);
368 ret = 1;
369 msgs->sort[++msgs->max_msgno] = i;
370 msgs->isort[i] = msgs->max_msgno;
371 set_lflag(stream, msgs, msgs->max_msgno, MN_EXLD, 0);
372 if(flags & MI_REFILTERING){
373 exbits &= ~(MSG_EX_FILTERED | MSG_EX_TESTED);
374 msgno_exceptions(stream, i, "0", &exbits, TRUE);
377 if(old_total <= 0L){ /* if no previous messages, */
378 if(!msgs->select){ /* select the new message */
379 msgs->sel_size = 8L;
380 len = (size_t)msgs->sel_size * sizeof(long);
381 msgs->select = (long *)fs_get(len);
384 msgs->sel_cnt = 1L;
385 msgs->sel_cur = 0L;
386 msgs->select[0] = 1L;
389 else if((flags & MI_REFILTERING)
390 && (exbits & (MSG_EX_FILTERED | MSG_EX_TESTED))
391 && !(exbits & MSG_EX_FILED)
392 && (!(exbits & MSG_EX_MANUNDEL)
393 || ((mc = mail_elt(stream, i)) && mc->deleted))
394 && (!(flags & MI_STATECHGONLY) || (exbits & MSG_EX_STATECHG))){
396 * We get here if the message was filtered by a filter that
397 * just changes status bits (it wasn't excluded), and now also
398 * if the message was merely tested for filtering. It has also
399 * not been manually undeleted. If it was manually undeleted, we
400 * don't want to reprocess the filter, undoing the user's
401 * manual undeleting. Of course, a new pine will re check this
402 * message anyway, so the user had better be using this
403 * manual undeleting only to temporarily save him or herself
404 * from an expunge before Saving or printing or something.
405 * Also, we want to still try filtering if the message has at
406 * all been marked deleted, even if the there was any manual
407 * undeleting, since this directly precedes an expunge, we want
408 * to make sure the filter does the right thing before getting
409 * rid of the message forever.
411 exbits &= ~(MSG_EX_FILTERED | MSG_EX_TESTED);
412 msgno_exceptions(stream, i, "0", &exbits, TRUE);
416 return(ret);
421 /*----------------------------------------------------------------------
422 Add the given number of raw message numbers to the end of the
423 current list...
425 Accepts: msgs - pointer to message manipulation struct
426 n - number to add
427 Returns: with fixed up msgno struct
429 Only have to adjust the sort array, as since new mail can't cause
430 selection!
431 ----*/
432 void
433 msgno_add_raw(MSGNO_S *msgs, long int n)
435 long slop, islop, old_total, old_size, old_isize;
436 size_t len, ilen;
438 if(!msgs || n <= 0L)
439 return;
441 old_total = msgs->max_msgno;
442 old_size = msgs->sort_size;
443 old_isize = msgs->isort_size;
444 slop = (msgs->max_msgno + n + 1L) % 64;
445 islop = (msgs->nmsgs + n + 1L) % 64;
446 msgs->sort_size = (msgs->max_msgno + n + 1L) + (64 - slop);
447 msgs->isort_size = (msgs->nmsgs + n + 1L) + (64 - islop);
448 len = (size_t) msgs->sort_size * sizeof(long);
449 ilen = (size_t) msgs->isort_size * sizeof(long);
450 if(msgs->sort){
451 if(old_size != msgs->sort_size)
452 fs_resize((void **) &(msgs->sort), len);
454 else
455 msgs->sort = (long *) fs_get(len);
457 if(msgs->isort){
458 if(old_isize != msgs->isort_size)
459 fs_resize((void **) &(msgs->isort), ilen);
461 else
462 msgs->isort = (long *) fs_get(ilen);
464 while(n-- > 0){
465 msgs->sort[++msgs->max_msgno] = ++msgs->nmsgs;
466 msgs->isort[msgs->nmsgs] = msgs->max_msgno;
469 if(old_total <= 0L){ /* if no previous messages, */
470 if(!msgs->select){ /* select the new message */
471 msgs->sel_size = 8L;
472 len = (size_t) msgs->sel_size * sizeof(long);
473 msgs->select = (long *) fs_get(len);
476 msgs->sel_cnt = 1L;
477 msgs->sel_cur = 0L;
478 msgs->select[0] = 1L;
483 /*----------------------------------------------------------------------
484 Remove all knowledge of the given raw message number
486 Accepts: msgs - pointer to message manipulation struct
487 rawno - number to remove
488 Returns: with fixed up msgno struct
490 After removing *all* references, adjust the sort array and
491 various pointers accordingly...
492 ----*/
493 void
494 msgno_flush_raw(MSGNO_S *msgs, long int rawno)
496 long i, old_sorted = 0L;
497 int shift = 0;
499 if(!msgs)
500 return;
502 /* blast rawno from sort array */
503 for(i = 1L; i <= msgs->max_msgno; i++){
504 if(msgs->sort[i] == rawno){
505 old_sorted = i;
506 shift++;
509 if(shift && i < msgs->max_msgno)
510 msgs->sort[i] = msgs->sort[i + 1L];
512 if(msgs->sort[i] > rawno)
513 msgs->sort[i] -= 1L;
516 /*---- now, fixup counts and select array ----*/
517 if(--msgs->nmsgs < 0)
518 msgs->nmsgs = 0L;
520 if(old_sorted){
521 if(--msgs->max_msgno < 0)
522 msgs->max_msgno = 0L;
524 msgno_flush_selected(msgs, old_sorted);
527 msgno_reset_isort(msgs);
529 { char b[100];
530 snprintf(b, sizeof(b),
531 "isort validity: end of msgno_flush_raw: rawno=%ld\n", rawno);
536 /*----------------------------------------------------------------------
537 Remove all knowledge of the given selected message number
539 Accepts: msgs - pointer to message manipulation struct
540 n - number to remove
541 Returns: with fixed up selec members in msgno struct
543 Remove reference and fix up selected message numbers beyond
544 the specified number
545 ----*/
546 void
547 msgno_flush_selected(MSGNO_S *msgs, long int n)
549 long i;
550 int shift = 0;
552 for(i = 0L; i < msgs->sel_cnt; i++){
553 if(!shift && (msgs->select[i] == n))
554 shift++;
556 if(shift && i + 1L < msgs->sel_cnt)
557 msgs->select[i] = msgs->select[i + 1L];
559 if(n < msgs->select[i] || msgs->select[i] > msgs->max_msgno)
560 msgs->select[i] -= 1L;
563 if(shift && msgs->sel_cnt > 1L)
564 msgs->sel_cnt -= 1L;
568 void
569 msgno_set_sort(MSGNO_S *msgs, SortOrder sort)
571 if(msgs){
572 if(sort == SortScore)
573 scores_are_used(SCOREUSE_INVALID);
575 msgs->sort_order = sort;
580 /*----------------------------------------------------------------------
581 Test to see if the given message number is in the selected message
582 list...
584 Accepts: msgs - pointer to message manipulation struct
585 n - number to test
586 Returns: true if n is in selected array, false otherwise
588 ----*/
590 msgno_in_select(MSGNO_S *msgs, long int n)
592 long i;
594 if(msgs)
595 for(i = 0L; i < msgs->sel_cnt; i++)
596 if(msgs->select[i] == n)
597 return(1);
599 return(0);
604 /*----------------------------------------------------------------------
605 return our index number for the given raw message number
607 Accepts: msgs - pointer to message manipulation struct
608 msgno - number that's important
609 part
610 Returns: our index number of given raw message
612 ----*/
614 msgno_exceptions(MAILSTREAM *stream, long int rawno, char *part, int *bits, int set)
616 PINELT_S **peltp = NULL;
617 PARTEX_S **partp = NULL;
618 MESSAGECACHE *mc;
620 if(!stream || rawno < 1L || rawno > stream->nmsgs)
621 return FALSE;
624 * Get pointer to exceptional part list, and scan down it
625 * for the requested part...
627 if((mc = mail_elt(stream, rawno)) && (*(peltp = (PINELT_S **) &mc->sparep)))
628 for(partp = &(*peltp)->exceptions; *partp; partp = &(*partp)->next){
629 if(part){
630 if(!strcmp(part, (*partp)->partno)){
631 if(bits){
632 if(set)
633 (*partp)->handling = *bits;
634 else
635 *bits = (*partp)->handling;
638 return(TRUE); /* bingo! */
641 else if(bits){
643 * The caller provided flags, but no part.
644 * We are looking to see if the bits are set in any of the
645 * parts. This doesn't count parts with non-digit partno's (like
646 * scores) because those are used differently.
647 * any of the flags...
649 if((*partp)->partno && *(*partp)->partno &&
650 isdigit((unsigned char) *(*partp)->partno) &&
651 (*bits & (*partp)->handling) == *bits)
652 return(TRUE);
654 else
656 * The caller didn't specify a part, so
657 * they must just be interested in whether
658 * the msg had any exceptions at all...
660 return(TRUE);
663 if(set && part){
664 if(!*peltp){
665 *peltp = (PINELT_S *) fs_get(sizeof(PINELT_S));
666 memset(*peltp, 0, sizeof(PINELT_S));
667 partp = &(*peltp)->exceptions;
670 (*partp) = (PARTEX_S *) fs_get(sizeof(PARTEX_S));
671 (*partp)->partno = cpystr(part);
672 (*partp)->next = NULL;
673 (*partp)->handling = *bits;
674 return(TRUE);
677 if(bits) /* init bits */
678 *bits = 0;
680 return(FALSE);
685 * Checks whether any parts of any of the messages in msgmap are marked
686 * for deletion.
689 msgno_any_deletedparts(MAILSTREAM *stream, MSGNO_S *msgmap)
691 long n, rawno;
692 PINELT_S *pelt;
693 PARTEX_S **partp;
694 MESSAGECACHE *mc;
696 for(n = mn_first_cur(msgmap); n > 0L; n = mn_next_cur(msgmap))
697 if((rawno = mn_m2raw(msgmap, n)) > 0L
698 && stream && rawno <= stream->nmsgs
699 && (mc = mail_elt(stream, rawno))
700 && (pelt = (PINELT_S *) mc->sparep))
701 for(partp = &pelt->exceptions; *partp; partp = &(*partp)->next)
702 if(((*partp)->handling & MSG_EX_DELETE)
703 && (*partp)->partno
704 && *(*partp)->partno != '0'
705 && isdigit((unsigned char) *(*partp)->partno))
706 return(1);
708 return(0);
713 msgno_part_deleted(MAILSTREAM *stream, long int rawno, char *part)
715 char *p;
716 int expbits;
719 * Is this attachment or any of it's parents in the
720 * MIME structure marked for deletion?
722 for(p = part; p && *p; p = strindex(++p, '.')){
723 if(*p == '.')
724 *p = '\0';
726 (void) msgno_exceptions(stream, rawno, part, &expbits, FALSE);
727 if(!*p)
728 *p = '.';
730 if(expbits & MSG_EX_DELETE)
731 return(TRUE);
734 /* Finally, check if the whole message body's deleted */
735 return(msgno_exceptions(stream, rawno, "", &expbits, FALSE)
736 ? (expbits & MSG_EX_DELETE) : FALSE);
742 * Set the score for a message to score, which can be anything including
743 * SCORE_UNDEF.
745 void
746 set_msg_score(MAILSTREAM *stream, long int rawmsgno, long int score)
748 int intscore;
750 /* scores are between SCORE_MIN and SCORE_MAX, so ok */
751 intscore = (int) score;
753 (void) msgno_exceptions(stream, rawmsgno, "S", &intscore, TRUE);
758 * Returns the score for a message. If that score is undefined the value
759 * returned will be SCORE_UNDEF, so the caller has to be prepared for that.
760 * The caller should calculate the undefined scores before calling this.
762 long
763 get_msg_score(MAILSTREAM *stream, long int rawmsgno)
765 int s;
766 long score;
768 if(msgno_exceptions(stream, rawmsgno, "S", &s, FALSE))
769 score = (long) s;
770 else
771 score = SCORE_UNDEF;
773 return(score);
777 void
778 clear_msg_score(MAILSTREAM *stream, long int rawmsgno)
780 if(!stream)
781 return;
783 set_msg_score(stream, rawmsgno, SCORE_UNDEF);
788 * Set all the score values to undefined.
790 void
791 clear_folder_scores(MAILSTREAM *stream)
793 long n;
795 if(!stream)
796 return;
798 for(n = 1L; n <= stream->nmsgs; n++)
799 clear_msg_score(stream, n);
804 * Calculates all of the scores for the searchset and stores them in the
805 * mail elts. Careful, this function uses patterns so if the caller is using
806 * patterns then the caller will probably have to reset the pattern functions.
807 * That is, will have to call first_pattern again with the correct type.
809 * Args: stream
810 * searchset -- calculate scores for this set of messages
811 * no_fetch -- we're in a callback from c-client, don't call c-client
813 * Returns 1 -- ok
814 * 0 -- error, because of no_fetch
817 calculate_some_scores(MAILSTREAM *stream, SEARCHSET *searchset, int no_fetch)
819 PAT_S *pat = NULL;
820 PAT_STATE pstate;
821 char *savebits;
822 long newscore, addtoscore, score;
823 int error = 0;
824 long rflags = ROLE_SCORE;
825 long n, i;
826 SEARCHSET *s;
827 MESSAGECACHE *mc;
828 HEADER_TOK_S *hdrtok;
830 dprint((7, "calculate_some_scores\n"));
832 if(nonempty_patterns(rflags, &pstate)){
834 /* calculate scores */
835 if(searchset){
837 /* this calls match_pattern which messes up searched bits */
838 savebits = (char *)fs_get((stream->nmsgs+1) * sizeof(char));
839 for(i = 1L; i <= stream->nmsgs; i++)
840 savebits[i] = (mc = mail_elt(stream, i)) ? mc->searched : 0;
843 * First set all the scores in the searchset to zero so that they
844 * will no longer be undefined.
846 score = 0L;
847 for(s = searchset; s; s = s->next)
848 for(n = s->first; n <= s->last; n++)
849 set_msg_score(stream, n, score);
851 for(pat = first_pattern(&pstate);
852 !error && pat;
853 pat = next_pattern(&pstate)){
855 newscore = pat->action->scoreval;
856 hdrtok = pat->action->scorevalhdrtok;
859 * This no_fetch probably isn't necessary since
860 * we will actually have fetched this with
861 * the envelope. Just making sure.
863 if(no_fetch){
864 error++;
865 break;
868 switch(match_pattern(pat->patgrp, stream, searchset, NULL, NULL,
869 (no_fetch ? MP_IN_CCLIENT_CB : 0)
870 | (SE_NOSERVER|SE_NOPREFETCH))){
871 case 1:
872 if(!pat->action || pat->action->bogus)
873 break;
875 for(s = searchset; s; s = s->next)
876 for(n = s->first; n <= s->last; n++)
877 if(n > 0L && stream && n <= stream->nmsgs
878 && (mc = mail_elt(stream, n)) && mc->searched){
879 if((score = get_msg_score(stream,n)) == SCORE_UNDEF)
880 score = 0L;
882 if(hdrtok)
883 addtoscore = scorevalfrommsg(stream, n, hdrtok, no_fetch);
884 else
885 addtoscore = newscore;
887 score += addtoscore;
888 set_msg_score(stream, n, score);
891 break;
893 case 0:
894 break;
896 case -1:
897 error++;
898 break;
902 for(i = 1L; i <= stream->nmsgs; i++)
903 if((mc = mail_elt(stream, i)) != NULL)
904 mc->searched = savebits[i];
906 fs_give((void **)&savebits);
908 if(error){
910 * Revert to undefined scores.
912 score = SCORE_UNDEF;
913 for(s = searchset; s; s = s->next)
914 for(n = s->first; n <= s->last; n++)
915 set_msg_score(stream, n, score);
920 return(error ? 0 : 1);
924 void
925 free_pine_elt(void **sparep)
927 PINELT_S **peltp;
929 peltp = (PINELT_S **) sparep;
931 if(peltp && *peltp){
932 msgno_free_exceptions(&(*peltp)->exceptions);
933 if((*peltp)->pthrd)
934 fs_give((void **) &(*peltp)->pthrd);
936 if((*peltp)->firsttext)
937 fs_give((void **) &(*peltp)->firsttext);
939 if((*peltp)->ice)
940 free_ice(&(*peltp)->ice);
942 fs_give((void **) peltp);