1 
2 //  ------------------------------------------------------------------
3 //  GoldED+
4 //  Copyright (C) 1990-1999 Odinn Sorensen
5 //  Copyright (C) 1999-2000 Alexander S. Aganichev
6 //  ------------------------------------------------------------------
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License as
9 //  published by the Free Software Foundation; either version 2 of the
10 //  License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 //  General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 //  MA 02111-1307 USA
21 //  ------------------------------------------------------------------
22 //  $Id: gearea.cpp,v 1.14 2011/02/22 23:51:03 stas_degteff Exp $
23 //  ------------------------------------------------------------------
24 //  Arealister and other area-specific code
25 //  ------------------------------------------------------------------
26 
27 #include <golded.h>
28 #include <gutlos.h>
29 
30 
31 //  ------------------------------------------------------------------
32 
33 extern int arealistnumgrps;
34 
35 bool in_arealist = false;
36 
37 GPickArealist* PickArealist;
38 
39 Echo area_maybe;
40 int areaswithgroupid = 0;
41 uint* areanumbers = NULL;
42 
43 //            111111111122222222223333333333444444444455555555556666666666777777777
44 //  0123456789012345678901234567890123456789012345678901234567890123456789012345678
45 // ��Area�Description�������������������������Msgs���New��EchoID��������������GrpĿ
46 // �   1> NET FidoNet Z3/4/5/6                 118+    3* NET.FIDOZX            A �
47 
48 // AREALISTFORMAT "AM D CPUN E G"
49 
50 int area_pos      = -1;
51 int area_width    = 4;
52 int marked_pos    = -1;
53 int marked_width  = 1;
54 const char marked_char   = MMRK_MARK;
55 int desc_pos      = -1;
56 int desc_width    = -1;
57 int count_pos     = -1;
58 int count_width   = 6;
59 int pmark_pos     = -1;
60 int pmark_width   = 1;
61 const char pmark_char    = '+';
62 int unread_pos    = -1;
63 int unread_width  = 6;
64 int changed_pos   = -1;
65 int changed_width = 1;
66 const char changed_char  = '*';
67 int echoid_pos    = -1;
68 int echoid_width  = 0;
69 int groupid_pos   = -1;
70 int groupid_width = 0;
71 
72 
73 //  ------------------------------------------------------------------
74 
GPickArealist()75 GPickArealist::GPickArealist() {
76 
77   areawin1 = 0;
78   areawin2 = 0;
79   tempwin1 = 0;
80   tempwin2 = 0;
81 
82   pmails   = 0;
83   pmareas  = 0;
84   pmscan   = false;
85 
86   area_fuzidx = 0;
87 
88 }
89 
90 
91 //  ------------------------------------------------------------------
92 
AreasRenumber()93 void GPickArealist::AreasRenumber() {
94 
95   for(int n=0,a=1,t=AL.size(); n<t; n++)
96     areanumbers[n] = AL[n]->isseparator() ? 0 : a++;
97 }
98 
99 
100 //  ------------------------------------------------------------------
101 
is_selectable(uint idx)102 bool GPickArealist::is_selectable(uint idx) {
103 
104   Area* area = AL.AreaNoToPtr(idx);
105   return (not area->isseparator());
106 
107 }
108 
109 
110 //  ------------------------------------------------------------------
111 
do_delayed()112 void GPickArealist::do_delayed() {
113 
114   Area* area = AL.AreaNoToPtr(index);
115 
116   const size_t buflen=strlen(title)+strlen(area_maybe);
117   const size_t tmplen=(buflen>MAXCOL?buflen:MAXCOL);
118   char * buf = new char[buflen+3];
119   buf[buflen] = '\0';
120   buf[buflen+1] = '\xFF';
121   buf[buflen+2] = '\0';
122   char * tmp = new char[tmplen+3];
123   tmp[tmplen] = '\0';
124   tmp[tmplen+1] = '\xFF';
125   tmp[tmplen+2] = '\0';
126 
127   update_statuslinef("%s: %u %s, %u %s, %u %s", "", area->echoid(), area->Msgn.Count(),
128                      (area->Msgn.Count() == 1 ? LNG->msg : LNG->msgs), area->unread,
129                      LNG->unread, area->PMrk.Count(), LNG->personal);
130 
131   strcpy(stpcpy(buf, title), area_maybe);
132   strsetsz(strcpy(tmp, buf), MAXCOL);
133   wwprintstr(tempwin, 0, 0, wattr, tmp);
134 
135   if(CFG->switches.get(arealistpagebar))
136     wscrollbar(W_VERT, maximum_index+1, maximum_index, index);
137 
138   if (buf[buflen] || buf[buflen+1]!='\xFF' || buf[buflen+2])
139   {
140     LOG.errpointer(__FILE__,__LINE__);
141     LOG.printf("! Buffer overflow: buf in GPickArealist::do_delayed(), 8 or 9 lines above");
142     PointerErrorExit();
143   }
144   if (tmp[tmplen] || tmp[tmplen+1]!='\xFF' || tmp[tmplen+2])
145   {
146     LOG.errpointer(__FILE__,__LINE__);
147     LOG.printf("! Buffer overflow: tmp in GPickArealist::do_delayed(), 15 or 16 lines above");
148     PointerErrorExit();
149   }
150   delete buf;
151   delete tmp;
152 }
153 
154 
155 //  ------------------------------------------------------------------
156 
close_all()157 void GPickArealist::close_all() {
158 
159   if(areawin1)
160     wunlink(areawin1);
161   if(areawin2)
162     wunlink(areawin2);
163   if(tempwin1)
164     wunlink(tempwin1);
165   if(tempwin2)
166     wunlink(tempwin2);
167 }
168 
169 
170 //  ------------------------------------------------------------------
171 
dispbuf(char * buf,int areano)172 void GPickArealist::dispbuf(char* buf, int areano) {
173 
174   Area* area = AL.AreaNoToPtr(areano);
175 
176   memset(buf, ' ', MAXCOL-2);
177   buf[MAXCOL-2] = NUL;
178 
179   char areabuf[33];
180   gsprintf(PRINTF_DECLARE_BUFFER(areabuf), "%u", CFG->switches.get(arealistnos) ? area->board() : areanumbers[areano]);
181   int areawidth = strlen(areabuf);
182 
183   char markedbuf[2] = { " " };
184   *markedbuf = area->ismarked() ? marked_char : ' ';
185   int markedwidth = 1;
186 
187   char descbuf[100];
188   int descwidth = strlen(strcpy(descbuf, area->desc()));
189 
190   char countbuf[33];
191   if (area->isscanned)
192     gsprintf(PRINTF_DECLARE_BUFFER(countbuf), "%u", (uint)area->Msgn.Count());
193   else
194     strcpy(countbuf,  "-");
195   int countwidth = strlen(countbuf);
196 
197   char pmarkbuf[2] = { " " };
198   *pmarkbuf = area->PMrk.Count() ? pmark_char : ' ';
199   int pmarkwidth = 1;
200 
201   char unreadbuf[33];
202   if (area->isscanned)
203     gsprintf(PRINTF_DECLARE_BUFFER(unreadbuf), "%u", (uint)((CFG->arealisttype == AL_TOTNEW) ? area->unread : area->lastread()));
204   else
205     strcpy(unreadbuf, "-");
206   int unreadwidth = strlen(unreadbuf);
207 
208   char changedbuf[2] = { " " };
209   *changedbuf = area->isunreadchg ? changed_char : ' ';
210   int changedwidth = 1;
211 
212   char echoidbuf[100];
213   int echoidwidth = strlen(strcpy(echoidbuf, area->echoid()));
214 
215   char groupidbuf[10] = { "" };
216   if (groupid_width)
217   {
218     if (area->groupid() & 0x8000u)
219     {
220       if (groupid_width > 2)
221         gsprintf(PRINTF_DECLARE_BUFFER(groupidbuf), "%u", area->groupid()&0x7FFF);
222     }
223     else if (g_isupper(area->groupid()))
224       gsprintf(PRINTF_DECLARE_BUFFER(groupidbuf), "%c", (char)area->groupid());
225   }
226   int groupidwidth = strlen(groupidbuf);
227 
228   areawidth    = MinV(areawidth,    area_width);
229   markedwidth  = MinV(markedwidth,  marked_width);
230   descwidth    = MinV(descwidth,    desc_width);
231   countwidth   = MinV(countwidth,   count_width);
232   pmarkwidth   = MinV(pmarkwidth,   pmark_width);
233   unreadwidth  = MinV(unreadwidth,  unread_width);
234   changedwidth = MinV(changedwidth, changed_width);
235   echoidwidth  = MinV(echoidwidth,  echoid_width);
236   groupidwidth = MinV(groupidwidth, groupid_width);
237 
238   memcpy(buf+area_pos+area_width-areawidth,          areabuf,    areawidth);
239   memcpy(buf+marked_pos,                             markedbuf,  markedwidth);
240   memcpy(buf+desc_pos,                               descbuf,    descwidth);
241   memcpy(buf+count_pos+count_width-countwidth,       countbuf,   countwidth);
242   memcpy(buf+pmark_pos,                              pmarkbuf,   pmarkwidth);
243   memcpy(buf+unread_pos+unread_width-unreadwidth,    unreadbuf,  unreadwidth);
244   memcpy(buf+changed_pos,                            changedbuf, changedwidth);
245   memcpy(buf+echoid_pos,                             echoidbuf,  echoidwidth);
246   memcpy(buf+groupid_pos+groupid_width-groupidwidth, groupidbuf, groupidwidth);
247 }
248 
249 //  ------------------------------------------------------------------
250 
center()251 void GPickArealist::center() {
252 
253   uint room, toproom, botroom;
254 
255   toproom = index;
256   botroom = maximum_index - index;
257   if(toproom > maximum_position/2) {
258     if(botroom > maximum_position/2)
259       room = maximum_position/2;
260     else if(botroom)
261       room = maximum_position - botroom;
262     else
263       room = maximum_position;
264   }
265   else
266     room = toproom;
267 
268   position = room;
269   display_page();
270 }
271 
272 
273 //  ------------------------------------------------------------------
274 
jump_to()275 void GPickArealist::jump_to() {
276 
277   uint n = index+1;
278   bool found = false;
279   // Search for next marked area, wrapping 'round if needed
280   for(; n<=maximum_index; n++) {
281     if(not AL[n]->isseparator() and AL[n]->ismarked()) {
282       found = true;
283       break;
284     }
285   }
286 
287   if(not found) {
288     for(n = minimum_index; n <= index; n++) {
289       if(not AL[n]->isseparator() and AL[n]->ismarked())
290         break;
291     }
292   }
293 
294   if(n > maximum_index)
295     n = minimum_index;
296 
297   while(AL[n]->isseparator()) {
298     if((++n) > maximum_index)
299       n = minimum_index;
300   }
301 
302   index = n;
303   center();
304 }
305 
306 
307 //  ------------------------------------------------------------------
308 
jumpmatch()309 void GPickArealist::jumpmatch() {
310 
311   uint n = index+1;
312   bool found = false;
313   // Search for next marked area, wrapping 'round if needed
314   for(; n<=maximum_index; n++) {
315     if(not AL[n]->isseparator() and (strnieql(area_maybe, AL[n]->echoid(), area_fuzidx) or striinc(area_maybe, AL[n]->echoid()))) {
316       found = true;
317       break;
318     }
319   }
320 
321   if(not found) {
322     for(n = minimum_index; n <= index; n++) {
323       if(not AL[n]->isseparator() and (strnieql(area_maybe, AL[n]->echoid(), area_fuzidx) or striinc(area_maybe, AL[n]->echoid())))
324         break;
325     }
326   }
327 
328   if(n > maximum_index)
329     n = minimum_index;
330 
331   while(AL[n]->isseparator()) {
332     if((++n) > maximum_index)
333       n = minimum_index;
334   }
335 
336   index = n;
337   center();
338 
339 }
340 
341 
342 //  ------------------------------------------------------------------
343 
open()344 void GPickArealist::open() {
345 
346   int active=NO;
347 
348   #if defined(GUTLOS_FUNCS)
349   g_set_ostitle_name("Arealist",0);
350   #endif
351 
352   if(ypos) {
353     if(tempwin1) {
354       tempwin = tempwin1;
355       areawin = areawin1;
356       active = YES;
357     }
358   }
359   else {
360     if(tempwin2) {
361       tempwin = tempwin2;
362       areawin = areawin2;
363       active = YES;
364     }
365   }
366 
367   if(active) {
368     wunhide(tempwin);
369     wprints(0,0, wattr, title);
370     wunhide(areawin);
371   }
372   else {
373     tempwin = wopen_(ypos, xpos, 1, MAXCOL, 5, battr, wattr, sbattr);
374     wprints(0,0, wattr, title);
375     areawin = wopen_(ypos+1, xpos, ylen+2, MAXCOL, btype, battr, wattr, sbattr);
376 
377     if(ypos) {
378       tempwin1 = tempwin;
379       areawin1 = areawin;
380     }
381     else {
382       tempwin2 = tempwin;
383       areawin2 = areawin;
384     }
385 
386     if(area_width)
387       wmessage(LNG->Area, TP_BORD, 1+area_pos+(marked_pos==area_pos+area_width?1:0), tattr);
388     if(desc_width)
389       wmessage(LNG->Description, TP_BORD, 1+desc_pos, tattr);
390     if(count_width)
391       wmessage(LNG->Msgs, TP_BORD, 1+count_pos+count_width-strlen(LNG->Msgs), tattr);
392     if(unread_width) {
393       if(CFG->arealisttype == AL_TOTLST)
394         wmessage(LNG->Last, TP_BORD, 1+unread_pos+unread_width-strlen(LNG->Last), tattr);
395       else if(CFG->arealisttype == AL_TOTNEW)
396         wmessage(LNG->New, TP_BORD, 1+unread_pos+unread_width-strlen(LNG->New), tattr);
397     }
398     if(echoid_width)
399       wmessage(LNG->EchoID, TP_BORD, 1+echoid_pos, tattr);
400     if(groupid_width) {
401       char grpbuf[40];
402       if(groupid_width > 2)
403         strcpy(grpbuf, LNG->Grp);
404       else {
405         *grpbuf = *(LNG->Grp);
406         grpbuf[1] = NUL;
407       }
408       wmessage(grpbuf, TP_BORD, 1+groupid_pos, tattr);
409     }
410 
411   }
412   if(CFG->switches.get(areaautonext) and ypos == 0 and index >= minimum_index and not AL[index]->ismarked()) {
413     jump_to();
414   }
415   else
416     center();
417 }
418 
419 
420 //  ------------------------------------------------------------------
421 
close()422 void GPickArealist::close() {
423 
424   whide();
425   whide();
426 }
427 
428 //  ------------------------------------------------------------------
429 
precursor()430 void GPickArealist::precursor() {
431 
432   *area_maybe = 0;
433   area_fuzidx = 0;
434 }
435 
436 
437 //  ------------------------------------------------------------------
438 
print_line(uint idx,uint pos,bool isbar)439 void GPickArealist::print_line(uint idx, uint pos, bool isbar) {
440 
441   vchar vbuf[256];
442   char buf[256];
443 
444   if(AL[idx]->isseparator()) {
445     Area* area = AL.AreaNoToPtr(idx);
446 
447     int sep_pos = (desc_pos != -1) ? desc_pos : echoid_pos;
448 
449     {for(int c = 0; c < sep_pos; c++)
450       vbuf[c] = _box_table(btype, 1);}
451     vbuf[sep_pos] = NUL;
452     wprintvs(pos, 0, battr|ACSET, vbuf);
453     wprints(pos, sep_pos, tattr, area->desc());
454 
455     int l = strlen(area->desc());
456     int n = MAXCOL-2-sep_pos-l;
457 
458     {for(int c = 0; c < n; c++)
459       vbuf[c] = _box_table(btype,1);}
460     vbuf[n] = NUL;
461     wprintvs(pos, sep_pos+l, battr|ACSET, vbuf);
462   }
463   else {
464     dispbuf(buf, idx);
465     wprints(pos, 0, isbar ? sattr : wattr, buf);
466     if(AL[idx]->ismarked())
467       wprintc(pos, marked_pos, isbar ? sattr : hattr, marked_char);
468   }
469 
470 }
471 
472 
473 //  ------------------------------------------------------------------
474 
AreaCatchUp(uint n)475 void GPickArealist::AreaCatchUp(uint n) {
476 
477   // Do not do catch up if there's active area
478   if(AA->isopen())
479     return;
480 
481   GMenuAreaCatchup MenuAreaCatchup;
482   GMsg* msg = (GMsg*)throw_calloc(1, sizeof(GMsg));
483 
484   int mode = MenuAreaCatchup.Run();
485 
486   if(mode != SCAN_QUIT) {
487     for(AL.item = AL.idx.begin(); AL.item != AL.idx.end(); AL.item++) {
488 
489       if((mode == SCAN_MARKED and (*AL.item)->ismarked()) or mode == SCAN_ALL or (mode == SCAN_CURRENT and (*AL.item) == AL[n])) {
490 
491         if((*AL.item)->isseparator())
492           continue;
493 
494         update_statuslinef("%s ...", "", (*AL.item)->echoid());
495 
496         AA = (*AL.item);
497         AA->Open();
498 
499         if(CFG->switches.get(highlightunread) and CFG->switches.get(areacatchupread)) {
500           w_info(LNG->Wait);
501           for(uint i=AA->lastread()+1; i <= AA->Msgn.Count(); i++) {
502             AA->LoadHdr(msg, AA->Msgn.CvtReln(i), false);
503             if(msg->timesread++ == 0)
504               AA->UpdateTimesread(msg);
505           }
506           w_info(NULL);
507         }
508 
509         AA->set_lastread(AA->Msgn.Count());
510         AA->isvalidchg = false;
511         AA->Close();
512       }
513     }
514   }
515   throw_free(msg);
516 }
517 
518 
519 //  ------------------------------------------------------------------
520 
AreaDropMsgMarks(uint n)521 void GPickArealist::AreaDropMsgMarks(uint n) {
522 
523   GMenuAreaDropMarks MenuAreaDropMarks;
524 
525   uint nummarks = 0;
526 
527   for(AL.item = AL.idx.begin(); AL.item != AL.idx.end(); AL.item++)
528     nummarks += (*AL.item)->Mark.Count();
529 
530   char buf[256];
531   gsprintf(PRINTF_DECLARE_BUFFER(buf), LNG->DropMarksInfo, longdotstr(nummarks));
532 
533   w_info(buf);
534   int mode = MenuAreaDropMarks.Run();
535   w_info(NULL);
536 
537   if(mode != SCAN_QUIT) {
538     for(AL.item = AL.idx.begin(); AL.item != AL.idx.end(); AL.item++) {
539       if((mode == SCAN_MARKED and (*AL.item)->ismarked()) or mode == SCAN_ALL or (mode == SCAN_CURRENT and (*AL.item) == AL[n])) {
540 
541         if((*AL.item)->isseparator())
542           continue;
543 
544         (*AL.item)->Mark.ResetAll();
545       }
546     }
547   }
548 }
549 
550 
551 //  ------------------------------------------------------------------
552 
handle_key()553 bool GPickArealist::handle_key() {
554 
555   uint n;
556   uint x;
557   const char* adesc;
558   char buf[256], tmp[256];
559 
560   int mode, changed, currno;
561 
562   gkey kk;
563 
564   if(key < KK_Commands) {
565     key = key_tolower(key);
566     if((key == Key_Esc) and esc_abort)
567       key = KK_AreaAbort;
568     else {
569       kk = SearchKey(key, AreaKey, AreaKeys);
570       if(kk)
571         key = kk;
572     }
573   }
574 
575 
576   switch(key) {
577 
578     case KK_AreaDropMsgMarks:
579       AreaDropMsgMarks(index);
580       break;
581 
582     case KK_AreaSelectMarks:
583       AL.Select_Mask();
584       break;
585 
586     case KK_AreaAskExit:
587       {
588         GMenuQuit MenuQuit;
589         aborted = gkbd.quitall = (MenuQuit.Run()!=0);
590         if(gkbd.quitall) {
591           precursor();
592           return false;
593         }
594       }
595       break;
596 
597     case KK_AreaAbort:
598       aborted = true;
599       // Drop Through
600 
601     case KK_AreaSelect:
602       if(AL[index]->isseparator()) {
603         if(not PlayMacro(key, KT_A))
604           SayBibi();
605         break;
606       }
607       precursor();
608       return false;
609 
610     case KK_AreaQuitNow:
611       aborted = gkbd.quitall = true;
612       precursor();
613       return false;
614 
615     case KK_AreaToggle:
616       AL[index]->set_marked(not AL[index]->ismarked());
617       display_bar();
618       precursor();
619       cursor_down();
620       break;
621 
622     case KK_AreaMark:
623       AL[index]->set_marked(true);
624       display_bar();
625       precursor();
626       cursor_down();
627       break;
628 
629     case KK_AreaUnmark:
630       AL[index]->set_marked(false);
631       display_bar();
632       precursor();
633       cursor_down();
634       break;
635 
636     case KK_AreaBoardnos:
637       CFG->switches.set(arealistnos, not CFG->switches.get(arealistnos));
638       update();
639       break;
640 
641     case KK_AreaCatchUp:
642       AreaCatchUp(index);
643       update();
644       break;
645 
646     case KK_AreaJumpNextMatch:
647       jumpmatch();
648       break;
649 
650     case KK_AreaJump:
651       {
652         precursor();
653         jump_to();
654       }
655       break;
656 
657     case KK_AreaDosShell:
658       DosShell();
659       break;
660 
661     case KK_AreaGotoPrev:   precursor(); cursor_up();    break;
662     case KK_AreaGotoNext:   precursor(); cursor_down();  break;
663     case KK_AreaGotoFirst:  precursor(); cursor_first(); break;
664     case KK_AreaGotoLast:   precursor(); cursor_last();  break;
665 
666     case KK_AreaSoundkill:
667       HandleGEvent(EVTT_STOPVOICE);
668       break;
669 
670     case KK_AreaTouchNetscan:
671       TouchNetscan();
672       break;
673 
674     case KK_AreaHeat:
675       {
676         GMenuAreaHeat MenuAreaHeat;
677         mode = MenuAreaHeat.Run();
678         if(mode != SCAN_QUIT) {
679           for(AL.item = AL.idx.begin(); AL.item != AL.idx.end(); AL.item++) {
680             if((mode == SCAN_MARKED and (*AL.item)->ismarked()) or mode == SCAN_ALL or (mode == SCAN_CURRENT and (*AL.item) == AL[index-1])) {
681               update_statuslinef("%s %s", "", 1+LNG->ScanningArea, (*AL.item)->echoid());
682               (*AL.item)->SetHighwaterMark();
683             }
684           }
685         }
686       }
687       break;
688 
689     case KK_AreaZap:
690       {
691         GMenuAreaZap MenuAreaZap;
692         mode = MenuAreaZap.Run();
693         if(mode != SCAN_QUIT) {
694           for(AL.item = AL.idx.begin(); AL.item != AL.idx.end(); AL.item++) {
695             if((mode == SCAN_MARKED and (*AL.item)->ismarked()) or mode == SCAN_ALL or (mode == SCAN_CURRENT and (*AL.item) == AL[index-1])) {
696               update_statuslinef("%s %s", "", 1+LNG->ScanningArea, (*AL.item)->echoid());
697               (*AL.item)->ResetHighwaterMark();
698             }
699           }
700         }
701       }
702       break;
703 
704     case KK_AreaScanPM:
705       pmscan = true;
706       pmails = 0;
707       pmareas = 0;
708       // DROP THROUGH //
709 
710     case KK_AreaScan:
711       {
712         currno = index;
713         GMenuAreaScan MenuAreaScan;
714         mode = MenuAreaScan.Run(pmscan);
715         if(mode != SCAN_QUIT) {
716 
717           w_info(LNG->Wait);
718 
719           strcpy(stecho, AL[index]->echoid());
720 
721           if(mode == SCAN_IMPORTQWK)
722             changed = ImportQWK();
723           else if(mode == SCAN_EXPORTQWK)
724             changed = ExportQWK();
725           else if(mode == SCAN_IMPORTSOUP)
726             changed = ImportSOUP();
727           else if(mode == SCAN_EXPORTSOUP)
728             changed = ExportSOUP();
729           else {
730             if(cmdlinedebughg)
731               LOG.printf("- AreaScan from arealist");
732             changed = AL.AreaScan(mode, currno, pmscan, pmails, pmareas);
733           }
734 
735           w_info();
736 
737           AL.SetActiveAreaNo(currno);
738           if(changed) {
739             AL.Sort();
740             AreasRenumber();
741             index = AL.AreaEchoToNo(stecho);
742             center();
743           }
744 
745           if(pmscan) {
746             if(pmails) {
747               w_infof(LNG->FoundPersonal,
748                 pmails, (pmails==1?"":"s"),
749                 pmareas, (pmareas==1?"":"s")
750               );
751             }
752             else {
753               w_info(LNG->NoPersonal);
754             }
755             waitkeyt(10000);
756             w_info();
757           }
758         }
759         pmscan = false;
760       }
761       break;
762 
763     case Key_Tick:
764       CheckTick(KK_AreaQuitNow);
765       break;
766 
767     case KK_AreaUndefine:
768       break;
769 
770     case KK_AreaWriteGoldlast:
771       w_info(LNG->Wait);
772       AL.WriteGoldLast();
773       w_info();
774       break;
775 
776     default:
777       if(key < KK_Macro) {
778         n = g_toupper(key & 0xFF);
779         if((area_fuzidx < area_maxfuz) or (key == Key_BS)) {
780 
781           // Incremental search in the echoids
782           if(not iscntrl(n) or (key == Key_BS)) {
783             if(n == ' ')
784               n = '_';
785             if(key != Key_BS)
786               area_maybe[area_fuzidx++] = (char)n;
787             else if(area_fuzidx)
788               area_fuzidx--;
789             area_maybe[area_fuzidx] = NUL;
790             strcpy(stpcpy(buf, title), area_maybe);
791             strsetsz(strcpy(tmp, buf), MAXCOL);
792             wwprintstr(tempwin, 0, 0, wattr, tmp);
793             if(area_fuzidx) {
794 
795               x = atoi(area_maybe);
796               if(x) {
797                 if(CFG->switches.get(arealistnos) and (isdigit(area_maybe[1]) or (area_maybe[1] == NUL))) {
798                   for(n=0; n<AL.size(); n++) {
799                     if(AL[n]->board() == x) {
800                       x = n;
801                       goto RedrawAreas;
802                     }
803                   }
804                   x = 0;  // No match found
805                 }
806                 else {
807                   for(n=0; n<area_fuzidx; n++) {
808                     if(not isdigit(area_maybe[n])) {
809                       x = 0;
810                       break;
811                     }
812                   }
813                 }
814               }
815 
816               if(x >= 1 and x<=AL.size()) {
817                 {
818                   for(int a=0, at=AL.size(); a<at; a++) {
819                     if(areanumbers[a] == x) {
820                       x = a;
821                       goto RedrawAreas;
822                     }
823                   }
824                 }
825                 x = (uint)-1;
826 
827               RedrawAreas:
828 
829                 if(x == (uint)-1)
830                   x = index;
831                 while(AL[x]->isseparator()) {
832                   x++;
833                   if(x > maximum_index)
834                     x = minimum_index;
835                 }
836                 if(x != index)
837                   display_line();
838                 #define _topidx (index-position)                    // Shorthand..
839                 #define _botidx (index+(maximum_position-position)) // Shorthand..
840                 if((_topidx <= x) and (x <= _botidx)) {
841                   position += (x-index);
842                   index = x;
843                   display_page();    /////////// NEW
844                 }
845                 else {
846                   index = x;
847                   center();
848                 }
849                 break;
850               }
851               else {
852                 // Regular search
853                 for(n=0; n<AL.size(); n++) {
854                   adesc = AL[n]->echoid();
855                   if(strnicmp(area_maybe, adesc, area_fuzidx) == 0) {
856                     AL.Sort();
857                     AreasRenumber();
858                     x = AL.AreaEchoToNo(adesc);
859                     goto RedrawAreas;
860                   }
861                 }
862                 // Search inside
863                 for(n=0; n<AL.size(); n++) {
864                   adesc = AL[n]->echoid();
865                   if(striinc(area_maybe, adesc)) {
866                     AL.Sort();
867                     AreasRenumber();
868                     x = AL.AreaEchoToNo(adesc);
869                     goto RedrawAreas;
870                   }
871                 }
872               }
873             }
874             else {
875               adesc = AL[index]->echoid();
876               AL.Sort();
877               AreasRenumber();
878               index = AL.AreaEchoToNo(adesc);
879               center();
880             }
881             break;
882           }
883         }
884       }
885       if(not PlayMacro(key, KT_A))
886         SayBibi();
887   }
888 
889   return true;
890 }
891 
892 //  ------------------------------------------------------------------
893 
Run(const char * _title,int wpos,int & idx)894 int GPickArealist::Run(const char* _title, int wpos, int& idx) {
895 
896   HandleGEvent(EVTT_AREALIST);
897 
898   xpos     = 0;                             // Window starting coloumn
899   ypos     = wpos;                          // Window starting row
900   xlen     = MAXCOL-2;                      // Window ending coloumn
901   ylen     = MAXROW-wpos-4;                 // Window ending row
902   title    = _title;                        // Window title
903   btype    = W_BAREA;                       // Window border type
904   battr    = C_AREAB;                       // Window border attributes
905   wattr    = C_AREAW;                       // Window Color
906   tattr    = C_AREAT;                       // Window Title Color
907   sattr    = C_AREAS;                       // Window Selection Bar Color
908   hattr    = C_AREAQ;                       // Window Highlight Color
909   sbattr   = C_AREAPB;                      // Window Scrollbar Color
910   helpcat  = H_Area;                        // Window Help Category
911 
912   maximum_index    = AL.size() - 1;             // List Entries - 1
913   maximum_position = MinV((size_t)ylen-1, AL.size()-1); // Display Pos
914   index            = AL.AreaIdToNo(idx);        // List Index
915   listwrap         = CFG->switches.get(displistwrap);  // True if wrap-around is supported
916   esc_abort        = (wpos!=0);
917   area_maxfuz      = MinV(sizeof(Echo), MAXCOL-strlen(title)-1);
918 
919   goldmark = ' ';
920 
921   areanumbers = (uint*)throw_calloc(AL.size(), sizeof(uint));
922   AreasRenumber();
923 
924   run_picker();
925 
926   throw_release(areanumbers);
927 
928   if(not aborted)
929     return AL[index]->areaid();
930 
931   idx = AL[index]->areaid();
932 
933   return -1;
934 }
935 
936 
937 //  ------------------------------------------------------------------
938 
AreaPick(char * title,int wpos,int * idx)939 int AreaPick(char* title, int wpos, int* idx) {
940 
941   GPickArealist p;
942   int new_area;
943 
944   if(gkbd.quitall)
945     return -1;
946 
947   PickArealist = &p;
948 
949   in_arealist = true;
950   new_area = p.Run(title, wpos, *idx);
951   in_arealist = false;
952 
953   PickArealist = NULL;
954 
955   return new_area;
956 }
957 
958 
959 //  ------------------------------------------------------------------
960 
961