5283431c3586698f2164976fb82ce2ed4b46d2cd
[citadel.git] / citadel / textclient / screen.c
1 /*
2  * Screen output handling
3  *
4  * Copyright (c) 1987-2011 by the citadel.org team
5  *
6  * This program is open source software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20
21
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <ctype.h>
29 #include <sys/types.h>
30 #include "sysdep.h"
31 #ifndef HAVE_SNPRINTF
32 #include "snprintf.h"
33 #endif
34 #include <libcitadel.h>
35 #include "citadel.h"
36 #include "citadel_ipc.h"
37 #include "citadel_decls.h"
38 #include "commands.h"
39 #include "screen.h"
40
41 int enable_status_line = 0;
42 char status_line[1024] = "     ";
43
44 /* the default paginator prompt will be replaced by the server's prompt when we learn it */
45 char *moreprompt = " -- more -- ";
46
47 extern int screenheight;
48 extern int screenwidth;
49 int lines_printed = 0;
50 int cols_printed = 0;
51
52 extern int rc_ansi_color;
53 extern int rc_prompt_control;
54 extern void check_screen_dims(void);
55
56 void do_keepalive(void);
57
58 /*
59  * Initialize the screen
60  */
61 void screen_new(void)
62 {
63         send_ansi_detect();
64         look_for_ansi();
65         cls(0);
66         color(DIM_WHITE);
67 }
68
69
70
71 /*
72  * Beep.
73  */
74 void ctdl_beep(void) {
75         putc(7, stdout);
76 }
77         
78
79
80
81 /*
82  * scr_printf() outputs to the terminal
83  */
84 int scr_printf(char *fmt, ...)
85 {
86         static char outbuf[4096];       /* static for performance -- not re-entrant -- change if needed */
87         va_list ap;
88         register int retval;
89         int i, len;
90
91         va_start(ap, fmt);
92         retval = vsnprintf(outbuf, sizeof outbuf, fmt, ap);
93         va_end(ap);
94
95         len = strlen(outbuf);
96         for (i=0; i<len; ++i) {
97                 scr_putc(outbuf[i]);
98         }
99         return retval;
100 }
101
102
103 /*
104  * Read one character from the terminal
105  */
106 int scr_getc(int delay)
107 {
108         unsigned char buf;
109
110         scr_flush();
111
112         buf = '\0';
113         if (!read (0, &buf, 1))
114                 logoff(NULL, 3);
115
116         lines_printed = 0;
117         return buf;
118 }
119
120 /*
121  * Issue the paginator prompt (more / hit any key to continue)
122  */
123 void hit_any_key(void) {
124         int a, b;
125
126         color(COLOR_PUSH);
127         color(DIM_RED);
128         scr_printf("%s\r", moreprompt);
129         color(COLOR_POP);
130         b=inkey();
131         for (a=0; a<screenwidth; ++a) {
132                 scr_putc(' ');
133         }
134         scr_printf("\r");
135
136         if ( (rc_prompt_control == 1) || ((rc_prompt_control == 3) && (userflags & US_PROMPTCTL)) ) {
137                 if (b == 'q' || b == 'Q' || b == 's' || b == 'S') {
138                         b = STOP_KEY;
139                 }
140                 if (b == 'n' || b == 'N') {
141                         b = NEXT_KEY;
142                 }
143         }
144
145         if (b==NEXT_KEY) sigcaught = SIGINT;
146         if (b==STOP_KEY) sigcaught = SIGQUIT;
147 }
148
149
150 /*
151  * Output one character to the terminal
152  */
153 int scr_putc(int c)
154 {
155         /* handle tabs normally */
156         if (c == '\t') {
157                 do {
158                         scr_putc(' ');
159                 } while ((cols_printed % 8) != 0);
160                 return(c);
161         }
162
163         /* Output the character... */
164         if (putc(c, stdout) == EOF) {
165                 logoff(NULL, 3);
166         }
167
168         if (c == '\n') {
169                 ++lines_printed;
170                 cols_printed = 0;
171         }
172         else if (c == '\r') {
173                 cols_printed = 0;
174         }
175         else if (isprint(c)) {
176                 ++cols_printed;
177                 if ((screenwidth > 0) && (cols_printed > screenwidth)) {
178                         ++lines_printed;
179                         cols_printed = 0;
180                 }
181         }
182
183         /* How many lines output before stopping for the paginator?
184          * Depends on whether we are displaying a status line.
185          */
186         int height_offset = ( ((enable_color) && (screenwidth > 0) && (enable_status_line)) ? (3) : (2) ) ;
187
188         /* Ok, go check it.  Stop and display the paginator prompt if necessary. */
189         if ((screenheight > 0) && (lines_printed > (screenheight-height_offset))) {
190                 lines_printed = 0;
191                 hit_any_key();
192                 lines_printed = 0;
193                 cols_printed = 0;
194         }
195
196         return c;
197 }
198
199 void scr_flush(void)
200 {
201         if ((enable_color) && (screenwidth > 0) && (enable_status_line)) {
202                 if (strlen(status_line) < screenwidth) {
203                         memset(&status_line[strlen(status_line)], 32, screenwidth - strlen(status_line));
204                 }
205                 printf("\033[s\033[1;1H\033[K\033[7m");
206                 fwrite(status_line, screenwidth, 1, stdout);
207                 printf("\033[27m\033[u");
208         }
209         fflush(stdout);
210 }
211
212
213 static volatile int caught_sigwinch = 0;
214
215
216 /*
217  * scr_winch() handles window size changes from SIGWINCH
218  * resizes all our windows for us
219  */
220 RETSIGTYPE scr_winch(int signum)
221 {
222         /* if we receive this signal, we must be running
223          * in a terminal that supports resizing.
224          */
225         have_xterm = 1;
226         caught_sigwinch = 1;
227         check_screen_dims();
228         signal(SIGWINCH, scr_winch);
229 }
230
231
232
233 /*
234  * Display a 3270-style "wait" indicator at the bottom of the screen
235  */
236 void scr_wait_indicator(int state) {
237         int sp = (screenwidth - 2);
238
239         if (!enable_status_line) return;
240
241         if (screenwidth > 0) {
242                 switch (state) {
243                         default:
244                         case 0:  /* Idle */
245                                 status_line[sp] = ' ';
246                                 break;
247                         case 1:  /* Waiting */
248                                 status_line[sp] = 'X';
249                                 break;
250                         case 2:  /* Receiving */
251                                 status_line[sp] = '<';
252                                 break;
253                         case 3:  /* Sending */
254                                 status_line[sp] = '>';
255                                 break;
256                 }
257                 scr_flush();
258         }
259 }
260