#if !defined(lint) && !defined(DOS)
static char rcsid[] = "$Id: flag.c 1142 2008-08-13 17:22:21Z hubert@u.washington.edu $";
#endif

/*
 * ========================================================================
 * Copyright 2006-2007 University of Washington
 * Copyright 2013 Eduardo Chappa
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * ========================================================================
 */

/*======================================================================
     flag.c
     Implements Pine message flag management routines
  ====*/


#include "../pith/headers.h"
#include "../pith/flag.h"
#include "../pith/pineelt.h"
#include "../pith/icache.h"
#include "../pith/mailindx.h"
#include "../pith/mailcmd.h"
#include "../pith/msgno.h"
#include "../pith/thread.h"
#include "../pith/sort.h"
#include "../pith/news.h"
#include "../pith/sequence.h"


/*
 * Internal prototypes
 */
void	flag_search(MAILSTREAM *, int, MsgNo, MSGNO_S *, long (*)(MAILSTREAM *));
long    flag_search_sequence(MAILSTREAM *, MSGNO_S *, long, int);



/*----------------------------------------------------------------------
  Return sequence number based on given index that are search-worthy

    Args: stream --
	  msgmap --
	  msgno --
	  flags -- flags for msgline_hidden

  Result:  0		     : index not search-worthy
	  -1		     : index out of bounds
	   1 - stream->nmsgs : sequence number to flag search

  ----*/
long
flag_search_sequence(MAILSTREAM *stream, MSGNO_S *msgmap, long int msgno, int flags)
{
    long rawno = msgno;

    return((msgno > stream->nmsgs
	    || msgno <= 0
            || (msgmap && !(rawno = mn_m2raw(msgmap, msgno))))
	      ? -1L		/* out of range! */
	      : ((get_lflag(stream, NULL, rawno, MN_EXLD)
		  || (msgmap && msgline_hidden(stream, msgmap, msgno, flags)))
		    ? 0L		/* NOT interesting! */
		    : rawno));
}



/*----------------------------------------------------------------------
  Perform mail_search based on flag bits

    Args: stream --
	  flags --
	  start --
	  msgmap --

  Result: if no set_* specified, call mail_search to light the searched
	  bit for all the messages matching the given flags.  If set_start
	  specified, it is an index (possibly into set_msgmap) telling
	  us where to search for invalid flag state hence when we
	  return everything with the searched bit is interesting and
	  everything with the valid bit lit is believably valid.

  ----*/
