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

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.9 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
 ******************************************************************************
 * Inludes code from pattern.c which have following copyright:
 *
 *  The Elm Mail System 
 *
 *			Copyright (c) 1988-1992 USENET Community Trust
 *			Copyright (c) 1986,1987 Dave Taylor
 ****************************************************************************/

#include "def_mcommon.h"
#include "s_elm.h"

DEBUG_VAR(Debug,__FILE__,"menu");

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

static CONST unsigned char *cs2us P_((const char *str));
static CONST unsigned char *cs2us(str) 
     CONST char *str;
{
    return (CONST unsigned char *)str;
}

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

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


int mc_matches_mbx(u,idx, meta_pattern)
     union mcommon_union *u;
     int idx;
     struct string * meta_pattern;
{
    struct MailboxView *mbxview = u->mbx.mw;
    struct header_rec *a = give_header(mbxview,idx);
    int r = 0;
    
    if (a) {
	r = from_matches(a, meta_pattern) || subject_matches(a, meta_pattern);
    }

    return r;
}

int from_matches(mss, pattern)
     struct header_rec *mss;
     struct string *pattern;
{
    /** Returns true iff the pattern occurs in it's entirety
	in the from line of the indicated message **/

    struct addr_item *p;
    int match = 0;

    if (mss) 
	for (p = mss->from;
	     p && p->fullname && p->addr;
	     p++) {

	    struct string *s = new_string2(ASCII_SET,s2us(p->addr));
	    
	    if (find_pattern_from_string(p->fullname,pattern,1))
		match++;
	    if (find_pattern_from_string(p->comment,pattern,1))
		match++;

	    if (find_pattern_from_string(s,pattern,1))
		match++;

	    free_string(&s);

	}

    return match;
}

int to_matches(mss, pattern)
     struct header_rec *mss;
     struct string * pattern;
{
    /** Returns true iff the pattern occurs in it's entirety
	in the TO line of the indicated message **/

    struct addr_item *p;
    int match = 0;
    
    if (mss) 
	for (p = mss->to;
	     p && p->fullname && p->addr;
	     p++) {
	    struct string *s = new_string2(ASCII_SET,s2us(p->addr));
	    
	    if (find_pattern_from_string(p->fullname,pattern,1))
		match++;
	    if (find_pattern_from_string(p->comment,pattern,1))
		match++;

	    if (find_pattern_from_string(s,pattern,1))
		match++;

	    free_string(&s);
	}

    return match;
}

int cc_matches(mss, pattern)
     struct header_rec *mss;
     struct string * pattern;
{
    /** Returns true iff the pattern occurs in it's entirety
	in the CC line of the indicated message **/
    
    struct addr_item *p;
    int match = 0;
    
    if (mss) 
	for (p = mss->cc;
	     p && p->fullname && p->addr;
	     p++) {
	    struct string *s = new_string2(ASCII_SET,s2us(p->addr));

	    if (find_pattern_from_string(p->fullname,pattern,1))
		match++;
	    if (find_pattern_from_string(p->comment,pattern,1))
		match++;

	    if (find_pattern_from_string(s,pattern,1))
		match++;

	    free_string(&s);
	}

    return match;
}

int subject_matches(mss, pattern)
     struct header_rec *mss;
     struct string * pattern;
{
    /** Returns true iff the pattern occurs in it's entirety
	in the subject line of the indicated message **/
        
    int ret = 0;

    if (mss && mss->subject)
	ret = find_pattern_from_string(mss->subject,
				       pattern,1);    
    return ret;
}


struct search_mes {
    struct string     * pat;
    int                 found;
};

S_(mw_init_handler mw_init_search)
static void mw_init_search(hdl)
    struct walk_handler *hdl;
{
    hdl->u.search_mes = safe_malloc(sizeof (* (hdl->u.search_mes)));
    
