static char rcsid[] = "@(#)$Id: message_limit.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 limit.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 char *us2s P_((unsigned char *str));
static char *us2s(str) 
     unsigned char *str;
{
    return (char *)str;
}

static int limit_selection P_((int based_on, struct string *pattern, 
				int *vector,
				struct MailboxView *mailbox));
static int limit_by_string_subject P_((const struct string *pattern,
				       int *vector,
				       struct MailboxView *mailbox));

static int limit_by_header P_((struct string *header, 
			       struct string*value,
			       int *vector,
			       struct MailboxView *mailbox,
			       struct menu_context  *page));

static int limit_by_string_subject(pattern,vector,mailbox)
     CONST struct string *pattern;
     int *vector;
     struct MailboxView *mailbox;
{
    int iindex;	
    int ret = 0;
    int mc = get_message_count(mailbox);

    DPRINT(Debug,9,(&Debug, 
		    "limit_by_string_subject: pattern=%S\n",
		    pattern));


    for (iindex = 0 ; iindex < mc ; iindex++) {
	struct header_rec * hdr = give_header(mailbox,iindex);
	int match = 0;
	
	if (hdr && hdr->subject)
	    match = find_pattern_from_string(hdr->subject,
					     pattern,1);
	
	if (match)
	    vector[ret++] = iindex;
    }

    DPRINT(Debug,9,(&Debug, 
		    "limit_by_string_subject=%d\n",
		    ret));

    return ret;
}

static int limit_by_header(header,value, vector, mailbox,page)
     struct string *header; 
     struct string *value;
     int *vector;
     struct MailboxView *mailbox;
     struct menu_context  *page;
{
    int ret = 0;
    int message_number;
    int mc = get_message_count(mailbox);
    struct string * Z = ascify_string(header);
    char * header1 = us2s(stream_from_string(Z,0,NULL));
    int LINES, COLUMNS;

    menu_get_sizes(page,&LINES,&COLUMNS);

    DPRINT(Debug,9,(&Debug, 
		    "limit_by_string_subject: header=%S value=%S\n",
		    header,value));

    DPRINT(Debug,9,(&Debug, 
		    "limit_by_string_subject: header1=%s\n",
		    header1));

    for (message_number = 0 ; message_number < mc ; message_number++) {
	struct header_rec *hdr;
	FILE *ZZ;

	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();
	    
	}

	if (give_message_data(mailbox,message_number,
			      &hdr,&ZZ,NULL,NO_mime_parse)) {

	    int match = 0;
	    header_list_ptr all_headers;

	    if (skip_envelope(hdr, ZZ) == -1) 
		continue;

	    all_headers = file_read_headers(ZZ,
					    RHL_CHECK_HEADER);

	    if (all_headers) {
		header_list_ptr walk;

		for (walk = locate_header_by_name(all_headers,header1);
		     walk;
		     walk = walk->next_this_header) {

		    if (!value)
			match++;
		    else {
			struct string * A = 
			    give_decoded_header(walk,			       
						!(hdr->status &
						  NOHDRENCODING),
						hdr -> header_charset);

			if (find_pattern_from_string(A,value,1))
			    match++;

			free_string(&A);
		    }
		}
		delete_headers(&all_headers);
	    }

	    if (match)
		vector[ret++] = message_number;
	    
	}
    }

    PutLineX(LINES-1, 0, CATGETS(elm_msg_cat, ElmSet, 
				   ElmSearchingInMessageDone,
				   "Searching %d. Done "),
	     (message_number+1));

    free(header1);
    free_string(&Z);


    DPRINT(Debug,9,(&Debug, 
		    "limit_by_string_subject=%d\n",
		    ret));

    return ret;
}

#define TO		1
#define FROM		2
#define CC              3

static int limit_selection(based_on, pattern, vector,mailbox)
     int based_on;
     struct string *pattern;
     int *vector;
     struct MailboxView *mailbox;
{
    int ret = 0;
    int iindex;
    int mc = get_message_count(mailbox);

    DPRINT(Debug,9,(&Debug, 
		    "limit_selection: based_on=%d pattern=%S\n",
		    based_on,pattern));


    for (iindex = 0 ; iindex < mc ; iindex++) {
	struct header_rec * hdr = give_header(mailbox,iindex);
	
	int match;
	
	switch (based_on) {
	    
	case FROM:
	    match = from_matches(hdr,pattern);
	    break;
	case TO:
	    match = to_matches(hdr,pattern);
	    break;
	case CC:
	    match = cc_matches(hdr,pattern);
	    break;
	case SUBJECT:
	default:
	    match = subject_matches(hdr,pattern);
	    break;
	}

	if (match)
	    vector[ret++] = iindex;
    }

    DPRINT(Debug,9,(&Debug, 
		    "limit_selection=%d\n",ret));

    return ret;
}