void
flag_search(MAILSTREAM *stream, int flags, MsgNo set_start, MSGNO_S *set_msgmap,
	    long int (*ping)(MAILSTREAM *))
{
    long	        n, i, new;
    char	       *seq;
    SEARCHPGM	       *pgm;
    SEARCHSET	       *full_set = NULL, **set;
    MESSAGECACHE       *mc;
    extern  MAILSTREAM *mm_search_stream;

    if(!stream)
      return;

    new = sp_new_mail_count(stream);

    /* Anything we don't already have flags for? */
    if(set_start){
	/*
	 * Use elt's sequence bit to coalesce runs in ascending
	 * sequence order...
	 */
	for(i = 1L; i <= stream->nmsgs; i++)
	  if((mc = mail_elt(stream, i)) != NULL)
	    mc->sequence = 0;

	for(i = set_start;
	    (n = flag_search_sequence(stream, set_msgmap, i, MH_ANYTHD)) >= 0L;
	    (flags & F_SRCHBACK) ? i-- : i++)
	  if(n > 0L && n <= stream->nmsgs
	     && (mc = mail_elt(stream, n)) && !mc->valid)
	    mc->sequence = 1;

	/* Unroll searchset in ascending sequence order */
	set = &full_set;
	for(i = 1L; i <= stream->nmsgs; i++)
	  if((mc = mail_elt(stream, i)) && mc->sequence){
	      if(*set){
		  if(((*set)->last ? (*set)->last : (*set)->first)+1L == i)
		    (*set)->last = i;
		  else
		    set = &(*set)->next;
	      }

	      if(!*set){
		  *set = mail_newsearchset();
		  (*set)->first = i;
	      }
	  }

	/*
	 * No search-worthy messsages?, prod the server for
	 * any flag updates and clear the searched bits...
	 */
	if(full_set){
	    if(full_set->first == 1
	       && full_set->last == stream->nmsgs
	       && full_set->next == NULL)
	      mail_free_searchset(&full_set);
	}
	else{
	    for(i = 1L; i <= stream->nmsgs; i++)
	      if((mc = mail_elt(stream, i)) != NULL)
	        mc->searched = 0;

	    if(ping)
	      (*ping)(stream);	/* prod server for any flag updates */

	    if(!(flags & F_NOFILT) && new != sp_new_mail_count(stream)){
		process_filter_patterns(stream, sp_msgmap(stream),
					sp_new_mail_count(stream));

		refresh_sort(stream, sp_msgmap(stream), SRT_NON);
		flag_search(stream, flags, set_start, set_msgmap, ping);
	    }

	    return;
	}
    }

    if((!is_imap_stream(stream) || modern_imap_stream(stream))
       && !(IS_NEWS(stream))){
	pgm = mail_newsearchpgm();

	if(flags & F_SEEN)
	  pgm->seen = 1;

	if(flags & F_UNSEEN)
	  pgm->unseen = 1;

	if(flags & F_DEL)
	  pgm->deleted = 1;

	if(flags & F_UNDEL)
	  pgm->undeleted = 1;

	if(flags & F_ANS)
	  pgm->answered = 1;

	if(flags & F_UNANS)
	  pgm->unanswered = 1;

	if(flags & F_FLAG)
	  pgm->flagged = 1;

	if(flags & F_UNFLAG)
	  pgm->unflagged = 1;

	if(flags & (F_FWD | F_UNFWD)){
	    STRINGLIST **slpp;

	    for(slpp = (flags & F_FWD) ? &pgm->keyword : &pgm->unkeyword;
		*slpp;
		slpp = &(*slpp)->next)
	      ;

	    *slpp = mail_newstringlist();
	    (*slpp)->text.data = (unsigned char *) cpystr(FORWARDED_FLAG);
	    (*slpp)->text.size = (unsigned long) strlen(FORWARDED_FLAG);
	}

	if(flags & F_RECENT)
	  pgm->recent = 1;

	if(flags & F_OR_SEEN){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->seen = 1;
	    pgm = pgm2;
	}

	if(flags & F_OR_UNSEEN){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->unseen = 1;
	    pgm = pgm2;
	}

	if(flags & F_OR_DEL){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->deleted = 1;
	    pgm = pgm2;
	}

	if(flags & F_OR_UNDEL){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->undeleted = 1;
	    pgm = pgm2;
	}

	if(flags & F_OR_FLAG){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->flagged = 1;
	    pgm = pgm2;
	}

	if(flags & F_OR_UNFLAG){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->unflagged = 1;
	    pgm = pgm2;
	}

	if(flags & F_OR_ANS){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->answered = 1;
	    pgm = pgm2;
	}

	if(flags & F_OR_UNANS){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->unanswered = 1;
	    pgm = pgm2;
	}

	if(flags & (F_OR_FWD | F_OR_UNFWD)){
	    STRINGLIST **slpp;
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();

	    for(slpp = (flags & F_OR_FWD)
			 ? &pgm2->or->second->keyword
			 : &pgm2->or->second->unkeyword;
		*slpp;
		slpp = &(*slpp)->next)
	      ;

	    *slpp = mail_newstringlist();
	    (*slpp)->text.data = (unsigned char *) cpystr(FORWARDED_FLAG);
	    (*slpp)->text.size = (unsigned long) strlen(FORWARDED_FLAG);

	    pgm = pgm2;
	}

	if(flags & F_OR_RECENT){
	    SEARCHPGM *pgm2 = mail_newsearchpgm();
	    pgm2->or = mail_newsearchor();
	    pgm2->or->first = pgm;
	    pgm2->or->second = mail_newsearchpgm();
	    pgm2->or->second->recent = 1;
	    pgm = pgm2;
	}

	pgm->msgno = full_set;

	pine_mail_search_full(mm_search_stream = stream, NULL,
			      pgm, SE_NOPREFETCH | SE_FREE);

	if(!(flags & F_NOFILT) && new != sp_new_mail_count(stream)){
	    process_filter_patterns(stream, sp_msgmap(stream),
				    sp_new_mail_count(stream));

	    flag_search(stream, flags, set_start, set_msgmap, ping);
	}
    }
    else{
	if(full_set){
	    /* sequence bits of interesting msgs set */
	    mail_free_searchset(&full_set);
	}
	else{
	    /* light sequence bits of interesting msgs */
	    for(i = 1L;
		(n = flag_search_sequence(stream, set_msgmap, i, MH_ANYTHD)) >= 0L;
		i++)
	      if(n > 0L && n <= stream->nmsgs
		 && (mc = mail_elt(stream, n)) && !mc->valid)
		mc->sequence = 1;
	      else
		mc->sequence = 0;
	}

	for(i = 1L; i <= stream->nmsgs; i++)
	  if((mc = mail_elt(stream, i)) != NULL)
	    mc->searched = 0;

	if((seq = build_sequence(stream, NULL, NULL)) != NULL){
	    pine_mail_fetch_flags(stream, seq, 0L);
	    fs_give((void **) &seq);
	}
    }
}



