static char rcsid[] = "@(#)$Id: thread.c,v 1.10 2006/04/16 21:01:35 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.10 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> 
 *      or  Kari Hurtta <elm@elmme-mailer.org>
 *****************************************************************************/

#include "def_elm.h"
#include "s_me.h"

DEBUG_VAR(Debug,__FILE__,"mail");

static void first_item P_((void));
static void first_item()
{
    lib_error(CATGETS(elm_msg_cat, MeSet, 
		      MeNoMoreThreadsAbove,
		      "No more threads above."));    
}

static void last_item P_((void));
static void last_item()
{
    lib_error(CATGETS(elm_msg_cat, MeSet, 
		      MeNoMoreThreadsBelow,
		      "No more threads below.")); 
}

static struct move_messages M = {
    first_item,
    last_item
};

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

struct sort_list {
    char  status_letter;
    int   idx;
};


struct menu_anon_param {
    struct MailboxView * mailbox; 

    struct sort_list   * sort_list;
    int                  sort_list_len;
};

struct sort_data1 {
    struct MailboxView *mailbox;
    int index;
};

static int compare_threads_1 P_((const struct thread_info *X1,
				 const struct thread_info *X2));
static int compare_threads_1(X1,X2)
     CONST struct thread_info *X1;
     CONST struct thread_info *X2;
{
    long diff = 0;
    int ret;

    switch (give_dt_sort_as_int(&thread_sortby)) {

    case SENT_DATE:   /* as THREAD sorting */

	diff = X1->time_sent_first - X2->time_sent_first;

	if (diff < 0)
	    return -1;
	if (diff > 0)
	    return 1;
	break;

    case REVERSE SENT_DATE:

	if (unstable_reverse_thread) {
	    /* Move thread new location when new mail arrives,
	       therfore use newest sent time
	    */

	    diff = X1->time_sent_last - X2->time_sent_last;
	} else
	    diff = X1->time_sent_first - X2->time_sent_first;

	if (diff < 0)
	    return 1;
	if (diff > 0)
	    return -1;
	break;

    case SUBJECT:

	if (! X1->thread_subject && ! X2->thread_subject)
	    return 0;
	if (! X1->thread_subject)
	    return -1;
	if (! X2->thread_subject)
	    return 1;

	ret = string_cmp(X1->thread_subject,X2->thread_subject, 
			 0 /* == Values not comparable */ );

	return ret;

    case REVERSE SUBJECT:

	if (! X1->thread_subject && ! X2->thread_subject)
	    return 0;
	if (! X1->thread_subject)
	    return -1;
	if (! X2->thread_subject)
	    return 1;

	ret = string_cmp(X1->thread_subject,X2->thread_subject, 
			 0 /* == Values not comparable */ );

	return ret;
    }

    return 0;
}

static int compare_threads P_((struct sort_data1 *p1,
			       struct sort_data1 *p2));
static int compare_threads(p1,p2)
     struct sort_data1 *p1; 
     struct sort_data1 *p2;
{
    int ret;

    /* give_thread_info checks that index is correct range */
    CONST struct thread_info *X1 = give_thread_info(p1->mailbox,
						    p1->index);
    CONST struct thread_info *X2 = give_thread_info(p2->mailbox,
						    p2->index);

    if (!X1 && !X2) {
	return p2->index - p1->index;
    }

    if (!X1) 
	return -1;
    if (!X2) 
	return 1;

    ret = compare_threads_1(X1,X2);

    if (ret != 0)
	return ret;

    return p2->index - p1->index;
}


static void sort_threads P_((struct MailboxView *mailbox,
			     struct menu_anon_param *A,
			     struct menu_context *page));

static void sort_threads(mailbox,A,page)
     struct MailboxView *mailbox;
     struct menu_anon_param *A;
     struct menu_context *page;
{
    /* Be sure that we have threads available */
    int num_threads = get_thread_count(mailbox,0);
    int old_len = A->sort_list_len;
    int cur = menu_header_get(page,header_current);
    int top     = menu_header_get(page,header_top_line);
    int real_cur = 0;
    int i;

    struct sort_data1 * array;

    /* Little dirty ... */
    typedef int (*compar) P_((const void *, const void *));
    compar X = (compar) compare_threads;


    int li,co;
    menu_get_sizes(page, &li, &co);   


