start sorting out the duplicated code in the privacy handler
[asterisk/asterisk.git] / 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 <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/time.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36
37 #include "asterisk.h"
38
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40
41 #include "asterisk/term.h"
42 #include "asterisk/options.h"
43 #include "asterisk/lock.h"
44 #include "asterisk/utils.h"
45
46 static int vt100compat = 0;
47
48 static char prepdata[80] = "";
49 static char enddata[80] = "";
50 static char quitdata[80] = "";
51
52 static const char *termpath[] = {
53         "/usr/share/terminfo",
54         "/usr/local/share/misc/terminfo",
55         "/usr/lib/terminfo",
56         NULL
57         };
58
59 /* Ripped off from Ross Ridge, but it's public domain code (libmytinfo) */
60 static short convshort(char *s)
61 {
62         register int a,b;
63
64         a = (int) s[0] & 0377;
65         b = (int) s[1] & 0377;
66
67         if (a == 0377 && b == 0377)
68                 return -1;
69         if (a == 0376 && b == 0377)
70                 return -2;
71
72         return a + b * 256;
73 }
74
75 int term_init(void)
76 {
77         char *term = getenv("TERM");
78         char termfile[256] = "";
79         char buffer[512] = "";
80         int termfd = -1, parseokay = 0, i;
81
82         if (!term)
83                 return 0;
84         if (!ast_opt_console || ast_opt_no_color || !ast_opt_no_fork)
85                 return 0;
86
87         for (i=0 ;; i++) {
88                 if (termpath[i] == NULL) {
89                         break;
90                 }
91                 snprintf(termfile, sizeof(termfile), "%s/%c/%s", termpath[i], *term, term);
92                 termfd = open(termfile, O_RDONLY);
93                 if (termfd > -1) {
94                         break;
95                 }
96         }
97         if (termfd > -1) {
98                 int actsize = read(termfd, buffer, sizeof(buffer) - 1);
99                 short sz_names = convshort(buffer + 2);
100                 short sz_bools = convshort(buffer + 4);
101                 short n_nums   = convshort(buffer + 6);
102
103                 /* if ((sz_names + sz_bools) & 1)
104                         sz_bools++; */
105
106                 if (sz_names + sz_bools + n_nums < actsize) {
107                         /* Offset 13 is defined in /usr/include/term.h, though we do not
108                          * include it here, as it conflicts with include/asterisk/term.h */
109                         short max_colors = convshort(buffer + 12 + sz_names + sz_bools + 13 * 2);
110                         if (max_colors > 0) {
111                                 vt100compat = 1;
112                         }
113                         parseokay = 1;
114                 }
115                 close(termfd);
116         }
117
118         if (!parseokay) {
119                 /* These comparisons should not be substrings nor case-insensitive, as
120                  * terminal types are very particular about how they treat suffixes and
121                  * capitalization.  For example, terminal type 'linux-m' does NOT
122                  * support color, while 'linux' does.  Not even all vt100* terminals
123                  * support color, either (e.g. 'vt100+fnkeys'). */
124                 if (!strcmp(term, "linux")) {
125                         vt100compat = 1;
126                 } else if (!strcmp(term, "xterm")) {
127                         vt100compat = 1;
128                 } else if (!strcmp(term, "xterm-color")) {
129                         vt100compat = 1;
130                 } else if (!strncmp(term, "Eterm", 5)) {
131                         /* Both entries which start with Eterm support color */
132                         vt100compat = 1;
133                 } else if (!strcmp(term, "vt100")) {
134                         vt100compat = 1;
135                 } else if (!strncmp(term, "crt", 3)) {
136                         /* Both crt terminals support color */
137                         vt100compat = 1;
138                 }
139         }
140
141         if (vt100compat) {
142                 /* Make commands show up in nice colors */
143                 snprintf(prepdata, sizeof(prepdata), "%c[%d;%d;%dm", ESC, ATTR_BRIGHT, COLOR_BROWN, COLOR_BLACK + 10);
144                 snprintf(enddata, sizeof(enddata), "%c[%d;%d;%dm", ESC, ATTR_RESET, COLOR_WHITE, COLOR_BLACK + 10);
145                 snprintf(quitdata, sizeof(quitdata), "%c[0m", ESC);
146         }
147         return 0;
148 }
149
150 char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
151 {
152         int attr=0;
153         char tmp[40];
154         if (!vt100compat) {
155                 ast_copy_string(outbuf, inbuf, maxout);
156                 return outbuf;
157         }
158         if (!fgcolor && !bgcolor) {
159                 ast_copy_string(outbuf, inbuf, maxout);
160                 return outbuf;
161         }
162         if ((fgcolor & 128) && (bgcolor & 128)) {
163                 /* Can't both be highlighted */
164                 ast_copy_string(outbuf, inbuf, maxout);
165                 return outbuf;
166         }
167         if (!bgcolor)
168                 bgcolor = COLOR_BLACK;
169
170         if (bgcolor) {
171                 bgcolor &= ~128;
172                 bgcolor += 10;
173         }
174         if (fgcolor & 128) {
175                 attr = ATTR_BRIGHT;
176                 fgcolor &= ~128;
177         }
178         if (fgcolor && bgcolor) {
179                 snprintf(tmp, sizeof(tmp), "%d;%d", fgcolor, bgcolor);
180         } else if (bgcolor) {
181                 snprintf(tmp, sizeof(tmp), "%d", bgcolor);
182         } else if (fgcolor) {
183                 snprintf(tmp, sizeof(tmp), "%d", fgcolor);
184         }
185         if (attr) {
186                 snprintf(outbuf, maxout, "%c[%d;%sm%s%c[0;%d;%dm", ESC, attr, tmp, inbuf, ESC, COLOR_WHITE, COLOR_BLACK + 10);
187         } else {
188                 snprintf(outbuf, maxout, "%c[%sm%s%c[0;%d;%dm", ESC, tmp, inbuf, ESC, COLOR_WHITE, COLOR_BLACK + 10);
189         }
190         return outbuf;
191 }
192
193 char *term_color_code(char *outbuf, int fgcolor, int bgcolor, int maxout)
194 {
195         int attr=0;
196         char tmp[40];
197         if ((!vt100compat) || (!fgcolor && !bgcolor)) {
198                 *outbuf = '\0';
199                 return outbuf;
200         }
201         if ((fgcolor & 128) && (bgcolor & 128)) {
202                 /* Can't both be highlighted */
203                 *outbuf = '\0';
204                 return outbuf;
205         }
206         if (!bgcolor)
207                 bgcolor = COLOR_BLACK;
208
209         if (bgcolor) {
210                 bgcolor &= ~128;
211                 bgcolor += 10;
212         }
213         if (fgcolor & 128) {
214                 attr = ATTR_BRIGHT;
215                 fgcolor &= ~128;
216         }
217         if (fgcolor && bgcolor) {
218                 snprintf(tmp, sizeof(tmp), "%d;%d", fgcolor, bgcolor);
219         } else if (bgcolor) {
220                 snprintf(tmp, sizeof(tmp), "%d", bgcolor);
221         } else if (fgcolor) {
222                 snprintf(tmp, sizeof(tmp), "%d", fgcolor);
223         }
224         if (attr) {
225                 snprintf(outbuf, maxout, "%c[%d;%sm", ESC, attr, tmp);
226         } else {
227                 snprintf(outbuf, maxout, "%c[%sm", ESC, tmp);
228         }
229         return outbuf;
230 }
231
232 char *term_strip(char *outbuf, char *inbuf, int maxout)
233 {
234         char *outbuf_ptr = outbuf, *inbuf_ptr = inbuf;
235
236         while (outbuf_ptr < outbuf + maxout) {
237                 switch (*inbuf_ptr) {
238                         case ESC:
239                                 while (*inbuf_ptr && (*inbuf_ptr != 'm'))
240                                         inbuf_ptr++;
241                                 break;
242                         default:
243                                 *outbuf_ptr = *inbuf_ptr;
244                                 outbuf_ptr++;
245                 }
246                 if (! *inbuf_ptr)
247                         break;
248                 inbuf_ptr++;
249         }
250         return outbuf;
251 }
252
253 char *term_prompt(char *outbuf, const char *inbuf, int maxout)
254 {
255         if (!vt100compat) {
256                 ast_copy_string(outbuf, inbuf, maxout);
257                 return outbuf;
258         }
259         snprintf(outbuf, maxout, "%c[%d;%d;%dm%c%c[%d;%d;%dm%s",
260                 ESC, ATTR_BRIGHT, COLOR_BLUE, COLOR_BLACK + 10,
261                 inbuf[0],
262                 ESC, 0, COLOR_WHITE, COLOR_BLACK + 10,
263                 inbuf + 1);
264         return outbuf;
265 }
266
267 char *term_prep(void)
268 {
269         return prepdata;
270 }
271
272 char *term_end(void)
273 {
274         return enddata;
275 }
276
277 char *term_quit(void)
278 {
279         return quitdata;
280 }