1 /*
2 * LIST.C
3 *
4 * Written on 10-Jul-94 by John Dennis and released to the public domain.
5 *
6 * Lists the messages in the messagebase.
7 */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <time.h>
12 #include "addr.h"
13 #include "nedit.h"
14 #include "msged.h"
15 #include "memextra.h"
16 #include "specch.h"
17 #include "winsys.h"
18 #include "menu.h"
19 #include "main.h"
20 #include "strextra.h"
21 #include "keys.h"
22 #include "dosmisc.h"
23 #include "help.h"
24 #include "maintmsg.h"
25 #include "nshow.h"
26 #include "dlist.h"
27 #include "list.h"
28 #include "screen.h"
29 #include "charset.h"
30 #include "config.h"
31 #include "group.h"
32
33 static int long_subj;
34 static int display_address = 1;
35
36 static void getheader(unsigned long n, MLHEAD * h, int check_sel);
37 static void showit(MLHEAD * h, int y, int sel);
38
39 static DLIST *ulist;
40
41 static char *forgroupmenu[] =
42 {
43 "Move Message(s)",
44 "Copy Message(s)",
45 "Redirect Message(s)",
46 "Forward Message(s)",
47 NULL
48 };
49
50 /*
51 * Checks to see if the message has been selected.
52 */
53
ulistFindUid(unsigned long uid)54 static int ulistFindUid(unsigned long uid)
55 {
56 DLISTNODE *p_node;
57 if (ulist == NULL)
58 {
59 return 0;
60 }
61 p_node = dlistTravFirst(ulist);
62 while (p_node != NULL)
63 {
64 unsigned long *puid;
65 puid = dlistGetElement(p_node);
66 if (*puid == uid)
67 {
68 return 1;
69 }
70 p_node = dlistTravNext(p_node);
71 }
72 return 0;
73 }
74
75 /*
76 * Removes a selection from the list.
77 */
78
ulistDropUid(unsigned long uid)79 static void ulistDropUid(unsigned long uid)
80 {
81 DLISTNODE *p_node;
82 if (ulist == NULL)
83 {
84 return;
85 }
86 p_node = dlistTravFirst(ulist);
87 while (p_node != NULL)
88 {
89 unsigned long *puid;
90 puid = dlistGetElement(p_node);
91 if (*puid == uid)
92 {
93 dlistDropNode(ulist, p_node);
94 }
95 p_node = dlistTravNext(p_node);
96 }
97 }
98
99 /*
100 * Adds a new message to the list of selected messages.
101 */
102
ulistAddUid(unsigned long uid)103 static int ulistAddUid(unsigned long uid)
104 {
105 unsigned long *puid;
106 DLISTNODE *p_node;
107
108 if (ulist == NULL)
109 {
110 ulist = dlistInit();
111 if (ulist == NULL)
112 {
113 return 0;
114 }
115 }
116 puid = xmalloc(sizeof *puid);
117 if (puid == NULL)
118 {
119 return 0;
120 }
121 p_node = dlistCreateNode(puid);
122 if (p_node == NULL)
123 {
124 xfree(puid);
125 return 0;
126 }
127 *puid = uid;
128 dlistAddNode(ulist, p_node);
129 return 1;
130 }
131
132 /*
133 * Frees the list of msgnumbers.
134 */
135
ulistTerm(void)136 static void ulistTerm(void)
137 {
138 DLISTNODE *p_node;
139 if (ulist == NULL)
140 {
141 return;
142 }
143 p_node = dlistTravFirst(ulist);
144 while (p_node != NULL)
145 {
146 unsigned long *puid;
147 puid = dlistGetElement(p_node);
148 xfree(puid);
149 p_node = dlistTravNext(p_node);
150 }
151 dlistTerm(ulist);
152 ulist = NULL;
153 }
154
155 /*
156 * Re-displays the entire screen.
157 */
158
update(MLHEAD * headers,unsigned long i,int y)159 static void update(MLHEAD * headers, unsigned long i, int y)
160 {
161 TTBeginOutput();
162 while (i <= CurArea.messages && y <= maxy - 4)
163 {
164 getheader(i, &headers[y - 1], 1);
165 showit(&headers[y - 1], y, 0);
166 i++;
167 y++;
168 }
169 if (y <= (maxy - 4))
170 {
171 WndClear(1, y, maxx - 2, maxy - 4, cm[LS_NTXT]);
172 }
173 TTEndOutput();
174 }
175
176 /*
177 * Shows a header on the screen.
178 */
179
showit(MLHEAD * h,int y,int sel)180 static void showit(MLHEAD * h, int y, int sel)
181 {
182 unsigned long msgn;
183 char line[384];
184 char msgnbuf[9];
185 int l;
186 char *cp;
187
188 TTBeginOutput();
189
190 msgn = SW->showrealmsgn ? h->umsgid : h->msgnum;
191 sprintf(msgnbuf, "%5ld %c", msgn, h->sel ? SC14 : ' ');
192 l = strlen(msgnbuf) - 1;
193
194 if (long_subj)
195 {
196 sprintf(line, "%c%s%-15.15s %-70s", h->times_read > 0 ? '*' : ' ',
197 msgnbuf, h->fr_name, h->subj);
198 }
199 else
200 {
201 sprintf(line, "%c%s%-15.15s %-15.15s %-70s",
202 h->times_read > 0 ? '*' : ' ', msgnbuf, h->fr_name,
203 h->to_name, h->subj);
204 }
205
206 /* caveat the broken subject line!!! */
207 for (cp=line; *cp; cp++)
208 if ((*cp >= 0 && *cp < ' ') && (*cp != SC14))
209 *cp = ' ';
210
211 if (sel)
212 {
213 if (l>0)
214 WndPutsn(1, y, l, cm[LS_STXT], line);
215 if (l>1)
216 WndPutsn(1+l, y, 1, cm[LS_STXT] | F_ALTERNATE, line + l);
217 if (l + 1 < maxx - 2)
218 WndPutsn(1+l+1, y, (maxx - 2) - (l + 1), cm[LS_STXT],
219 line+l+1);
220 }
221 else if (stricmp(h->to_name, ST->username) == 0 ||
222 stricmp(h->fr_name, ST->username) == 0)
223 {
224 if (l > 0)
225 WndPutsn(1, y, l, cm[LS_ITXT], line);
226 if (l>1)
227 WndPutsn(1+l, y, 1, cm[LS_ITXT] | F_ALTERNATE, line + l);
228 if (l + 1 < maxx - 2)
229 WndPutsn(l + 2, y, (maxx - 2) - (l + 1), cm[LS_ITXT],
230 line + l + 1);
231 }
232 else
233 {
234 if (l > 0)
235 WndPutsn(1, y, l, cm[LS_NTXT], line);
236 if (l>1)
237 WndPutsn(1+l, y, 1, cm[LS_NTXT] | F_ALTERNATE, line + l);
238 if (l + 1 < maxx - 2)
239 WndPutsn(l + 2, y, (maxx - 2) - (l + 1), cm[LS_NTXT],
240 line + l + 1);
241 }
242
243 TTEndOutput();
244
245 }
246
247 /*
248 * Gets a header from the msgbase.
249 */
250
getheader(unsigned long n,MLHEAD * h,int check_sel)251 static void getheader(unsigned long n, MLHEAD * h, int check_sel)
252 {
253 msg *x;
254 char *text;
255 char *charset; int level;
256 char *tokens[5];
257 LOOKUPTABLE *ltable = NULL;
258
259 /* Read the message header */
260
261 memset(h, 0, sizeof *h);
262 x = MsgReadHeader((unsigned int)n, RD_ALL);
263 if (x == NULL)
264 {
265 return;
266 }
267
268
269 /* Search the CHRS kludge */
270
271 if (ST->input_charset != NULL)
272 {
273 charset = xstrdup(ST->input_charset);
274 level = 2;
275 }
276 else
277 {
278 charset = xstrdup("ASCII");
279 level = 2; /* ASCII 2 is nonsense, but get_readtable will return
280 the correct table */
281 }
282
283 while ((text = MsgReadText((unsigned int)n)) != NULL)
284 {
285 if (*text == '\01')
286 {
287 if (strncmp(text + 1, "CHRS:", 5) == 0)
288 {
289 memset(tokens, 0, sizeof(tokens));
290 parse_tokens(text + 7, tokens, 2);
291 if (tokens[1] != NULL)
292 {
293
294 if ( have_readtable(tokens[0], atoi(tokens[1])) ||
295 ST->input_charset == NULL)
296 {
297 release(charset);
298 charset = xstrdup(tokens[0]);
299 level = atoi(tokens[1]);
300 }
301 }
302 }
303 release(text);
304 }
305 else
306 {
307 /* Kludges are over! */
308 release(text);
309 /* break; this does not work, we have to read the whole msg */
310 }
311 }
312
313 MsgClose();
314
315 ltable = get_readtable(charset, level);
316 release(charset);
317
318 /* copy the header info */
319
320 h->msgnum = n;
321 h->umsgid = x->msgnum;
322 h->to_net = x->to.net;
323 h->to_node = x->to.node;
324 h->fr_net = x->from.net;
325 h->fr_node = x->from.node;
326 h->times_read = x->times_read;
327 if (check_sel)
328 {
329 h->sel = ulistFindUid(x->msgnum);
330 }
331 else
332 {
333 h->sel = 0;
334 }
335
336 text = translate_text(x->subj, ltable);
337 strncpy(h->subj, text, 72);
338 h->subj[72] = '\0';
339 release(text);
340
341 text = translate_text(x->isto, ltable);
342 strncpy(h->to_name, text, 36);
343 h->to_name[36] = '\0';
344 release(text);
345
346 text = translate_text(x->isfrom, ltable);
347 strncpy(h->fr_name, text, 36);
348 h->fr_name[36] = '\0';
349 release(text);
350
351 dispose(x);
352 }
353
354 /*
355 * Deletes the selected messages, or the current one if none.
356 */
357
DeleteMsgs(unsigned long * CurrMsgn)358 static void DeleteMsgs(unsigned long *CurrMsgn)
359 {
360 if (ulist == NULL || dlistIsEmpty(ulist))
361 {
362 /*
363 if (!confirm("Erase message?"))
364 {
365 return;
366 }
367 */
368 CurArea.current = *CurrMsgn;
369 deletemsg();
370 }
371 else
372 {
373 int confirm_temp;
374 DLISTNODE *p_node;
375 unsigned long msgn, oldmsgn;
376 char messagetxt[80];
377
378 if (!confirm("Erase all selected messages?"))
379 {
380 return;
381 }
382 if (!OpenMsgWnd(50, 6, "Deleting Messages", NULL, 0, 0))
383 {
384 return;
385 }
386 SendMsgWnd("Press Esc to interrupt", 2);
387
388 confirm_temp = SW->confirmations;
389 SW->confirmations = 0;
390
391 oldmsgn = 0L;
392
393 p_node = dlistTravFirst(ulist);
394 while (p_node != NULL)
395 {
396 unsigned long *puid;
397
398 if (KeyHit() && GetKey() == Key_Esc)
399 {
400 p_node = NULL;
401 break;
402 }
403
404 puid = dlistGetElement(p_node);
405 msgn = UidToMsgn(*puid);
406
407 sprintf(messagetxt, "Working on message #%lu",
408 SW->showrealmsgn ? *puid: msgn);
409 SendMsgWnd(messagetxt, 1);
410
411 if (oldmsgn == 0L)
412 {
413 oldmsgn = msgn - 1;
414 }
415 if (msgn != 0L)
416 {
417 CurArea.current = msgn;
418 deletemsg();
419 }
420 p_node = dlistTravNext(p_node);
421 }
422
423 if (oldmsgn == 0L)
424 {
425 oldmsgn = *CurrMsgn;
426 }
427 *CurrMsgn = oldmsgn;
428 CurArea.current = oldmsgn;
429 SW->confirmations = confirm_temp;
430
431 CloseMsgWnd();
432 }
433 }
434
435 /*
436 * Forwards, redirects, moves or copies a group of messages.
437 */
438
movemsgs(int rc,int to_area)439 static int movemsgs(int rc, int to_area)
440 {
441 int clear = (to_area == -1);
442
443 if (rc == 2 || rc == 3)
444 {
445 DrawHeader();
446 }
447 switch (rc)
448 {
449 case 0: /* Move */
450 to_area = move_msg(to_area);
451 break;
452
453 case 1: /* Copy */
454 to_area = copy_msg(to_area);
455 break;
456
457 case 2: /* Redirect */
458 to_area = redirect_msg(to_area);
459 break;
460
461 case 3: /* Forward */
462 to_area = forward_msg(to_area);
463 break;
464
465 case -1: /* Escape */
466 return -1;
467 }
468
469 if (clear)
470 {
471 TTBeginOutput();
472 WndClearLine(0, cm[MN_NTXT]);
473 WndWriteStr(2, 0, cm[LS_TTXT], CurArea.description);
474
475 if (rc == 2 || rc == 3)
476 {
477 int i;
478 for (i = 1; i <= 5; i++)
479 {
480 WndClearLine(i, cm[MN_NTXT]);
481 }
482 WndBox(0, 1, maxx - 1, maxy - 2, cm[LS_BTXT], SBDR);
483 }
484 TTEndOutput();
485 }
486 return to_area;
487 }
488
489 /*
490 * Moves, copies, redirects or forwards the selected messages, or the
491 * current one if none.
492 */
493
MoveMsgs(unsigned long * CurrMsgn)494 static void MoveMsgs(unsigned long *CurrMsgn)
495 {
496 int rc;
497 WND *hCurr;
498
499 rc = DoMenu((maxx / 2) - 10, (maxy / 2) - 1, (maxx / 2) + 9, (maxy / 2) + 2,
500 forgroupmenu, 0, SELBOX_MOVEMSG, "");
501
502 if (ulist == NULL || dlistIsEmpty(ulist))
503 {
504 CurArea.current = *CurrMsgn;
505 hCurr = WndTop();
506 WndCurr(hMnScr);
507 groupmove = 1;
508 movemsgs(rc, -1);
509 groupmove = 0;
510 WndCurr(hCurr);
511 }
512 else
513 {
514 DLISTNODE *p_node, *p_old_node;
515 unsigned long msgn, oldmsgn;
516 int to_area = -1;
517 char messagetxt[80];
518 int ogroup;
519
520 ogroup = group_set_group(0); /* allow copies etc. to everywhere */
521
522 oldmsgn = 0L;
523
524 switch(rc)
525 {
526 case 0:
527 strcpy(messagetxt," Moving");
528 break;
529
530 case 1:
531 strcpy(messagetxt," Copying");
532 break;
533
534 case 2:
535 strcpy(messagetxt," Redirecting");
536 break;
537
538 case 3:
539 strcpy(messagetxt," Forwarding");
540 break;
541
542 default:
543 strcpy(messagetxt," <internal error>");
544 break;
545 }
546 strcat(messagetxt, " Messages ");
547
548 if (!OpenMsgWnd(50, 6, messagetxt, NULL, 0, 0))
549 {
550 return;
551 }
552 SendMsgWnd("Press Esc to stop", 2);
553
554 p_node = dlistTravFirst(ulist);
555 while (p_node != NULL)
556 {
557 unsigned long *puid;
558
559 if (KeyHit() && GetKey() == Key_Esc)
560 {
561 p_node = NULL;
562 break;
563 }
564
565 puid = dlistGetElement(p_node);
566 msgn = UidToMsgn(*puid);
567
568 sprintf(messagetxt, "Working on message #%lu",
569 SW->showrealmsgn ? *puid: msgn);
570 SendMsgWnd(messagetxt, 1);
571
572 if (oldmsgn == 0L)
573 {
574 oldmsgn = msgn - 1L;
575 }
576 p_old_node = p_node;
577 if (msgn != 0L)
578 {
579 CurArea.current = msgn;
580 hCurr = WndTop();
581 WndCurr(hMnScr);
582 groupmove = 1;
583 to_area = movemsgs(rc, to_area);
584 groupmove = 0;
585 WndCurr(hCurr);
586 }
587 p_node = dlistTravNext(p_node);
588 dlistDropNode(ulist, p_old_node);
589
590 if (to_area == -1) /* an escape or an error occured */
591 {
592 p_node = NULL;
593 }
594 }
595 if (oldmsgn == 0L)
596 {
597 oldmsgn = *CurrMsgn;
598 }
599 *CurrMsgn = oldmsgn;
600 CurArea.current = oldmsgn;
601
602 CloseMsgWnd();
603
604 group_set_group(ogroup);
605 }
606 }
607
608 /*
609 * Puts a list of messages up in a window on the screen. Allows for
610 * some basic management of those messages.
611 */
612
do_list(void)613 int do_list(void)
614 {
615 EVT event;
616 WND *hWnd, *hCurr;
617 static int in_list = 0; /* stop recursion */
618 MLHEAD *headers; /* headers */
619 int done = 0; /* finished ? */
620 int down = 0;
621 int ForceEvt = 0; /* forced/piped keypress */
622 int Msg; /* message */
623 int lbutton = 0;
624 unsigned long i, a, j;
625 int y;
626
627 begin:
628
629 if (in_list || !CurArea.status) /* stop recursion */
630 {
631 return 0;
632 }
633 else
634 {
635 in_list = 1;
636 }
637
638 /* Open the window and draw the screen and allocate the memory. */
639
640 TTBeginOutput();
641 WndClearLine(0, cm[MN_NTXT]);
642 WndClearLine(maxy - 1, cm[MN_NTXT]);
643 WndWriteStr(2, 0, cm[LS_TTXT], CurArea.description);
644 hCurr = WndTop();
645 hWnd = WndOpen(0, 1, maxx - 1, maxy - 2, NBDR | NOSAVE, 0, cm[LS_NTXT]);
646 headers = xcalloc(maxy, sizeof(MLHEAD));
647
648 WndBox(0, 0, maxx - 1, maxy - 3, cm[LS_BTXT], SBDR);
649
650 message = KillMsg(message);
651
652 if (done == 2)
653 {
654 done = 0; /* this an subsequent entry into the list which
655 results from a window resize operation. */
656 }
657 else
658 {
659 a = CurArea.current;
660 /* this is the first entry - set the pointer to
661 the current message in this area */
662 }
663 y = 1;
664 update(headers, a, y);
665 TTEndOutput();
666
667
668 while (!done)
669 {
670 TTBeginOutput();
671 #if defined(MSDOS) && !defined(__FLAT__)
672 /* shows memory if compiled under dos */
673
674 if (SW->statbar)
675 {
676 char line[255];
677 sprintf(line, "%c %3ldK ", SC7, (long)(corerem() / 1024));
678 WndCurr(WndTop());
679 WndPutsn(maxx - 7, maxy - 1, 1, cm[CM_ITXT] | F_ALTERNATE,
680 line + 1);
681 WndPutsn(maxx - 6, maxy - 1, 6, cm[CM_ITXT], line + 1);
682 WndCurr(hWnd);
683 }
684 #endif
685
686 WndWriteStr(3, 0, cm[LS_TTXT], "Msg");
687 WndWriteStr(9, 0, cm[LS_TTXT], "From");
688 if (long_subj)
689 {
690 char tmp[8];
691
692 WndWriteStr(25, 0, cm[LS_TTXT], "Subject");
693
694 memset(tmp, SC8, 7);
695 *(tmp + 7) = '\0';
696 WndWriteStr(41, 0, cm[LS_BTXT] | F_ALTERNATE, tmp);
697 }
698 else
699 {
700 char tmp[8];
701
702 memset(tmp, SC8, 7);
703 *(tmp + 7) = '\0';
704 WndWriteStr(25, 0, cm[LS_BTXT] | F_ALTERNATE, tmp);
705 WndWriteStr(25, 0, cm[LS_TTXT], "To");
706 WndWriteStr(41, 0, cm[LS_TTXT], "Subject");
707 }
708 showit(&headers[y - 1], y, 1);
709 TTEndOutput();
710
711 if (down)
712 {
713 /* If a selection has occured, then force cursor down. */
714
715 Msg = Key_Dwn;
716 event.msg = Msg;
717 event.msgtype = WND_WM_CHAR;
718 down = 0;
719 }
720 else if (ForceEvt)
721 {
722 /*
723 * These events are from the mouse (no point in
724 * duplicating code).
725 */
726
727 Msg = ForceEvt;
728 event.msg = Msg;
729 event.msgtype = WND_WM_CHAR;
730 ForceEvt = 0;
731 }
732 else
733 {
734 Msg = MnuGetMsg(&event, hWnd->wid);
735 }
736
737 switch (event.msgtype)
738 {
739 case WND_WM_RESIZE:
740 /* the window has been resized. we have to exit and
741 rebuild the list. */
742 maxx = term.NCol;
743 maxy = term.NRow;
744 done = 2;
745 break;
746
747 case WND_WM_MOUSE:
748 switch (Msg)
749 {
750 case LMOU_RPT:
751 {
752 int y1 = event.y;
753
754 if (y1 > maxy - 4 && lbutton)
755 {
756 ForceEvt = Key_Dwn;
757 }
758 else if (y1 < 1 && lbutton)
759 {
760 ForceEvt = Key_Up;
761 }
762 }
763 break;
764
765 case LMOU_CLCK:
766 case MOU_LBTDN:
767 case MOU_LBTUP:
768 case MOUSE_EVT:
769 {
770 int y1 = event.y - 1, ok = 0;
771
772 if (Msg == MOU_LBTDN)
773 {
774 lbutton = 1;
775 }
776 else if (Msg == MOU_LBTUP)
777 {
778 lbutton = 0;
779 }
780
781 if (y1 > maxy - 4)
782 {
783 if (Msg == MOU_LBTDN && lbutton)
784 {
785 ForceEvt = Key_Dwn;
786 }
787 }
788 else
789 {
790 if (y1 < 1)
791 {
792 if (Msg == MOU_LBTDN && lbutton)
793 {
794 ForceEvt = Key_Up;
795 }
796 }
797 else
798 {
799 /* The event occured on the list. */
800
801 if (y == y1 && (Msg == MOU_LBTUP || Msg == LMOU_CLCK))
802 {
803 ForceEvt = Key_Ent;
804 continue;
805 }
806 showit(&headers[y - 1], y, 0);
807 if (y > y1)
808 {
809 if (a - y - y1 >= 1)
810 {
811 a -= y - y1;
812 ok = TRUE;
813 }
814 }
815 else
816 {
817 if (a + y1 - y <= CurArea.messages)
818 {
819 a += y1 - y;
820 ok = TRUE;
821 }
822 }
823
824 if (ok == TRUE)
825 {
826 y = y1;
827 if (Msg == MOU_LBTUP || Msg == LMOU_CLCK)
828 {
829 ForceEvt = Key_Ent;
830 }
831 }
832 }
833 }
834 }
835 break;
836
837 default:
838 break;
839 }
840 break;
841
842 case WND_WM_CHAR:
843 switch (Msg)
844 {
845 case Key_PgDn:
846 i = maxy - 4 - y;
847 while (i > 0 && a < CurArea.messages)
848 {
849 i--;
850 a++;
851 }
852 y = 1;
853 update(headers, a, y);
854 break;
855
856 case Key_PgUp:
857 if (y == 1)
858 {
859 i = maxy - 5;
860 }
861 else
862 {
863 i = y - 1;
864 }
865 while (i > 0 && a > 1)
866 {
867 i--;
868 a--;
869 }
870 y = 1;
871 update(headers, a, y);
872 break;
873
874 case Key_Up:
875 if (a > 1)
876 {
877 showit(&headers[y - 1], y, 0);
878 a--;
879 y--;
880
881 if (y < 1)
882 {
883 y = 1;
884 WndScroll(1, 1, maxx - 2, maxy - 4, 0);
885 if (SW->statbar)
886 {
887 memmove(headers + 1, headers,
888 sizeof(MLHEAD) * (maxy - 2));
889 }
890 else
891 {
892 memmove(headers + 1, headers,
893 sizeof(MLHEAD) * (maxy - 1));
894 }
895 getheader(a, &headers[0], 1);
896 }
897 }
898 break;
899
900 case Key_Dwn:
901 if (a < CurArea.messages)
902 {
903 showit(&headers[y - 1], y, 0);
904 a++;
905 y++;
906
907 if (y > maxy - 4)
908 {
909 y = maxy - 4;
910 WndScroll(1, 1, maxx - 2, y, 1);
911 if (SW->statbar)
912 {
913 memmove(headers, headers + 1,
914 sizeof(MLHEAD) * (maxy - 2));
915 }
916 else
917 {
918 memmove(headers, headers + 1,
919 sizeof(MLHEAD) * (maxy - 1));
920 }
921 getheader(a, &headers[y - 1], 1);
922 }
923 }
924 break;
925
926 case Key_Home:
927 a = CurArea.first;
928 update(headers, a, y = 1);
929 break;
930
931 case Key_End:
932 a = CurArea.last;
933 update(headers, a, y = 1);
934 break;
935
936 case '+':
937 ulistTerm();
938 for (j = CurArea.first; j <= CurArea.messages; j++)
939 {
940 ulistAddUid(MsgnToUid(j));
941 }
942 update(headers, a, y = 1);
943 break;
944
945 case '-':
946 ulistTerm();
947 update(headers, a, y = 1);
948 break;
949
950 case Key_Spc:
951 if (headers[y - 1].sel == 0)
952 {
953 headers[y - 1].sel = 1;
954 ulistAddUid(headers[y - 1].umsgid);
955 }
956 else
957 {
958 ulistDropUid(headers[y - 1].umsgid);
959 headers[y - 1].sel = 0;
960 }
961 showit(&headers[y - 1], y, 1);
962 down = 1;
963 break;
964
965 case Key_Del:
966 DeleteMsgs(&a);
967 if (a > CurArea.last)
968 {
969 a = CurArea.last;
970 }
971 update(headers, a, y = 1);
972 break;
973
974 case Key_A_H:
975 if (ST->helpfile)
976 {
977 DoHelp(2);
978 }
979 break;
980
981 case Key_Ent:
982 CurArea.current = a;
983 done = 3;
984 break;
985
986 case Key_A_X:
987 case Key_Esc:
988 done = 1;
989 break;
990
991 case Key_A_S:
992 long_subj ^= 1;
993 update(headers, a, y = 1);
994 break;
995
996 case Key_A_A:
997 display_address ^= 1;
998 update(headers, a, y = 1);
999 break;
1000
1001 case Key_A_M:
1002 MoveMsgs(&a);
1003 if (a > CurArea.last)
1004 {
1005 a = CurArea.last;
1006 }
1007 update(headers, a, y = 1);
1008 break;
1009
1010 default:
1011 break;
1012 }
1013 break;
1014 }
1015 }
1016 in_list = 0;
1017 ulistTerm();
1018 xfree(headers);
1019 WndClose(hWnd);
1020 WndCurr(hCurr);
1021
1022 switch(done)
1023 {
1024 case 1:
1025 return 0; /* exit with ESC */
1026 case 2: /* resize occured, continue with
1027 rebuilding the list */
1028 goto begin;
1029 case 3:
1030 return 1; /* exit with Enter */
1031 }
1032
1033 abort(); /* something went wrong! */
1034 }
1035