    if (num_threads < 1) {
	A->sort_list_len = 0;

	menu_header_change(page, header_top_line,0);
	menu_header_change(page,header_current,0);

	return;
    }

    if (cur >= 0 && cur < A->sort_list_len)
	real_cur = A->sort_list[cur].idx;

    A->sort_list = safe_realloc(A->sort_list,
				num_threads * sizeof (A->sort_list[0]));

    for (i = old_len; i < num_threads; i++) {
	A->sort_list[i].idx = i;
	A->sort_list[i].status_letter = '\0';
    }
    A->sort_list_len = num_threads;

    array = safe_malloc(num_threads * sizeof(array[0]));

    for (i = 0; i < num_threads; i++) {
	array[i].index   = A->sort_list[i].idx;
	array[i].mailbox = mailbox;
    }

    qsort(array,num_threads,sizeof (array[0]), X);

    for (i = 0; i < num_threads; i++) {
	if (array[i].index   != A->sort_list[i].idx) {
	    A->sort_list[i].idx = array[i].index;
	    A->sort_list[i].status_letter = '\0';
	}
    }
    free(array);

    /* FIXME -- not very effective */
    for (i = 0; i < A->sort_list_len; i++) {
	if (real_cur == A->sort_list[i].idx) {
	    menu_header_change(page,header_current,i);
	    if (i < top || i >= top+li)
		menu_header_change(page,header_current,i);
	    break;
	}
    }
    menu_trigger_redraw(page);
}

static int calculate_status P_((struct menu_anon_param *A,
				int index));

/* return 1 if changed */
static int calculate_status(A,index)
     struct menu_anon_param *A;
     int index;
{
    int * vector = NULL;
    int len;
    char new_val;

    if (index < 0 || index > A->sort_list_len)
	panic("THREAD PANIC",__FILE__,__LINE__,"calculate_status",
	      "Bad index",0);

    vector = give_thread_message_list(A->mailbox,A->sort_list[index].idx,
				      &len);
    if (vector) {
	int i;
	int all_deleted = 1;
	int all_expired = 1;

	new_val = ' ';

	for (i = 0; i < len; i++) {
	    
	    if (!ison_status_message(A->mailbox,vector[i],status_basic,
				     DELETED))
		all_deleted = 0;
	    if (!ison_status_message(A->mailbox,vector[i],status_basic,
				     EXPIRED))
		all_expired = 0;
	    
	    if (' ' == new_val &&
		ison_status_message(A->mailbox,vector[i],status_basic,UNREAD))
		new_val = 'O';
	    
	    if ((' ' == new_val || 'O' == new_val) &&
		ison_status_message(A->mailbox,vector[i],status_basic,NEW))
		new_val = 'N';
	    
	}

	if (all_expired)
	    new_val = 'E';
	if (all_deleted)
	    new_val = 'D';

	free(vector);
    } else
	new_val = 'Z';

    
    if (A->sort_list[index].status_letter != new_val) {
	A->sort_list[index].status_letter = new_val;
	return 1;
    }
    return 0;
}

enum { thread_mp_mailbox,
       thread_mp_param,
       thread_mp_COUNT };


S_(header_line_redraw thread_show_header)
static void thread_show_header P_((struct menu_context  *ptr,
				   struct menu_param *list,
				   int line_number,
				   int index,
				   int is_current));