/*----------------------------------------------------------------------
    count messages on stream with specified system flag attributes

  Args: stream -- The stream/folder to look at message status
        flags -- flags on folder/stream to examine

 Result: count of messages flagged as requested

 Task: return count of message flagged as requested while being
       as server/network friendly as possible.

 Strategy: run thru flags to make sure they're all valid.  If any
	   invalid, do a search starting with the invalid message.
	   If all valid, ping the server to let it know we're 
	   receptive to flag updates.  At this 

  ----------------------------------------------------------------------*/
long
count_flagged(MAILSTREAM *stream, long int flags)
{
    long		n, count;
    MESSAGECACHE       *mc;

    if(!stream)
      return(0L);

    flag_search(stream, flags, 1, NULL, pine_mail_ping);

    /* Paw thru once more since all should be updated */
    for(n = 1L, count = 0L; n <= stream->nmsgs; n++)
      if((((mc = mail_elt(stream, n)) && mc->searched)
	  || (mc && mc->valid && FLAG_MATCH(flags, mc, stream)))
	 && !get_lflag(stream, NULL, n, MN_EXLD)){	  
	  mc->searched = 1;	/* caller may be interested! */
	  count++;
      }

    return(count);
}



/*----------------------------------------------------------------------
     Find the first message with the specified flags set

  Args: flags -- Flags in messagecache to match on
        stream -- The stream/folder to look at message status

 Result: Message number of first message with specified flags set or the
	 number of the last message if none found.
  ----------------------------------------------------------------------*/
MsgNo
first_sorted_flagged(long unsigned int flags, MAILSTREAM *stream, long int set_start, int opts)
{
    MsgNo	  i, n, start_with, winner = 0L;
    MESSAGECACHE *mc;
    int		  last;
    MSGNO_S      *msgmap;

    msgmap = sp_msgmap(stream);

    last = (opts & FSF_LAST);

    /* set_start only affects which search bits we light */
    start_with = set_start ? set_start
			   : (flags & F_SRCHBACK)
			       ? mn_get_total(msgmap) : 1L;
    flag_search(stream, flags, start_with, msgmap, NULL);

    for(i = start_with;
	(n = flag_search_sequence(stream, msgmap, i,
				 (opts & FSF_SKIP_CHID) ? 0 : MH_ANYTHD)) >= 0L;
	(flags & F_SRCHBACK) ? i-- : i++)
      if(n > 0L && n <= stream->nmsgs
	 && (((mc = mail_elt(stream, n)) && mc->searched)
	     || (mc && mc->valid && FLAG_MATCH(flags, mc, stream)))){
	  winner = i;
	  if(!last)
	    break;
      }

    if(winner == 0L && flags != F_UNDEL && flags != F_NONE){
	dprint((4,
	   "First_sorted_flagged didn't find a winner, look for undeleted\n"));
	winner = first_sorted_flagged(F_UNDEL, stream, 0L,
		opts | (mn_get_revsort(msgmap) ? 0 : FSF_LAST));
    }

    if(winner == 0L && flags != F_NONE){
	dprint((4,
          "First_sorted_flagged didn't find an undeleted, look for visible\n"));
	winner = first_sorted_flagged(F_NONE, stream, 0L,
		opts | (mn_get_revsort(msgmap) ? 0 : FSF_LAST));
    }

    dprint((4,
	       "First_sorted_flagged returning winner = %ld\n", winner));
    return(winner ? winner
		  : (mn_get_revsort(msgmap)
		      ? 1L : mn_get_total(msgmap)));
}



