static char rcsid[] = "@(#)$Id: pattern.c,v 1.52 2006/04/09 07:37:19 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.52 $   $State: Exp $
 *
 *  Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI> 
 *                           (was hurtta+elm@ozone.FMI.FI)
 ******************************************************************************
 *  The Elm Mail System 
 *
 *			Copyright (c) 1988-1992 USENET Community Trust
 *			Copyright (c) 1986,1987 Dave Taylor
 ****************************************************************************/

/**    General pattern matching for the ELM mailer.     

**/

#include "def_elm.h"
#include "s_elm.h"

static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str) 
     char *str;
{
    return (unsigned char *)str;
}


#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif       

#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif

static char *tag_word = NULL;
static char *tagged_word = NULL;
static char *Tagged_word = NULL;
static char *delete_word = NULL;
static char *mark_delete_word = NULL;
static char *Mark_delete_word = NULL;
static char *undelete_word = NULL;
static char *undeleted_word = NULL;
static char *Undeleted_word = NULL;

static int DoAll P_((int func,struct menu_common *menu, 
		     struct screen_parts *LOC));
static int DoFlagged P_((int func, struct menu_common *menu,
			 struct screen_parts *LOC));

DEBUG_VAR(Debug,__FILE__,"mbox");

int meta_match(function, menu, page, LOC)
     int function;
     struct menu_common *menu;
     struct menu_context *page;
     struct screen_parts *LOC;
{
    
    /** Perform specific function based on whether an entered string 
	matches either the From or Subject lines.. 
	Return TRUE if the current message was matched, else FALSE.
    **/
    
    int i, tagged=0, count=0, curtag = 0;
    char		msg[SLEN];

    struct string * meta_pattern = NULL;
    int status, line;

    if (delete_word == NULL) {
	tag_word = catgets(elm_msg_cat, ElmSet, ElmTag, "Tag");
	tagged_word = catgets(elm_msg_cat, ElmSet, ElmTagged, "tagged");
	Tagged_word = catgets(elm_msg_cat, ElmSet, ElmCapTagged, "Tagged");
	delete_word = catgets(elm_msg_cat, ElmSet, ElmDelete, "Delete");
	mark_delete_word = catgets(elm_msg_cat, ElmSet, ElmMarkDelete, "marked for deletion");
	Mark_delete_word = catgets(elm_msg_cat, ElmSet, ElmCapMarkDelete, "Marked for deletion");
	undelete_word = catgets(elm_msg_cat, ElmSet, ElmUndelete, "Undelete");
	undeleted_word = catgets(elm_msg_cat, ElmSet, ElmUndeleted, "undeleted");
	Undeleted_word = catgets(elm_msg_cat, ElmSet, ElmCapUndeleted, "Undeleted");
    }
    
    menu_Write_to_screen(LOC->prompt_page,
			 CATGETS(elm_msg_cat, ElmSet, 
				 ElmMessagesMatchPattern,
				 "%s %S that match pattern..."), 
			 function==TAGGED?tag_word: function==DELETED?delete_word:undelete_word, 
			 mcommon_give_item(menu, m_items));
    