static void thread_show_header(ptr,list,line_number,index,is_current)
     struct menu_context  *ptr;
     struct menu_param *list;	   
     int line_number;
     int index;
     int is_current;
{
    struct menu_anon_param *A = mp_lookup_anon(list,thread_mp_param);

    int LINES, COLUMNS;

    menu_get_sizes(ptr, &LINES, &COLUMNS);

    menu_ClearLine(ptr,line_number);	    
    menu_MoveCursor(ptr,line_number,0);

    if (is_current) {

	if (has_highlighting && ! arrow_cursor) {

	    menu_StartXX(ptr,pg_INVERSE);

	    menu_PutLine0(ptr,line_number,0,"   ");

	} else {
	    menu_PutLine0(ptr,line_number,0,"-> ");

	}

    } else 
	menu_PutLine0(ptr,line_number,0,"   ");

    if (index >= 0 && index < A->sort_list_len) {
	CONST struct thread_info *X;

	if (!A->sort_list[index].status_letter)
	    calculate_status(A,index);

	/* give_thread_info checks that index is correct range */
	X = give_thread_info(A->mailbox,A->sort_list[index].idx);
	if (X) {
	    /* Message menu is show time as sending timezone,
	       but on thread view we use localtime 
	    */

	    char buffer[7];
	    struct tm * tmres = localtime(& X->time_sent_first);
	    struct string * S = NULL;
	    int l;

	    S = format_string(FRM("%c %3d %3.3s %-2d "),
			  A->sort_list[index].status_letter ?
			  A->sort_list[index].status_letter : '?',
			  index+1, 
			  arpa_monname[tmres->tm_mon], tmres->tm_mday);

	    l = string_len(S);
			           
	    if (COLUMNS > l+3) {
		struct string *S1;

		if (X->time_sent_first != X->time_sent_last) {
		    tmres = localtime(& X->time_sent_last);
		    S1 = format_string(FRM("- %3.3s %-2d %04d "),
				       arpa_monname[tmres->tm_mon], 
				       tmres->tm_mday,tmres->tm_year+1900);
		    
		} else {
		    S1 = format_string(FRM("%04d          "),
				       tmres->tm_year+1900);
		}
		
		append_string(&S,S1);
		free_string(&S1);

		l = string_len(S);
	    }
	    
	    if (COLUMNS > l+3) {
		struct string *S1;
		if (X->num_messages != 1) {
		    S1 = format_string(FRM("[%3d] "),
				       X->num_messages);
		} else {
		    S1 = format_string(FRM("      "));		    
		}

		append_string(&S,S1);
		free_string(&S1);

		l = string_len(S);		
	    }

	    menu_PutLineX(ptr,line_number,3,FRM("%S"),S);
	    free_string(&S);
	    
	    if (X->thread_subject && COLUMNS > l+3) {
		struct string * buffer2 = NULL;
		int X1 = 0;
		int subj_width = COLUMNS-l-3;
		int was_len;

		/* clip_from_string updates X1 */
		buffer2 = curses_printable_clip(X->thread_subject,&X1,
						subj_width,
						&was_len,subj_width);
						
		
		if (buffer2) {
		    menu_PutLineX(ptr,line_number,l+3,FRM("%S"),
				  buffer2);		    
		    free_string(&buffer2);
		}	    		


		if (is_current && !arrow_cursor) {
		    while (was_len < subj_width) {
			menu_Writechar(ptr,' ');
			was_len++;
		    }
		}

	    } 
	}

    }

    if (is_current) {
	if (has_highlighting && ! arrow_cursor) {
	    menu_EndXX(ptr,pg_INVERSE);
	}
    }
    menu_Writechar(ptr,'\r');
    menu_Writechar(ptr,'\n');
}

S_(header_line_redraw thread_show_current)
static void thread_show_current P_((struct menu_context  *ptr,
				    struct menu_param *list,
				    int line_number,
				    int index,
				    int is_current));
static void thread_show_current(ptr,list,line_number,index,is_current)
     struct menu_context  *ptr;
     struct menu_param *list;	   
     int line_number;
     int index;
     int is_current;
{

    if (has_highlighting && ! arrow_cursor) {
	thread_show_header(ptr,list,line_number,index,is_current);
    } else {
	if (!is_current)
	    menu_PutLine0(ptr,line_number,0,"  ");  /* remove old pointer... */
	else
	    menu_PutLine0(ptr,line_number,0,"->");
    }
}

S_(header_line_redraw thread_show_status)
static void thread_show_status P_((struct menu_context  *ptr,
				    struct menu_param *list,
				    int line_number,
				    int index,
				    int is_current));
static void thread_show_status(ptr,list,line_number,index,is_current)
     struct menu_context  *ptr;
     struct menu_param *list;	   
     int line_number;
     int index;
     int is_current;
{
    struct menu_anon_param *A = mp_lookup_anon(list,thread_mp_param);


    if (has_highlighting && ! arrow_cursor) {
	thread_show_header(ptr,list,line_number,index,is_current);
    } else {
	if (!is_current)
	    menu_PutLine0(ptr,line_number,0,"  ");  /* remove old pointer... */
	else
	    menu_PutLine0(ptr,line_number,0,"->");

	if (index >= 0 && index < A->sort_list_len) {
	    CONST struct thread_info *X;

	    /* give_thread_info checks that index is correct range */
	    X = give_thread_info(A->mailbox,A->sort_list[index].idx);
	    if (X) {

	    menu_PutLineX(ptr,line_number,3,
			  FRM("%c"),
			  A->sort_list[index].status_letter ?
			  A->sort_list[index].status_letter : '?');
	    }
	}
    }
}