    hdl->u.search_mes -> pat     = NULL;
    hdl->u.search_mes -> found   = 0;
}

S_(mw_free_handler mw_free_search)
static void mw_free_search(hdl)
     struct walk_handler *hdl;
{

    free(hdl->u.search_mes);
    hdl->u.search_mes = NULL;
}

S_(mw_action_handler mw_action_search)
static void mw_action_search(hdl,ptr,state_in,fp,state_out) 
     struct walk_handler *hdl; 
     mime_t *ptr;
     in_state_t *state_in; 
     FILE *fp;                    /* Same than state_in */
     out_state_t *state_out;   /* NULL */
{
    charset_t res = NULL;
    char buffer[1024];
    int l;

    if (ptr->description &&
	find_pattern_from_string(ptr->description,
				 hdl->u.search_mes -> pat,1)) {

	hdl->u.search_mes -> found = 1;
	DPRINT(Debug,3,(&Debug, "%S found from description: %S\n",
			hdl->u.search_mes -> pat, ptr->description));
    }

    mime_get_charset(&res, ptr->TYPE_opts,NULL,
		     default_mimetext_charset /* FIXME:  No correct */);
    
    while (0 < (l =  state_getl(buffer,sizeof buffer,state_in))) {
	struct string *x =  new_string(res);

	add_streambytes_to_string(x,l,s2us(buffer),NULL);

	if (find_pattern_from_string(x,hdl->u.search_mes -> pat,1)) {
	    hdl->u.search_mes -> found = 1;

	    DPRINT(Debug,3,(&Debug, "%S found from: %S\n",
			    hdl->u.search_mes -> pat, x));

	}

	free_string(&x);
    }

}

static struct handler_type search_mech_type = {
    WALKTYPE_magic,
    mw_init_search,
    mw_free_search,
    mw_action_search
};

int mc_match_in_text_mbx(u,meta_pattern,  page, LOC)
     union mcommon_union *u;
     struct string * meta_pattern;
     struct menu_context  *page;
     struct screen_parts *LOC; 
{
    struct MailboxView *mbxview = u->mbx.mw;
    int LINES, COLUMNS;

    /* function match_in_message() from pattern.c */


    /** Match a string INSIDE a message...starting at the current 
	message read each line and try to find the pattern.  As
	soon as we do, set current and leave! 
	Returns 1 if found, 0 if not
    **/
    
    char buffer[VERY_LONG_STRING];
    int  message_number, lines, line, line_len, err;
    int mc;
    int ret = 0;
    int selected = get_selected(mbxview);

    struct walk_handler * walk = malloc_walk_handler(&search_mech_type);

    menu_get_sizes(page, &LINES, &COLUMNS);

    message_number = get_current(mbxview)-1;
    
    walk->u.search_mes -> pat    = meta_pattern;

    lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmSearchingFolderPattern,
			  "Searching folder for pattern..."));
    
       
    mc = get_message_count(mbxview);
    while (message_number < mc) {
	
	struct header_rec *hdr = give_header(mbxview,message_number);
	
	if (!selected || (selected && 
			  hdr->status & VISIBLE)) {
	    
	    FILE *ZZ;
	    
	    in_state_t  state_in;
	    int val = (message_number+1) / (float) mc * 100;
	    
	    if ((message_number+1) % readmsginc == 0 ||
		val % readdatapercentinc       == 0) {
		
		PutLineX(LINES-1, 0, CATGETS(elm_msg_cat, ElmSet, 
					       ElmSearchingInMessage,
					       "Searching %d (%02d%%) "),
			 (message_number+1), val);
		
		CleartoEOLN();
		
	    }

	    /* Search first from subject and from */
	    if (from_matches(hdr, meta_pattern) || 
		subject_matches(hdr, meta_pattern)) {
		
		int current = message_number+1; 
		set_current(mbxview,current);
		
		clear_error();
		ret = 1;
		
		PutLineX(LINES-1, 0, CATGETS(elm_msg_cat, ElmSet, 
					       ElmSearchingInMessageFound,
					       "Searching %d (%02d%%) FOUND"),
			 (message_number+1), val);
		
		CleartoEOLN();
		
		goto out;		
	    }
	    
	    if (!give_message_data(mbxview,message_number,
				   &hdr,&ZZ,NULL,mime_parse_routine)) {
	     failXX:
		err = errno;
		
		DPRINT(Debug,1,(&Debug, 
				"Error: seek %ld bytes into file failed. errno %d (%s)\n",
				hdr ? hdr->offset : -1, err, 
				"match_in_message"));
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmMatchSeekFailed,
				  "ELM [match] failed looking %ld bytes into file (%s)."),
			  hdr ? hdr->offset : -1, 
			  error_description(err));		
		ret = 1;	/* fake it out to avoid replacing error message */
		goto out;
	    }
	    
	    if (!hdr->mime_parsed) {
		DPRINT(Debug,1,(&Debug,
				"mime_parse_routine was not called\n"));
		mime_parse_routine(NULL,hdr,ZZ);
	    }

	    {
		struct menu_common MENU;
		int vis;

		set_mcommon_from_mbxview(&MENU,mbxview);

		vis = compute_visible(message_number+1, &MENU);
		menu_header_status_update(LOC->header_page,vis-1);

	    }


	    /* Copy some headers from part 1 */
	    if (skip_envelope(hdr, ZZ) != -1) {
	
		int found  = 0;

		header_list_ptr all_headers = file_read_headers(ZZ,
								RHL_MARK_FOLDING);
		header_list_ptr next_hdr;
		
		for (next_hdr = all_headers; 
		     next_hdr; 
		     next_hdr = next_hdr -> next_header) {
		    CONST char * hdr_name = give_header_name(next_hdr->header_name);
		    struct string *s = new_string2(ASCII_SET,cs2us(hdr_name));
	  
		    struct string *buffer = 
			give_decoded_header(next_hdr,
					    !(hdr->status & 
					      NOHDRENCODING),
					    hdr -> header_charset);


		    if (find_pattern_from_string(buffer,meta_pattern,1))
			found++;
		    if (find_pattern_from_string(s,meta_pattern,1))
			found++;

		    free_string(&buffer);
		    free_string(&s);
		}

		if (all_headers)
		    delete_headers(&all_headers);

		if (found) {
		    int current = message_number+1; 
		    set_current(mbxview,current);
		    
		    clear_error();
		    ret = 1;
		    
		    PutLineX(LINES-1, 0, CATGETS(elm_msg_cat, ElmSet, 
						   ElmSearchingInMessageFound,
						   "Searching %d (%02d%%) FOUND"),
			     (message_number+1), val);
		    
		    CleartoEOLN();
		    
		    goto out;				   
		}

	    } else
		goto failXX;
	    
	    in_state_clear(&state_in,  STATE_in_file);
	    set_in_state_file(ZZ,&state_in);
	    
	    simple_mime_walk(&(hdr->mime_rec), walk, &state_in, NULL);
	    
	    in_state_destroy(&state_in); 
	    
	    if (walk->u.search_mes ->found) {
	    
		int current = message_number+1; 
		set_current(mbxview,current);
		
		clear_error();
		ret = 1;
		
		PutLineX(LINES-1, 0, CATGETS(elm_msg_cat, ElmSet, 
					       ElmSearchingInMessageFound,
					       "Searching %d (%02d%%) FOUND"),
			 (message_number+1), val);
		
		CleartoEOLN();
		
		goto out;
	    }	    
	}
	/** now we've passed the end of THIS message...increment and 
	    continue the search with the next message! **/
	
	message_number++;
    }

 out:
    free_walk_handler(&walk);
    return(ret);


}

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


syntax highlighted by Code2HTML, v. 0.9.1