* Do not define _BSD_SOURCE but define _DEFAULT_SOURCE instead.
[alpine.git] / pith / msgno.c
blobcf36f3a10866b390d7c89613bb285e8042758829
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: msgno.c 854 2007-12-07 17:44:43Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2016 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "../pith/headers.h"
20 #include "../pith/msgno.h"
21 #include "../pith/flag.h"
22 #include "../pith/mailindx.h"
23 #include "../pith/pineelt.h"
24 #include "../pith/icache.h"
27 /* internal prototypes */
28 void set_msg_score(MAILSTREAM *, long, long);
32 * * * * Message number management functions * * *
36 /*----------------------------------------------------------------------
37 Initialize a message manipulation structure for the given total
39 Accepts: msgs - pointer to pointer to message manipulation struct
40 tot - number of messages to initialize with
41 ----*/
42 void
43 msgno_init(MSGNO_S **msgs, long int tot, SortOrder def_sort, int def_sort_rev)
45 long slop = (tot + 1L) % 64;
46 size_t len;
48 if(!msgs)
49 return;
51 if(!(*msgs)){
52 (*msgs) = (MSGNO_S *)fs_get(sizeof(MSGNO_S));
53 memset((void *)(*msgs), 0, sizeof(MSGNO_S));
56 (*msgs)->sel_cur = 0L;
57 (*msgs)->sel_cnt = 1L;
58 (*msgs)->sel_size = 8L;
59 len = (size_t)(*msgs)->sel_size * sizeof(long);
60 if((*msgs)->select)
61 fs_resize((void **)&((*msgs)->select), len);
62 else
63 (*msgs)->select = (long *)fs_get(len);
65 (*msgs)->select[0] = (tot) ? 1L : 0L;
67 (*msgs)->sort_size = (tot + 1L) + (64 - slop);
68 len = (size_t)(*msgs)->sort_size * sizeof(long);
69 if((*msgs)->sort)
70 fs_resize((void **)&((*msgs)->sort), len);
71 else
72 (*msgs)->sort = (long *)fs_get(len);
74 memset((void *)(*msgs)->sort, 0, len);
75 for(slop = 1L ; slop <= tot; slop++) /* reusing "slop" */
76 (*msgs)->sort[slop] = slop;
79 * If there is filtering happening, isort will become larger than sort.
80 * Sort is a list of raw message numbers in their sorted order. There
81 * are missing raw numbers because some of the messages are excluded
82 * (MN_EXLD) from the view. Isort has one entry for every raw message
83 * number, which maps to the corresponding msgno (the row in the sort
84 * array). Some of the entries in isort are not used because those
85 * messages are excluded, but the entry is still there because we want
86 * to map from rawno to message number and the row number is the rawno.
88 (*msgs)->isort_size = (*msgs)->sort_size;
89 if((*msgs)->isort)
90 fs_resize((void **)&((*msgs)->isort), len);
91 else
92 (*msgs)->isort = (long *)fs_get(len);
94 (*msgs)->max_msgno = tot;
95 (*msgs)->nmsgs = tot;
97 /* set the inverse array */
98 msgno_reset_isort(*msgs);
100 (*msgs)->sort_order = def_sort;
101 (*msgs)->reverse_sort = def_sort_rev;
102 (*msgs)->flagged_hid = 0L;
103 (*msgs)->flagged_exld = 0L;
104 (*msgs)->flagged_chid = 0L;
105 (*msgs)->flagged_chid2= 0L;
106 (*msgs)->flagged_coll = 0L;
107 (*msgs)->flagged_usor = 0L;
108 (*msgs)->flagged_tmp = 0L;
109 (*msgs)->flagged_stmp = 0L;
112 * This one is the total number of messages which are flagged
113 * hid OR chid. It isn't the sum of those two because a
114 * message may be flagged both at the same time.
116 (*msgs)->flagged_invisible = 0L;
119 * And this keeps track of visible threads in the THRD_INDX. This is
120 * weird because a thread is visible if any of its messages are
121 * not hidden, including those that are CHID hidden. You can't just
122 * count up all the messages that are hid or chid because you would
123 * miss a thread that has its top-level message hidden but some chid
124 * message not hidden.
126 (*msgs)->visible_threads = -1L;
131 * Isort makes mn_raw2m fast. Alternatively, we could look through
132 * the sort array to do mn_raw2m.
134 void
135 msgno_reset_isort(MSGNO_S *msgs)
137 long i;
139 if(msgs){
141 * Zero isort so raw messages numbers which don't appear in the
142 * sort array show up as undefined.
144 memset((void *) msgs->isort, 0,
145 (size_t) msgs->isort_size * sizeof(long));
147 /* fill in all the defined entries */
148 for(i = 1L; i <= mn_get_total(msgs); i++)
149 msgs->isort[msgs->sort[i]] = i;
155 /*----------------------------------------------------------------------
156 Release resources of a message manipulation structure
158 Accepts: msgs - pointer to message manipulation struct
159 n - number to test
160 Returns: with specified structure and its members free'd
161 ----*/
162 void
163 msgno_give(MSGNO_S **msgs)
165 if(msgs && *msgs){
166 if((*msgs)->sort)
167 fs_give((void **) &((*msgs)->sort));
169 if((*msgs)->isort)
170 fs_give((void **) &((*msgs)->isort));
172 if((*msgs)->select)
173 fs_give((void **) &((*msgs)->select));
175 fs_give((void **) msgs);
181 /*----------------------------------------------------------------------
182 Release resources of a message part exception list
184 Accepts: parts -- list of parts to free
185 Returns: with specified structure and its members free'd
186 ----*/
187 void
188 msgno_free_exceptions(PARTEX_S **parts)
190 if(parts && *parts){
191 if((*parts)->next)
192 msgno_free_exceptions(&(*parts)->next);
194 fs_give((void **) &(*parts)->partno);
195 fs_give((void **) parts);
201 /*----------------------------------------------------------------------
202 Increment the current message number
204 Accepts: msgs - pointer to message manipulation struct
205 ----*/
206 void
207 msgno_inc(MAILSTREAM *stream, MSGNO_S *msgs, int flags)
209 long i;
211 if(!msgs || mn_get_total(msgs) < 1L)
212 return;
214 for(i = msgs->select[msgs->sel_cur] + 1; i <= mn_get_total(msgs); i++){
215 if(!msgline_hidden(stream, msgs, i, flags)){
216 (msgs)->select[((msgs)->sel_cur)] = i;
217 break;
224 /*----------------------------------------------------------------------
225 Decrement the current message number
227 Accepts: msgs - pointer to message manipulation struct
228 ----*/
229 void
230 msgno_dec(MAILSTREAM *stream, MSGNO_S *msgs, int flags)
232 long i;
234 if(!msgs || mn_get_total(msgs) < 1L)
235 return;
237 for(i = (msgs)->select[((msgs)->sel_cur)] - 1L; i >= 1L; i--){
238 if(!msgline_hidden(stream, msgs, i, flags)){
239 (msgs)->select[((msgs)->sel_cur)] = i;
240 break;
247 /*----------------------------------------------------------------------
248 Got thru the message mapping table, and remove messages with DELETED flag
250 Accepts: stream -- mail stream to removed message references from
251 msgs -- pointer to message manipulation struct
252 f -- flags to use a purge criteria
253 ----*/
254 void
255 msgno_exclude_deleted(MAILSTREAM *stream, MSGNO_S *msgs, char *sequence)
257 long i, rawno;
258 MESSAGECACHE *mc;
259 int need_isort_reset = 0;
261 if(!msgs || msgs->max_msgno < 1L)
262 return;
265 * With 3.91 we're using a new strategy for finding and operating
266 * on all the messages with deleted status. The idea is to do a
267 * mail_search for deleted messages so the elt's "searched" bit gets
268 * set, and then to scan the elt's for them and set our local bit
269 * to indicate they're excluded...
271 (void) count_flagged(stream, F_DEL);
273 if(sequence)
274 mail_sequence (stream,(unsigned char *) sequence);
277 * Start with the end of the folder and work backwards so that
278 * msgno_exclude doesn't have to shift the entire array each time when
279 * there are lots of deleteds. In fact, if everything is deleted (like
280 * might be the case in a huge newsgroup) then it never has to shift
281 * anything. It is always at the end of the array just eliminating the
282 * last one instead. So instead of an n**2 operation, it is n.
284 for(i = msgs->max_msgno; i >= 1L; i--)
285 if((rawno = mn_m2raw(msgs, i)) > 0L && stream && rawno <= stream->nmsgs
286 && (mc = mail_elt(stream, rawno))
287 && (sequence ? mc->sequence : 1)
288 && ((mc->valid && mc->deleted) || (!mc->valid && mc->searched))){
289 msgno_exclude(stream, msgs, i, 0);
290 need_isort_reset++;
293 if(need_isort_reset)
294 msgno_reset_isort(msgs);
297 * If we excluded away a zoomed display, unhide everything...
299 if(msgs->max_msgno > 0L && any_lflagged(msgs, MN_HIDE) >= msgs->max_msgno)
300 for(i = 1L; i <= msgs->max_msgno; i++)
301 set_lflag(stream, msgs, i, MN_HIDE, 0);
306 void
307 msgno_exclude(MAILSTREAM *stream, MSGNO_S *msgmap, long int msgno, int reset_isort)
309 long i;
311 /*--- clear all flags to keep our counts consistent ---*/
312 set_lflag(stream, msgmap, msgno, MN_HIDE | MN_CHID | MN_CHID2 | MN_SLCT, 0);
313 set_lflag(stream, msgmap, msgno, MN_EXLD, 1); /* mark excluded */
315 /* erase knowledge in sort array (shift array down) */
316 for(i = msgno + 1L; i <= msgmap->max_msgno; i++)
317 msgmap->sort[i-1L] = msgmap->sort[i];
319 msgmap->max_msgno = MAX(0L, msgmap->max_msgno - 1L);
320 if(reset_isort)
321 msgno_reset_isort(msgmap);
323 msgno_flush_selected(msgmap, msgno);
328 /*----------------------------------------------------------------------
329 Accepts: stream -- mail stream to removed message references from
330 msgs -- pointer to message manipulation struct
331 flags
332 MI_REFILTERING -- do includes appropriate for refiltering
333 MI_STATECHGONLY -- when refiltering, maybe only re-include
334 messages which have had state changes
335 since they were originally filtered
336 Returns 1 if any new messages are included (indicating that we need
337 to re-sort)
338 0 if no new messages are included
339 ----*/
341 msgno_include(MAILSTREAM *stream, MSGNO_S *msgs, int flags)
343 long i, slop, old_total, old_size;
344 int exbits, ret = 0;
345 size_t len;
346 MESSAGECACHE *mc;
348 if(!msgs)
349 return(ret);
351 for(i = 1L; i <= stream->nmsgs; i++){
352 if(!msgno_exceptions(stream, i, "0", &exbits, FALSE))
353 exbits = 0;
355 if((((flags & MI_REFILTERING) && (exbits & MSG_EX_FILTERED)
356 && !(exbits & MSG_EX_FILED)
357 && (!(flags & MI_STATECHGONLY) || (exbits & MSG_EX_STATECHG)))
358 || (!(flags & MI_REFILTERING) && !(exbits & MSG_EX_FILTERED)))
359 && get_lflag(stream, NULL, i, MN_EXLD)){
360 old_total = msgs->max_msgno;
361 old_size = msgs->sort_size;
362 slop = (msgs->max_msgno + 1L) % 64;
363 msgs->sort_size = (msgs->max_msgno + 1L) + (64 - slop);
364 len = (size_t) msgs->sort_size * sizeof(long);
365 if(msgs->sort){
366 if(old_size != msgs->sort_size)
367 fs_resize((void **)&(msgs->sort), len);
369 else
370 msgs->sort = (long *)fs_get(len);
372 ret = 1;
373 msgs->sort[++msgs->max_msgno] = i;
374 msgs->isort[i] = msgs->max_msgno;
375 set_lflag(stream, msgs, msgs->max_msgno, MN_EXLD, 0);
376 if(flags & MI_REFILTERING){
377 exbits &= ~(MSG_EX_FILTERED | MSG_EX_TESTED);
378 msgno_exceptions(stream, i, "0", &exbits, TRUE);
381 if(old_total <= 0L){ /* if no previous messages, */
382 if(!msgs->select){ /* select the new message */
383 msgs->sel_size = 8L;
384 len = (size_t)msgs->sel_size * sizeof(long);
385 msgs->select = (long *)fs_get(len);
388 msgs->sel_cnt = 1L;
389 msgs->sel_cur = 0L;
390 msgs->select[0] = 1L;
393 else if((flags & MI_REFILTERING)
394 && (exbits & (MSG_EX_FILTERED | MSG_EX_TESTED))
395 && !(exbits & MSG_EX_FILED)
396 && (!(exbits & MSG_EX_MANUNDEL)
397 || ((mc = mail_elt(stream, i)) && mc->deleted))
398 && (!(flags & MI_STATECHGONLY) || (exbits & MSG_EX_STATECHG))){
400 * We get here if the message was filtered by a filter that
401 * just changes status bits (it wasn't excluded), and now also
402 * if the message was merely tested for filtering. It has also
403 * not been manually undeleted. If it was manually undeleted, we
404 * don't want to reprocess the filter, undoing the user's
405 * manual undeleting. Of course, a new pine will re check this
406 * message anyway, so the user had better be using this
407 * manual undeleting only to temporarily save him or herself
408 * from an expunge before Saving or printing or something.
409 * Also, we want to still try filtering if the message has at
410 * all been marked deleted, even if the there was any manual
411 * undeleting, since this directly precedes an expunge, we want
412 * to make sure the filter does the right thing before getting
413 * rid of the message forever.
415 exbits &= ~(MSG_EX_FILTERED | MSG_EX_TESTED);
416 msgno_exceptions(stream, i, "0", &exbits, TRUE);
420 return(ret);
425 /*----------------------------------------------------------------------
426 Add the given number of raw message numbers to the end of the
427 current list...
429 Accepts: msgs - pointer to message manipulation struct
430 n - number to add
431 Returns: with fixed up msgno struct
433 Only have to adjust the sort array, as since new mail can't cause
434 selection!
435 ----*/
436 void
437 msgno_add_raw(MSGNO_S *msgs, long int n)
439 long slop, islop, old_total, old_size, old_isize;
440 size_t len, ilen;
442 if(!msgs || n <= 0L)
443 return;
445 old_total = msgs->max_msgno;
446 old_size = msgs->sort_size;
447 old_isize = msgs->isort_size;
448 slop = (msgs->max_msgno + n + 1L) % 64;
449 islop = (msgs->nmsgs + n + 1L) % 64;
450 msgs->sort_size = (msgs->max_msgno + n + 1L) + (64 - slop);
451 msgs->isort_size = (msgs->nmsgs + n + 1L) + (64 - islop);
452 len = (size_t) msgs->sort_size * sizeof(long);
453 ilen = (size_t) msgs->isort_size * sizeof(long);
454 if(msgs->sort){
455 if(old_size != msgs->sort_size)
456 fs_resize((void **) &(msgs->sort), len);
458 else
459 msgs->sort = (long *) fs_get(len);
461 if(msgs->isort){
462 if(old_isize != msgs->isort_size)
463 fs_resize((void **) &(msgs->isort), ilen);
465 else
466 msgs->isort = (long *) fs_get(ilen);
468 while(n-- > 0){
469 msgs->sort[++msgs->max_msgno] = ++msgs->nmsgs;
470 msgs->isort[msgs->nmsgs] = msgs->max_msgno;
473 if(old_total <= 0L){ /* if no previous messages, */
474 if(!msgs->select){ /* select the new message */
475 msgs->sel_size = 8L;
476 len = (size_t) msgs->sel_size * sizeof(long);
477 msgs->select = (long *) fs_get(len);
480 msgs->sel_cnt = 1L;
481 msgs->sel_cur = 0L;
482 msgs->select[0] = 1L;
487 /*----------------------------------------------------------------------
488 Remove all knowledge of the given raw message number
490 Accepts: msgs - pointer to message manipulation struct
491 rawno - number to remove
492 Returns: with fixed up msgno struct
494 After removing *all* references, adjust the sort array and
495 various pointers accordingly...
496 ----*/
497 void
498 msgno_flush_raw(MSGNO_S *msgs, long int rawno)
500 long i, old_sorted = 0L;
501 int shift = 0;
503 if(!msgs)
504 return;
506 /* blast rawno from sort array */
507 for(i = 1L; i <= msgs->max_msgno; i++){
508 if(msgs->sort[i] == rawno){
509 old_sorted = i;
510 shift++;
513 if(shift && i < msgs->max_msgno)
514 msgs->sort[i] = msgs->sort[i + 1L];
516 if(msgs->sort[i] > rawno)
517 msgs->sort[i] -= 1L;
520 /*---- now, fixup counts and select array ----*/
521 if(--msgs->nmsgs < 0)
522 msgs->nmsgs = 0L;
524 if(old_sorted){
525 if(--msgs->max_msgno < 0)
526 msgs->max_msgno = 0L;
528 msgno_flush_selected(msgs, old_sorted);
531 msgno_reset_isort(msgs);
533 { char b[100];
534 snprintf(b, sizeof(b),
535 "isort validity: end of msgno_flush_raw: rawno=%ld\n", rawno);
540 /*----------------------------------------------------------------------
541 Remove all knowledge of the given selected message number
543 Accepts: msgs - pointer to message manipulation struct
544 n - number to remove
545 Returns: with fixed up selec members in msgno struct
547 Remove reference and fix up selected message numbers beyond
548 the specified number
549 ----*/
550 void
551 msgno_flush_selected(MSGNO_S *msgs, long int n)
553 long i;
554 int shift = 0;
556 for(i = 0L; i < msgs->sel_cnt; i++){
557 if(!shift && (msgs->select[i] == n))
558 shift++;
560 if(shift && i + 1L < msgs->sel_cnt)
561 msgs->select[i] = msgs->select[i + 1L];
563 if(n < msgs->select[i] || msgs->select[i] > msgs->max_msgno)
564 msgs->select[i] -= 1L;
567 if(shift && msgs->sel_cnt > 1L)
568 msgs->sel_cnt -= 1L;
572 void
573 msgno_set_sort(MSGNO_S *msgs, SortOrder sort)
575 if(msgs){
576 if(sort == SortScore)
577 scores_are_used(SCOREUSE_INVALID);
579 msgs->sort_order = sort;
584 /*----------------------------------------------------------------------
585 Test to see if the given message number is in the selected message
586 list...
588 Accepts: msgs - pointer to message manipulation struct
589 n - number to test
590 Returns: true if n is in selected array, false otherwise
592 ----*/
594 msgno_in_select(MSGNO_S *msgs, long int n)
596 long i;
598 if(msgs)
599 for(i = 0L; i < msgs->sel_cnt; i++)
600 if(msgs->select[i] == n)
601 return(1);
603 return(0);
608 /*----------------------------------------------------------------------
609 return our index number for the given raw message number
611 Accepts: msgs - pointer to message manipulation struct
612 msgno - number that's important
613 part
614 Returns: our index number of given raw message
616 ----*/
618 msgno_exceptions(MAILSTREAM *stream, long int rawno, char *part, int *bits, int set)
620 PINELT_S **peltp;
621 PARTEX_S **partp;
622 MESSAGECACHE *mc;
624 if(!stream || rawno < 1L || rawno > stream->nmsgs)
625 return FALSE;
628 * Get pointer to exceptional part list, and scan down it
629 * for the requested part...
631 if((mc = mail_elt(stream, rawno)) && (*(peltp = (PINELT_S **) &mc->sparep)))
632 for(partp = &(*peltp)->exceptions; *partp; partp = &(*partp)->next){
633 if(part){
634 if(!strcmp(part, (*partp)->partno)){
635 if(bits){
636 if(set)
637 (*partp)->handling = *bits;
638 else
639 *bits = (*partp)->handling;
642 return(TRUE); /* bingo! */
645 else if(bits){
647 * The caller provided flags, but no part.
648 * We are looking to see if the bits are set in any of the
649 * parts. This doesn't count parts with non-digit partno's (like
650 * scores) because those are used differently.
651 * any of the flags...
653 if((*partp)->partno && *(*partp)->partno &&
654 isdigit((unsigned char) *(*partp)->partno) &&
655 (*bits & (*partp)->handling) == *bits)
656 return(TRUE);
658 else
660 * The caller didn't specify a part, so
661 * they must just be interested in whether
662 * the msg had any exceptions at all...
664 return(TRUE);
667 if(set && part){
668 if(!*peltp){
669 *peltp = (PINELT_S *) fs_get(sizeof(PINELT_S));
670 memset(*peltp, 0, sizeof(PINELT_S));
671 partp = &(*peltp)->exceptions;
674 (*partp) = (PARTEX_S *) fs_get(sizeof(PARTEX_S));
675 (*partp)->partno = cpystr(part);
676 (*partp)->next = NULL;
677 (*partp)->handling = *bits;
678 return(TRUE);
681 if(bits) /* init bits */
682 *bits = 0;
684 return(FALSE);
689 * Checks whether any parts of any of the messages in msgmap are marked
690 * for deletion.
693 msgno_any_deletedparts(MAILSTREAM *stream, MSGNO_S *msgmap)
695 long n, rawno;
696 PINELT_S *pelt;
697 PARTEX_S **partp;
698 MESSAGECACHE *mc;
700 for(n = mn_first_cur(msgmap); n > 0L; n = mn_next_cur(msgmap))
701 if((rawno = mn_m2raw(msgmap, n)) > 0L
702 && stream && rawno <= stream->nmsgs
703 && (mc = mail_elt(stream, rawno))
704 && (pelt = (PINELT_S *) mc->sparep))
705 for(partp = &pelt->exceptions; *partp; partp = &(*partp)->next)
706 if(((*partp)->handling & MSG_EX_DELETE)
707 && (*partp)->partno
708 && *(*partp)->partno != '0'
709 && isdigit((unsigned char) *(*partp)->partno))
710 return(1);
712 return(0);
717 msgno_part_deleted(MAILSTREAM *stream, long int rawno, char *part)
719 char *p;
720 int expbits;
723 * Is this attachment or any of it's parents in the
724 * MIME structure marked for deletion?
726 for(p = part; p && *p; p = strindex(++p, '.')){
727 if(*p == '.')
728 *p = '\0';
730 (void) msgno_exceptions(stream, rawno, part, &expbits, FALSE);
731 if(!*p)
732 *p = '.';
734 if(expbits & MSG_EX_DELETE)
735 return(TRUE);
738 /* Finally, check if the whole message body's deleted */
739 return(msgno_exceptions(stream, rawno, "", &expbits, FALSE)
740 ? (expbits & MSG_EX_DELETE) : FALSE);
746 * Set the score for a message to score, which can be anything including
747 * SCORE_UNDEF.
749 void
750 set_msg_score(MAILSTREAM *stream, long int rawmsgno, long int score)
752 int intscore;
754 /* scores are between SCORE_MIN and SCORE_MAX, so ok */
755 intscore = (int) score;
757 (void) msgno_exceptions(stream, rawmsgno, "S", &intscore, TRUE);
762 * Returns the score for a message. If that score is undefined the value
763 * returned will be SCORE_UNDEF, so the caller has to be prepared for that.
764 * The caller should calculate the undefined scores before calling this.
766 long
767 get_msg_score(MAILSTREAM *stream, long int rawmsgno)
769 int s;
770 long score;
772 if(msgno_exceptions(stream, rawmsgno, "S", &s, FALSE))
773 score = (long) s;
774 else
775 score = SCORE_UNDEF;
777 return(score);
781 void
782 clear_msg_score(MAILSTREAM *stream, long int rawmsgno)
784 if(!stream)
785 return;
787 set_msg_score(stream, rawmsgno, SCORE_UNDEF);
792 * Set all the score values to undefined.
794 void
795 clear_folder_scores(MAILSTREAM *stream)
797 long n;
799 if(!stream)
800 return;
802 for(n = 1L; n <= stream->nmsgs; n++)
803 clear_msg_score(stream, n);
808 * Calculates all of the scores for the searchset and stores them in the
809 * mail elts. Careful, this function uses patterns so if the caller is using
810 * patterns then the caller will probably have to reset the pattern functions.
811 * That is, will have to call first_pattern again with the correct type.
813 * Args: stream
814 * searchset -- calculate scores for this set of messages
815 * no_fetch -- we're in a callback from c-client, don't call c-client
817 * Returns 1 -- ok
818 * 0 -- error, because of no_fetch
821 calculate_some_scores(MAILSTREAM *stream, SEARCHSET *searchset, int no_fetch)
823 PAT_S *pat = NULL;
824 PAT_STATE pstate;
825 char *savebits;
826 long newscore, addtoscore, score;
827 int error = 0;
828 long rflags = ROLE_SCORE;
829 long n, i;
830 SEARCHSET *s;
831 MESSAGECACHE *mc;
832 HEADER_TOK_S *hdrtok;
834 dprint((7, "calculate_some_scores\n"));
836 if(nonempty_patterns(rflags, &pstate)){
838 /* calculate scores */
839 if(searchset){
841 /* this calls match_pattern which messes up searched bits */
842 savebits = (char *)fs_get((stream->nmsgs+1) * sizeof(char));
843 for(i = 1L; i <= stream->nmsgs; i++)
844 savebits[i] = (mc = mail_elt(stream, i)) ? mc->searched : 0;
847 * First set all the scores in the searchset to zero so that they
848 * will no longer be undefined.
850 score = 0L;
851 for(s = searchset; s; s = s->next)
852 for(n = s->first; n <= s->last; n++)
853 set_msg_score(stream, n, score);
855 for(pat = first_pattern(&pstate);
856 !error && pat;
857 pat = next_pattern(&pstate)){
859 newscore = pat->action->scoreval;
860 hdrtok = pat->action->scorevalhdrtok;
863 * This no_fetch probably isn't necessary since
864 * we will actually have fetched this with
865 * the envelope. Just making sure.
867 if(hdrtok && no_fetch){
868 error++;
869 break;
872 switch(match_pattern(pat->patgrp, stream, searchset, NULL, NULL,
873 (no_fetch ? MP_IN_CCLIENT_CB : 0)
874 | (SE_NOSERVER|SE_NOPREFETCH))){
875 case 1:
876 if(!pat->action || pat->action->bogus)
877 break;
879 for(s = searchset; s; s = s->next)
880 for(n = s->first; n <= s->last; n++)
881 if(n > 0L && stream && n <= stream->nmsgs
882 && (mc = mail_elt(stream, n)) && mc->searched){
883 if((score = get_msg_score(stream,n)) == SCORE_UNDEF)
884 score = 0L;
886 if(hdrtok)
887 addtoscore = scorevalfrommsg(stream, n, hdrtok, no_fetch);
888 else
889 addtoscore = newscore;
891 score += addtoscore;
892 set_msg_score(stream, n, score);
895 break;
897 case 0:
898 break;
900 case -1:
901 error++;
902 break;
906 for(i = 1L; i <= stream->nmsgs; i++)
907 if((mc = mail_elt(stream, i)) != NULL)
908 mc->searched = savebits[i];
910 fs_give((void **)&savebits);
912 if(error){
914 * Revert to undefined scores.
916 score = SCORE_UNDEF;
917 for(s = searchset; s; s = s->next)
918 for(n = s->first; n <= s->last; n++)
919 set_msg_score(stream, n, score);
924 return(error ? 0 : 1);
928 void
929 free_pine_elt(void **sparep)
931 PINELT_S **peltp;
933 peltp = (PINELT_S **) sparep;
935 if(peltp && *peltp){
936 msgno_free_exceptions(&(*peltp)->exceptions);
937 if((*peltp)->pthrd)
938 fs_give((void **) &(*peltp)->pthrd);
940 if((*peltp)->ice)
941 free_ice(&(*peltp)->ice);
943 fs_give((void **) peltp);