/*----------------------------------------------------------------------
     Find the next message with specified flags set

  Args: flags  -- Flags in messagecache to match on
        stream -- The stream/folder to look at message status
        start  -- Start looking after this message
        opts   -- These bits are both input and output. On input the bit
		  NSF_TRUST_FLAGS tells us whether we need to ping or not.
		  On input, the bit NSF_SEARCH_BACK tells us that we want to
		  know about matches <= start if we don't find any > start.
		  On output, NSF_FLAG_MATCH is set if we matched a message.
  Returns: Message number of the matched message, if any; else the start # or
	   the max_msgno if the mailbox changed dramatically.
  ----------------------------------------------------------------------*/
MsgNo
next_sorted_flagged(long unsigned int flags, MAILSTREAM *stream, long int start, int *opts)
{
    MsgNo	  i, n, dir;
    MESSAGECACHE *mc;
    int           rev, fss_flags = 0;
    MSGNO_S      *msgmap;

    msgmap = sp_msgmap(stream);

    /*
     * Search for the next thing the caller's interested in...
     */

    fss_flags = (opts && *opts & NSF_SKIP_CHID) ? 0 : MH_ANYTHD;
    rev = (opts && *opts & NSF_SEARCH_BACK);
    dir = (rev ? -1L : 1L);

    flag_search(stream, flags | (rev ? F_SRCHBACK : 0), start + dir,
		msgmap,
		(opts && ((*opts) & NSF_TRUST_FLAGS)) ? NULL : pine_mail_ping);

    for(i = start + dir;
	(n = flag_search_sequence(stream, msgmap,
				  i, fss_flags)) >= 0L;
	i += dir)
      if(n > 0L && n <= stream->nmsgs
	 && (((mc = mail_elt(stream, n)) && mc->searched)
	     || (mc && mc->valid && FLAG_MATCH(flags, mc, stream)))){
	  /* actually found a msg matching the flags */
	  if(opts)
	    (*opts) |= NSF_FLAG_MATCH;

	  return(i);
      }
    

    return(MIN(start, mn_get_total(msgmap)));
}



/*----------------------------------------------------------------------
  get the requested LOCAL flag bits for the given pine message number

   Accepts: msgs - pointer to message manipulation struct
            n - message number to get
	    f - bitmap of interesting flags
   Returns: non-zero if flag set, 0 if not set or no elt (error?)

   NOTE: this can be used to test system flags
  ----*/
