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: gealst.cpp,v 1.30 2010/03/28 17:20:21 stas_degteff Exp $
23 // ------------------------------------------------------------------
24 // Arealist functions.
25 // ------------------------------------------------------------------
26
27 #if defined(_MSC_VER)
28 /* C4786: 'identifier' : identifier was truncated to 'number'
29 characters in the debug information
30 */
31 #pragma warning(disable: 4786)
32 #endif
33 #include <algorithm>
34 #include <limits.h>
35 #include <golded.h>
36
37 #if defined(__USE_ALLOCA__)
38 #include <malloc.h>
39 #endif
40
41
42 // ------------------------------------------------------------------
43
44 AreaList AL;
45
46 int AreaTypeOrder[17] = {
47 0,
48 1, // GMB_NET
49 2, // GMB_EMAIL
50 3, // GMB_NET | GMB_EMAIL
51 4, // GMB_ECHO
52 5,
53 6,
54 7,
55 8, // GMB_NEWSGROUP
56 9,
57 10,
58 11,
59 12, // GMB_ECHO | GMB_NEWSGROUP
60 13,
61 14,
62 15,
63 16 // GMB_LOCAL
64 };
65
66
67 // ------------------------------------------------------------------
68 // Areagroups compare
69
compare_groups(int _ga,int _gb)70 int compare_groups(int _ga, int _gb)
71 {
72 register int ga = _ga ? _ga : INT_MAX;
73 register int gb = _gb ? _gb : INT_MAX;
74
75 const char *gap = NULL;
76 const char *gbp = NULL;
77
78 const char *g;
79
80 for(g = CFG->arealistgrouporder; *g != NUL;) {
81
82 int gr = getgroup(g);
83
84 if(gr == ga)
85 gap = g;
86
87 if(gr == gb)
88 gbp = g;
89
90 if(*g == '#') {
91 do {
92 g++;
93 } while(isdigit(*g));
94 }
95 else
96 g++;
97 }
98
99 if(gap == NULL) {
100 if(gbp != NULL)
101 return 1;
102 else
103 return compare_two(ga, gb);
104 }
105 else {
106 if(gbp == NULL)
107 return -1;
108 else
109 return compare_two(gap, gbp);
110 }
111 }
112
113
114 // ------------------------------------------------------------------
115 // Arealist compare
116
AreaListCmp(const Area ** __a,const Area ** __b)117 extern "C" int AreaListCmp(const Area** __a, const Area** __b) {
118
119 const Area* a = *__a;
120 const Area* b = *__b;
121 const Area* A = a;
122 const Area* B = b;
123 int cmp = 0;
124
125 bool sepfirst = false;
126
127 bool rev = false;
128 char* ptr = AL.sortspec;
129
130 while(*ptr) {
131 switch(*ptr) {
132 case '-':
133 rev = true;
134 A = b; B = a;
135 break;
136 case '+':
137 rev = false;
138 A = a; B = b;
139 break;
140 case 'A':
141 case 'a':
142 sepfirst = true;
143 if((cmp = A->aka().compare(B->aka())) != 0)
144 return cmp;
145 break;
146 case 'B':
147 case 'b':
148 if(A->isseparator() and B->isseparator())
149 break;
150 else if(A->isseparator()) {
151 if(B->board())
152 return sepfirst?-1:1;
153 }
154 else if(B->isseparator()) {
155 if(A->board())
156 return sepfirst?1:-1;
157 }
158 else if((cmp = compare_two(A->board(), B->board())) != 0)
159 return cmp;
160 break;
161 case 'D':
162 case 'd':
163 if((cmp = stricmp(A->desc(), B->desc())) != 0)
164 return cmp;
165 break;
166 case 'E':
167 case 'e':
168 if((cmp = stricmp(A->echoid(), B->echoid())) != 0)
169 return cmp;
170 break;
171 case 'F':
172 case 'f':
173 if(*area_maybe) {
174 bool amay = make_bool(striinc(area_maybe, A->echoid()));
175 bool bmay = make_bool(striinc(area_maybe, B->echoid()));
176
177 if((cmp = compare_two(bmay, amay)) != 0)
178 return cmp;
179 }
180 break;
181 case 'G':
182 case 'g':
183 sepfirst = true;
184 if((cmp = compare_groups(A->groupid(), B->groupid())) != 0)
185 return cmp;
186 break;
187 case 'M':
188 case 'm':
189 if(A->isseparator() and B->isseparator())
190 break;
191 else if(A->isseparator()) {
192 if(B->ismarked())
193 return sepfirst?-1:1;
194 }
195 else if(B->isseparator()) {
196 if(A->ismarked())
197 return sepfirst?1:-1;
198 }
199 else if((cmp = compare_two(B->ismarked(), A->ismarked())) != 0)
200 return cmp;
201 break;
202 case 'P':
203 if(A->isseparator() and B->isseparator())
204 break;
205 else if(A->isseparator()) {
206 if(B->PMrk.Count())
207 return sepfirst?-1:1;
208 }
209 else if(B->isseparator()) {
210 if(A->PMrk.Count())
211 return sepfirst?1:-1;
212 }
213 else {
214 register int aunread = A->PMrk.Count();
215 register int bunread = B->PMrk.Count();
216
217 aunread = (rev or aunread) ? aunread : INT_MAX;
218 bunread = (rev or bunread) ? bunread : INT_MAX;
219 if((cmp = compare_two(aunread, bunread)) != 0)
220 return cmp;
221 }
222 break;
223 case 'p':
224 if(A->isseparator() and B->isseparator())
225 break;
226 else if(A->isseparator()) {
227 if(B->PMrk.Count())
228 return sepfirst?-1:1;
229 }
230 else if(B->isseparator()) {
231 if(A->PMrk.Count())
232 return sepfirst?1:-1;
233 }
234 else if((cmp = compare_two(B->PMrk.Count()?1:0, A->PMrk.Count()?1:0)) != 0)
235 return cmp;
236 break;
237 case 'O':
238 case 'o':
239 if((cmp = compare_two(A->areaid(), B->areaid())) != 0)
240 return cmp;
241 break;
242 case 'T':
243 case 't':
244 sepfirst = true;
245 if((cmp = compare_two(CFG->areatypeorder[A->type()&0xFF], CFG->areatypeorder[B->type()&0xFF])) != 0)
246 return cmp;
247 break;
248 case 'U':
249 if(A->isseparator() and B->isseparator())
250 break;
251 else if(A->isseparator()) {
252 if(B->unread)
253 return sepfirst?-1:1;
254 }
255 else if(B->isseparator()) {
256 if(A->unread)
257 return sepfirst?1:-1;
258 }
259 else {
260 register int aunread = A->unread;
261 register int bunread = B->unread;
262
263 aunread = (rev or aunread) ? aunread : INT_MAX;
264 bunread = (rev or bunread) ? bunread : INT_MAX;
265 if((cmp = compare_two(aunread, bunread)) != 0)
266 return cmp;
267 }
268 break;
269 case 'u':
270 if(A->isseparator() and B->isseparator())
271 break;
272 else if(A->isseparator()) {
273 if(B->unread)
274 return sepfirst?-1:1;
275 }
276 else if(B->isseparator()) {
277 if(A->unread)
278 return sepfirst?1:-1;
279 }
280 else if((cmp = compare_two(B->unread?1:0, A->unread?1:0)) != 0)
281 return cmp;
282 break;
283 case 'X':
284 case 'x':
285 if(A->isseparator() and B->isseparator())
286 break;
287 else if(A->isseparator()) {
288 return sepfirst?-1:1;
289 }
290 else if(B->isseparator()) {
291 return sepfirst?1:-1;
292 }
293 else if ((cmp = strcmp(A->basetype().c_str(), B->basetype().c_str())) != 0)
294 return cmp;
295 break;
296 case 'Y':
297 case 'y':
298 if(A->isseparator() and B->isseparator())
299 break;
300 else if(A->isseparator()) {
301 if(B->isnewmail())
302 return sepfirst?-1:1;
303 }
304 else if(B->isseparator()) {
305 if(A->isnewmail())
306 return sepfirst?1:-1;
307 }
308 else if((cmp = compare_two(B->isnewmail(), A->isnewmail())) != 0)
309 return cmp;
310 break;
311 case 'Z':
312 case 'z':
313 if(A->isseparator() and B->isseparator())
314 break;
315 else if(A->isseparator())
316 return sepfirst?-1:1;
317 else if(B->isseparator())
318 return sepfirst?1:-1;
319 else if((cmp = stricmp(A->path(), B->path())) != 0)
320 return cmp;
321 break;
322 case 'S':
323 case 's':
324 if((cmp = compare_two(B->isseparator(), A->isseparator())) != 0)
325 return cmp;
326 break;
327 }
328 ptr++;
329 }
330
331 if(cmp == 0) {
332 cmp = compare_two(B->isseparator(), A->isseparator());
333 }
334
335 return cmp;
336 }
337
AreaListCmp2(const Area * a,const Area * b)338 static bool AreaListCmp2(const Area* a, const Area* b) {
339
340 return AreaListCmp(&a, &b) < 0;
341 }
342
343 // ------------------------------------------------------------------
344 // Arealist sort areas
345
Sort(const char * specs,int first,int last)346 void AreaList::Sort(const char* specs, int first, int last) {
347
348 if(specs)
349 strxcpy(sortspec, specs, sizeof(sortspec));
350 else
351 strcpy(sortspec, CFG->arealistsort);
352 if(last == -1)
353 last = idx.size();
354 if(*sortspec) {
355 std::sort(idx.begin()+first, idx.begin()+last, AreaListCmp2);
356 }
357 }
358
359
360 // ------------------------------------------------------------------
361
AreaEchoToNo(const char * echoid)362 int AreaList::AreaEchoToNo(const char* echoid) {
363
364 for(uint n=0; n<idx.size(); n++)
365 if(strieql(echoid, idx[n]->echoid()))
366 return n;
367 return -1;
368 }
369
370
371 // ------------------------------------------------------------------
372
AreaEchoToPtr(const char * echoid)373 Area* AreaList::AreaEchoToPtr(const char* echoid) {
374
375 for(uint n=0; n<idx.size(); n++)
376 if(strieql(echoid, idx[n]->echoid()))
377 return idx[n];
378 return NULL;
379 }
380
381
382 // ------------------------------------------------------------------
383
AreaNoToId(int __areano)384 int AreaList::AreaNoToId(int __areano) {
385
386 if(in_range(__areano, 0, int(idx.size()-1)))
387 return idx[__areano]->areaid();
388 else {
389 LOG.ErrIndex();
390 LOG.printf("! Arealist index out of bounds.");
391 LOG.printf(": Tried to access record %i, but the range was only 0 - %u.", __areano, (uint)(idx.size()-1));
392 LOG.printf("+ Advice: Report this to the author.");
393 IndexErrorExit();
394 return 0;
395 }
396 }
397
398
399 // ------------------------------------------------------------------
400
AreaNoToPtr(int __areano)401 Area* AreaList::AreaNoToPtr(int __areano) {
402
403 if(in_range(__areano, 0, int(idx.size()-1)))
404 return idx[__areano];
405 else {
406 LOG.ErrIndex();
407 LOG.printf("! Arealist index out of bounds.");
408 LOG.printf(": Tried to access record %i, but the range was only 0 - %u.", __areano, (uint)(idx.size()-1));
409 LOG.printf("+ Advice: Report this to the author.");
410 IndexErrorExit();
411 return 0;
412 }
413 }
414
415
416 // ------------------------------------------------------------------
417
AreaIdToNo(int __areaid)418 int AreaList::AreaIdToNo(int __areaid) {
419
420 uint _areano = 0;
421 while(_areano < idx.size()) {
422 if(idx[_areano]->areaid() == __areaid)
423 return _areano;
424 _areano++;
425 }
426 return -1;
427 }
428
429
430 // ------------------------------------------------------------------
431
AreaIdToPtr(int __areaid)432 Area* AreaList::AreaIdToPtr(int __areaid) {
433
434 int _areano = AreaIdToNo(__areaid);
435 if(_areano != -1)
436 return idx[_areano];
437 return NULL;
438 }
439
440
441 // ------------------------------------------------------------------
442
SetActiveAreaId(int __areaid)443 int AreaList::SetActiveAreaId(int __areaid) {
444
445 int _areano = AreaIdToNo(__areaid);
446 SetActiveAreaNo(_areano);
447 return _areano; // Return the areano
448 }
449
450
451 // ------------------------------------------------------------------
452
453 class SelMaskPick : public gwinpick {
454
455 gwindow window;
456 int DESC_LEN;
457
458 void open(); // Called after window is opened
459 void close(); // Called after window is closed
460 void print_line(uint idx, uint pos, bool isbar);
461 bool handle_key(); // Handles keypress
462
463 public:
464
465 void Run();
466
467 };
468
open()469 void SelMaskPick::open() {
470
471 window.openxy(ypos, xpos, ylen+2, xlen+2, btype, battr, LGREY_|_BLACK);
472 window.title(title, tattr);
473 window.shadow(C_SHADOW);
474 update();
475 }
476
close()477 void SelMaskPick::close() {
478
479 window.close();
480
481 }
482
print_line(uint idx,uint pos,bool isbar)483 void SelMaskPick::print_line(uint idx, uint pos, bool isbar) {
484
485 #if defined(__USE_ALLOCA__)
486 char *buf = (char*)alloca(DESC_LEN+3);
487 #else
488 __extension__ char buf[DESC_LEN+3];
489 #endif
490
491 *buf = ' '; strxcpy(buf+1, AL.alistselections[idx], DESC_LEN);
492 window.printns(pos, 0, isbar ? sattr : wattr, buf, xlen);
493 }
494
handle_key()495 bool SelMaskPick::handle_key() {
496
497 switch(key) {
498 case Key_Esc:
499 aborted = true;
500
501 /// Drop through
502 case Key_Ent:
503 return false;
504
505 case Key_Tick:
506 break;
507
508 default:
509 if(key < KK_Commands) {
510 kbput(key);
511 edit_string(AL.alistselections[index], DESC_LEN-1, LNG->SelectMarksEdit, H_SelectMarks);
512 display_bar();
513 }
514 break;
515 }
516
517 return true;
518 }
519
Run()520 void SelMaskPick::Run() {
521
522 DESC_LEN = (sizeof(Desc) > (MAXCOL-6)) ? MAXCOL-6 : sizeof(Desc);
523
524 ypos = (MAXROW-18)/2;
525 xpos = (MAXCOL-DESC_LEN-4)/2-1;
526 ylen = 16;
527 xlen = DESC_LEN+2;
528 btype = W_BMENU;
529 battr = C_MENUB;
530 wattr = C_MENUW;
531 tattr = C_MENUT;
532 sattr = C_MENUS;
533 hattr = C_MENUQ;
534
535 title = LNG->SelectMarks;
536 helpcat = H_SelectMarks;
537 listwrap = true;
538
539 maximum_index = 15;
540 maximum_position = 16;
541
542 index = position = AL.mask;
543
544 run_picker();
545
546 if(not aborted)
547 AL.mask = (byte)index;
548
549 }
550
551
Select_Mask()552 void AreaList::Select_Mask() {
553
554 SelMaskPick& SelMask = *new SelMaskPick;
555 throw_new(&SelMask);
556
557 SelMask.Run();
558
559 extern bool in_arealist;
560 extern GPickArealist* PickArealist;
561
562 if(in_arealist) {
563 PickArealist->update();
564 PickArealist->do_delayed();
565 }
566
567 delete &SelMask;
568 }
569
570
571 // ------------------------------------------------------------------
572
573