    if (function == TAGGED) {	/* are messages already tagged??? */
	int mc = mcommon_get_count(menu);

	
	for (i=0; i < mc; i++) {
	    if (mcommon_ison_status(menu,i,status_basic,TAGGED))
		tagged++;
	}


	if (tagged) {
	    char	tagmsg[SLEN];
	    int ch;

	    int delay_redraw = 0;
	again:
	    if (tagged > 1) {
		elm_sfprintf(tagmsg, sizeof tagmsg,
			     CATGETS(elm_msg_cat, ElmSet, 
				     ElmSomeMessagesATagged,
				     "Some %S are already tagged."), 
			     mcommon_give_item(menu,m_items));

		ch = prompt_letter(1,"",*def_ans_yes,
				   PROMPT_yesno|PROMPT_redraw_mark|
				   PROMPT_ctrlL|PROMPT_cancel,
				   LOC->prompt_page,
				   CATGETS(elm_msg_cat, ElmSet, ElmRemoveTags,
					   "%s Remove Tags? (%c/%c) "),
				   tagmsg, *def_ans_yes, *def_ans_no);
	    } else {
		elm_sfprintf(tagmsg, sizeof tagmsg,
			     CATGETS(elm_msg_cat, ElmSet, 
				     ElmAMessageATagged,
				     "One %S is already tagged."), 
			     mcommon_give_item(menu,m_item));
		ch = prompt_letter(1,"",*def_ans_yes,
				   PROMPT_yesno|PROMPT_redraw_mark|
				   PROMPT_ctrlL|PROMPT_cancel,
				   LOC->prompt_page,			   
				   CATGETS(elm_msg_cat, ElmSet, ElmRemoveTag,
					   "%s Remove Tag? (%c/%c) "),
				   tagmsg, *def_ans_yes, *def_ans_no);
	    }
	    
	    if (('L'&31)    == ch ||
		REDRAW_MARK == ch) {
		menu_ClearScreen(page);   /* Reset possible redraw flag */
		
		/* Call refresh routines of children */
		menu_redraw_children(page);
		
		if (menu_need_redraw(LOC->prompt_page))		    
		    menu_ClearScreen(LOC->prompt_page);   /* Clear redraw mark from prompt_area*/
	    
		/* NOTICE: using menu_trigger_redraw(page) on here
		   may cause redraw loop!
		*/
		delay_redraw++;
		goto again;
	    }

	    if (delay_redraw)
		menu_trigger_redraw(page);

	    if (TERMCH_interrupt_char == ch)
		goto clean;

	    if (ch != *def_ans_no) {	/* remove tags... */
		for (i=0; i < mc; i++) {
		    int vis;

		    mcommon_clearf_status(menu,i,status_basic,TAGGED);
    
		    vis = compute_visible(i+1, menu);
		    menu_header_status_update(LOC->header_page,vis-1);
		  
		}
	    }
	}
    }
	
    /* FIXME --optionally_enter*  should use prompt_area */
    line = menu_GetAbsLine(LOC->prompt_page,1);
    status = optionally_enter2(page,
			       &meta_pattern, line, 0,
			       OE_REDRAW_MARK|
			       OE_SIG_CHAR /* Ctrl-C */, 
			       CATGETS(elm_msg_cat, ElmSet, ElmEnterPattern, 
				       "Enter pattern: "));

    {
	int delay_redraw = 0;
	
	while (status == REDRAW_MARK) {
	    menu_ClearScreen(page);   /* Reset possible redraw flag */

	    /* Call refresh routines of children */
	    menu_redraw_children(page);
	    
	    if (menu_need_redraw(LOC->prompt_page))		    
		menu_ClearScreen(LOC->prompt_page);   /* Clear redraw mark from prompt_area*/
	    
	    delay_redraw++;   /* Can't trigger redraw yet... */

	    status = optionally_enter2(page,
				       &meta_pattern, line, 0,
				       OE_REDRAW_MARK|OE_APPEND_CURRENT|
				       OE_SIG_CHAR /* Ctrl-C */,
				       CATGETS(elm_msg_cat, ElmSet, 
					       ElmEnterPattern, 
					       "Enter pattern: "));
	}

	if (delay_redraw)
	    menu_trigger_redraw(page);    
    }

    if (status != 0 || !meta_pattern ||
	string_len(meta_pattern) == 0) {

	if (meta_pattern)
	    free_string( & (meta_pattern));

	menu_ClearLine(LOC->prompt_page,1);
	return(curtag);
    }
    
    if (function == DELETED && 
	string_matches_ascii(meta_pattern, s2us("tagged"))) {

	if (meta_pattern)
	    free_string( & (meta_pattern));
	
	return(DeleteTagged(menu, page, LOC->header_page));

    } else if (string_matches_ascii(meta_pattern, s2us("flagged"))) 
	count = DoFlagged(function, menu, LOC);

    else if (string_matches_ascii(meta_pattern, s2us("all")))
	count = DoAll(function, menu, LOC);