S_(subpage_simple_redraw sb_update_thread_menu)
static int sb_update_thread_menu P_((struct menu_context  *ptr,
				     struct menu_param *list));
static int sb_update_thread_menu(ptr,list)
     struct menu_context  *ptr;
     struct menu_param *list;
{
    menu_ClearScreen(ptr);

    menu_print_format_center(ptr,0,
			     CATGETS(elm_msg_cat, MeSet, MeThreadMenuLine1,
				     "To select thread, press <return>.  j = move down, k = move up, q = quit menu"));
    menu_print_format_center(ptr,1,
			     CATGETS(elm_msg_cat, MeSet, MeThreadMenuLine2,
				     "Or m)ail message,  d)elete or u)ndelete messages of thread"));

    return 1;
}



S_(subpage_simple_redraw sb_update_threadtitle)
static int sb_update_threadtitle P_((struct menu_context  *ptr,
				     struct menu_param *list));
static int sb_update_threadtitle(ptr,list)
     struct menu_context  *ptr;
     struct menu_param *list;
{
    struct menu_common *mptr = mp_lookup_mcommon(list,thread_mp_mailbox);
    struct string * f1 = mcommon_title(mptr);
    struct menu_anon_param *A = mp_lookup_anon(list,thread_mp_param);
    int num_threads = get_thread_count(A->mailbox,0);

    struct string * buffer = NULL;
    struct string * buffer2 = NULL;

    int LINES, COLUMNS;
    int l1,l2,l;

    menu_ClearScreen(ptr);
    menu_get_sizes(ptr, &LINES, &COLUMNS);   

    
    if (1 == num_threads)
	buffer = format_string(CATGETS(elm_msg_cat, MeSet, 
				       MeShownWithThread,
				       "%S with 1 thread"),
			       f1);
    else
	buffer = format_string(CATGETS(elm_msg_cat, MeSet, 
				       MeShownWithThreads,
				       "%S with %d threads"),
			   f1,num_threads);

    l1 = string_len(buffer);
    
    buffer2 = format_string(FRM("[ELM %s]"),
			    version_buff);
    l2 = string_len(buffer2);
    l = l1 + l2 + 1; /* Assumed */
    
    if (l > COLUMNS) {
	if (l2 < COLUMNS)
	    menu_PutLineX(ptr,2,(COLUMNS - l2)/2,FRM("%S"),buffer2);
	if (l1 > COLUMNS) 
	    menu_PutLineX(ptr,1,1,FRM("%S"),buffer);
	else
	    menu_PutLineX(ptr,1,(COLUMNS - l1)/2,FRM("%S"),buffer);
    } else {
	menu_PutLineX(ptr,1,(COLUMNS - l)/2,FRM("%S %S"),buffer,buffer2);
    }


    free_string(&buffer2);
    free_string(&buffer);
    free_string(&f1);


    return 1;   /* subpage area updated completely */

}

static void set_thread_screen P_((struct menu_context  *page, 
				 struct screen_parts *LOC,
				 struct menu_param  *LIST));
static void set_thread_screen(page,LOC,LIST)
     struct menu_context  *page;
     struct screen_parts *LOC;
     struct menu_param  *LIST;
{
    int   LINES, COLUMNS;	
    int  headers_per_page;

    menu_get_sizes(page,&LINES, &COLUMNS);

    /* 1)  Title part of screen */

    if (! LOC->title_page)
	LOC->title_page = new_menu_subpage(page,0,4,sb_update_threadtitle,
					   LIST);
    else
	menu_subpage_relocate(LOC->title_page,page,0,4);


    /* 3) menu part */


    if (LOC->menu_page && LINES < 14)
	erase_menu_context (&(LOC->menu_page));
    else if (LOC->menu_page)
	menu_subpage_relocate(LOC->menu_page,page,LINES-7,3);
    else if (mini_menu && LINES > 14)
	LOC->menu_page = new_menu_subpage(page,LINES-7,3,
					  sb_update_thread_menu,LIST);

    /* 4) prompt part  */

    if (LOC->prompt_page)
	menu_subpage_relocate(LOC->prompt_page,page,LINES-4,4);
    else 
	LOC->prompt_page = new_menu_subpage(page,LINES-4,4,
					    subpage_simple_noredraw,LIST);


