static char rcsid[] = "@(#)$Id: limit.c,v 1.45 2006/04/09 07:37:18 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.45 $ $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
*****************************************************************************/
/** This stuff is inspired by MH and dmail and is used to 'select'
a subset of the existing mail in the folder based on one of a
number of criteria. The basic tricks are pretty easy - we have
as status of VISIBLE associated with each header stored in the
(er) mind of the computer (!) and simply modify the commands to
check that flag...the global variable `selected' is set to the
number of messages currently selected, or ZERO if no select.
**/
#include "def_elm.h"
#include "s_elm.h"
#include "s_aliases.h"
DEBUG_VAR(Debug,__FILE__,"mbox");
static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str)
char *str;
{
return (unsigned char *)str;
}
static int SelectTaggedMessages P_((struct menu_common *menu,
int *vector));
static int SelectTaggedMessages(menu, vector)
struct menu_common *menu;
int *vector;
{
int iindex, count = 0;
int mc = mcommon_get_count(menu);
for (iindex = 0; iindex < mc; iindex++) {
if (mcommon_ison_status(menu,iindex, status_basic,TAGGED)) {
vector[count++] = iindex;
}
}
return(count);
}
static int SelectFlaggedMessages P_((struct menu_common *menu,
int *vector));
static int SelectFlaggedMessages(menu, vector)
struct menu_common *menu;
int *vector;
{
int iindex, count = 0;
int mc = mcommon_get_count(menu);
for (iindex = 0; iindex < mc; iindex++) {
if (mcommon_ison_status(menu,iindex, status_1,S1_FLAGGED)) {
vector[count++] = iindex;
}
}
return(count);
}
void limit(menu, page,LOC)
struct menu_common *menu;
struct menu_context *page;
struct screen_parts *LOC;
{
/** if we changed selection criteria = need redraw
use menu_trigger_redraw(page)
*/
int last_selected, all;
struct string *criteria = NULL;
int li,co;
int delay_redraw = 0;
menu_get_sizes(LOC->prompt_page,&li,&co);
last_selected = mcommon_get_selected(menu);
all = 0;
if (mcommon_get_selected(menu)) {
int c;
redraw0:
menu_PutLineX(LOC->prompt_page,
1, 0,
CATGETS(elm_msg_cat, ElmSet, ElmLimitAlreadyHave,
"Already have selection criteria - add more? (%c/%c) %c%c"),
*def_ans_yes, *def_ans_no, *def_ans_no, BACKSPACE);
c = menu_ReadCh(LOC->prompt_page,
REDRAW_MARK|READCH_sig_char);
if (TERMCH_interrupt_char == c) {
/* Ctrl-C */
menu_ClearScreen(LOC->prompt_page);
if (delay_redraw)
menu_trigger_redraw(page);
return;
}
if (REDRAW_MARK == c) {
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++;
goto redraw0;
}
if (
#ifdef ASCII_CTYPE
isascii(c) &&
#endif
tolower((unsigned char)c) == *def_ans_yes) {
menu_Write_to_screen(LOC->prompt_page,
CATGETS(elm_msg_cat, ElmSet, ElmYesWord, "Yes."));
menu_PutLineX(LOC->prompt_page,
0, co-30,
CATGETS(elm_msg_cat, ElmSet, ElmLimitAdding,
"Adding criteria..."));
} else {
menu_Write_to_screen(LOC->prompt_page,
CATGETS(elm_msg_cat, ElmSet, ElmNoWord, "No."));
menu_PutLineX(LOC->prompt_page,
0, co-30,
CATGETS(elm_msg_cat, ElmSet, ElmLimitChanging,
"Change criteria..."));
mcommon_set_selected(menu,0);
menu_trigger_redraw(LOC->title_page);
menu_trigger_redraw(LOC->header_page);
}
}
while(1) {
int line;
int code;
int f = 0;
/* CLear previous prompt */
menu_MoveCursor(LOC->prompt_page,1,0);
menu_CleartoEOLN(LOC->prompt_page);
redraw:
/* FIXME --optionally_enter* should use prompt_area */
line = menu_GetAbsLine(LOC->prompt_page,1);
code = optionally_enter2(page,
&criteria,line,0,
OE_REDRAW_MARK|OE_ALLOW_MIMEENC|f|
OE_SIG_CHAR /* Ctrl-C */,
CATGETS(elm_msg_cat, ElmSet,
ElmLimitEnterCriteria,
"Enter criteria or '?' for help: "));
if (REDRAW_MARK == code) {
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++;
goto redraw;
}
if (0 != code) {
if (criteria)
free_string(& criteria);
menu_trigger_redraw(LOC->title_page);
menu_trigger_redraw(LOC->header_page);
if (delay_redraw)
menu_trigger_redraw(page);
return;
}
clear_error();
if (!criteria || string_len(criteria) == 0) {
/* no change */
if (criteria)
free_string(& criteria);
mcommon_set_selected(menu,last_selected);
menu_trigger_redraw(LOC->title_page);
menu_trigger_redraw(LOC->header_page);
if (last_selected)
lib_error(CATGETS(elm_msg_cat, ElmSet,
ElmLimitReturnToLastSelection,
"Returned to last selection."));
if (delay_redraw)
menu_trigger_redraw(page);
return;
}
if (string_matches_ascii(criteria,s2us("all"))) {
all++;
mcommon_set_selected(menu,0);
} else if (string_matches_ascii(criteria,s2us("?"))) {
mcommon_limit_print_help(menu,last_selected);
continue;
} else {
int X = 0;
int i,c;
int len = string_len(criteria);
uint16 lastsep = 0;
int count;
while (X <len) {
uint16 sep;
struct string * part = NULL;
int reslen = 0;
int * selarr = 0;
if (!get_word_from_string(criteria,&part,&X,
GWF_lowercase | GWF_trim_space,
/* ASCII assumed */
s2us("&|"),&sep)) {
if (part)
free_string(&part);
break;
}
if (string_matches_ascii(part, s2us("tagged"))) {
int n = mcommon_get_count(menu);
if (n < 1)
goto fail;
selarr = safe_malloc(n * sizeof(selarr[0]));
reslen = SelectTaggedMessages(menu,selarr);
} else if (string_matches_ascii(part, s2us("flagged"))) {
int n = mcommon_get_count(menu);
if (n < 1)
goto fail;
selarr = safe_malloc(n * sizeof(selarr[0]));
reslen = SelectFlaggedMessages(menu,selarr);
} else
reslen = mcommon_limit_helper(menu,part,&selarr,
page);
switch (lastsep) {
int additional_criteria;
int i,c;
case 0: /* First selection */
additional_criteria = mcommon_get_selected(menu);
if (!additional_criteria) {
c = mcommon_get_count(menu);
for (i = 0; i < c; i++)
mcommon_clearf_status(menu,i,status_basic,VISIBLE);
goto action_or;
}
goto action_and;
/* and */
action_and:
case 0x0026 /* & */:
/* !!! ASCII assumed on get_word_from_string */
c = mcommon_get_count(menu);
for (i = 0; i < c; i++) {
int match = 0;
int j;
for (j = 0; j < reslen; j++)
if (i == selarr[j]) {
match++;
break;
}
if (!match)
mcommon_clearf_status(menu,i,status_basic,VISIBLE);
}
break;
/* or */
action_or:
case 0x007C /* | */:
/* !!! ASCII assumed on get_word_from_string() */
/* also | do not exists on iso 646 sets ... */
for (i = 0; i < reslen; i++) {
int x = selarr[i];
mcommon_setf_status(menu,x,status_basic,VISIBLE);
}
break;
default:
panic("LIMIT PANIC",__FILE__,__LINE__,"limit",
"bad separator",0);
}
X++;
fail:
if (part)
free_string(&part);
if (selarr)
free(selarr);
lastsep = sep;
}
count = 0;
c = mcommon_get_count(menu);
for (i = 0; i < c; i++)
if (mcommon_ison_status(menu,i,status_basic,VISIBLE))
count++;
mcommon_set_selected(menu,count);
}
if (all && last_selected)
lib_error(CATGETS(elm_msg_cat, ElmSet, ElmLimitReturnToUnlimited,
"Returned to unlimited display."));
else {
mcommon_limit_print_result(menu);
}
/* we need a redraw if there had been a selection or there is now. */
if (last_selected || mcommon_get_selected(menu)) {
/* if current message won't be on new display,
go to first message */
int current = mcommon_get_current(menu);
if (mcommon_get_selected(menu) &&
mcommon_isoff_status(menu,current-1,status_basic,
VISIBLE)) {
current = visible_to_index(1,menu)+1;
mcommon_set_current(menu,current);
copy_current(menu,LOC->header_page);
}
get_page(menu, LOC->header_page);
menu_trigger_redraw(LOC->title_page);
menu_trigger_redraw(LOC->header_page);
}
break;
}
if (delay_redraw)
menu_trigger_redraw(page);
else
menu_trigger_redraw(LOC->prompt_page);
if (criteria)
free_string(& criteria);
}
int next_message(iindex, skipdel, menu)
int iindex, skipdel;
struct menu_common *menu;
{
/** Given 'iindex', this routine will return the actual iindex into the
array of the NEXT message, or '-1' iindex is the last.
If skipdel, return the iindex for the NEXT undeleted message.
If selected, return the iindex for the NEXT message marked VISIBLE.
**/
int remember_for_debug, stat;
int mc = mcommon_get_count(menu);
int selected = mcommon_get_selected(menu);
if (iindex < 0) return(-1); /* invalid argument value! */
remember_for_debug = iindex;
for(iindex++; iindex < mc; iindex++) {
if ((mcommon_ison_status(menu,iindex,
status_basic,VISIBLE) || !selected)
&& (mcommon_isoff_status(menu,iindex,
status_basic,DELETED) || (!skipdel))) {
DPRINT(Debug,9,(&Debug,
"[Next%s%s: given %d returning %d]\n",
(skipdel ? " undeleted" : ""),
(selected ? " visible" : ""),
remember_for_debug+1, iindex+1));
return(iindex);
}
}
return(-1);
}
int prev_message(iindex, skipdel, menu)
int iindex, skipdel;
struct menu_common *menu;
{
/** Like next_message, but the PREVIOUS message. **/
int remember_for_debug, stat;
int mc = mcommon_get_count(menu);
int selected = mcommon_get_selected(menu);
if (iindex >= mc)
return(-1); /* invalid argument value! */
remember_for_debug = iindex;
for(iindex--; iindex >= 0; iindex--) {
if ((mcommon_ison_status(menu,iindex,
status_basic,VISIBLE) || (!selected))
&& (mcommon_isoff_status(menu,iindex,
status_basic,DELETED) || (!skipdel))) {
DPRINT(Debug,4,(&Debug,
"[Previous%s%s: given %d returning %d]\n",
(skipdel ? " undeleted" : ""),
(selected ? " visible" : ""),
remember_for_debug+1, iindex+1));
return(iindex);
}
}
return(-1);
}
int compute_visible(message,menu)
int message;
struct menu_common *menu;
{
/** return the 'virtual' iindex of the specified message in the
set of messages - that is, if we have the 25th message as
the current one, but it's #2 based on our limit criteria,
this routine, given 25, will return 2.
**/
int iindex, count = 0;
if (! mcommon_get_selected(menu))
return(message);
if (message < 1) message = 1; /* normalize */
for (iindex = 0; iindex < message; iindex++) {
DPRINT(Debug,4,(&Debug,
"[compute-visible: displayed message %d is actually %d]\n",
count, message));
if (mcommon_ison_status(menu,iindex,status_basic,VISIBLE))
count++;
}
DPRINT(Debug,4,(&Debug,
"[compute-visible: displayed message %d is actually %d]\n",
count, message));
return(count);
}
int visible_to_index(message,menu)
int message;
struct menu_common *menu;
{
/** Given a 'virtual' iindex, return a real one. This is the
flip-side of the routine above, and returns (message_count+1)
if it cannot map the virtual iindex requested (too big)
**/
int iindex = 0, count = 0;
int mc = mcommon_get_count(menu);
for (iindex = 0; iindex < mc; iindex++) {
if (mcommon_ison_status(menu,iindex,status_basic,VISIBLE))
count++;
if (count == message) {
DPRINT(Debug,4,(&Debug,
"visible-to-index: (up) index %d is displayed as %d\n",
message, iindex));
return(iindex);
}
}
DPRINT(Debug,4,(&Debug, "index %d is NOT displayed!\n", message));
return mc+1;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1