    else {
	int mc       = mcommon_get_count(menu);
	int current  = mcommon_get_current(menu);
	int selected = mcommon_get_selected(menu);

	for (i = 0; i < mc; i++) {
	    if (mcommon_matches(menu,i,meta_pattern) &&
		(!selected ||
		 (selected && mcommon_ison_status(menu,i,
						  status_basic,VISIBLE))
		 )) {
		 
		int vis;

		if (function == UNDELETE)
		    mcommon_clearf_status(menu,i,status_basic,DELETED);

		else if ((function == DELETED) && 
			 (mcommon_get_type(menu,i) & SYSTEM)) {

		    if(i == current - 1) curtag--;
		    count--;

		} else
		    mcommon_setf_status(menu,i, status_basic,function);

		vis = compute_visible(i+1, menu);
		menu_header_status_update(LOC->header_page,vis-1); 

		if(i == current - 1) curtag++;
		count++;
	    }
	}
    }

    menu_ClearLine(LOC->prompt_page,1);	/* remove "pattern: " prompt */
    
    if (count > 1) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmTaggedMessages,
			  "%s %d %S."), 
		  function==TAGGED? Tagged_word : 
		  function==DELETED? Mark_delete_word : Undeleted_word,
		  count, 
		  mcommon_give_item(menu,m_items));
    } else if (count == 1) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmTaggedMessage,
			  "%s 1 %S."), 
		  function==TAGGED? Tagged_word : 
		  function==DELETED? Mark_delete_word : Undeleted_word, 
		  mcommon_give_item(menu,m_item));
	} else {
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmNoMatchesNoTags,
			      "No matches. No %S %s."), 
		      mcommon_give_item(menu,m_items),
		      function==TAGGED? tagged_word : 
		      function==DELETED? mark_delete_word: undeleted_word);
	}

 clean:
    if (meta_pattern)
	free_string( & (meta_pattern));

    return(curtag);
}

int pattern_match(menu, page, LOC)
     struct menu_common *menu;
     struct menu_context *page;
     struct screen_parts *LOC;
{
    /** Get a pattern from the user and try to match it with the
	from/subject lines being displayed.  If matched (ignoring
	case), move current message pointer to that message, if
	not, error and return ZERO **/
    
    /* If redraw is needed use  
         menu_trigger_redraw(page)
    */

    int i;
    
    /* Elm 2.4 remembers old entered patterns, so we need to keep
       that static. This leaks these malloced areas on end of program */

    static struct string * pattern = NULL;
    static struct string * alt_pattern = NULL;
    int ret = 0 ;

    int delay_redraw = 0;
    int anywhere = FALSE;
    int matched;

    struct string * SEARCH = NULL;  /* SHARED: point either to
				       pattern or alt_pattern */

    int val;
    int line;


    int append = 0;


    /* Redraw loop */
    append = OE_ALT_SOLIDUS;
    do {

	menu_PutLineX(LOC->prompt_page,0,40, 
		      CATGETS(elm_msg_cat, ElmSet, ElmMatchAnywhere,
			      "/ = Match anywhere in %S."), 
		      mcommon_give_item(menu, m_items));

	/* FIXME --optionally_enter*  should use prompt_area */
	line = menu_GetAbsLine(LOC->prompt_page,1);
	val = optionally_enter2(page,
				&pattern, line, 0, 
				OE_REDRAW_MARK|append|
				OE_SIG_CHAR /* Ctrl-C */, 
				CATGETS(elm_msg_cat, ElmSet, ElmMatchPattern,
					"Match pattern:"));     

	if (REDRAW_MARK == val) { 
	    menu_ClearScreen(page);   /* Clear possible redraw mark */

	    /* Call refresh routines of children */
	    menu_redraw_children(page);
	    
	    if (menu_need_redraw(LOC->prompt_page))		    
		menu_ClearScreen(LOC->prompt_page);   /* Clear redraw mark from prompt_area*/
	    
	    /* NOTICE: using menu_trigger_redraw(page) on here
	       may cause redraw loop!
	    */
	    delay_redraw++;
	    if (pattern && 
		string_len(pattern) > 0)
		append = OE_APPEND_CURRENT;
	}
    } while (val == REDRAW_MARK); 
	
    anywhere = FALSE;
    SEARCH = pattern;
	