int
get_lflag(MAILSTREAM *stream, MSGNO_S *msgs, long int n, int f)
{
    MESSAGECACHE *mc;
    PINELT_S	 *pelt;
    unsigned long rawno;

    rawno = msgs ? mn_m2raw(msgs, n) : n;
    if(!stream || rawno < 1L || rawno > stream->nmsgs)
      return(0);

    mc = mail_elt(stream, rawno);
    if(!mc || (pelt = (PINELT_S *) mc->sparep) == NULL)
      return(f ? 0 : 1);

    return((!f)
	     ? !(pelt->hidden || pelt->excluded || pelt->selected ||
		 pelt->colhid || pelt->collapsed || pelt->searched)
	     : (((f & MN_HIDE) ? pelt->hidden : 0)
		|| ((f & MN_EXLD) ? pelt->excluded : 0)
		|| ((f & MN_SLCT) ? pelt->selected : 0)
		|| ((f & MN_STMP) ? pelt->tmp : 0)
		|| ((f & MN_USOR) ? pelt->unsorted : 0)
		|| ((f & MN_COLL) ? pelt->collapsed : 0)
		|| ((f & MN_CHID) ? pelt->colhid : 0)
		|| ((f & MN_CHID2) ? pelt->colhid2 : 0)
		|| ((f & MN_SRCH) ? pelt->searched : 0)));
}



/*----------------------------------------------------------------------
  set the requested LOCAL flag bits for the given pine message number

   Accepts: msgs - pointer to message manipulation struct
            n - message number to set
	    f - bitmap of interesting flags
	    v - value (on or off) flag should get
   Returns: our index number of first

   NOTE: this isn't to be used for setting IMAP system flags
  ----*/
int
set_lflag(MAILSTREAM *stream, MSGNO_S *msgs, long int n, int f, int v)
{
    MESSAGECACHE *mc;
    long          rawno = 0L;
    PINETHRD_S   *thrd, *topthrd = NULL;
    PINELT_S    **peltp, *pelt;

    if(n < 1L || n > mn_get_total(msgs))
      return(0L);

    if((rawno=mn_m2raw(msgs, n)) > 0L && stream && rawno <= stream->nmsgs
       && (mc = mail_elt(stream, rawno))){
	int was_invisible, is_invisible;
	int chk_thrd_cnt = 0, thrd_was_visible, was_hidden, is_hidden;

	if((*(peltp = (PINELT_S **) &mc->sparep) == NULL)){
	    *peltp = (PINELT_S *) fs_get(sizeof(PINELT_S));
	    memset(*peltp, 0, sizeof(PINELT_S));
	}

	pelt = (*peltp);

	was_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0;

	if((chk_thrd_cnt = ((msgs->visible_threads >= 0L)
	   && THRD_INDX_ENABLED() && (f & MN_HIDE) && (pelt->hidden != v))) != 0){
	    thrd = fetch_thread(stream, rawno);
	    if(thrd && thrd->top){
		if(thrd->top == thrd->rawno)
		  topthrd = thrd;
		else
		  topthrd = fetch_thread(stream, thrd->top);
	    }

	    if(topthrd){
		thrd_was_visible = thread_has_some_visible(stream, topthrd);
		was_hidden = pelt->hidden ? 1 : 0;
	    }
	}

	if((f & MN_HIDE) && pelt->hidden != v){
	    pelt->hidden = v;
	    msgs->flagged_hid += (v) ? 1L : -1L;

	    if(pelt->hidden && THREADING() && !THRD_INDX()
	       && stream == ps_global->mail_stream
	       && ps_global->thread_disp_style == THREAD_MUTTLIKE)
	      clear_index_cache_for_thread(stream, fetch_thread(stream, rawno),
					   sp_msgmap(stream));
	}

	if((f & MN_CHID) && pelt->colhid != v){
	    pelt->colhid = v;
	    msgs->flagged_chid += (v) ? 1L : -1L;
	}

	if((f & MN_CHID2) && pelt->colhid2 != v){
	    pelt->colhid2 = v;
	    msgs->flagged_chid2 += (v) ? 1L : -1L;
	}

	if((f & MN_COLL) && pelt->collapsed != v){
	    pelt->collapsed = v;
	    msgs->flagged_coll += (v) ? 1L : -1L;
	}

	if((f & MN_USOR) && pelt->unsorted != v){
	    pelt->unsorted = v;
	    msgs->flagged_usor += (v) ? 1L : -1L;
	}

	if((f & MN_EXLD) && pelt->excluded != v){
	    pelt->excluded = v;
	    msgs->flagged_exld += (v) ? 1L : -1L;
	}

	if((f & MN_SLCT) && pelt->selected != v){
	    pelt->selected = v;
	    msgs->flagged_tmp += (v) ? 1L : -1L;
	}

	if((f & MN_SRCH) && pelt->searched != v){
	    pelt->searched = v;
	    msgs->flagged_srch += (v) ? 1L : -1L;
	}

	if((f & MN_STMP) && pelt->tmp != v){
	    pelt->tmp = v;
	    msgs->flagged_stmp += (v) ? 1L : -1L;
	}

	is_invisible = (pelt->hidden || pelt->colhid) ? 1 : 0;

	if(was_invisible != is_invisible)
	  msgs->flagged_invisible += (v) ? 1L : -1L;
	
	/*
	 * visible_threads keeps track of how many of the max_thrdno threads
	 * are visible and how many are MN_HIDE-hidden.
	 */
	if(chk_thrd_cnt && topthrd
	   && (was_hidden != (is_hidden = pelt->hidden ? 1 : 0))){
	    if(!thrd_was_visible && !is_hidden){
		/* it is visible now, increase count by one */
		msgs->visible_threads++;
	    }
	    else if(thrd_was_visible && is_hidden){
		/* thread may have been hidden, check */
		if(!thread_has_some_visible(stream, topthrd))
		  msgs->visible_threads--;
	    }
	    /* else no change */
	}
    }

    return(1);
}


