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