    if (val == OE_ALT_SOLIDUS) {

	append = 0;

	menu_MoveCursor(LOC->prompt_page,0,40);
	menu_CleartoEOLN(LOC->prompt_page);


	do {
	    
	    /* FIXME --optionally_enter*  should use prompt_area */
	    line = menu_GetAbsLine(LOC->prompt_page,1);
	    val = optionally_enter2(page,
				    &alt_pattern, line, 0, 
				    OE_REDRAW_MARK|append|
				    OE_SIG_CHAR /* Ctrl-C */, 
				    CATGETS(elm_msg_cat, ElmSet,
					    ElmMatchPatternInEntire, 
					    "Match pattern (in entire %S):"),
				    mcommon_give_item(menu,m_item));

	    if (REDRAW_MARK == val) { 
		menu_ClearScreen(page);   /* Clear possible redraw mark */
		
		/* Call refresh routines of children */
		menu_redraw_children(page);
		
		if (menu_need_redraw(LOC->prompt_page))		    
		    menu_ClearScreen(LOC->prompt_page); /* Clear redraw mark from prompt_area*/
		
		/* NOTICE: using menu_trigger_redraw(page) on here
		   may cause redraw loop!
		*/
		delay_redraw++;
		append = OE_APPEND_CURRENT;
	    }

	} while (val == REDRAW_MARK); 

	anywhere = TRUE;
	SEARCH = alt_pattern;	 
    } 

    if (0 != val) {
	if (-1 == val)   /* Ctrl-C */
	    goto out;

	ret = EOF;
	goto out;	
    }
    
    if (SEARCH) {

	if (string_len(SEARCH) == 0) {
	    ret = 0;
	    goto out;
	}
	
	if (anywhere) 
	    ret = mcommon_match_in_text(menu,SEARCH,page, LOC);
	else {

	      int current = mcommon_get_current(menu);
	      int mc = mcommon_get_count(menu);
	      int selected = mcommon_get_selected(menu);

	      for (i = current; i < mc; i++) {
		  if (mcommon_matches(menu,i,SEARCH) &&
		      (!selected ||
		       (selected && mcommon_ison_status(menu,i,
							status_basic,VISIBLE))
		       )) {
		      
		      current = ++i;
		      mcommon_set_current(menu,current);
		      copy_current(menu,LOC->header_page);
		      get_page(menu, LOC->header_page);

		      ret = 1;
		      goto out;
		  }
	      }
	  }
    }

 out:

    /* NOTE: 
       We do not free pattern and alt_pattern -- they are static
       and should have remembered, so that behauviour matches
       to Elm 2.4
    */
    
    if (delay_redraw)
	menu_trigger_redraw(page);
    else
	menu_trigger_redraw(LOC->prompt_page);		  

    return(ret);
}


/* This will tag, delete, or undelete all or the currently visible messages */
static int DoAll(func, menu, LOC)
     int func;
     struct menu_common *menu;
     struct screen_parts *LOC;
{
    int i, count = 0;
    int mc = mcommon_get_count(menu);
    int selected = mcommon_get_selected(menu);

    for (i=0; i < mc; i++) {

	if (!selected ||
	    (selected && mcommon_ison_status(menu,i,status_basic,VISIBLE))) {

	    int vis;

	    if (func == UNDELETE)
		mcommon_clearf_status(menu,i,status_basic,DELETED);
	    else
		mcommon_setf_status(menu,i,status_basic,func);

	    vis = compute_visible(i+1, menu);

	    menu_header_status_update(LOC->header_page,vis-1);   /* ! ! ! */

	    ++count;
	}
    }

    DPRINT(Debug,7,(&Debug, "DoAll=%d\n",count));

    return(count);
}

static int DoFlagged(func, menu, LOC)
     int func;
     struct menu_common *menu;
     struct screen_parts *LOC;
{
    int i, count = 0;
    int mc = mcommon_get_count(menu);
    int selected = mcommon_get_selected(menu);
        
    for (i=0; i < mc; i++) {
	if (!selected ||
	    (selected && mcommon_ison_status(menu,i,status_basic,VISIBLE))) {
	    
	    if (mcommon_ison_status(menu,i,status_1,S1_FLAGGED)) {
		
		int vis;

		if (func == UNDELETE)
		    mcommon_clearf_status(menu,i,status_basic,DELETED);
		else
		    mcommon_setf_status(menu,i,status_basic,func);
		
		vis = compute_visible(i+1, menu);
		
		menu_header_status_update(LOC->header_page,vis-1);   /* ! ! ! */
		
		++count;
	    }
	}
    }


    DPRINT(Debug,7,(&Debug, "DoFlagged=%d\n",count));

    return(count);
}

/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1