]> code.citadel.org Git - citadel.git/blob - citadel/screen.c
* oops...also close the client on EOF/error on tty OUTPUT
[citadel.git] / citadel / screen.c
1 /* $Id$ */
2
3 /*
4  * Handle full-screen curses stuff
5  */
6
7 #include "sysdep.h"
8 #include "screen.h"
9 #include <stdio.h>
10 #include <signal.h>
11 #include <string.h>
12 #include <stdarg.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #ifdef HAVE_VW_PRINTW
16 #define _vwprintw vw_printw
17 #else
18 /* SYSV style curses (Solaris, etc.) */
19 #define _vwprintw vwprintw
20 #endif
21 #ifndef HAVE_SNPRINTF
22 #include "snprintf.h"
23 #endif
24 #include "citadel.h"
25 #include "citadel_ipc.h"
26 #include "citadel_decls.h"
27 #include "commands.h"
28
29 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
30 static SCREEN *myscreen = NULL;
31 static WINDOW *mainwindow = NULL;
32 static WINDOW *statuswindow = NULL;
33
34 char rc_screen;
35 char arg_screen;
36 #endif
37
38 extern int screenheight;
39 extern int screenwidth;
40 extern int rc_ansi_color;
41 extern void check_screen_dims(void);
42
43 void do_keepalive(void);
44
45
46 int is_curses_enabled(void) {
47 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
48         return mainwindow != NULL;
49 #else
50         return 0;
51 #endif
52 }
53
54 /*
55  * status_line() is a convenience function for writing a "typical"
56  * status line to the window.
57  */
58 void status_line(const char *humannode, const char *bbs_city,
59                  const char *room_name, int secure, int newmailcount)
60 {
61 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
62         if (statuswindow) {
63                 if (secure) {
64                         sln_printf("Encrypted ");
65                         waddch(statuswindow, ACS_VLINE);
66                         waddch(statuswindow, ' ');
67                 }
68                 if (room_name)
69                         sln_printf("%s on ", room_name);
70                 if (humannode)
71                         sln_printf("%s ", humannode);
72                 if (newmailcount > 0) {
73                         waddch(statuswindow, ACS_VLINE);
74                         sln_printf(" %d new mail ", newmailcount);
75                 }
76                 sln_printf("\n");
77         }
78 #endif /* HAVE_CURSES_H */
79 }
80
81
82 /*
83  * Display a 3270-style "wait" indicator at the bottom of the screen
84  */
85 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
86 void wait_indicator(int state) {
87
88         if (!isendwin() && statuswindow) {
89
90                 mvwinch(statuswindow, 0, screenwidth - 2);
91                 switch (state) {
92                 default:
93                 case 0:         /* Idle */
94                         waddch(statuswindow, ' ');
95                         break;
96                 case 1:         /* Waiting */
97                         waddch(statuswindow, 'X');
98                         break;
99                 case 2:         /* Receiving */
100                         waddch(statuswindow, '<');
101                         break;
102                 case 3:         /* Sending */
103                         waddch(statuswindow, '>');
104                         break;
105                 }
106                 waddch(statuswindow, '\r');
107                 wrefresh(statuswindow);
108                 wrefresh(mainwindow);   /* this puts the cursor back */
109         }
110 }
111 #endif
112
113
114 /*
115  * Initialize the screen.  If newterm() fails, myscreen will be NULL and
116  * further handlers will assume we should be in line mode.
117  */
118 void screen_new(void)
119 {
120 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
121         if (arg_screen != RC_NO && rc_screen != RC_NO)
122                 myscreen = newterm(NULL, stdout, stdin);
123         if (myscreen) {
124                 cbreak();
125                 noecho();
126                 nonl();
127                 intrflush(stdscr, FALSE);
128                 keypad(stdscr, TRUE);
129                 /* Setup all our colors */
130                 start_color();
131                 if (rc_ansi_color)
132                         enable_color = 1;
133                 /*init_pair(DIM_BLACK, COLOR_BLACK, COLOR_BLACK);*/
134                 init_pair(DIM_RED, COLOR_RED, COLOR_BLACK);
135                 init_pair(DIM_GREEN, COLOR_GREEN, COLOR_BLACK);
136                 init_pair(DIM_YELLOW, COLOR_YELLOW, COLOR_BLACK);
137                 init_pair(DIM_BLUE, COLOR_BLUE, COLOR_BLACK);
138                 init_pair(DIM_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
139                 init_pair(DIM_CYAN, COLOR_CYAN, COLOR_BLACK);
140                 init_pair(DIM_WHITE, COLOR_WHITE, COLOR_BLACK);
141
142                 if (COLOR_PAIRS > 8)
143                         init_pair(8, COLOR_WHITE, COLOR_BLUE);
144         } else
145 #endif /* HAVE_CURSES_H */
146         {
147                 send_ansi_detect();
148                 look_for_ansi();
149                 cls(0);
150                 color(DIM_WHITE);
151         }
152         screen_set();
153         windows_new();
154 }
155
156
157 /*
158  * Kill the screen completely (used at exit).  It is safe to call this
159  * function more than once.
160  */
161 void screen_delete(void)
162 {
163         windows_delete();
164         screen_reset();
165 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
166         if (myscreen) {
167                 delscreen(myscreen);
168         }
169         myscreen = NULL;
170 #endif
171 }
172
173 /*
174  * Beep.
175  */
176 void ctdl_beep(void) {
177 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
178         if (myscreen)
179                 beep();
180         else
181 #endif
182         putc(7, stdout);
183 }
184         
185
186
187 /*
188  * Set screen/IO parameters, e.g. at start of program or return from external
189  * program run.
190  */
191 int screen_set(void)
192 {
193 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
194         if (myscreen) {
195                 set_term(myscreen);
196                 wrefresh(curscr);
197                 return 1;
198         }
199 #endif /* HAVE_CURSES_H */
200         return 0;
201 }
202
203
204 /*
205  * Reset screen/IO parameters, e.g. at exit or fork of external program.
206  */
207 int screen_reset(void)
208 {
209 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
210         if (myscreen) {
211                 if (!isendwin()) endwin();
212                 return 1;
213         }
214 #endif /* HAVE_CURSES_H */
215         return 0;
216 }
217
218
219 /*
220  * scr_printf() outputs to the main window (or screen if not in curses)
221  */
222 int scr_printf(char *fmt, ...)
223 {
224         va_list ap;
225         register int retval;
226
227         va_start(ap, fmt);
228 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
229         if (mainwindow) {
230                 retval = _vwprintw(mainwindow, fmt, ap);
231         } else
232 #endif
233                 retval = vprintf(fmt, ap);
234         va_end(ap);
235         return retval;
236 }
237
238
239 /*
240  * err_printf() outputs to error status window (or stderr if not in curses)
241  */
242 int err_printf(char *fmt, ...)
243 {
244         va_list ap;
245         register int retval;
246
247         va_start(ap, fmt);
248 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
249         if (mainwindow) {               /* FIXME: direct to error window */
250                 retval = _vwprintw(mainwindow, fmt, ap);
251                 if (fmt[strlen(fmt) - 1] == '\n')
252                         wrefresh(mainwindow);
253         } else
254 #endif
255                 retval = vfprintf(stderr, fmt, ap);
256         va_end(ap);
257         return retval;
258 }
259
260
261 /*
262  * sln_printf() outputs to error status window (or stderr if not in curses)
263  */
264 int sln_printf(char *fmt, ...)
265 {
266         va_list ap;
267         register int retval;
268 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
269         static char buf[4096];
270 #endif
271
272         va_start(ap, fmt);
273 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
274         if (statuswindow) {
275                 register char *i;
276                 
277                 retval = vsnprintf(buf, 4096, fmt, ap);
278                 for (i = buf; *i; i++) {
279                         if (*i == '\r' || *i == '\n')
280                                 wclrtoeol(statuswindow);
281                         sln_putc(*i);
282                         if (*i == '\r' || *i == '\n') {
283                                 wrefresh(statuswindow);
284                                 mvwinch(statuswindow, 0, 0);
285                         }
286                 }
287         } else
288 #endif
289                 retval = vprintf(fmt, ap);
290         va_end(ap);
291         return retval;
292 }
293
294
295 /*
296  * sln_printf_if() outputs to status window, no output if not in curses
297  */
298 int sln_printf_if(char *fmt, ...)
299 {
300         register int retval = 1;
301 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
302         static char buf[4096];
303         va_list ap;
304
305         va_start(ap, fmt);
306         if (statuswindow) {
307                 register char *i;
308                 
309                 retval = vsnprintf(buf, 4096, fmt, ap);
310                 for (i = buf; *i; i++) {
311                         if (*i == '\r' || *i == '\n')
312                                 wclrtoeol(statuswindow);
313                         sln_putc(*i);
314                         if (*i == '\r' || *i == '\n') {
315                                 wrefresh(statuswindow);
316                                 mvwinch(statuswindow, 0, 0);
317                         }
318                 }
319         }
320         va_end(ap);
321 #endif
322         return retval;
323 }
324
325
326 int scr_getc(int delay)
327 {
328   unsigned char buf;
329
330 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
331         if (mainwindow) {
332                 wtimeout(mainwindow, delay);
333                 return wgetch(mainwindow);
334         }
335 #endif
336
337         buf = '\0';
338         if (!read (0, &buf, 1))
339                 logoff(NULL, 3);
340         return buf;
341 }
342
343 /* the following is unused and looks broken, but there may
344    be some input problems still lurking in curses mode, so
345    i'll leave it blocked out for now for informational
346    purposes. */
347 #if 0
348 int scr_blockread(void)
349   {
350     int a = 0;
351 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
352     wtimeout(mainwindow, S_KEEPALIVE); 
353     while (1)
354       {
355         do_keepalive();
356         a = wgetch(mainwindow); /* will block for food */
357         if (a != ERR)
358           break;
359         /* a = scr_getc(); */
360       }
361 #endif
362     return a;
363   }
364 #endif /* 0 */
365
366 /*
367  * scr_putc() outputs a single character
368  */
369 int scr_putc(int c)
370 {
371 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
372         if (mainwindow) {
373                 if (c == 7) beep();
374                 if (waddch(mainwindow, c) != OK)
375                         logoff(NULL, 3);
376                 return c;
377         }
378 #endif
379         if (putc(c, stdout) == EOF)
380                 logoff(NULL, 3);
381         return c;
382 }
383
384
385 int sln_putc(int c)
386 {
387 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
388         if (statuswindow)
389                 return ((waddch(statuswindow, c) == OK) ? c : EOF);
390 #endif
391         return putc(c, stdout);
392 }
393
394
395 int sln_putc_if(int c)
396 {
397 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
398         if (statuswindow)
399                 return ((waddch(statuswindow, c) == OK) ? c : EOF);
400 #endif
401         return 1;
402 }
403
404
405 /*
406  * scr_color() sets the window color for mainwindow
407  */
408 int scr_color(int colornum)
409 {
410 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
411         if (mainwindow) {
412 #ifdef HAVE_WCOLOR_SET
413                 wcolor_set(mainwindow, (colornum & 7), NULL);
414 #else
415                 wattron(mainwindow, COLOR_PAIR((colornum & 7)));
416 #endif
417                 if (colornum & 8) {
418                         wattron(mainwindow, A_BOLD);
419                 } else {
420                         wattroff(mainwindow, A_BOLD);
421                 }
422                 return 1;
423         }
424 #endif
425         return 0;
426 }
427
428
429 void scr_flush(void)
430 {
431 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
432         if (mainwindow)
433                 wrefresh(mainwindow);
434         else
435 #endif
436                 fflush(stdout);
437 }
438
439
440 void err_flush(void)
441 {
442 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
443         if (mainwindow)         /* FIXME: error status window needed */
444                 wrefresh(mainwindow);
445         else
446 #endif
447                 fflush(stderr);
448 }
449
450
451 void sln_flush(void)
452 {
453 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
454         if (statuswindow)
455                 wrefresh(statuswindow);
456         else
457 #endif
458                 fflush(stdout);
459 }
460
461 static volatile int caught_sigwinch = 0;
462
463 /*
464  * this is not supposed to be called from a signal handler.
465  */
466 int scr_set_windowsize()
467 {
468 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
469         if (mainwindow && caught_sigwinch) {
470                 caught_sigwinch = 0;
471 #ifdef HAVE_RESIZETERM
472                 resizeterm(screenheight + 1, screenwidth);
473 #endif
474 #ifdef HAVE_WRESIZE
475                 wresize(mainwindow, screenheight, screenwidth);
476                 wresize(statuswindow, 1, screenwidth);
477 #endif
478                 mvwin(statuswindow, screenheight, 0);
479                 status_line(serv_info.serv_humannode, serv_info.serv_bbs_city,
480                             room_name, secure, -1);
481                 wnoutrefresh(mainwindow);
482                 wnoutrefresh(statuswindow);
483                 doupdate();
484                 return 1;
485         }
486 #endif /* HAVE_CURSES_H */
487         return 0;
488 }
489
490 /*
491  * scr_winch() handles window size changes from SIGWINCH
492  * resizes all our windows for us
493  */
494 RETSIGTYPE scr_winch(int signum)
495 {
496         /* if we receive this signal, we must be running
497            in a terminal that supports resizing. */
498         have_xterm = 1;
499         caught_sigwinch = 1;
500         check_screen_dims();
501         signal(SIGWINCH, scr_winch);
502 }
503
504
505 /*
506  * Initialize the window(s) we will be using.
507  */
508 void windows_new(void)
509 {
510 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
511         register int x, y;
512
513         if (myscreen) {
514                 getmaxyx(stdscr, y, x);
515                 mainwindow = newwin(y - 1, x, 0, 0);
516                 screenwidth = x;
517                 screenheight = y - 1;
518                 immedok(mainwindow, FALSE);
519                 leaveok(mainwindow, FALSE);
520                 scrollok(mainwindow, TRUE);
521                 statuswindow = newwin(1, x, y - 1, 0);
522
523                 if (COLOR_PAIRS > 8)
524                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(8));
525                 else
526                         wbkgdset(statuswindow, ' ' | COLOR_PAIR(DIM_WHITE));
527
528                 werase(statuswindow);
529                 immedok(statuswindow, FALSE);
530                 leaveok(statuswindow, FALSE);
531                 scrollok(statuswindow, FALSE);
532                 wrefresh(statuswindow);
533         }
534 #else /* HAVE_CURSES_H */
535
536 #endif /* HAVE_CURSES_H */
537 }
538
539
540 /*
541  * Deinitialize the window(s) we were using (at exit).
542  */
543 void windows_delete(void)
544 {
545 #if defined(HAVE_CURSES_H) && !defined(DISABLE_CURSES)
546         if (mainwindow)
547                 delwin(mainwindow);
548         mainwindow = NULL;
549         if (statuswindow)
550                 delwin(statuswindow);
551         statuswindow = NULL;
552 #else /* HAVE_CURSES_H */
553
554 #endif /* HAVE_CURSES_H */
555 }