1 /*
2 * AREAS.C
3 *
4 * Written by jim nutt, John Dennis and released into the public domain
5 * by John Dennis in 1994.
6 *
7 * This file contains the routines to select one of the areas specified
8 * in the config files. It pops up a list with all the areas and lets
9 * the user choose.
10 */
11
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <string.h>
15 #include <time.h>
16 #include "addr.h"
17 #include "nedit.h"
18 #include "msged.h"
19 #include "winsys.h"
20 #include "menu.h"
21 #include "main.h"
22 #include "misc.h"
23 #include "memextra.h"
24 #include "specch.h"
25 #include "keys.h"
26 #include "unused.h"
27 #include "help.h"
28 #include "version.h"
29 #include "strextra.h"
30 #include "areas.h"
31 #include "group.h"
32
33 char **alist = NULL;
34 char **alist2 = NULL;
35
36 static int AreaBox(char **Itms, int y1, int real_y2, int len, int def, WND * hPrev, WND * hWnd, int Sel, int Norm, int indent);
37
BuildList(char *** lst)38 void BuildList(char ***lst)
39 {
40 int i;
41 AREA *a;
42 char line[256];
43 unsigned long unread, last;
44 int areano;
45
46 *lst = xcalloc(SW->groupareas + 2 ,sizeof(char *));
47
48 for (i = 0; i < SW->groupareas; i++)
49 {
50 areano = group_getareano(i);
51
52 if (areano>=0)
53 {
54 a = arealist + areano;
55 memset(line, ' ', sizeof line);
56
57 if (a->scanned)
58 {
59 last = a->lastread;
60 if (last > a->messages)
61 {
62 last = a->messages;
63 }
64 unread = a->messages - a->lastread;
65 if (unread > a->messages)
66 {
67 unread = a->messages;
68 }
69
70 /* F_ALTERNATE for SC14 is set in SelShowItem */
71 sprintf(line, "%c%-*.*s", unread ? (SC14) : ' ',
72 maxx - 25, maxx - 25, a->description);
73 line[strlen(line)] = ' ';
74 sprintf(line + maxx - 23, "%6lu%6lu%6lu",
75 a->messages, unread, last);
76 }
77 else
78 {
79 sprintf(line, " %-*.*s", maxx - 25, maxx - 25, a->description);
80 line[strlen(line)] = ' ';
81 sprintf(line + maxx - 19, " - - -");
82 }
83 }
84 else
85 {
86 memset(line, '=', sizeof line);
87 sprintf(line + 2, " Group: %s ", group_getname(-areano));
88 line[strlen(line)]='=';
89 line[sizeof(line) - 1] = '\0';
90 }
91
92 (*lst)[i] = xstrdup(line);
93 }
94 (*lst)[i] = NULL;
95 }
96
SelShowItem(char * text,int y,int len,int Attr,int indent)97 static void SelShowItem(char *text, int y, int len, int Attr, int indent)
98 {
99 char line[256];
100
101 memset(line, ' ', sizeof(line));
102
103 if (strlen(text) + indent > sizeof(line) - 1)
104 {
105 strcpy(line,"<--- internal buffer overflow --->");
106 }
107
108 strcpy(line + indent, text);
109 line[sizeof(line)-1] = 0;
110 if (indent)
111 {
112 WndPutsn(1, y, indent, Attr, line);
113 }
114 WndPutsn(1 + indent, y, 1, Attr | F_ALTERNATE, line + indent);
115 if (len > (indent + 1))
116 {
117 WndPutsn(2 + indent, y, len - (indent + 1), Attr, line+indent+1);
118 }
119 }
120
SelShowPage(char ** text,int top,int bot,int len,int pos,int Attr,int indent)121 static void SelShowPage(char **text, int top, int bot, int len, int pos, int Attr, int indent)
122 {
123 int i, y;
124
125 y = top;
126 for (i = pos; text[i] != NULL; i++)
127 {
128 if (y > bot)
129 {
130 break;
131 }
132 SelShowItem(text[i], y++, len, Attr, indent);
133 }
134 if (y <= bot)
135 {
136 while (y <= bot)
137 {
138 SelShowItem(" ", y++, len, Attr, indent);
139 }
140 }
141 }
142
CalcDef(int max,int cur,int * top,int miny,int maxy,int * y)143 static void CalcDef(int max, int cur, int *top, int miny, int maxy, int *y)
144 {
145 int dif;
146 unused(cur);
147 dif = (maxy - 1) - miny;
148 if ((max - 1) - *top < dif && max > dif)
149 {
150 *y = maxy;
151 *top = (max - 1) - dif;
152 }
153 }
154
setup_areabox_coordinates(int * currItem,int * curY,int * Top,int * y2,int * page,int y1,int real_y2,int itemCnt)155 static void setup_areabox_coordinates(int *currItem, int *curY,
156 int *Top, int *y2, int *page,
157 int y1, int real_y2, int itemCnt)
158 {
159
160 *y2=min(real_y2, itemCnt);
161 *page = *y2 - y1;
162
163 *curY = y1;
164
165 *Top = *currItem;
166
167 if (*currItem + y1 < y1)
168 {
169 *curY = y1 + *currItem;
170 *Top = 0;
171 }
172 else
173 {
174 if ((itemCnt - *currItem) <= (*y2 - y1))
175 {
176 (*Top) -= ((*y2 - y1 + 1) - (itemCnt - *Top));
177 *curY = y1 + (*currItem - *Top);
178 if (*Top < 0)
179 {
180 *Top = 0;
181 (*curY)--;
182 }
183 }
184 }
185 }
186
187
188 static int AreaBoxCurItem;
189
AreaBox(char ** Itms,int y1,int real_y2,int len,int def,WND * hPrev,WND * hWnd,int Sel,int Norm,int indent)190 static int AreaBox(char **Itms, int y1, int real_y2, int len, int def,
191 WND * hPrev, WND * hWnd, int Sel, int Norm, int indent)
192 {
193 EVT e;
194 char find[30];
195 int itemCnt, Stuff, done, curY, Msg, currItem, Top, page, i, y2;
196 int real_areano;
197
198 itemCnt = 0;
199 Stuff = 0;
200 for (i = 0; Itms[i] != NULL; i++)
201 {
202 itemCnt++;
203 }
204
205 currItem = def;
206
207 setup_areabox_coordinates(&currItem, &curY, &Top, &y2, &page,
208 y1, real_y2, itemCnt);
209
210 done = 0;
211
212 TTBeginOutput();
213 SelShowPage(Itms, y1, y2, len, Top, Norm, indent);
214 SelShowItem(Itms[currItem], curY, len, Sel, indent);
215 TTEndOutput();
216
217 TTClearQue(); /* clear input queue */
218
219 memset(find, '\0', sizeof find);
220 while (!done)
221 {
222 if (!*find)
223 {
224 WndCurr(hPrev);
225 WndClear(16, 0, maxx - 36, 0, cm[MN_NTXT]);
226 WndWriteStr(0, 0, cm[MN_NTXT], ">>Pick New Area:");
227 WndCurr(hWnd);
228 }
229
230 if (!Stuff)
231 {
232 Msg = MnuGetMsg(&e, hWnd->wid);
233 }
234 else
235 {
236 e.msgtype = WND_WM_CHAR;
237 Msg = Stuff;
238 Stuff = 0;
239 }
240
241 switch (e.msgtype)
242 {
243 case WND_WM_RESIZE:
244 maxx = term.NCol;
245 maxy = term.NRow;
246 AreaBoxCurItem = currItem;
247 return -2; /* leave the list so it can be rebuilt with
248 the proper window dimensions */
249
250 case WND_WM_MOUSE:
251 switch (Msg)
252 {
253 case RMOU_CLCK:
254 case MOU_RBTUP:
255 return -1;
256
257 case LMOU_RPT:
258 case MOU_LBTDN:
259 case LMOU_CLCK:
260 {
261 int x, y;
262 WndGetRel(e.x, e.y, &x, &y);
263 if (y >= y1 && y <= y2) /* in window */
264 {
265 Stuff = 0;
266 if (x >= 0 && x < len)
267 {
268 if (y == curY)
269 {
270 if (Msg == LMOU_CLCK || Msg == MOU_LBTUP)
271 {
272 if (group_getareano(currItem) >= 0)
273 return currItem;
274 }
275 else
276 {
277 continue;
278 }
279 }
280
281 SelShowItem(Itms[currItem], curY, len, Norm, indent);
282
283 if (y > curY)
284 {
285 currItem += y - curY;
286 }
287 else
288 {
289 currItem -= curY - y;
290 }
291
292 curY = y;
293 SelShowItem(Itms[currItem], curY, len, Sel, indent);
294
295 if (Msg == LMOU_CLCK || Msg == MOU_LBTUP)
296 {
297 if (group_getareano(currItem) >= 0)
298 return currItem;
299 }
300 }
301 }
302 else
303 {
304 if (Msg != LMOU_CLCK)
305 {
306 if (y < y1)
307 {
308 Stuff = Key_Up;
309 }
310 else
311 {
312 Stuff = Key_Dwn;
313 }
314 }
315 }
316 }
317 memset(find, '\0', sizeof find);
318 break;
319
320 default:
321 break;
322 }
323 break;
324
325 case WND_WM_CHAR:
326 switch (Msg)
327 {
328 case Key_Home:
329 if (!currItem)
330 {
331 break;
332 }
333 TTBeginOutput();
334 SelShowItem(Itms[currItem], curY, len, Norm, indent);
335 currItem = 0;
336 Top = 0;
337 curY = y1;
338 SelShowPage(Itms, y1, y2, len, Top, Norm, indent);
339 SelShowItem(Itms[currItem], curY, len, Sel, indent);
340 TTEndOutput();
341 memset(find, '\0', sizeof find);
342 break;
343
344 case Key_A_H:
345 case Key_F1:
346 if (ST->helpfile != NULL)
347 {
348 DoHelp(3);
349 }
350 break;
351
352 case Key_End:
353 if (currItem == itemCnt - 1)
354 {
355 break;
356 }
357 TTBeginOutput();
358 SelShowItem(Itms[currItem], curY, len, Norm, indent);
359 currItem = itemCnt - 1;
360 while (currItem && currItem >= (itemCnt - page))
361 {
362 currItem--;
363 }
364 Top = currItem;
365 currItem = itemCnt - 1;
366 curY = currItem - Top + y1;
367 CalcDef(itemCnt, currItem, &Top, y1, y2, &curY);
368 SelShowPage(Itms, y1, y2, len, Top, Norm, indent);
369 SelShowItem(Itms[currItem], curY, len, Sel, indent);
370 TTEndOutput();
371 memset(find, '\0', sizeof find);
372 break;
373
374 case Key_Dwn:
375 if (currItem == itemCnt - 1)
376 {
377 break;
378 }
379 SelShowItem(Itms[currItem], curY, len, Norm, indent);
380 currItem++;
381 if (curY == y2)
382 {
383 WndScroll(1, y1, len, y2, 1);
384 Top++;
385 }
386 else
387 {
388 curY++;
389 }
390 SelShowItem(Itms[currItem], curY, len, Sel, indent);
391 memset(find, '\0', sizeof find);
392 break;
393
394 case Key_Up:
395 if (!currItem)
396 {
397 break;
398 }
399 SelShowItem(Itms[currItem], curY, len, Norm, indent);
400 currItem--;
401 if (curY == y1)
402 {
403 WndScroll(1, y1, len, y2, 0);
404 if (Top)
405 {
406 Top--;
407 }
408 }
409 else
410 {
411 curY--;
412 }
413 SelShowItem(Itms[currItem], curY, len, Sel, indent);
414 memset(find, '\0', sizeof find);
415 break;
416
417 case Key_PgUp:
418 if (!currItem)
419 {
420 break;
421 }
422 TTBeginOutput();
423 SelShowItem(Itms[currItem], curY, len, Norm, indent);
424 if ((currItem -= page) < 0)
425 {
426 currItem = 0;
427 }
428 Top = currItem;
429 curY = y1;
430 SelShowPage(Itms, y1, y2, len, Top, Norm, indent);
431 SelShowItem(Itms[currItem], curY, len, Sel, indent);
432 TTEndOutput();
433 memset(find, '\0', sizeof find);
434 break;
435
436 case Key_PgDn:
437 if (currItem == itemCnt - 1)
438 {
439 break;
440 }
441 TTBeginOutput();
442 SelShowItem(Itms[currItem], curY, len, Norm, indent);
443 Top = currItem;
444
445 if ((currItem += page) > itemCnt - 1)
446 {
447 currItem = itemCnt - 1;
448 if (currItem > page)
449 {
450 Top = currItem - page;
451 }
452 else
453 {
454 Top = 0;
455 }
456 }
457
458 curY = currItem - Top + y1;
459 CalcDef(itemCnt, currItem, &Top, y1, y2, &curY);
460 SelShowPage(Itms, y1, y2, len, Top, Norm, indent);
461 SelShowItem(Itms[currItem], curY, len, Sel, indent);
462 TTEndOutput();
463 memset(find, '\0', sizeof find);
464 break;
465
466 case Key_Ent:
467 case Key_Rgt:
468 if (group_getareano(currItem) >= 0)
469 {
470 size_t i;
471
472 i = (size_t) (((char *)(strchr(Itms[currItem] + 1, ' '))) - Itms[currItem]);
473 i--;
474 if (i > 28)
475 {
476 i = 28;
477 }
478 strncpy(find, Itms[currItem] + 1, i);
479 *(find + i) = '\0';
480 strupr(find);
481 WndCurr(hPrev);
482 WndWriteStr(17, 0, cm[MN_NTXT], find);
483 WndCurr(hWnd);
484 return currItem;
485 }
486 break;
487
488 case Key_Esc:
489 if (SW->confirmations)
490 {
491 if (confirm("Exit " PROG "?"))
492 {
493 return -1;
494 }
495 }
496 else
497 {
498 return -1;
499 }
500 memset(find, '\0', sizeof find);
501 break;
502
503 case Key_A_X:
504 return -1;
505
506 case '*':
507 case '#':
508 case Key_A_S:
509 case Key_A_T:
510 arealist_area_scan(Msg == '*' || Msg == Key_A_T);
511
512 for (i = 0; i < SW->groupareas; i++)
513 {
514 xfree(alist[i]);
515 }
516 xfree(alist);
517 BuildList(&alist);
518 Itms = alist;
519 TTBeginOutput();
520 SelShowPage(Itms, y1, y2, len, Top, Norm, indent);
521 SelShowItem(Itms[currItem], curY, len, Sel, indent);
522 TTEndOutput();
523 memset(find, '\0', sizeof find);
524 break;
525
526 case Key_A_1:
527 case Key_A_2:
528 case Key_A_3:
529 case Key_A_4:
530 case Key_A_5:
531 case Key_A_6:
532 case Key_A_7:
533 case Key_A_8:
534 case Key_A_9:
535 case Key_A_0:
536 case Key_A_G:
537 case Key_C_G:
538
539 real_areano = group_getareano(currItem);
540 i = 1;
541
542 switch(Msg)
543 {
544 case Key_C_G:
545 i = sel_group();
546 break;
547 case Key_A_1:
548 group_set_group(1);
549 break;
550 case Key_A_2:
551 group_set_group(2);
552 break;
553 case Key_A_3:
554 group_set_group(3);
555 break;
556 case Key_A_4:
557 group_set_group(4);
558 break;
559 case Key_A_5:
560 group_set_group(5);
561 break;
562 case Key_A_6:
563 group_set_group(6);
564 break;
565 case Key_A_7:
566 group_set_group(7);
567 break;
568 case Key_A_8:
569 group_set_group(8);
570 break;
571 case Key_A_9:
572 group_set_group(9);
573 break;
574 case Key_A_0:
575 group_set_group(0);
576 break;
577 }
578
579 if (i)
580 {
581 /* group has changed ... we have quite some work! */
582
583 /* find the new position of the currently selected group */
584 currItem = group_getareano(0) < 0 ? 1 : 0;
585
586 for (i = 0; i < SW->groupareas; i++)
587 {
588 if (group_getareano(i) == real_areano)
589 {
590 currItem = i;
591 break;
592 }
593 }
594
595 /* delete the old area list */
596
597 for (i = 0; alist[i] != NULL; i++)
598 {
599 xfree(alist[i]);
600 }
601 xfree(alist);
602
603 /* Build a new area list */
604 BuildList(&alist);
605 Itms = alist;
606 itemCnt = 0;
607 for (i = 0; Itms[i] != NULL; i++)
608 {
609 itemCnt++;
610 }
611
612 /* Do coordinate arithmetics */
613 y2 = min(maxy - 4, SW->groupareas);
614 setup_areabox_coordinates(&currItem, &curY, &Top,
615 &y2, &page,
616 y1, real_y2, itemCnt);
617
618 /* Redraw everything */
619 TTBeginOutput();
620 SelShowPage(Itms, y1, y2, len, Top, Norm, indent);
621 SelShowItem(Itms[currItem], curY, len, Sel, indent);
622 if (y2 < real_y2)
623 {
624 WndClear(1, y2 + 1, len, real_y2, Norm);
625 }
626 TTEndOutput();
627 memset(find, '\0', sizeof find);
628 }
629 break;
630 default:
631 if (Msg > 32 && Msg < 127)
632 {
633 if (strlen(find) >= 28)
634 {
635 break;
636 }
637 *(find + strlen(find)) = (char)toupper((char)Msg);
638 WndCurr(hPrev);
639 WndWriteStr(17, 0, cm[MN_NTXT], find);
640 WndCurr(hWnd);
641 i = currItem;
642
643 while (i < itemCnt)
644 {
645 if (SW->arealistexactmatch)
646 {
647 if (stristr(Itms[i] + 1, find) == Itms[i] + 1)
648 {
649 break;
650 }
651 }
652 else
653 {
654 if (stristr(Itms[i] + 1, find) != NULL)
655 {
656 break;
657 }
658 }
659 i++;
660 }
661 if (i == itemCnt)
662 {
663 for (i = 0; i < currItem; i++)
664 {
665 if (SW->arealistexactmatch)
666 {
667 if (stristr(Itms[i] + 1, find) == Itms[i] + 1)
668 {
669 break;
670 }
671 }
672 else
673 {
674 if (stristr(Itms[i] + 1, find) != NULL)
675 {
676 break;
677 }
678 }
679 }
680 if (i == currItem)
681 {
682 i = itemCnt;
683 }
684 }
685 if ((i != currItem) && (i != itemCnt))
686 {
687 SelShowItem(Itms[currItem], curY, len, Norm, indent);
688 currItem = i;
689 curY = y1;
690 Top = currItem;
691
692 if ((itemCnt - 1) - currItem < y2 - y1)
693 {
694 if (currItem > y2 - y1)
695 {
696 curY = y2;
697 Top = currItem - (y2 - y1);
698 }
699 else
700 {
701 curY = currItem + y1;
702 Top = 0;
703 }
704 }
705 SelShowPage(Itms, y1, y2, len, Top, Norm, indent);
706 SelShowItem(Itms[currItem], curY, len, Sel, indent);
707 }
708 }
709 else if (Msg == '\b' && *find)
710 {
711 *(find + strlen(find) - 1) = '\0';
712 WndCurr(hPrev);
713 WndClear(17 + strlen(find), 0, maxx - 36, 0, cm[CM_NINF]);
714 WndCurr(hWnd);
715 }
716 else
717 {
718 memset(find, '\0', sizeof find);
719 }
720 break;
721
722 }
723 break;
724 }
725 }
726 return -1;
727 }
728
mainArea(void)729 int mainArea(void)
730 {
731 WND *hCurr, *hWnd;
732 int ret = -1, wid, dep, i;
733
734 do
735 {
736 msgederr = 0;
737 wid = maxx - 1;
738 dep = maxy - 2;
739
740 TTBeginOutput();
741 WndClearLine(0, cm[MN_NTXT]);
742 WndClearLine(maxy - 1, cm[MN_NTXT]);
743 hCurr = WndTop();
744 hWnd = WndOpen(0, 1, wid, dep, NBDR | NOSAVE, 0, cm[MN_BTXT]);
745 WndBox(0, 0, maxx - 1, maxy - 3, cm[MN_BTXT], SBDR);
746
747 WndWriteStr(3, 0, cm[LS_TTXT], "EchoID");
748 WndWriteStr(maxx - 19, 0, cm[LS_TTXT], "Msgs");
749 WndWriteStr(maxx - 12, 0, cm[LS_TTXT], "New");
750 WndWriteStr(maxx - 7, 0, cm[LS_TTXT], "Last");
751 TTEndOutput();
752
753
754 BuildList(&alist);
755
756 ret = AreaBox(alist, 1, dep - 2, wid - 1,
757 (ret == -2) ? AreaBoxCurItem : SW->grouparea,
758 hCurr, hWnd, cm[MN_STXT], cm[MN_NTXT], 1);
759
760 for (i = 0; alist[i] != NULL; i++)
761 {
762 xfree(alist[i]);
763 }
764
765 xfree(alist);
766
767 if (ret == -1)
768 {
769 msgederr = 1;
770 }
771 if (ret == -2)
772 {
773 /* returncode -2 means that the list should be restarted;
774 it did only exit because it had to be rebuild because
775 of a terminal window resize operation */
776 window_resized = 1;
777 }
778
779 WndClose(hWnd);
780 WndCurr(hCurr);
781
782 /* returncode -3 means rebuild because group has changed */
783
784 } while (ret == -2 || ret == -3);
785
786 return ret;
787 }
788
selectarea(char * topMsg,int def)789 int selectarea(char *topMsg, int def)
790 {
791 WND *hCurr, *hWnd;
792 int ret, wid, dep, i;
793
794 msgederr = 0;
795 wid = maxx - 1;
796 dep = maxy - 2;
797
798 WndClearLine(0, cm[MN_NTXT]);
799 WndClearLine(maxy - 1, cm[MN_NTXT]);
800 hCurr = WndTop();
801 hWnd = WndOpen(0, 1, wid, dep, NBDR, 0, cm[MN_BTXT]);
802 WndBox(0, 0, maxx - 1, maxy - 3, cm[MN_BTXT], SBDR);
803 WndCurr(hCurr);
804 WndClear(0, 0, maxx - 36, 0, cm[CM_NINF]);
805 WndCurr(hWnd);
806 WndWriteStr(3, 0, cm[LS_TTXT], "EchoID");
807 WndWriteStr(maxx - 21, 0, cm[LS_TTXT], "Msgs");
808 WndWriteStr(maxx - 13, 0, cm[LS_TTXT], "New");
809 WndWriteStr(maxx - 7, 0, cm[LS_TTXT], "Last");
810
811 BuildList(&alist2);
812
813 do
814 {
815 ret = SelBox(alist2, 1, dep - 2, wid - 1, def, hCurr, hWnd,
816 cm[MN_STXT], cm[MN_NTXT], SELBOX_REPLYOTH, topMsg);
817 } while (ret != -1 && group_getareano(ret) < 0);
818
819 /* don't allow group separators
820 as selection */
821
822 for (i = 0; i < SW->groupareas; i++)
823 {
824 xfree(alist2[i]);
825 }
826
827 xfree(alist2);
828
829 if (ret < 0)
830 {
831 msgederr = 1;
832 }
833
834 WndClose(hWnd);
835 WndCurr(hCurr);
836
837 if (ret < 0)
838 {
839 return def;
840 }
841
842 return ret;
843 }
844