    /* 2) thread part */
    headers_per_page = LOC->menu_page ? LINES-12 : LINES-9;
    if (headers_per_page < 1) {
	headers_per_page = 1;
    }

    if (! LOC->header_page)
	LOC->header_page = new_menu_header(page,4,
					   headers_per_page,
					   thread_show_header,
					   thread_show_current,
					   null_header_param_changed,
					   thread_show_status,
					   LIST);
    else 
	menu_header_relocate(LOC->header_page,page,
			     4,headers_per_page);


}


static void check_thread_screen P_((struct screen_parts *LOC,
				    struct menu_param *list));
static void check_thread_screen(LOC,list)
     struct screen_parts *LOC;
     struct menu_param *list;
{
    /* 1) title page */
    if (menu_resized(LOC->title_page)) {
	DPRINT(Debug,1, (&Debug, "title page resized\n"));

    }
    if (menu_need_redraw(LOC->title_page)) {
	DPRINT(Debug,1, (&Debug, "title page redraw???\n"));
	sb_update_threadtitle(LOC->title_page,list);
    }

    /* 2) headers part */
    if (menu_resized(LOC->header_page)) {
	DPRINT(Debug,1, (&Debug, "header page resized\n"));
    }
    if (menu_need_redraw(LOC->header_page)) {
	DPRINT(Debug,1, (&Debug, "header page redraw\n"));
	menu_ClearScreen(LOC->header_page);
    }


    if (LOC->menu_page) {
	/* 3) menu page */
	if (menu_resized(LOC->menu_page)) {
	    DPRINT(Debug,1, (&Debug, "menu page resized\n"));
	    
	}
	if (menu_need_redraw(LOC->menu_page)) {
	    DPRINT(Debug,1, (&Debug, "menu page redraw\n"));
	    sb_update_thread_menu(LOC->menu_page,list);
	}
    }

    /* 4) prompt part */
    if (menu_resized(LOC->prompt_page)) {
	DPRINT(Debug,1, (&Debug, "prompt page resized\n"));
    }
    if (menu_need_redraw(LOC->prompt_page)) {
	DPRINT(Debug,7, (&Debug, "prompt page redraw\n"));

	menu_ClearScreen(LOC->prompt_page);

	show_last_error();	/* for those operations that have to
				 * clear the footer except for a message.
				 */
    }

}


void ViewThreads(mailbox,aview, parent_page)
     struct MailboxView *mailbox;
     struct AliasView *aview;
     struct menu_context  *parent_page;

{
    struct menu_context  * page;
    struct screen_parts  LOC  = { NULL, NULL, NULL, NULL };
    struct menu_common MENU;
    int mailbox_sort_needed = 0;
    struct menu_anon_param A;


    struct menu_param  PARAM[thread_mp_COUNT+1] = {   
	{ mp_menu_common, 0 },
	{ mp_anon_param,0 },
	{ mp_END,0 }
    };
    int ch;
    int update = 1;
    int c;


    /* we need update thread list, becuase it may be changed meanwhile */
    update_mailbox_threads(mailbox);
    
    
    set_mcommon_from_mbxview(&MENU,mailbox);    
    mp_list_set_mcommon(PARAM,thread_mp_mailbox,&MENU);    

    A.mailbox = mailbox;
    A.sort_list = NULL;
    A.sort_list_len = 0;
    mp_list_set_anon(PARAM,thread_mp_param,&A);





    page = new_menu_context();
    set_thread_screen(page,&LOC,PARAM);

    sort_threads(mailbox,&A,LOC.header_page);

    c = get_current(mailbox);
    if (c > 0) {
	int i;
	struct folder_view INDEX;
	int li,co;
    
	INDEX.thread_number = -1;

	give_index_number(mailbox,c-1,&INDEX);

	menu_get_sizes(LOC.header_page, &li, &co);   


	/* FIXME -- not very effective */
	for (i = 0; i < A.sort_list_len; i++) {
	    if (INDEX.thread_number == A.sort_list[i].idx) {
		menu_header_change(LOC.header_page,header_current,i);
		if (i > li)
		    menu_header_change(LOC.header_page, header_top_line,i);
	    }
	}	
    }


