From 605dd03b364370ad23e4bfe9b466dcf8afaa7a1d Mon Sep 17 00:00:00 2001 From: Sean Bright Date: Sat, 4 Sep 2021 13:07:14 -0400 Subject: [PATCH] term.c: Add support for extended number format terminfo files. ncurses 6.1 introduced an extended number format for terminfo files which the terminfo parsing in Asterisk is not able to parse. This results in some TERM values that do support color (screen-256color on Ubuntu 20.04 for example) to not get a color console. ASTERISK-29630 #close Change-Id: I27a4fcfab502219924af2d6b1c46feba92903cb3 --- main/term.c | 105 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 27 deletions(-) diff --git a/main/term.c b/main/term.c index 617f82ef38..be10163c94 100644 --- a/main/term.c +++ b/main/term.c @@ -74,7 +74,7 @@ static int opposite(int color) } /* Ripped off from Ross Ridge, but it's public domain code (libmytinfo) */ -static short convshort(char *s) +static short convshort(unsigned char *s) { register int a, b; @@ -89,11 +89,83 @@ static short convshort(char *s) return a + b * 256; } +static inline int convint(unsigned char *s) +{ + return s[0] + | s[1] << 8 + | s[2] << 16 + | s[3] << 24; +} + +#define MAGIC_LEGACY (00432) +#define MAGIC_EXTNUM (01036) + +#define HEADER_LEN (12) +#define MAX_COLORS_INDEX (13) + +static int parse_terminfo_file(int fd) +{ + int bytes_read, bytes_needed, num_size; + short magic, sz_names, sz_bools; + unsigned char buffer[1024]; + + bytes_read = read(fd, buffer, sizeof(buffer)); + if (bytes_read < HEADER_LEN) { + return 0; + } + + magic = convshort(buffer); + + if (magic == MAGIC_LEGACY) { + num_size = 2; + } else if (magic == MAGIC_EXTNUM) { + /* Extended number format (ncurses 6.1) */ + num_size = 4; + } else { + /* We don't know how to parse this file */ + return 0; + } + + sz_names = convshort(buffer + 2); + sz_bools = convshort(buffer + 4); + + /* From term(5): + * Between the boolean section and the number section, a null byte will be + * inserted, if necessary, to ensure that the number section begins on an + * even byte. */ + if ((sz_names + sz_bools) & 1) { + sz_bools++; + } + + bytes_needed = HEADER_LEN + sz_names + sz_bools + ((MAX_COLORS_INDEX + 1) * num_size); + if (bytes_needed <= bytes_read) { + /* Offset 13 is defined in /usr/include/term.h, though we do not + * include it here, as it conflicts with include/asterisk/term.h */ + int max_colors; + int offset = HEADER_LEN + sz_names + sz_bools + MAX_COLORS_INDEX * num_size; + + if (num_size == 2) { + /* In the legacy terminfo format, numbers are signed shorts */ + max_colors = convshort(buffer + offset); + } else { + /* Extended number format makes them signed ints */ + max_colors = convint(buffer + offset); + } + + if (max_colors > 0) { + vt100compat = 1; + } + + return 1; + } + + return 0; +} + int ast_term_init(void) { char *term = getenv("TERM"); char termfile[256] = ""; - char buffer[512] = ""; int termfd = -1, parseokay = 0, i; if (ast_opt_no_color) { @@ -110,36 +182,15 @@ int ast_term_init(void) return 0; } - for (i = 0;; i++) { - if (termpath[i] == NULL) { - break; - } + for (i = 0; !parseokay && termpath[i]; i++) { snprintf(termfile, sizeof(termfile), "%s/%c/%s", termpath[i], *term, term); + termfd = open(termfile, O_RDONLY); if (termfd > -1) { - break; + parseokay = parse_terminfo_file(termfd); + close(termfd); } } - if (termfd > -1) { - int actsize = read(termfd, buffer, sizeof(buffer) - 1); - short sz_names = convshort(buffer + 2); - short sz_bools = convshort(buffer + 4); - short n_nums = convshort(buffer + 6); - - /* if ((sz_names + sz_bools) & 1) - sz_bools++; */ - - if (sz_names + sz_bools + n_nums < actsize) { - /* Offset 13 is defined in /usr/include/term.h, though we do not - * include it here, as it conflicts with include/asterisk/term.h */ - short max_colors = convshort(buffer + 12 + sz_names + sz_bools + 13 * 2); - if (max_colors > 0) { - vt100compat = 1; - } - parseokay = 1; - } - close(termfd); - } if (!parseokay) { /* These comparisons should not be substrings nor case-insensitive, as