/*
 * Copy value of flag from to flag to.
 */
void
copy_lflags(MAILSTREAM *stream, MSGNO_S *msgmap, int from, int to)
{
    unsigned long i;
    int           hide;

    hide = ((to == MN_SLCT) && (any_lflagged(msgmap, MN_HIDE) > 0L));

    set_lflags(stream, msgmap, to, 0);

    if(any_lflagged(msgmap, from))
      for(i = 1L; i <= mn_get_total(msgmap); i++)
	if(get_lflag(stream, msgmap, i, from))
	  set_lflag(stream, msgmap, i, to, 1);
	else if(hide)
	  set_lflag(stream, msgmap, i, MN_HIDE, 1);
}


/*
 * Set flag f to value v in all message.
 */
void
set_lflags(MAILSTREAM *stream, MSGNO_S *msgmap, int f, int v)
{
    unsigned long i;

    if((v == 0 && any_lflagged(msgmap, f)) || v )
      for(i = 1L; i <= mn_get_total(msgmap); i++)
	set_lflag(stream, msgmap, i, f, v);
}



/*----------------------------------------------------------------------
  return whether the given flag is set somewhere in the folder

   Accepts: msgs - pointer to message manipulation struct
	    f - flag bitmap to act on
   Returns: number of messages with the given flag set.
	    NOTE: the sum, if multiple flags tested, is bogus
  ----*/
long
any_lflagged(MSGNO_S *msgs, int f)
{
    if(!msgs)
      return(0L);

    if(f == MN_NONE)
      return(!(msgs->flagged_hid || msgs->flagged_exld || msgs->flagged_tmp ||
	       msgs->flagged_coll || msgs->flagged_chid || msgs->flagged_srch));
    else if(f == (MN_HIDE | MN_CHID))
      return(msgs->flagged_invisible);		/* special non-bogus case */
    else
      return(((f & MN_HIDE)   ? msgs->flagged_hid  : 0L)
	     + ((f & MN_EXLD) ? msgs->flagged_exld : 0L)
	     + ((f & MN_SLCT) ? msgs->flagged_tmp  : 0L)
	     + ((f & MN_SRCH) ? msgs->flagged_srch  : 0L)
	     + ((f & MN_STMP) ? msgs->flagged_stmp  : 0L)
	     + ((f & MN_COLL) ? msgs->flagged_coll  : 0L)
	     + ((f & MN_USOR) ? msgs->flagged_usor  : 0L)
	     + ((f & MN_CHID) ? msgs->flagged_chid : 0L)
	     + ((f & MN_CHID2) ? msgs->flagged_chid2 : 0L));
}