summaryrefslogtreecommitdiff
path: root/vchat-ui.c
diff options
context:
space:
mode:
authorerdgeist <>2003-02-12 17:48:37 +0000
committererdgeist <>2003-02-12 17:48:37 +0000
commitdea6bf757aa9a875eab35b2b650412e7605f1308 (patch)
tree14ed8374c3a3862529313088375693a7de70d3a7 /vchat-ui.c
CVS moved to erdgeist.org
Diffstat (limited to 'vchat-ui.c')
-rwxr-xr-xvchat-ui.c1504
1 files changed, 1504 insertions, 0 deletions
diff --git a/vchat-ui.c b/vchat-ui.c
new file mode 100755
index 0000000..e9368b4
--- /dev/null
+++ b/vchat-ui.c
@@ -0,0 +1,1504 @@
1/*
2 * vchat-client - alpha version
3 * vchat-ui.c - user-interface and readline handling
4 *
5 * Copyright (C) 2001 Andreas Kotes <count@flatline.de>
6 *
7 * This program is free software. It can be redistributed and/or modified,
8 * provided that this copyright notice is kept intact. This program is
9 * distributed in the hope that it will be useful, but without any warranty;
10 * without even the implied warranty of merchantability or fitness for a
11 * particular purpose. In no event shall the copyright holder be liable for
12 * any direct, indirect, incidental or special damages arising in any way out
13 * of the use of this software.
14 *
15 */
16
17/* general includes */
18#include <unistd.h>
19#include <ncurses.h>
20#include <signal.h>
21#include <stdlib.h>
22#include <errno.h>
23#include <termios.h>
24#include <sys/ioctl.h>
25#include <readline/readline.h>
26#include <readline/history.h>
27#include <openssl/pem.h>
28#include <regex.h>
29#include "vchat.h"
30
31/* version of this module */
32unsigned char *vchat_ui_version = "$Id$";
33
34/* externally used variables */
35/* current string in topic window */
36unsigned char topicstr[TOPICSTRSIZE] = "[] VChat 0.16";
37/* current string in console window */
38unsigned char consolestr[CONSOLESTRSIZE] = "[ Get help: .h for server /h for client commands";
39
40static unsigned int ui_init = 0;
41
42/* our windows */
43static WINDOW *console = NULL;
44static WINDOW *input = NULL;
45static WINDOW *topic = NULL;
46static WINDOW *channel = NULL;
47static WINDOW *private = NULL;
48static WINDOW *output = NULL;
49/* our screen dimensions */
50static int screensx = 0;
51static int screensy = 0;
52/* length of last input on line (for clearing) */
53static int lastlen = 0;
54/* current horizontal scrolling offset for input line */
55static int scroff = 0;
56/* cache for stepping value of horizontal scrolling */
57unsigned int hscroll = 0;
58
59static int outputshown = 0;
60static int outputwidth_desired = 0;
61
62static int privheight = 0;
63static int privheight_desired = 0;
64static int privwinhidden = 0;
65int usetime = 1;
66int outputcountdown = 0;
67
68struct sb_entry {
69 int id;
70 time_t when;
71 int stamp;
72 unsigned char *what;
73 struct sb_entry *link;
74};
75
76struct sb_data {
77 struct sb_entry *entries;
78 int count;
79 int scroll;
80};
81
82static struct sb_data *sb_pub = NULL;
83static struct sb_data *sb_priv = NULL;
84static struct sb_data *sb_out = NULL;
85
86/* Tells, which window is active */
87static int sb_win = 0; /* 0 for pub, 1 for priv */
88
89/* struct to keep filter list */
90struct filt {
91 unsigned char colour;
92 unsigned int id;
93 unsigned char *text;
94 regex_t regex;
95 struct filt *next;
96};
97
98typedef struct filt filt;
99
100static filt *filterlist = NULL;
101static int filtertype = 0;
102static int currentstamp = 0;
103
104/* Prototype declarations */
105
106static void resize (int);
107static void drawwin (WINDOW *win, struct sb_data *sb);
108static int writescr (WINDOW *win, struct sb_entry *entry);
109static int testfilter ( struct sb_entry *entry);
110static int gettextwidth (char *textbuffer);
111static void resize_output (void);
112static int getsbeheight (struct sb_entry *entry, const int xwidth, int needstime );
113static int getsbdataheight (struct sb_data *data, const int xwidth, int needstime );
114/* CURRENTLY UNUSED
115static void writecolorized (WINDOW *win, unsigned char *string);
116*/
117
118enum {
119 RMFILTER_RMANDCONT,
120 RMFILTER_RMANDSTOP,
121 RMFILTER_KEEPANDCONT,
122 RMFILTER_KEEPANDSTOP
123};
124
125/* readlines callback when a line is completed */
126static void
127linecomplete (unsigned char *line)
128{
129 int i;
130
131 /* send linefeed, return pointer, reset cursors */
132 waddch (input, '\n');
133 wmove (input, 0, 0);
134 rl_point = 0;
135 scroff = 0;
136
137 if (line) {
138 i = strlen(line)-1;
139 while (line[i] == ' ') line[i--]='\0';
140
141 if (line[0] && strchr(line,' ') == NULL && line[i] == ':')
142 line[i--] = '\0';
143
144 /* empty line? nada. */
145 if (!line[0])
146 return;
147
148 /* add line to history and have it handled in vchat-protocol.c */
149 add_history (line);
150 handleline (line);
151 free (line);
152
153 /* wipe input line and reset cursor */
154 wmove (input, 0, 0);
155 for (i = 0; i < input->_maxx; i++)
156 waddch (input, ' ');
157 wmove (input, 0, 0);
158 wrefresh (input);
159 }
160}
161
162/* redraw-callback for readline */
163static void
164vciredraw (void)
165{
166 int i;
167 /* hscroll value cache set up? */
168 if (!hscroll)
169 {
170 /* check config-option or set hardcoded default */
171 hscroll = getintoption (CF_HSCROLL);
172 if (!hscroll)
173 hscroll = 5;
174 }
175
176 /* calculate horizontal scrolling offset */
177 if (rl_point - scroff < 0)
178 scroff = rl_point - 4;
179 if (rl_point - scroff > input->_maxx)
180 scroff = rl_point - input->_maxx + 2;
181 if (rl_point - scroff > input->_maxx - (hscroll - 2))
182 scroff += hscroll;
183 else if (rl_point - scroff < input->_maxx - (hscroll + 2))
184 scroff -= hscroll;
185 if (scroff < 0)
186 scroff = 0;
187
188 /* wipe input line */
189 wmove (input, 0, 0);
190 for (i = 0; i < input->_maxx; i++)
191 waddch (input, ' ');
192
193 /* show current line, move cursor, redraw! */
194 mvwaddnstr (input, 0, 0, &rl_line_buffer[scroff], input->_maxx);
195 wmove (input, 0, rl_point - scroff);
196 wrefresh (input);
197}
198
199/* called by the eventloop in vchat-client.c */
200void
201userinput (void)
202{
203 /* let readline handle what the user typed .. */
204 rl_callback_read_char ();
205}
206
207static int
208calcdrawcus (unsigned char * const str) {
209 unsigned char *tmp = str;
210 int zero = 0;
211 while( *tmp && (*tmp!=' ') && (*tmp!='\n')) { if(*tmp==1) zero+=2; tmp++; }
212 return (tmp - str) - zero;
213}
214
215static void
216sb_flush ( struct sb_data *sb ) {
217 struct sb_entry *now = sb->entries, *prev = NULL, *tmp;
218 while( now ) {
219 tmp = (struct sb_entry*)((unsigned long)prev ^ (unsigned long)now->link);
220 free(now->what );
221 free(now);
222 prev = now;
223 now = tmp;
224 }
225 sb->entries = NULL;
226}
227
228static void
229sb_clear ( struct sb_data **sb ) {
230 sb_flush(*sb);
231 free( *sb );
232 *sb = NULL;
233}
234
235static struct sb_entry*
236sb_add (struct sb_data *sb, unsigned char *line, time_t when) {
237 struct sb_entry *newone = malloc (sizeof(struct sb_entry));
238 if( newone ) {
239 if( sb->count == sb->scroll ) sb->scroll++;
240 newone->id = sb->count++;
241 newone->when = when;
242 newone->what = strdup(line);
243 newone->link = sb->entries;
244 newone->stamp= 0xffff;
245 if( sb->entries ) sb->entries->link = (struct sb_entry*)((unsigned long)sb->entries->link ^ (unsigned long)newone);
246 sb->entries = newone;
247 }
248 return newone;
249}
250
251void flushout ( )
252{
253 sb_flush(sb_out);
254 writeout(" ");
255 outputwidth_desired = 0;
256 outputshown = 0;
257}
258
259void hideout( )
260{
261 outputshown = 0;
262 resize(0);
263}
264
265void showout (void)
266{
267 writeout(" ");
268 outputcountdown = 6;
269 outputshown = 1;
270 resize(0);
271}
272
273void writeout (unsigned char *str)
274{
275 sb_add(sb_out,str,time(NULL));
276 int i = 1 + gettextwidth( str );
277 if( i > outputwidth_desired ) outputwidth_desired = i;
278}
279
280int writechan (unsigned char *str) {
281 struct sb_entry *tmp;
282 int i = 0;
283 time_t now = time(NULL);
284 tmp = sb_add(sb_pub,str,now);
285
286 if ( (sb_pub->scroll == sb_pub->count) && ((filtertype == 0) || ( testfilter(tmp)))) {
287 i = writescr(channel, tmp);
288 wnoutrefresh(channel);
289 }
290 consoleline(NULL);
291 return i;
292}
293
294int writecf (formtstr id,unsigned char *str) {
295 struct sb_entry *tmp;
296 int i = 0;
297 time_t now = time(NULL);
298 snprintf(tmpstr,TMPSTRSIZE,getformatstr(id),str);
299 tmp = sb_add(sb_pub,tmpstr,now);
300 if ( (sb_pub->scroll == sb_pub->count) &&
301 ((filtertype == 0) || ( testfilter(tmp)))) {
302 i = writescr(channel, tmp);
303 wnoutrefresh(channel);
304 }
305 consoleline(NULL);
306 return i;
307}
308
309int writepriv (unsigned char *str) {
310 int i = 0;
311 time_t now = time (NULL);
312 struct sb_entry *tmp;
313
314 if (private) {
315 tmp = sb_add(sb_priv,str,now);
316 if ( (sb_priv->scroll == sb_priv->scroll) &&
317 ((filtertype == 0) || ( testfilter(tmp)))) {
318 i = writescr(private, tmp);
319 }
320 if( privwinhidden ) {
321 privheight_desired = privwinhidden;
322 privwinhidden = 0;
323 resize(0);
324 }
325 wnoutrefresh(private);
326 topicline(NULL);
327 } else
328 i = writechan( str );
329
330 return i;
331}
332
333/* Get #if 's out of code */
334
335#if NCURSES_VERSION_MAJOR >= 5
336
337typedef struct {
338 attr_t attr;
339 short pair;
340} ncurs_attr;
341
342#define WATTR_GET( win, orgattr ) wattr_get( win, &orgattr.attr, &orgattr.pair, NULL)
343#define WATTR_SET( win, orgattr ) wattr_set( win, orgattr.attr, orgattr.pair, NULL)
344#define BCOLR_SET( attr, colour ) attr->pair = colour;
345
346#else
347
348typedef struct {
349 attr_t attr;
350} ncurs_attr;
351
352#define WATTR_GET( win, orgattr ) orgattr.attr = wattr_get(win);
353#define WATTR_SET( win, orgattr ) wattr_set( win, orgattr.attr);
354#define BCOLR_SET( attr, colour ) attr->attr = ((attr->attr) & ~A_COLOR) | COLOR_PAIR((colour));
355
356#endif
357
358/* 'A' - 'Z' attriute type */
359static int attributes[] = { A_ALTCHARSET, A_BOLD, 0, A_DIM, 0, 0, 0, 0, A_INVIS, 0, 0, A_BLINK,
360 0, A_NORMAL, 0, A_PROTECT, 0, A_REVERSE, A_STANDOUT, 0, A_UNDERLINE,
361 0, 0, 1, 0, 0 };
362
363static void
364docolorize (unsigned char colour, ncurs_attr *attr, ncurs_attr orgattr) {
365 if( colour== '0') {
366 *attr = orgattr;
367 } else if( ( colour > '0') && ( colour <= '9')) {
368 BCOLR_SET( attr, colour - '0' );
369 } else {
370 unsigned char upc = colour & ( 0x20 ^ 0xff ); /* colour AND NOT 0x20 */
371 attr_t newattr;
372 if( ( upc >= 'A') && ( upc<='Z' ) && ( newattr = attributes[upc - 'A']) )
373 attr->attr = ( colour & 0x20 ) ? attr->attr | newattr : attr->attr & ~newattr;
374 }
375}
376
377/* draw arbitrary strings */
378static int
379writescr ( WINDOW *win, struct sb_entry *entry ) {
380 unsigned char tmp [64];
381 int charcount = 0;
382 int i;
383 int textlen = strlen( entry->what );
384 int timelen = ((win == channel)||(win == private)) && usetime ?
385 (int)strftime(tmp,64,getformatstr(FS_TIME),localtime(&entry->when)) : 0;
386 unsigned char textbuffer[ textlen+timelen+1 ];
387 ncurs_attr attrbuffer[ textlen+timelen+1 ];
388 ncurs_attr orgattr;
389
390 /* illegal window? return */
391 if( !win || !(textlen+timelen)) return 0;
392
393 /* store original attributes */
394 WATTR_GET( win, orgattr);
395 attrbuffer[ 0 ] = orgattr;
396
397 /* copy time string */
398 for( i = 0; i < timelen; i++ )
399 if( tmp[ i ] == 1 ) {
400 docolorize( tmp[++i], attrbuffer+charcount, orgattr);
401 } else {
402 attrbuffer[ charcount+1 ] = attrbuffer[ charcount ];
403 textbuffer[ charcount++ ] = tmp[ i ];
404 }
405
406 timelen = charcount;
407
408 /* copy text */
409 for( i = 0; i< textlen; i++ )
410 if( entry->what[ i ] == 1 ) {
411 docolorize( entry->what[++i], attrbuffer+charcount, orgattr);
412 } else {
413 attrbuffer[ charcount+1 ] = attrbuffer[ charcount ];
414 textbuffer[ charcount++ ] = entry->what[ i ];
415 }
416
417 /* zero terminate text --- very important :) */
418 textbuffer[ charcount ] = 0;
419
420 /* hilite */
421 if((win == channel)||(win == private)) { /* do not higlight bars */
422 filt *flt = filterlist;
423 unsigned char *instr = textbuffer;
424 regmatch_t match;
425 int j;
426
427 while( flt ) {
428 if ( (flt->colour != '-') && (flt->colour != '+')) {
429 i = timelen;
430 while( i < charcount ) {
431 if( regexec( &flt->regex, instr+i, 1, &match, 0 )) {
432 i = charcount;
433 } else {
434 for( j = i + match.rm_so; j < i + match.rm_eo; j++)
435 docolorize( flt->colour, attrbuffer+j, orgattr );
436 i += 1 + match.rm_so;
437 }
438 }
439 }
440 flt = flt->next;
441 }
442 }
443
444 if (win->_curx) waddch(win,'\n');
445
446 for( i = 0; i < charcount; i++ ) {
447 /* on start of line or attribute changes set new attribute */
448 if( !i || memcmp( attrbuffer+i, attrbuffer+i-1, sizeof(ncurs_attr)))
449 WATTR_SET( win, attrbuffer[i]);
450 if( textbuffer[ i ] == ' ') {
451 if ((calcdrawcus(textbuffer+i+1) + win->_curx > win->_maxx - 1)&&
452 (calcdrawcus(textbuffer+i+1) < win->_maxx)) {
453 /* line wrap found */
454 WATTR_SET( win, orgattr);
455 waddstr( win, "\n ");
456 WATTR_SET( win, attrbuffer[ i ]);
457 }
458 }
459 /* plot character */
460 waddch( win, textbuffer[ i ]);
461 }
462
463 /* restore old attributes */
464 WATTR_SET (win, orgattr);
465
466 return charcount;
467}
468
469static void
470resize_output ( )
471{
472 int outputwidth = (outputwidth_desired + 7 > screensx) ? screensx - 7 : outputwidth_desired;
473 int outputheight = getsbdataheight(sb_out, outputwidth-1, 0);
474
475 if (outputheight + 5 > screensy ) outputheight = screensy - 5;
476 wresize(output,outputheight,outputwidth);
477 mvwin(output,(screensy-outputheight)>>1,(screensx-outputwidth)>>1);
478 drawwin(output, sb_out);
479}
480
481static void
482doscroll( int up ) {
483 WINDOW *destwin = (sb_win && private) ? private : channel;
484 struct sb_data *sb = (sb_win && private) ? sb_priv : sb_pub;
485 struct sb_entry *now = sb->entries, *prev = NULL, *tmp;
486 int lines = destwin->_maxy>>1;
487
488 if( sb->scroll != sb->count )
489 while( now && (now->id != sb->scroll) ) {
490 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp;
491 }
492
493 if( !up ) {
494 prev = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev);
495 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp;
496 }
497
498 while( now && (lines > 0)) {
499 if ( (!filtertype) || ( (now->stamp != currentstamp) && ( (now->stamp == (currentstamp | (1<<15))) || testfilter( now ) ) ) )
500 {
501 lines -= getsbeheight( now, destwin->_maxx, usetime );
502 }
503 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp;
504 }
505 if( now )
506 sb->scroll = now->id;
507 else
508 if( !up ) sb->scroll = sb->count;
509
510 drawwin(destwin, sb);
511 wnoutrefresh(destwin);
512 if( sb_win && private ) topicline(NULL); else consoleline(NULL);
513}
514
515
516void
517scrollup (void)
518{
519 doscroll( 1 );
520}
521
522void
523scrolldown (void)
524{
525 doscroll( 0 );
526}
527
528void
529scrollwin (vod)
530{
531 if (!sb_win && private) sb_win = 1;
532 else sb_win = 0;
533 topicline(NULL);
534 consoleline(NULL);
535}
536
537void
538growprivwin (vod) {
539 if( private ) {
540 if( privwinhidden)
541 privwinhidden = 0;
542 if( ++privheight_desired > screensy - 5)
543 privheight_desired = screensy - 5;
544 resize(0);
545 }
546}
547
548void toggleprivwin (vod) {
549 if( outputshown ) {
550 outputshown = 0;
551 resize(0);
552 } else {
553 if( private ) {
554 if( privwinhidden ) {
555 privheight_desired = privwinhidden;
556 privwinhidden = 0;
557 } else {
558 privwinhidden = privheight_desired;
559 privheight_desired = 1;
560 }
561 resize(0);
562 }
563 }
564}
565
566void
567shrinkprivwin (vod) {
568 if( private && !privwinhidden ) {
569 if( --privheight_desired < 1) privheight_desired = 1;
570 if( privheight_desired > screensy - 5) privheight_desired = screensy - 5;
571 resize(0);
572 }
573}
574
575/* nick completion callback for readline */
576static char **
577vcccomplete (char *text, int start, int end)
578{
579 char **matches;
580 matches = (char **) NULL;
581 /* are we at start of line, with no characters typed? message completion */
582 if (start == 0 && end == 0)
583 {
584#ifdef OLDREADLINE
585 matches = completion_matches (text, (CPFunction *) ul_mnickcomp);
586#else
587 matches = rl_completion_matches (text, (rl_compentry_func_t *) ul_mnickcomp);
588#endif
589 rl_attempted_completion_over = 1;
590 }
591 /* start of line? get matches for channel! */
592 else if (start == 0)
593 {
594#ifdef OLDREADLINE
595 matches = completion_matches (text, (CPFunction *) ul_cnickcomp);
596#else
597 matches = rl_completion_matches (text, (rl_compentry_func_t *) ul_cnickcomp);
598#endif
599 /* no, we want no 'normal' completion if started typing on the beginning
600 * of the line */
601 rl_attempted_completion_over = 1;
602 }
603 return (matches);
604}
605
606/* clear message window */
607void
608clearpriv ()
609{
610 WINDOW *dest = NULL;
611 /* do we have a private window? */
612 if (private)
613 dest = private;
614 else
615 dest = channel;
616
617 /* clear window, move cursor to bottom, redraw */
618 wclear (dest);
619 wmove (dest, dest->_maxy, dest->_maxx);
620 wrefresh (dest);
621}
622
623/* clear channel window */
624void
625clearchan ()
626{
627 /* clear window, move cursor to bottom, redraw */
628 wclear (channel);
629 wmove (channel, channel->_maxy, channel->_maxx);
630 wrefresh (channel);
631}
632
633/* Get window size */
634
635void ttgtsz(int *x,int *y) {
636#ifdef TIOCGSIZE
637 struct ttysize getit;
638#else
639#ifdef TIOCGWINSZ
640 struct winsize getit;
641#endif
642#endif
643
644 *x=0; *y=0;
645#ifdef TIOCGSIZE
646 if(ioctl(1,TIOCGSIZE,&getit)!= -1) {
647 *x=getit.ts_cols;
648 *y=getit.ts_lines;
649 }
650#else
651#ifdef TIOCGWINSZ
652 if(ioctl(1,TIOCGWINSZ,&getit)!= -1) {
653 *x=getit.ws_col;
654 *y=getit.ws_row;
655 }
656#endif
657#endif
658 }
659
660static void
661redraw (void)
662{
663 sb_pub->scroll = sb_pub->count;
664 sb_priv->scroll = sb_priv->count;
665
666 resize(0);
667}
668
669/* resize display on SIGWINCH */
670void
671resize (int signal)
672{
673 int xsize,ysize;
674 //errmsg ("! SIGWINCH raised without code for it, hope you didn't make it smaller ;)");
675 //endwin();
676 ttgtsz(&xsize,&ysize);
677 resizeterm(ysize,xsize);
678 //refresh();
679 /* store screen-dimensions to local functions */
680 getmaxyx (stdscr, screensy, screensx);
681
682 if (!privheight_desired) privheight_desired = getintoption(CF_PRIVHEIGHT);
683 if ( privheight_desired > screensy - 5) privheight = screensy - 5; else privheight = privheight_desired;
684
685 /* check dimensions or bump user */
686 if (screensy - privheight < 4)
687 {
688 fprintf (stderr, "vchat-client: screen to short (only %d rows, at least %d expected), bailing out.\n", screensy, privheight + 6);
689 snprintf (errstr, ERRSTRSIZE, "vchat-client: screen to short (only %d rows, at least %d expected), bailing out.\n", screensy, privheight + 6);
690 cleanup (0);
691 }
692 if (screensx < 14)
693 {
694 fprintf (stderr, "vchat-client: screen to thin (only %d cols, at least %d expected), bailing out.\n", screensx, 14);
695 snprintf (errstr, ERRSTRSIZE, "vchat-client: screen to thin (only %d cols, at least %d expected), bailing out.\n", screensx, 14);
696 cleanup (0);
697 }
698
699 wresize(console,1,screensx);
700 wresize(input,1,screensx);
701 if (private)
702 wresize(private,privheight,screensx);
703 wresize(topic,1,screensx);
704 wresize(channel,screensy-(privheight+3),screensx);
705
706 mvwin(console,screensy-2,0);
707 mvwin(input,screensy-1,0);
708 if(private) mvwin(private,0,0);
709 mvwin(topic,privheight,0);
710 mvwin(channel,privheight+1,0);
711
712 drawwin(channel, sb_pub);
713 if(private) drawwin(private, sb_priv);
714 wnoutrefresh(channel);
715 if(private) wnoutrefresh(private);
716
717 if(outputshown) resize_output();
718 topicline(NULL);
719 consoleline(NULL);
720 if(loggedin) vciredraw();
721}
722
723static int
724gettextwidth (char *textbuffer)
725{
726 int width = 0;
727
728 do switch( *(textbuffer++) ) {
729 case 1:
730 if (!*(textbuffer++)) return width;
731 break;
732 case 0:
733 return width;
734 break;
735 default:
736 width++;
737 break;
738 } while( 1 );
739}
740
741static int
742getsbdataheight (struct sb_data *data, const int xwidth, int needstime )
743{
744 struct sb_entry *now = data->entries, *prev = NULL, *tmp;
745 int height = 0;
746 while( now ) {
747 height += getsbeheight( now, xwidth, needstime);
748 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp;
749 }
750 return height;
751}
752
753static int
754getsbeheight (struct sb_entry *entry, const int xwidth, int needstime )
755{
756 int curx = 0, lines = 1;
757 char tmp[ 64 ], *textbuffer;
758
759 if( needstime ) {
760 int timelen = (int)strftime(tmp,64,getformatstr(FS_TIME),localtime(&entry->when));
761 tmp[ timelen ] = 2;
762 textbuffer=tmp;
763 } else {
764 textbuffer = entry->what;
765 }
766
767 do switch( *textbuffer++ ) {
768 case ' ':
769 if ((calcdrawcus(textbuffer) + curx > xwidth - 1) &&
770 (calcdrawcus(textbuffer) < xwidth)) {
771 lines++; curx = 4;
772 } else {
773 if( curx++ == xwidth ) {
774 curx = 0; lines++;
775 }
776 }
777 break;
778 case 1:
779 if (!*textbuffer++) return lines;
780 break;
781 case 0:
782 return lines;
783 break;
784 case 2:
785 textbuffer=entry->what;
786 break;
787 default:
788 if( curx++ == xwidth ) {
789 curx = 0; lines++;
790 }
791 break;
792 } while( 1 );
793
794}
795
796static int
797analyzefilters( void ) {
798 filt *filters = filterlist;
799 int type = 0;
800
801 sb_pub->scroll = sb_pub->count;
802 sb_priv->scroll = sb_priv->count;
803
804 if( ++currentstamp == 0x3fff ) currentstamp = 1;
805
806 while( (type!=1) && filters ) {
807 if( filters->colour == '-' ) type = 2;
808 if( filters->colour == '+' ) type = 1;
809 filters=filters->next;
810 }
811 return type;
812}
813
814static int
815testfilter ( struct sb_entry* entry ) {
816 int match = 0;
817 filt *filters = filterlist;
818 char filtercolour = filtertype == 2 ? '-' : '+';
819
820 while( !match && filters ) {
821 if( filters->colour == filtercolour )
822 match = regexec( &filters->regex, entry->what, 0, NULL, 0 ) ? 0 : 1;
823 filters=filters->next;
824 }
825 match = ( filtertype == 2 ) ? ( 1 - match ) : match;
826 entry->stamp = (match << 15) | currentstamp;
827
828 return match;
829}
830
831static void
832drawwin (WINDOW *win, struct sb_data *sb )
833{
834 if (win) {
835 struct sb_entry *now = sb->entries, *prev = NULL, *tmp;
836 struct sb_entry *vis[win->_maxy + 1];
837 int sumlines = 0, sumbuffers = 0;
838
839 /* public scrollback */
840 if( sb->scroll != sb->count )
841 while( now && (now->id != sb->scroll) ) {
842 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp;
843 }
844
845 if( (win == output) || (filtertype == 0)) {
846 while( now && (sumlines <= win->_maxy )) {
847 sumlines += getsbeheight( now, win->_maxx, ((win == channel)||(win == private)) && usetime );
848 vis[ sumbuffers++ ] = now;
849 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp;
850 }
851 } else {
852 while( now && (sumlines <= win->_maxy )) {
853 if ( (now->stamp != currentstamp) &&
854 ( (now->stamp == (currentstamp | (1<<15))) || testfilter( now ) )
855 )
856 {
857 sumlines += getsbeheight( now, win->_maxx, ((win == channel)||(win == private)) && usetime );
858 vis[ sumbuffers++ ] = now;
859 }
860 tmp = now; now = (struct sb_entry*)((unsigned long)now->link ^ (unsigned long)prev); prev = tmp;
861 }
862 }
863
864 /* If buffer is not completely filled, clear window */
865 if( sumlines < win->_maxy + 1 )
866 wclear(win);
867
868 /* Move pointer to bottom to let curses scroll */
869 wmove(win, win->_maxy, win->_maxx);
870
871 /* Plot visible lines */
872 while (sumbuffers--) writescr( win, vis[sumbuffers] );
873 }
874}
875
876#ifdef OLDREADLINE
877typedef int rl_command_func_t __P((int, int));
878#endif
879
880/* initialize curses and display */
881void
882initui (void)
883{
884 Keymap keymap;
885
886 /* init curses */
887 if (!ui_init) {
888 initscr ();
889 ui_init = 1;
890 }
891
892 /* install signalhandler */
893
894 signal (SIGWINCH, resize);
895
896 /* set options */
897 keypad (stdscr, TRUE);
898 nonl ();
899 cbreak ();
900
901 /* color or monochome display? */
902 if (has_colors ())
903 {
904 /* start color and set a colorset */
905 start_color ();
906 use_default_colors();
907 init_pair (1, COLOR_RED, -1);
908 init_pair (2, COLOR_GREEN, -1);
909 init_pair (3, COLOR_YELLOW, -1);
910 init_pair (4, COLOR_BLUE, -1);
911 init_pair (5, COLOR_MAGENTA, -1);
912 init_pair (6, COLOR_CYAN, -1);
913 init_pair (7, COLOR_WHITE, -1);
914 init_pair (8, COLOR_WHITE, COLOR_RED);
915 init_pair (9, COLOR_WHITE, COLOR_BLUE);
916 }
917 else
918 {
919 /* monochrome, start color and set a colorset anyways */
920 start_color ();
921 init_pair (1, -1, -1);
922 init_pair (2, -1, -1);
923 init_pair (3, -1, -1);
924 init_pair (4, -1, -1);
925 init_pair (5, -1, -1);
926 init_pair (6, -1, -1);
927 init_pair (7, -1, -1);
928 init_pair (8, -1, -1);
929 init_pair (9, -1, -1);
930 }
931
932 /* store screen-dimensions to local functions */
933 getmaxyx (stdscr, screensy, screensx);
934
935 if (!privheight_desired) privheight_desired = getintoption(CF_PRIVHEIGHT);
936 if ( privheight_desired > screensy - 5) privheight = screensy - 5; else privheight = privheight_desired;
937
938 /* check dimensions or bump user */
939 if (screensy - privheight < 4)
940 {
941 fprintf (stderr, "vchat-client: screen to short (only %d rows, at least %d expected), bailing out.\n", screensy, privheight + 6);
942 snprintf (errstr, ERRSTRSIZE, "vchat-client: screen to short (only %d rows, at least %d expected), bailing out.\n", screensy, privheight + 6);
943 cleanup (0);
944 }
945 if (screensx < 14)
946 {
947 fprintf (stderr, "vchat-client: screen to thin (only %d cols, at least %d expected), bailing out.\n", screensx, 14);
948 snprintf (errstr, ERRSTRSIZE, "vchat-client: screen to thin (only %d cols, at least %d expected), bailing out.\n", screensx, 14);
949 cleanup (0);
950 }
951
952 /* setup our windows */
953 console = newwin (1, screensx, screensy - 2, 0);
954 input = newwin (1, screensx, screensy - 1, 0);
955 if (privheight) private = newwin (privheight, screensx, 0, 0);
956 topic = newwin (1, screensx, privheight, 0);
957 channel = newwin (screensy - (privheight+3), screensx, (privheight+1), 0);
958 output = newwin (1, screensx, 1, 0);
959
960 /* promblems opening windows? bye! */
961 if (!console || !input || !topic || !channel || !output )
962 {
963 fprintf (stderr, "vchat-client: could not open windows, bailing out.\n");
964 cleanup (0);
965 }
966
967 /* Prepare our scrollback buffers */
968 sb_pub = (struct sb_data*)malloc( sizeof(struct sb_data));
969 sb_out = (struct sb_data*)malloc( sizeof(struct sb_data));
970 if( privheight)
971 sb_priv = (struct sb_data*)malloc( sizeof(struct sb_data));
972 else
973 sb_priv = sb_pub;
974
975 memset( sb_pub, 0, sizeof(struct sb_data));
976 memset( sb_priv, 0, sizeof(struct sb_data));
977 memset( sb_out, 0, sizeof(struct sb_data));
978
979 /* set colors for windows */
980 if (has_colors()) {
981 wattrset (console, COLOR_PAIR (9));
982 wattrset (input, COLOR_PAIR (0));
983 wattrset (topic, COLOR_PAIR (9));
984 wbkgd (output, COLOR_PAIR(8));
985 wbkgd (console, COLOR_PAIR (9));
986 wbkgd (channel, COLOR_PAIR (0));
987 wbkgd (input, COLOR_PAIR (0));
988 if (private)
989 wbkgd (private, COLOR_PAIR (0));
990 wbkgd (topic, COLOR_PAIR (9));
991 } else {
992 wattron (console, A_REVERSE);
993 wattron (topic, A_REVERSE);
994 wattron (output, A_REVERSE);
995 wbkgd(output, A_REVERSE);
996 }
997
998 /* set some options */
999 scrollok (channel, TRUE);
1000 if (private)
1001 scrollok (private, TRUE);
1002 scrollok (input, TRUE);
1003 scrollok (output, TRUE);
1004 //idlok(channel,TRUE);
1005 wtimeout (input, 100);
1006
1007 /* setup readlines display */
1008 /* FIXME: present only in newer readline versions
1009 rl_set_screen_size (1, screensx);
1010 */
1011
1012 /* use our callback to draw display */
1013 rl_redisplay_function = vciredraw;
1014
1015 /* get keymap, throw out unwanted binding */
1016 keymap = rl_get_keymap ();
1017 rl_unbind_command_in_map ("clear-screen", keymap);
1018 rl_unbind_command_in_map ("complete", keymap);
1019 rl_unbind_command_in_map ("possible-completions", keymap);
1020 rl_unbind_command_in_map ("insert-completions", keymap);
1021
1022 /* bind CTRL-L to clearmsg() */
1023 rl_bind_key ('J'-'@', (rl_command_func_t *) clearpriv);
1024 rl_bind_key ('O'-'@', (rl_command_func_t *) clearchan);
1025 rl_bind_key ('L'-'@', (rl_command_func_t *) redraw);
1026 rl_bind_key ('B'-'@', (rl_command_func_t *) scrollup);
1027 rl_bind_key ('P'-'@', (rl_command_func_t *) scrollup);
1028 rl_bind_key ('F'-'@', (rl_command_func_t *) scrolldown);
1029 rl_bind_key ('N'-'@', (rl_command_func_t *) scrolldown);
1030 rl_bind_key ('R'-'@', (rl_command_func_t *) scrollwin);
1031 rl_bind_key ('T'-'@', (rl_command_func_t *) shrinkprivwin);
1032 rl_bind_key ('G'-'@', (rl_command_func_t *) growprivwin);
1033 rl_bind_key ('X'-'@', (rl_command_func_t *) toggleprivwin);
1034
1035 /* bind TAB to menu complete from readline */
1036 rl_bind_key ('\t', (rl_command_func_t *) rl_menu_complete);
1037
1038 /* application name for .inputrc - err, we don't load it */
1039 rl_readline_name = "vchat-client";
1040
1041 /* set up nick completion functions .. */
1042#ifdef OLDREADLINE
1043 rl_completion_entry_function = (Function *) ul_nickcomp;
1044 rl_attempted_completion_function = vcccomplete;
1045#else
1046 rl_completion_entry_function = (rl_compentry_func_t *) ul_nickcomp;
1047 rl_attempted_completion_function = (rl_completion_func_t *) vcccomplete;
1048#endif
1049
1050 /* .. and 'line completed' callback */
1051#ifdef OLDREADLINE
1052 rl_callback_handler_install ("", linecomplete);
1053#else
1054 rl_callback_handler_install ("", (rl_vcpfunc_t *) linecomplete);
1055#endif
1056
1057 writeout( ">> Ctrl-X <<");
1058
1059 if (errstr[0] != '\0') {
1060 writeout(errstr);
1061 writeout( " ");
1062 }
1063
1064 writeout (vchat_cl_version);
1065 writeout (vchat_ui_version);
1066 writeout (vchat_io_version);
1067 writeout (vchat_us_version);
1068 writeout (vchat_cm_version);
1069 showout( );
1070}
1071
1072/* render colorized line to window */
1073/* DOES NOT WRAP !!!
1074 CURRENTLY UNUSED
1075 Enable, when needed
1076
1077static void
1078writecolorized( WINDOW *win, unsigned char *string) {
1079 ncurs_attr old_att, new_att;
1080 int i;
1081
1082 WATTR_GET( win, old_att );
1083 new_att = old_att;
1084 for( i = 0; string[ i ]; i++ )
1085 if( string[ i ] == 1 ) {
1086 docolorize( string[++i], &new_att, old_att);
1087 } else {
1088 WATTR_SET( win, new_att );
1089 waddch( win, string[ i ] );
1090 }
1091 WATTR_SET( win, old_att );
1092}
1093*/
1094
1095/* render consoleline to screen */
1096void
1097consoleline (unsigned char *message)
1098{
1099 /* clear console, set string (or default), redraw display */
1100 int i;
1101 ncurs_attr old_att, new_att;
1102
1103 memset( &new_att, 0, sizeof(new_att));
1104 BCOLR_SET( (&new_att), 8 );
1105 wmove (console, 0, 0);
1106 WATTR_GET( console, old_att);
1107 if(sb_pub->scroll!=sb_pub->count) WATTR_SET( console, new_att);
1108
1109 for (i = 0; i < console->_maxx; i++)
1110 waddch (console, ' ');
1111 mvwaddnstr (console, 0, 0, message ? message : consolestr, console->_maxx);
1112 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_SBINF),sb_pub->scroll,sb_pub->count);
1113 mvwaddstr (console, 0, console->_maxx - (strlen(tmpstr)-1),tmpstr);
1114 if (sb_win == 0) mvwaddch (console, 0, console->_maxx,'*');
1115
1116 WATTR_SET( console, old_att);
1117
1118 wnoutrefresh(console);
1119 if(outputshown) {
1120 redrawwin(output);
1121 wnoutrefresh(output);
1122 }
1123 wnoutrefresh(input);
1124 doupdate();
1125}
1126
1127/* render topicline to screen */
1128void
1129topicline (unsigned char *message)
1130{
1131 int i;
1132 ncurs_attr old_att, new_att;
1133
1134 memset( &new_att, 0, sizeof(new_att));
1135 BCOLR_SET( (&new_att), 8 );
1136
1137 /* clear topic, set string (or default), redraw display */
1138 wmove (topic, 0, 0);
1139
1140 WATTR_GET( topic, old_att);
1141 if( private && (sb_priv->scroll!=sb_priv->count))
1142 WATTR_SET( topic, new_att);
1143
1144 for (i = 0; i < topic->_maxx; i++)
1145 waddch (topic, ' ');
1146 mvwaddnstr (topic, 0, 0, message ? message : topicstr, topic->_maxx);
1147 if (private) {
1148 snprintf(tmpstr,TMPSTRSIZE,getformatstr(FS_SBINF),sb_priv->scroll,sb_priv->count);
1149 mvwaddstr (topic, 0, topic->_maxx - (strlen(tmpstr)-1),tmpstr);
1150 if (sb_win == 1) mvwaddch (topic, 0, topic->_maxx,'*');
1151 }
1152 WATTR_SET( topic, old_att);
1153
1154 wnoutrefresh(topic);
1155 if(outputshown) {
1156 redrawwin(output);
1157 wnoutrefresh(output);
1158 }
1159 wnoutrefresh(input);
1160 doupdate();
1161}
1162
1163/* end userinterface */
1164void
1165exitui (void)
1166{
1167 if (ui_init) {
1168 rl_callback_handler_remove ();
1169 endwin ();
1170 ui_init = 0;
1171 }
1172}
1173
1174/* prompt for a nick */
1175/* FIXME: must not be called when used rl_callback_read_char()/userinput()
1176 * before */
1177void
1178nickprompt (void)
1179{
1180 int i;
1181
1182 if (nick)
1183 return;
1184
1185 /* prompt user for nick unless he enters one */
1186 consoleline("Please enter your nickname:");
1187 while (!nick || !nick[0])
1188 {
1189 if (nick)
1190 free (nick);
1191 nick = readline("");
1192 }
1193 setstroption(CF_NICK,nick);
1194
1195 /* try to get readlines stats clean again */
1196 //rl_free_line_state ();
1197 rl_point = 0;
1198 rl_done = 0;
1199 rl_line_buffer[0] = 0;
1200 lastlen = 23;
1201
1202 /* wipe input line and reset cursor */
1203 wmove (input, 0, 0);
1204 for (i = 0; i < input->_maxx; i++)
1205 waddch(input, ' ');
1206 wmove(input, 0, 0);
1207
1208 /* reset consoleline */
1209 consoleline(NULL);
1210}
1211
1212/* special callback for readline, doesn't show the characters */
1213static void
1214vcnredraw (void)
1215{
1216 int i;
1217 unsigned char *passbof="-*-*-*-*-*-*-";
1218
1219 /* wipe input line and reset cursor */
1220 wmove(input, 0, 0);
1221 for (i = 0; i < input->_maxx; i++)
1222 waddch(input, ' ');
1223 wmove(input, 0, 0);
1224
1225 /* draw as many stars as there are characters */
1226 mvwaddnstr(input, 0, 0, &passbof[rl_point%2], 12);
1227 wmove(input, 0, input->_maxx);
1228 wrefresh(input);
1229}
1230
1231/* passphrase callback for OpenSSL */
1232/* FIXME: must not be called when used rl_callback_read_char()/userinput()
1233 * before */
1234int
1235passprompt (char *buf, int size, int rwflag, void *userdata)
1236{
1237 int i;
1238 unsigned char *passphrase = NULL;
1239
1240 /* use special non-revealing redraw function */
1241 /* FIXME: passphrase isn't protected against e.g. swapping */
1242 rl_redisplay_function = vcnredraw;
1243
1244 /* prompt user for non-empty passphrase */
1245 consoleline("Please enter PEM passphrase for private key:");
1246 while (!passphrase || !passphrase[0])
1247 {
1248 if (passphrase)
1249 free (passphrase);
1250 passphrase = readline ("");
1251 }
1252
1253 /* reset redrawing function to default, reset consoleline */
1254 rl_redisplay_function = vciredraw;
1255 consoleline(NULL);
1256
1257 /* copy passphrase to buffer */
1258 strncpy (buf, passphrase, size);
1259
1260 /* try to get readlines stats clean again */
1261 //rl_free_line_state ();
1262 rl_point = 0;
1263 rl_done = 0;
1264 rl_line_buffer[0] = 0;
1265 lastlen = 23;
1266
1267 /* wipe input line and reset cursor */
1268 wmove (input, 0, 0);
1269 for (i = 0; i < input->_maxx; i++)
1270 waddch (input, ' ');
1271 wmove (input, 0, 0);
1272 wrefresh (input);
1273
1274 /* return passphrase to OpenSSL */
1275 return strlen (buf);
1276}
1277
1278/* Filter stuff */
1279static int
1280check_valid_colour( char colour ) {
1281 return !( (colour !='-')&&(colour !='+') && (colour < '0' || colour > '9') &&
1282 (colour < 'A' || colour > 'Z' || !attributes[ colour-'A' ]) &&
1283 (colour < 'a' || colour > 'z' || !attributes[ colour-'a' ]));
1284}
1285
1286
1287/* scans filterlist and removes possible matches
1288 test functions may return:
1289 RMFILTER_RMANDCONT
1290 RMFILTER_RMANDSTOP
1291 RMFILTER_KEEPANDCONT
1292 RMFILTER_KEEPANDSTOP
1293 returns number of removed entries
1294*/
1295static int
1296removefromfilterlist( int(*test)(filt *flt, void *data, char colour), void *data, char colour) {
1297 filt **flt = &filterlist, *tmp;
1298 int removed = 0, stop = 0;
1299
1300 while( *flt && !stop ) {
1301 switch( test( *flt, data, colour ) ) {
1302 case RMFILTER_RMANDSTOP: /* remove */
1303 stop = 1;
1304 case RMFILTER_RMANDCONT:
1305 snprintf( tmpstr, TMPSTRSIZE, " Removed ID: [% 3d] Color: [%c] Regex: [%s] ", (*flt)->id, (*flt)->colour, (*flt)->text);
1306 writeout(tmpstr);
1307 /* Release regex.h resources */
1308 regfree( &((*flt)->regex));
1309 /* free ASCII text memory */
1310 free( (*flt)->text);
1311 /* unlink from list */
1312 tmp = *flt;
1313 *flt = (*flt)->next;
1314 /* free filter block itself */
1315 free( tmp );
1316 /* reflect changes on whole screen */
1317 removed++;
1318 break;
1319 case RMFILTER_KEEPANDSTOP: /* don't remove but stop scanning */
1320 stop = 1;
1321 break;
1322 default:
1323 /* advance in list */
1324 if( *flt ) flt = &((*flt)->next);
1325 break;
1326 }
1327 }
1328 /* return number of removed items */
1329 return removed;
1330}
1331
1332static int
1333test_clear( filt *flt, void *data, char c ) {
1334 if( !c || ( c == flt->colour ) || ( (c == '*') && (flt->colour != '-') && (flt->colour != '+') ) )
1335 return RMFILTER_RMANDCONT;
1336 else
1337 return RMFILTER_KEEPANDCONT;
1338}
1339
1340static int
1341test_simplerm( filt *flt, void *data, char colour) {
1342 if( !strcmp( flt->text, (char*)data))
1343 return test_clear(flt, NULL, colour);
1344 else
1345 return RMFILTER_KEEPANDCONT;
1346}
1347
1348static int
1349test_numericrm( filt *flt, void *data, char colour) {
1350 if( flt->id == (long)data)
1351 return test_clear(flt, NULL, colour);
1352 else
1353 return RMFILTER_KEEPANDCONT;
1354}
1355
1356/* clears filter list */
1357void
1358clearfilters( char colour ) {
1359 flushout( );
1360 if( removefromfilterlist( test_clear, NULL, colour ) ) {
1361 /* There actually WERE items removed */
1362 filtertype = analyzefilters( );
1363 } else {
1364 writeout(" No matches on filter list. ");
1365 }
1366 showout();
1367}
1368
1369/* removes filter pattern */
1370void
1371removefilter( unsigned char *tail ) {
1372 int rmv = 0, val;
1373 unsigned char* end;
1374
1375 flushout( );
1376
1377 rmv = removefromfilterlist( test_simplerm, (void *)tail, 0 );
1378 if(!rmv) {
1379 val = strtol((char*)tail, (char **)&end, 10);
1380 if( (tail != end) && (!*end) )
1381 rmv = removefromfilterlist( test_numericrm, (void *)val, 0);
1382 }
1383
1384 if( rmv ) {
1385 /* There actually WERE items removed */
1386 filtertype = analyzefilters( );
1387 } else {
1388 snprintf( tmpstr, TMPSTRSIZE, " Not on filter list: %s ", tail);
1389 writeout( tmpstr );
1390 }
1391 showout();
1392}
1393
1394static unsigned int uniqueidpool = 1;
1395
1396/* returns unique id for filter pattern or 0 for failure */
1397unsigned int
1398addfilter( char colour, unsigned char *regex ) {
1399 filt *newflt = malloc( sizeof(filt)), **flt = &filterlist;
1400
1401 if( !newflt ) return 0;
1402 flushout( );
1403
1404 /* check colour validity */
1405 if( !check_valid_colour( colour ) ){
1406 free( newflt );
1407 writeout( " Not a valid colour code. " );
1408 showout( );
1409 return 0;
1410 }
1411
1412 if( regcomp( &newflt->regex, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE) ) {
1413 /* couldn't compile regex ... print error, return */
1414 free( newflt );
1415
1416 snprintf( tmpstr, TMPSTRSIZE, " %s ", regex);
1417 writeout( " Bad regular expression: ");
1418 writeout( tmpstr );
1419 showout( );
1420 return 0;
1421 } else {
1422 int len = strlen(regex) + 1;
1423 /* grab id from ID pool an increase free ID counter */
1424 newflt->id = uniqueidpool++;
1425 newflt->colour = colour;
1426 newflt->next = NULL;
1427 /* take a copy of plain regex text for later identification by user */
1428 newflt->text = malloc( len );
1429 memcpy( newflt->text, regex, len );
1430 }
1431
1432 /* append new filter to filterlist */
1433 while( *flt ) flt=&((*flt)->next);
1434 *flt = newflt;
1435
1436 filtertype = analyzefilters( );
1437
1438 if ( colour == '-' ) {
1439 snprintf( tmpstr, TMPSTRSIZE, " \"%s\" successfully added to ignorance list. ( ID = %d). ", (*flt)->text, (*flt)->id);
1440 } else if( colour == '+' ) {
1441 snprintf( tmpstr, TMPSTRSIZE, " \"%s\" successfully added to zoom list. ( ID = %d). ", (*flt)->text, (*flt)->id);
1442 } else {
1443 snprintf( tmpstr, TMPSTRSIZE, " \"%s\" successfully added to hilitelist. (ID = %d). ", (*flt)->text, (*flt)->id);
1444 }
1445 writeout(tmpstr );
1446 showout( );
1447
1448 return newflt->id;
1449}
1450
1451void
1452listfilters( void ) {
1453 filt *flt = filterlist;
1454 int shownhi = 0, shownign = 0, shownzoom = 0;
1455
1456 flushout( );
1457
1458 while( flt ) {
1459 if( (flt->colour != '-') && (flt->colour != '+')) {
1460 if(!shownhi) {
1461 writeout(" Your hilites:");
1462 shownhi = 1;
1463 }
1464 snprintf( tmpstr, TMPSTRSIZE, " ID: [% 3d] Color: [%c] Regex: [%s]", flt->id, flt->colour, flt->text);
1465 writeout( tmpstr );
1466 }
1467 flt = flt->next;
1468 }
1469
1470 flt = filterlist;
1471
1472 while( flt ) {
1473 if( flt->colour == '-') {
1474 if(!shownign) {
1475 if(shownhi) writeout(" ");
1476 writeout(" You do ignore:");
1477 shownign = 1;
1478 }
1479 snprintf( tmpstr, TMPSTRSIZE, " ID: [% 3d] Regex: [%s]", flt->id, flt->text);
1480 writeout( tmpstr );
1481 }
1482 flt = flt->next;
1483 }
1484
1485 flt = filterlist;
1486
1487 while( flt ) {
1488 if( flt->colour == '+') {
1489 if(!shownzoom) {
1490 if(shownhi || shownign) writeout(" ");
1491 writeout(" On your whitelist:");
1492 shownzoom = 1;
1493 }
1494 snprintf( tmpstr, TMPSTRSIZE, " ID: [% 3d] Regex: [%s]", flt->id, flt->text);
1495 writeout( tmpstr );
1496 }
1497 flt = flt->next;
1498 }
1499
1500 if( !shownign && !shownhi && !shownzoom) {
1501 writeout(" No entries on your filter list. ");
1502 }
1503 showout();
1504}