    for (;;) {

	if (menu_resized(page)) {
	    set_thread_screen(page,&LOC,PARAM);
	    
	    update = 1;
	} 

	new_mail_check(mailbox, page, &LOC);      

	if (update_view(mailbox)) {
	    update = 1;
	    mailbox_sort_needed = 1;

	    /* We do not sort mailbox, because we do not show
	       message list */

	    update_mailbox_threads(mailbox);
	    sort_threads(mailbox,&A,LOC.header_page);
	}

	
	if (update || menu_need_redraw(page)) {
	    menu_ClearScreen(page);
	    
	    /* Call refresh routines of children */
	    menu_redraw_children(page);
	    
	    update = 0;
	    show_last_error(); 
	} 

	check_thread_screen(&LOC, PARAM);

	{
	    int lin,col;
	    
	    menu_ClearLine(LOC.prompt_page,0);

	    menu_PutLineX (LOC.prompt_page,0, 0, 
			   CATGETS(elm_msg_cat, MeSet, MeThreadMenuPrompt,
				   "Thread command: "));
	    menu_GetXYLocation(LOC.prompt_page,&lin,&col);
	    
	    menu_CleartoEOS(LOC.prompt_page);   
	    
	    show_last_error();
	    menu_MoveCursor(LOC.prompt_page,lin,col);
	    
	    ch = menu_ReadCh(LOC.prompt_page, 
			     REDRAW_MARK|READCH_CURSOR|READCH_resize|
			     READCH_sig_char);

	    menu_CleartoEOS(LOC.prompt_page);
	    set_error("");	/* clear error buffer */
	}

	ch = do_movement1(LOC.header_page,ch,A.sort_list_len,&M);

	switch (ch) {
	    int cur;
	    int top;
	    int li,co;

	case RESIZE_MARK:
	    DPRINT(Debug,4, (&Debug, " ... resizing\n"));
	    continue;

	case ctrl('L'):
	case REDRAW_MARK:
	    update = 1;
	    break;

	case DOWN_MARK :
	case 'j'    :  
	    cur = menu_header_get(LOC.header_page,header_current);	    
	    cur++;
	    while (0 <= cur && cur < A.sort_list_len) {
		if (A.sort_list[cur].status_letter != 'D' &&
		    A.sort_list[cur].status_letter != 'Z') {
		    goto found1;
		}
		cur++;
	    }
	    
	    lib_error(CATGETS(elm_msg_cat, MeSet, 
			      MeNoMoreUndThreadsBelow,
			      "No more undeleted threads below.")); 

	    break;
	found1:
	    top     = menu_header_get(LOC.header_page,header_top_line);
	    menu_header_change(LOC.header_page, header_current,cur);

	    menu_get_sizes(LOC.header_page, &li, &co);   

	    if (top+li <= cur)
		menu_header_change(LOC.header_page, header_top_line,cur);
	    break;

	case UP_MARK :
	case 'k'     :  
	    cur = menu_header_get(LOC.header_page,header_current);	    
	    cur--;
	    while (0 <= cur && cur < A.sort_list_len) {
		if (A.sort_list[cur].status_letter != 'D' &&
		    A.sort_list[cur].status_letter != 'Z') {
		    goto found2;
		}
		cur--;
	    }

	    lib_error(CATGETS(elm_msg_cat, MeSet, 
			      MeNoMoreUndThreadsAbove,
			      "No more undeleted threads above."));    

	    break;
	found2:
	    top     = menu_header_get(LOC.header_page,header_top_line);
	    menu_header_change(LOC.header_page, header_current,cur);

	    menu_get_sizes(LOC.header_page, &li, &co);   
	    if (top > cur) {
		top = cur-li+1;
		if (top < 0)
		    top = 0;

		menu_header_change(LOC.header_page, header_top_line,top);
	    }
	    break;
	case 'd':
	    cur = menu_header_get(LOC.header_page,header_current);

	    if (0 <= cur && cur < A.sort_list_len) {
		int len;
		int * vector = give_thread_message_list(mailbox,A.sort_list[cur].idx,
							&len);
		if (vector) {
		    int i;

		    for (i = 0; i < len; i++) {
			setf_status_message(mailbox,vector[i],status_basic,
					    DELETED);
		    }

		    free(vector);
		}

		if (calculate_status(&A,cur)) {
		    menu_header_status_update(LOC.header_page,cur);
		}
	    }	    

	    if (resolve_mode) {
		cur = menu_header_get(LOC.header_page,header_current);	    
		cur++;
		while (0 <= cur && cur < A.sort_list_len) {
		    if (A.sort_list[cur].status_letter != 'D' &&
			A.sort_list[cur].status_letter != 'Z') {
			goto found1;
		    }
		    cur++;
		}	   
	    }

	    break;
	case 'u':
	    cur = menu_header_get(LOC.header_page,header_current);

	    if (0 <= cur && cur < A.sort_list_len) {
		int len;
		int * vector = give_thread_message_list(mailbox,A.sort_list[cur].idx,
							&len);
		if (vector) {
		    int i;

		    for (i = 0; i < len; i++) {
			clearf_status_message(mailbox,vector[i],status_basic,
					    DELETED);
		    }

		    free(vector);
		}

		if (calculate_status(&A,cur)) {
		    menu_header_status_update(LOC.header_page,cur);
		}
	    }	    

	    if (resolve_mode) {
		cur = menu_header_get(LOC.header_page,header_current);	    
		cur++;
		while (0 <= cur && cur < A.sort_list_len) {
		    if (A.sort_list[cur].status_letter != 'Z') {
			goto found1;
		    }
		    cur++;
		}	   
	    }

	    break;
	case '\n':
	    cur = menu_header_get(LOC.header_page,header_current);

	    if (0 <= cur && cur < A.sort_list_len) {
		int need_resort = 0;

		ViewThread1(mailbox,aview,A.sort_list[cur].idx,page,
			    &need_resort);

		if (calculate_status(&A,cur)) {
		    menu_header_status_update(LOC.header_page,cur);
		}

		/* New mails may be arrived meanwhile */

		update = 1;
		if (need_resort)
		    mailbox_sort_needed = 1;
		
		/* We do not sort mailbox, because we do not show
		   message list */
		
		update_mailbox_threads(mailbox);
		sort_threads(mailbox,&A,LOC.header_page);
	    }
	    break;

	case 'm':
	    menu_Write_to_screen(LOC.prompt_page,
				 CATGETS(elm_msg_cat, MeSet,
					 MeMail,
					 "Mail"));
	    FlushBuffer();
	    send_msg_l(-1, NULL, NULL, NULL,
		       MAIL_EDIT_MSG,allow_forms,
		       mailbox, aview,page, LOC.prompt_page);
	    break;


	case 'i':
	case 'q':
	case 'x':
	case TERMCH_interrupt_char:
	case EOF:
	    goto OUT;

	case 0:
	    break;

	default:
	    if (ch > '0' && ch <= '9') {
		int value;

		struct string * str = format_string(CATGETS(elm_msg_cat, MeSet,
							    MeThreadItem,
							    "thread"));

		menu_Write_to_screen(LOC.prompt_page,
				     CATGETS(elm_msg_cat, MeSet,
					     MeNewCurrentThread,
					     "New current thread"));

		cur = menu_header_get(LOC.header_page,header_current);
		value = read_number(ch, str, cur+1, page, LOC.prompt_page);

		free_string(&str);

		if (value > A.sort_list_len) {
		    lib_error(CATGETS(elm_msg_cat, MeSet,
				      MeNotThatManyThread,
				      "Not that many threads."));

		} else if (value > 0) {
		    cur = value-1;

		    top     = menu_header_get(LOC.header_page,header_top_line);
		    menu_header_change(LOC.header_page, header_current,cur);
		    
		    menu_get_sizes(LOC.header_page, &li, &co);   
		    
		    if (top+li <= cur)
			menu_header_change(LOC.header_page, header_top_line,cur);
		    else if (top > cur) {
			top = cur-li+1;
			if (top < 0)
			    top = 0;
			
			menu_header_change(LOC.header_page, header_top_line,top);
		    }
		    
		}

	    } else {
		if (isascii(ch) && isprint(ch))
		    lib_error(CATGETS(elm_msg_cat, MeSet,
				      MeThreadUnknownCommand,		       
				      "Unknown command: %c"), 
			      ch);
		else
		    lib_error(CATGETS(elm_msg_cat, MeSet,
				      MeUnknownCommand2,			
				      "Unknown command."));
	    }
	}
    }
    
    OUT:
    free_mailbox_screen(&LOC);
    
    erase_menu_context(&page);
    
    if (mailbox_sort_needed)
	resort_mailbox(mailbox,1);

    menu_trigger_redraw(parent_page);

    /* Force default return to parent page ... */
    menu_set_default(parent_page); 
}

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


syntax highlighted by Code2HTML, v. 0.9.1