int mc_limit_helper_mbx(u,str,retarr, page)
     union mcommon_union *u;
     struct string *str;
     int **retarr;
     struct menu_context  *page;
{
    int ret = -1;   

    int *vector = NULL;
    struct MailboxView *mbxview = u->mbx.mw;

    int n = get_message_count(mbxview);

    if (n < 1) 
	goto fail;
    
    vector = safe_malloc(n * sizeof(vector[0]));

    if (string_matches_ascii(str, s2us("thread"))) {
	int current = get_current(mbxview);
	struct header_rec * hdr = give_header(mbxview,current-1);
	
	struct string * temp;
	
	if (!hdr)
	    goto fail;   
	if (!hdr->subject)
	    goto fail;
	
	temp = skip_ascii_head_from_string(hdr-> subject, s2us("Re: "),1);

	ret = limit_by_string_subject(temp,vector,mbxview);
	free_string(&temp);

    } else {
	struct string *first = NULL;
	struct string *rest  = NULL;
	int L = string_len(str);
	uint16 delim;
	int pos = 0;

	if (!get_word_from_string(str,&first,&pos,GWF_lowercase,
				  /* ASCII assumed */
				  s2us(" \t:"),&delim))
	    goto fail2;

	if (pos < L)
	    pos++;
	
	if (pos < L &&
	    0x0020 /* space */ == give_unicode_from_string(str,pos))
	    pos++;

	if (0x003A /* : */ == delim) {
	    rest = clip_from_string(str,&pos,L);

	    ret = limit_by_header(first, rest, vector,  mbxview, page);

	} else if (string_matches_ascii(first,s2us("subject"))) {

	    rest = clip_from_string(str,&pos,L);

	    ret = limit_selection(SUBJECT, rest, vector, mbxview);

	} else if (string_matches_ascii(first, s2us("to"))) {
	    rest = clip_from_string(str,&pos,L);

	    ret = limit_selection(TO, rest, vector, mbxview);

	} else if (string_matches_ascii(first, s2us("cc"))) {
	    rest = clip_from_string(str,&pos,L);
		    
	    ret = limit_selection(CC, rest, vector, mbxview);
	    
	} else if (string_matches_ascii(first, s2us("from"))) {
	    rest = clip_from_string(str,&pos,L);

	    ret = limit_selection(FROM, rest, vector, mbxview);

	} else if (string_matches_ascii(first, s2us("header"))) {
	    struct string *header  = NULL;
	    uint16 delim;

	    /* Continue seach from pos where previous ended */

	    if (!get_word_from_string(str,&header,&pos,
				      GWF_lowercase|GWF_trim_space,
				      /* ASCII assumed */
				      s2us(":"),&delim))
		goto fail3;

	    if (pos < L)
		pos++;
	    
	    if (pos < L &&
		0x0020 /* space */ == give_unicode_from_string(str,pos))
		pos++;

	    rest = clip_from_string(str,&pos,L);
	    
	    ret = limit_by_header(header,rest,vector, mbxview, page);
	    
	fail3:
	    if (header)
		free_string(&header);

	} else {
	    
	    lib_error(CATGETS(elm_msg_cat, ElmSet, 
			      ElmLimitNotValidCriterion,
			      "\"%S\" not a valid criterion."), 
			    first);
	    
	}

    fail2:
		
	if (first)
	    free_string(&first);
	if (rest)
	    free_string(&rest);
		
    }

 fail:

		if (ret <= 0) {
		    if (vector)
			free(vector);
	*retarr = NULL;
    } else
	*retarr = vector;

		return ret;
}

void mc_limit_print_help_mbx(last_selected)
     int last_selected;
{
    if (last_selected)
	lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmEnterLastSelected,
			      "Enter: {\"subject\",\"to\",\"from\",\"cc\",\"header\"} [pattern] OR {\"tagged\",\"all\",...}"));
    else
	lib_transient(CATGETS(elm_msg_cat, ElmSet, ElmEnterSelected,
			      "Enter: {\"subject\",\"to\",\"from\",\"header\"} [pattern] OR \"thread\",\"tagged\",...}"));
    
}

void mc_limit_print_result_mbx(u)
     union mcommon_union *u;
{
    struct MailboxView *mbxview = u->mbx.mw;

    if (get_selected(mbxview) > 1)
	lib_error(CATGETS(elm_msg_cat, ElmSet,
			  ElmLimitMessagesSelected, 
			  "%d messages selected."), 
		  get_selected(mbxview));
    else if (get_selected(mbxview) == 1)
	lib_error(CATGETS(elm_msg_cat, ElmSet, 
			  ElmLimitMessageSelected,
			  "1 message selected."));
    else
	lib_error(CATGETS(elm_msg_cat, ElmSet,
			  ElmLimitNoMessagesSelected, 
			  "No messages selected."));
}

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


syntax highlighted by Code2HTML, v. 0.9.1