568 lines
16 KiB
C++
568 lines
16 KiB
C++
|
|
// ------------------------------------------------------------------
|
|
// GoldED+
|
|
// Copyright (C) 1990-1999 Odinn Sorensen
|
|
// Copyright (C) 1999-2000 Alexander S. Aganichev
|
|
// ------------------------------------------------------------------
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License as
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
// MA 02111-1307 USA
|
|
// ------------------------------------------------------------------
|
|
// $Id$
|
|
// ------------------------------------------------------------------
|
|
// Advanced search functions.
|
|
// ------------------------------------------------------------------
|
|
|
|
#include <golded.h>
|
|
#include <gmnubase.h>
|
|
#include <geval.h>
|
|
#include <gesrch.h>
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
golded_search_manager::golded_search_manager() {
|
|
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
golded_search_manager::~golded_search_manager() {
|
|
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
inline void search_item_option(bool& a, const char* s) {
|
|
|
|
if(s[1] == '^')
|
|
a = not a;
|
|
else
|
|
a = s[1] != '\'';
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
const char* search_item_set(search_item& item, const char* s) {
|
|
|
|
while(*s) {
|
|
switch(*s) {
|
|
case '!': search_item_option(item.reverse, s); break;
|
|
case '<': search_item_option(item.where.from, s); break;
|
|
case '>': search_item_option(item.where.to, s); break;
|
|
case ':': search_item_option(item.where.subject, s); break;
|
|
case '#': search_item_option(item.where.body, s); break;
|
|
case '.': search_item_option(item.where.tagline, s); break;
|
|
case '_': search_item_option(item.where.tearline, s); break;
|
|
case '*': search_item_option(item.where.origin, s); break;
|
|
case '@': search_item_option(item.where.signature, s); break;
|
|
case '%': search_item_option(item.where.kludges, s); break;
|
|
case '=': search_item_option(item.case_sensitive, s); break;
|
|
case '?':
|
|
s++;
|
|
switch(tolower(*s)) {
|
|
case 'r': item.type = gsearch::regex; break;
|
|
case 'w': item.type = gsearch::wildcard; break;
|
|
case 'p': item.type = gsearch::plain; break;
|
|
case 'f':
|
|
item.type = gsearch::fuzzy;
|
|
if(isdigit(s[1])) {
|
|
item.fuzzydegree = atoi(s+1);
|
|
while(isdigit(s[1]))
|
|
s++;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case '^':
|
|
case '\'':
|
|
break;
|
|
default:
|
|
return s;
|
|
}
|
|
s++;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void golded_search_manager::prepare_from_string(const char* prompt, int what) {
|
|
|
|
// Get defaults
|
|
reverse = false;
|
|
direction = DIR_NEXT;
|
|
search_item default_item;
|
|
const char* p = prompt;
|
|
|
|
if(*p == '-' or *p == '+') {
|
|
direction = (*p == '-') ? DIR_PREV : DIR_NEXT;
|
|
p++;
|
|
}
|
|
p = search_item_set(default_item, p);
|
|
if(default_item.reverse) {
|
|
default_item.reverse = false;
|
|
reverse = true;
|
|
}
|
|
|
|
if(what == GFIND_HDR or what == GFIND_HDRTXT) {
|
|
if(not (default_item.where.from or default_item.where.to or default_item.where.subject)) {
|
|
default_item.where.from = true;
|
|
default_item.where.to = true;
|
|
default_item.where.subject = true;
|
|
}
|
|
if(what == GFIND_HDRTXT)
|
|
default_item.where.body = true;
|
|
}
|
|
|
|
char buf[256];
|
|
char* b = buf;
|
|
bool item_complete = false;
|
|
search_item item = default_item;
|
|
|
|
p = search_item_set(item, strskip_wht(p));
|
|
|
|
do {
|
|
|
|
switch(*p) {
|
|
|
|
// Logic AND
|
|
case '&':
|
|
item.logic = search_item::logic_and;
|
|
item_complete = true;
|
|
p++;
|
|
break;
|
|
|
|
// Logic OR
|
|
case '|':
|
|
item.logic = search_item::logic_or;
|
|
item_complete = true;
|
|
p++;
|
|
break;
|
|
|
|
// Get quoted string
|
|
case '\"':
|
|
case '\'':
|
|
{
|
|
char q = *p++;
|
|
while(*p) {
|
|
if(*p == q) {
|
|
p++;
|
|
break;
|
|
}
|
|
switch(*p) {
|
|
case '\\':
|
|
if(*(++p))
|
|
*b++ = *p++;
|
|
break;
|
|
default:
|
|
*b++ = *p++;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Get literal escaped character
|
|
case '\\':
|
|
if(*(++p))
|
|
*b++ = *p++;
|
|
break;
|
|
|
|
// Skip whitespace
|
|
case ' ':
|
|
p++;
|
|
|
|
case NUL:
|
|
break;
|
|
|
|
default:
|
|
*b++ = *p++;
|
|
}
|
|
|
|
if(item_complete or (*p == NUL)) {
|
|
item_complete = false;
|
|
*b = NUL;
|
|
if(*buf != NUL) {
|
|
item.pattern = buf;
|
|
items.push_back(item);
|
|
}
|
|
if(*p == NUL)
|
|
break;
|
|
item = default_item;
|
|
p = search_item_set(item, strskip_wht(p));
|
|
b = buf;
|
|
}
|
|
|
|
} while(*p);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool golded_search_manager::search(GMsg* msg, bool quick, bool shortcircuit) {
|
|
|
|
std::vector<search_item>::iterator item = items.begin();
|
|
bool exit = false;
|
|
bool and_cycle = false;
|
|
bool or_cycle = false;
|
|
|
|
for(int i=0; i<items.size(); i++, item++) {
|
|
|
|
if(shortcircuit) {
|
|
if(item->logic == search_item::logic_and) {
|
|
if(not and_cycle) {
|
|
if(exit)
|
|
return true;
|
|
}
|
|
else
|
|
if(not exit)
|
|
continue;
|
|
and_cycle = true;
|
|
}
|
|
else {
|
|
if(and_cycle) {
|
|
and_cycle = (item->logic == search_item::logic_and);
|
|
if(not exit)
|
|
continue;
|
|
} else {
|
|
and_cycle = (item->logic == search_item::logic_and);
|
|
if(exit)
|
|
return true;
|
|
}
|
|
or_cycle = (item->logic == search_item::logic_or);
|
|
}
|
|
}
|
|
|
|
int found = 0;
|
|
if(item->where.from) {
|
|
if(item->search(*msg->ifrom ? msg->ifrom : msg->By())) {
|
|
msg->foundwhere |= GFIND_FROM;
|
|
found++;
|
|
if(quick)
|
|
goto quick_found;
|
|
}
|
|
}
|
|
if(item->where.to) {
|
|
if(item->search(*msg->ito ? msg->ito : msg->to)) {
|
|
msg->foundwhere |= GFIND_TO;
|
|
found++;
|
|
if(quick)
|
|
goto quick_found;
|
|
}
|
|
else if(*msg->icc and item->search(msg->icc)) {
|
|
msg->foundwhere |= GFIND_TO;
|
|
found++;
|
|
if(quick)
|
|
goto quick_found;
|
|
}
|
|
else if(*msg->ibcc and item->search(msg->ibcc)) {
|
|
msg->foundwhere |= GFIND_TO;
|
|
found++;
|
|
if(quick)
|
|
goto quick_found;
|
|
}
|
|
}
|
|
if(item->where.subject) {
|
|
if(item->search(msg->re)) {
|
|
msg->foundwhere |= GFIND_SUBJECT;
|
|
found++;
|
|
if(quick)
|
|
goto quick_found;
|
|
}
|
|
}
|
|
if(item->where.body or item->where.tagline or item->where.tearline or item->where.origin or item->where.signature or item->where.kludges) {
|
|
Line* line = msg->lin;
|
|
while(line) {
|
|
uint type = line->type;
|
|
bool search_this_line = false;
|
|
if(item->where.body and not (type & (GLINE_TAGL|GLINE_TEAR|GLINE_ORIG|GLINE_SIGN|GLINE_KLUDGE)))
|
|
search_this_line = true;
|
|
if(item->where.tagline and (type & GLINE_TAGL))
|
|
search_this_line = true;
|
|
if(item->where.tearline and (type & GLINE_TEAR))
|
|
search_this_line = true;
|
|
if(item->where.origin and (type & GLINE_ORIG))
|
|
search_this_line = true;
|
|
if(item->where.signature and (type & GLINE_SIGN))
|
|
search_this_line = true;
|
|
if(item->where.kludges and (type & GLINE_KLUDGE))
|
|
search_this_line = true;
|
|
if(search_this_line) {
|
|
if(item->search(line->txt.c_str())) {
|
|
line->type |= GLINE_HIGH;
|
|
if(type & (GLINE_TAGL|GLINE_TEAR|GLINE_ORIG|GLINE_SIGN|GLINE_KLUDGE)) {
|
|
if(type & GLINE_TAGL)
|
|
msg->foundwhere |= GFIND_TAGLINE;
|
|
else if(type & GLINE_TEAR)
|
|
msg->foundwhere |= GFIND_TEARLINE;
|
|
else if(type & GLINE_ORIG)
|
|
msg->foundwhere |= GFIND_ORIGIN;
|
|
else if(type & GLINE_SIGN)
|
|
msg->foundwhere |= GFIND_SIGNATURE;
|
|
else if(type & GLINE_KLUDGE)
|
|
msg->foundwhere |= GFIND_KLUDGES;
|
|
}
|
|
else {
|
|
msg->foundwhere |= GFIND_BODY;
|
|
}
|
|
found++;
|
|
if(quick)
|
|
goto quick_found;
|
|
}
|
|
}
|
|
line = line->next;
|
|
}
|
|
}
|
|
|
|
quick_found:
|
|
|
|
if(item->reverse)
|
|
found = not found;
|
|
|
|
// Perform short-circuit logic analysis
|
|
if(shortcircuit) {
|
|
exit = found ? true : false;
|
|
if(item == items.end()-1)
|
|
return exit;
|
|
}
|
|
// else save success/failure as score
|
|
else {
|
|
item->score = found ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
if(not shortcircuit) {
|
|
gevalhum logic;
|
|
if(items.size()) {
|
|
for(int i=0; i<items.size(); i++) {
|
|
logic.push_value(items[i].score);
|
|
if((i+1) < items.size()) {
|
|
if(items[i].logic == search_item::logic_and)
|
|
logic.push_operator(geval::logic_and);
|
|
else
|
|
logic.push_operator(geval::logic_or);
|
|
}
|
|
}
|
|
return (bool)logic.evaluate();
|
|
}
|
|
}
|
|
|
|
// It should never end up here unless there are no items
|
|
return false;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void search_mgr_form::before() {
|
|
|
|
gwinput2::before();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void search_mgr_form::after() {
|
|
|
|
gwinput2::after();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void search_mgr_form::select(gstrarray& menu, const char* title) {
|
|
|
|
int srow = window.start_row + current->row;
|
|
int scol = window.start_column + current->column;
|
|
|
|
if((current->id < id_direction) and ((current->id % 3) == 2))
|
|
scol -= 20;
|
|
|
|
GMnu m;
|
|
m.Init();
|
|
m.SetColor(7, 7, 7, 112, 8);
|
|
m.SetTitle(title, 14);
|
|
m.SetBorder(0, 7);
|
|
m.SetPos(srow, scol);
|
|
m.SetMask(0);
|
|
m.Begin();
|
|
for(int i=0; i<menu.size(); i++)
|
|
m.Item(i, menu[i].c_str());
|
|
m.End();
|
|
|
|
vcurhide();
|
|
m.Start();
|
|
vcurshow();
|
|
|
|
if(m.FinalTag() != -1) {
|
|
if(not ((current->id < id_direction) and ((current->id % 3) == 2))) {
|
|
strbtrim(strcpy(current->buf, menu[m.FinalTag()].c_str()+1));
|
|
current->update();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
bool search_mgr_form::validate() {
|
|
|
|
gstrarray menu;
|
|
|
|
if(current->id >= id_direction) {
|
|
switch(current->id) {
|
|
case id_direction:
|
|
menu.insert(menu.end(), "F Forward");
|
|
menu.insert(menu.end(), "B Backward ");
|
|
select(menu, "Direction");
|
|
break;
|
|
case id_messages:
|
|
menu.insert(menu.end(), "N New");
|
|
menu.insert(menu.end(), "U Unread ");
|
|
menu.insert(menu.end(), "A All");
|
|
select(menu, "Messages");
|
|
break;
|
|
case id_action:
|
|
menu.insert(menu.end(), "R Read");
|
|
menu.insert(menu.end(), "T Tag");
|
|
menu.insert(menu.end(), "D Delete ");
|
|
menu.insert(menu.end(), "W Write");
|
|
menu.insert(menu.end(), "C Copy");
|
|
menu.insert(menu.end(), "M Move");
|
|
select(menu, "Action");
|
|
break;
|
|
case id_areas:
|
|
menu.insert(menu.end(), "C Current ");
|
|
menu.insert(menu.end(), "A All");
|
|
menu.insert(menu.end(), "T Tagged");
|
|
select(menu, "Areas");
|
|
break;
|
|
}
|
|
}
|
|
else if((current->id % 3) == 1) {
|
|
menu.insert(menu.end(), "a and ");
|
|
menu.insert(menu.end(), "o or");
|
|
select(menu, "Logic");
|
|
}
|
|
else if((current->id % 3) == 2) {
|
|
menu.insert(menu.end(), " Plain ");
|
|
menu.insert(menu.end(), " Regex ");
|
|
menu.insert(menu.end(), " Wildcard ");
|
|
menu.insert(menu.end(), " Fuzzy ");
|
|
menu.insert(menu.end(), " Success if not found ");
|
|
menu.insert(menu.end(), " Case sensitive ");
|
|
menu.insert(menu.end(), " Search \"from\" ");
|
|
menu.insert(menu.end(), " Search \"to\" ");
|
|
menu.insert(menu.end(), " Search \"subject\" ");
|
|
menu.insert(menu.end(), " Search msg body ");
|
|
menu.insert(menu.end(), " Search tagline ");
|
|
menu.insert(menu.end(), " Search tearline ");
|
|
menu.insert(menu.end(), " Search origin ");
|
|
menu.insert(menu.end(), " Search signature ");
|
|
menu.insert(menu.end(), " Search kludges ");
|
|
select(menu, "Options");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void AdvancedSearch(GMsg*, int&, int&) {
|
|
|
|
int patterns = 9;
|
|
int width = 77;
|
|
int height = patterns+11;
|
|
int widths[3] = { 55, 5, 7 };
|
|
int field_widths[3] = { 100, 5, 7 };
|
|
int border_type = BT_SINGLE;
|
|
int title_color = YELLOW | _BLUE;
|
|
int heading_color = YELLOW | _BLUE;
|
|
int window_color = LGREY | _BLUE;
|
|
int border_color = LBLUE | _BLUE;
|
|
int edit_color = YELLOW | _BLUE;
|
|
int idle_color = LGREY | _BLUE;
|
|
int active_color = WHITE | _BLUE;
|
|
int shadow_color = DGREY | _BLACK;
|
|
|
|
widths[0] = width - 3*2 - 2 - 5 - 7 - 2;
|
|
|
|
gwindow window;
|
|
|
|
window.openxy(1, ((MAXCOL-width)/2), height, width,
|
|
border_type, border_color, window_color);
|
|
window.shadow(shadow_color);
|
|
|
|
window.horizontal_line( 1, 0, width-2, border_type, border_color);
|
|
window.horizontal_line(patterns+2, 0, width-2, border_type, border_color);
|
|
|
|
window.vertical_line(0, widths[0]+2, patterns+3, border_type, border_color);
|
|
window.vertical_line(0, widths[0]+widths[1]+5, patterns+3, border_type, border_color);
|
|
|
|
window.title(" Advanced Search Manager ", title_color);
|
|
|
|
window.prints(0, 1, heading_color, "Pattern");
|
|
window.prints(0, widths[0]+4, heading_color, "Logic");
|
|
window.prints(0, widths[0]+widths[1]+7, heading_color, "Options");
|
|
|
|
window.prints(patterns+3, 1, heading_color, "Direction : ");
|
|
window.prints(patterns+4, 1, heading_color, "Messages : ");
|
|
window.prints(patterns+5, 1, heading_color, "Action : ");
|
|
window.prints(patterns+6, 1, heading_color, "Areas : ");
|
|
window.prints(patterns+7, 1, heading_color, "Destination : ");
|
|
window.prints(patterns+8, 1, heading_color, "Identifier : ");
|
|
|
|
search_mgr_form iform(window);
|
|
|
|
iform.setup(idle_color, active_color, edit_color, _box_table(border_type, 13), true);
|
|
|
|
std::string buffers[9*3 + 6];
|
|
|
|
int i = 0;
|
|
for(int r=0; r<9; r++) {
|
|
int cs = 1;
|
|
for(int c=0; c<3; c++,i++) {
|
|
char z[80];
|
|
sprintf(z, "%i,%i", r+1, c+1);
|
|
buffers[i] = z;
|
|
iform.add_field(i, r+2, cs, widths[c], buffers[i], field_widths[c]);
|
|
cs += widths[c] + 3;
|
|
}
|
|
}
|
|
|
|
buffers[i+0] = "Forward";
|
|
buffers[i+1] = "New";
|
|
buffers[i+2] = "Read";
|
|
buffers[i+3] = "Current";
|
|
buffers[i+4] = "C:\\TEMP\\DUMPFILE.TXT";
|
|
buffers[i+5] = "Testing";
|
|
|
|
for(int y=0; y<6; y++,i++)
|
|
iform.add_field(100+y, patterns+3+y, 15, width-15-3, buffers[i], width-15-3, gwinput::cvt_none, y>=4 ? gwinput::entry_conditional : gwinput::entry_noedit);
|
|
|
|
iform.run(0);
|
|
|
|
window.close();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|