Remove constant conditionals (dead-code).
[asterisk/asterisk.git] / main / term.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2010, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Terminal Routines
22  *
23  * \author Mark Spencer <markster@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/_private.h"
33 #include <sys/time.h>
34 #include <signal.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37
38 #include "asterisk/term.h"
39 #include "asterisk/lock.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/threadstorage.h"
42
43 static int vt100compat;
44
45 static char enddata[80] = "";
46 static char quitdata[80] = "";
47
48 static const char * const termpath[] = {
49         "/usr/share/terminfo",
50         "/usr/local/share/misc/terminfo",
51         "/usr/lib/terminfo",
52         NULL
53         };
54
55 AST_THREADSTORAGE(commonbuf);
56
57 struct commonbuf {
58         short which;
59         char buffer[AST_TERM_MAX_ROTATING_BUFFERS][AST_TERM_MAX_ESCAPE_CHARS];
60 };
61
62 static int opposite(int color)
63 {
64         int lookup[] = {
65                 /* BLACK */ COLOR_BLACK,
66                 /* RED */ COLOR_MAGENTA,
67                 /* GREEN */ COLOR_GREEN,
68                 /* BROWN */ COLOR_BROWN,
69                 /* BLUE */ COLOR_CYAN,
70                 /* MAGENTA */ COLOR_RED,
71                 /* CYAN */ COLOR_BLUE,
72                 /* WHITE */ COLOR_BLACK };
73         return color ? lookup[color - 30] : 0;
74 }
75
76 /* Ripped off from Ross Ridge, but it's public domain code (libmytinfo) */
77 static short convshort(char *s)
78 {
79         register int a, b;
80
81         a = (int) s[0] & 0377;
82         b = (int) s[1] & 0377;
83
84         if (a == 0377 && b == 0377)
85                 return -1;
86         if (a == 0376 && b == 0377)
87                 return -2;
88
89         return a + b * 256;
90 }
91
92 int ast_term_init(void)
93 {
94         char *term = getenv("TERM");
95         char termfile[256] = "";
96         char buffer[512] = "";
97         int termfd = -1, parseokay = 0, i;
98
99         if (ast_opt_no_color) {
100                 return 0;
101         }
102
103         if (!ast_opt_console) {
104                 /* If any remote console is not compatible, we'll strip the color codes at that point */
105                 vt100compat = 1;
106                 goto end;
107         }
108
109         if (!term) {
110                 return 0;
111         }
112
113         for (i = 0;; i++) {
114                 if (termpath[i] == NULL) {
115                         break;
116                 }
117                 snprintf(termfile, sizeof(termfile), "%s/%c/%s", termpath[i], *term, term);
118                 termfd = open(termfile, O_RDONLY);
119                 if (termfd > -1) {
120                         break;
121                 }
122         }
123         if (termfd > -1) {
124                 int actsize = read(termfd, buffer, sizeof(buffer) - 1);
125                 short sz_names = convshort(buffer + 2);
126                 short sz_bools = convshort(buffer + 4);
127                 short n_nums   = convshort(buffer + 6);
128
129                 /* if ((sz_names + sz_bools) & 1)
130                         sz_bools++; */
131
132                 if (sz_names + sz_bools + n_nums < actsize) {
133                         /* Offset 13 is defined in /usr/include/term.h, though we do not
134                          * include it here, as it conflicts with include/asterisk/term.h */
135                         short max_colors = convshort(buffer + 12 + sz_names + sz_bools + 13 * 2);
136                         if (max_colors > 0) {
137                                 vt100compat = 1;
138                         }
139                         parseokay = 1;
140                 }
141                 close(termfd);
142         }
143
144         if (!parseokay) {
145                 /* These comparisons should not be substrings nor case-insensitive, as
146                  * terminal types are very particular about how they treat suffixes and
147                  * capitalization.  For example, terminal type 'linux-m' does NOT
148                  * support color, while 'linux' does.  Not even all vt100* terminals
149                  * support color, either (e.g. 'vt100+fnkeys'). */
150                 if (!strcmp(term, "linux")) {
151                         vt100compat = 1;
152                 } else if (!strcmp(term, "xterm")) {
153                         vt100compat = 1;
154                 } else if (!strcmp(term, "xterm-color")) {
155                         vt100compat = 1;
156                 } else if (!strcmp(term, "xterm-256color")) {
157                         vt100compat = 1;
158                 } else if (!strncmp(term, "Eterm", 5)) {
159                         /* Both entries which start with Eterm support color */
160                         vt100compat = 1;
161                 } else if (!strcmp(term, "vt100")) {
162                         vt100compat = 1;
163                 } else if (!strncmp(term, "crt", 3)) {
164                         /* Both crt terminals support color */
165                         vt100compat = 1;
166                 }
167         }
168
169 end:
170         if (vt100compat) {
171                 /* Make commands show up in nice colors */
172                 if (ast_opt_light_background) {
173                         snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, COLOR_BLACK);
174                 } else if (ast_opt_force_black_background) {
175                         snprintf(enddata, sizeof(enddata), "%c[%d;%d;%dm", ESC, ATTR_RESET, COLOR_WHITE, COLOR_BLACK + 10);
176                 } else {
177                         snprintf(enddata, sizeof(enddata), "%c[%dm", ESC, ATTR_RESET);
178                 }
179                 snprintf(quitdata, sizeof(quitdata), "%c[%dm", ESC, ATTR_RESET);
180         }
181         return 0;
182 }
183
184 char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
185 {
186         int attr = 0;
187
188         if (!vt100compat) {
189                 ast_copy_string(outbuf, inbuf, maxout);
190                 return outbuf;
191         }
192         if (!fgcolor) {
193                 ast_copy_string(outbuf, inbuf, maxout);
194                 return outbuf;
195         }
196
197         if (fgcolor & 128) {
198                 attr = ast_opt_light_background ? 0 : ATTR_BRIGHT;
199                 fgcolor &= ~128;
200         }
201
202         if (bgcolor) {
203                 bgcolor &= ~128;
204         }
205
206         if (ast_opt_light_background) {
207                 fgcolor = opposite(fgcolor);
208         }
209
210         if (ast_opt_force_black_background) {
211                 if (!bgcolor) {
212                         bgcolor = COLOR_BLACK;
213                 }
214                 snprintf(outbuf, maxout, "%c[%d;%d;%dm%s%s", ESC, attr, fgcolor, bgcolor + 10, inbuf, term_end());
215         } else {
216                 snprintf(outbuf, maxout, "%c[%d;%dm%s%s", ESC, attr, fgcolor, inbuf, term_end());
217         }
218         return outbuf;
219 }
220
221 static void check_fgcolor(int *fgcolor, int *attr)
222 {
223         *attr = ast_opt_light_background ? 0 : ATTR_BRIGHT;
224         if (*fgcolor & 128) {
225                 *fgcolor &= ~128;
226         }
227
228         if (ast_opt_light_background) {
229                 *fgcolor = opposite(*fgcolor);
230         }
231 }
232
233 static void check_bgcolor(int *bgcolor)
234 {
235         if (*bgcolor) {
236                 *bgcolor &= ~128;
237         }
238 }
239
240 static int check_colors_allowed(void)
241 {
242         return vt100compat;
243 }
244
245 int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor)
246 {
247         int attr = 0;
248
249         if (!check_colors_allowed()) {
250                 return -1;
251         }
252
253         check_fgcolor(&fgcolor, &attr);
254         check_bgcolor(&bgcolor);
255
256         if (ast_opt_force_black_background) {
257                 ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
258         } else if (bgcolor) {
259                 ast_str_append(str, 0, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10);
260         } else {
261                 ast_str_append(str, 0, "%c[%d;%dm", ESC, attr, fgcolor);
262         }
263
264         return 0;
265 }
266
267 char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
268 {
269         int attr = 0;
270
271         if (!check_colors_allowed()) {
272                 *outbuf = '\0';
273                 return outbuf;
274         }
275
276         check_fgcolor(&fgcolor, &attr);
277         check_bgcolor(&bgcolor);
278
279         if (ast_opt_force_black_background) {
280                 snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, COLOR_BLACK + 10);
281         } else if (bgcolor) {
282                 snprintf(outbuf, maxout, "%c[%d;%d;%dm", ESC, attr, fgcolor, bgcolor + 10);
283         } else {
284                 snprintf(outbuf, maxout, "%c[%d;%dm", ESC, attr, fgcolor);
285         }
286
287         return outbuf;
288 }
289
290 const char *ast_term_color(int fgcolor, int bgcolor)
291 {
292         struct commonbuf *cb = ast_threadstorage_get(&commonbuf, sizeof(*cb));
293         char *buf;
294
295         if (!cb) {
296                 return "";
297         }
298         buf = cb->buffer[cb->which++];
299         if (cb->which == AST_TERM_MAX_ROTATING_BUFFERS) {
300                 cb->which = 0;
301         }
302
303         return term_color_code(buf, fgcolor, bgcolor, AST_TERM_MAX_ESCAPE_CHARS);
304 }
305
306 const char *ast_term_reset(void)
307 {
308         return term_end();
309 }
310
311 char *term_strip(char *outbuf, const char *inbuf, int maxout)
312 {
313         char *outbuf_ptr = outbuf;
314         const char *inbuf_ptr = inbuf;
315
316         while (outbuf_ptr < outbuf + maxout) {
317                 switch (*inbuf_ptr) {
318                         case ESC:
319                                 while (*inbuf_ptr && (*inbuf_ptr != 'm'))
320                                         inbuf_ptr++;
321                                 break;
322                         default:
323                                 *outbuf_ptr = *inbuf_ptr;
324                                 outbuf_ptr++;
325                 }
326                 if (! *inbuf_ptr)
327                         break;
328                 inbuf_ptr++;
329         }
330         return outbuf;
331 }
332
333 /* filter escape sequences */
334 void term_filter_escapes(char *line)
335 {
336         int i;
337         int len = strlen(line);
338
339         for (i = 0; i < len; i++) {
340                 if (line[i] != ESC)
341                         continue;
342                 if ((i < (len - 2)) &&
343                     (line[i + 1] == 0x5B)) {
344                         switch (line[i + 2]) {
345                         case 0x30:
346                         case 0x31:
347                         case 0x33:
348                                 continue;
349                         }
350                 }
351                 /* replace ESC with a space */
352                 line[i] = ' ';
353         }
354 }
355
356 const char *term_end(void)
357 {
358         return enddata;
359 }
360
361 const char *term_quit(void)
362 {
363         return quitdata;
364 }