Annotation of libaitcli/src/aitcli.c, revision 1.2.2.21

1.1       misho       1: /*************************************************************************
                      2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
                      3: *  by Michael Pounov <misho@openbsd-bg.org>
                      4: *
                      5: * $Author: misho $
1.2.2.21! misho       6: * $Id: aitcli.c,v 1.2.2.20 2010/12/07 16:20:24 misho Exp $
1.1       misho       7: *
                      8: *************************************************************************/
                      9: #include "global.h"
1.2.2.7   misho      10: #include "cli.h"
1.1       misho      11: 
                     12: 
                     13: #pragma GCC visibility push(hidden)
                     14: 
                     15: // ------------------------------------------------
                     16: 
                     17: int cli_Errno;
                     18: char cli_Error[STRSIZ];
                     19: 
                     20: #pragma GCC visibility pop
                     21: 
                     22: // cli_GetErrno() Get error code of last operation
1.2.2.2   misho      23: inline int
                     24: cli_GetErrno()
1.1       misho      25: {
                     26:        return cli_Errno;
                     27: }
                     28: 
                     29: // io_GetError() Get error text of last operation
1.2.2.2   misho      30: inline const char *
                     31: cli_GetError()
1.1       misho      32: {
                     33:        return cli_Error;
                     34: }
                     35: 
                     36: // cli_SetErr() Set error to variables for internal use!!!
1.2.2.2   misho      37: inline void
                     38: cli_SetErr(int eno, char *estr, ...)
1.1       misho      39: {
                     40:        va_list lst;
                     41: 
                     42:        cli_Errno = eno;
                     43:        memset(cli_Error, 0, STRSIZ);
                     44:        va_start(lst, estr);
                     45:        vsnprintf(cli_Error, STRSIZ, estr, lst);
                     46:        va_end(lst);
                     47: }
                     48: 
                     49: // ------------------------------------------------------------
                     50: 
1.2.2.2   misho      51: static inline void
                     52: clrscrEOL(linebuffer_t * __restrict buf)
1.1       misho      53: {
1.2.2.2   misho      54:        register int i;
1.1       misho      55: 
1.2.2.2   misho      56:        if (buf) {
                     57:                write(buf->line_out, K_CR, 1);
1.1       misho      58: 
1.2.2.2   misho      59:                for (i = 0; i < buf->line_len; i++)
                     60:                        write(buf->line_out, K_SPACE, 1);
                     61:        }
1.1       misho      62: }
                     63: 
1.2.2.2   misho      64: static inline void
                     65: printfEOL(linebuffer_t * __restrict buf, int len, int prompt)
1.2       misho      66: {
1.2.2.2   misho      67:        if (buf) {
                     68:                write(buf->line_out, K_CR, 1);
1.2       misho      69: 
1.2.2.2   misho      70:                if (prompt && buf->line_prompt)
                     71:                        write(buf->line_out, buf->line_prompt, buf->line_bol);
1.2       misho      72: 
1.2.2.2   misho      73:                write(buf->line_out, buf->line_buf, len == -1 ? buf->line_eol - buf->line_bol: len);
                     74:        }
1.2       misho      75: }
                     76: 
1.2.2.2   misho      77: static inline void
                     78: printfCR(linebuffer_t * __restrict buf, int prompt)
1.2       misho      79: {
1.2.2.2   misho      80:        if (buf) {
                     81:                write(buf->line_out, K_CR, 1);
                     82: 
                     83:                if (prompt)
                     84:                        if (prompt && buf->line_prompt)
                     85:                                write(buf->line_out, buf->line_prompt, buf->line_bol);
                     86:        }
1.2       misho      87: }
                     88: 
1.2.2.2   misho      89: static inline void
1.2.2.4   misho      90: printfNL(linebuffer_t * __restrict buf, int prompt)
                     91: {
                     92:        if (buf) {
                     93:                write(buf->line_out, K_ENTER, 1);
                     94: 
                     95:                if (prompt)
                     96:                        if (prompt && buf->line_prompt)
                     97:                                write(buf->line_out, buf->line_prompt, buf->line_bol);
                     98:        }
                     99: }
                    100: 
1.2.2.2   misho     101: // ------------------------------------------------------------
                    102: 
1.2.2.3   misho     103: static int
                    104: bufCHAR(int idx, void * __restrict buffer)
                    105: {
                    106:        linebuffer_t *buf = buffer;
                    107:        int pos;
                    108: 
                    109:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    110:                return RETCODE_ERR;
                    111: 
                    112:        pos = buf->line_eol - buf->line_bol;
                    113: 
                    114:        if (buf->line_mode == LINEMODE_INS)
                    115:                memmove(buf->line_buf + pos + buf->line_keys[idx].key_len, buf->line_buf + pos, 
                    116:                                buf->line_len - buf->line_eol);
                    117:        if (buf->line_mode == LINEMODE_INS || buf->line_eol == buf->line_len - 1)
                    118:                buf->line_len += buf->line_keys[idx].key_len;
                    119:        buf->line_eol += buf->line_keys[idx].key_len;
                    120: 
                    121:        memcpy(buf->line_buf + pos, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
                    122:        buf->line_buf[buf->line_len - 1] = 0;
                    123: 
                    124:        write(buf->line_out, buf->line_keys[idx].key_ch, buf->line_keys[idx].key_len);
                    125: 
                    126:        if (buf->line_mode == LINEMODE_INS) {
1.2.2.12  misho     127:                write(buf->line_out, (const u_char*) buf->line_buf + pos + buf->line_keys[idx].key_len, 
                    128:                                buf->line_len - buf->line_eol);
1.2.2.3   misho     129:                printfEOL(buf, -1, 1);
                    130:        }
                    131:        return RETCODE_OK;
                    132: }
                    133: 
                    134: static int
                    135: bufEOL(int idx, void * __restrict buffer)
                    136: {
                    137:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    138:                return RETCODE_ERR;
                    139: 
                    140:        printfCR(buffer, 1);
                    141:        return RETCODE_EOL;
                    142: }
                    143: 
                    144: static int
                    145: bufEOF(int idx, void * __restrict buffer)
                    146: {
1.2.2.12  misho     147:        /*
1.2.2.3   misho     148:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    149:                return RETCODE_ERR;
1.2.2.12  misho     150:        */
1.2.2.3   misho     151: 
                    152:        return RETCODE_EOF;
                    153: }
                    154: 
                    155: static int
                    156: bufUP(int idx, void * __restrict buffer)
                    157: {
                    158:        linebuffer_t *buf = buffer;
                    159:        int pos;
                    160: 
                    161:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    162:                return RETCODE_ERR;
                    163: 
                    164:        if (!buf->line_h)
                    165:                buf->line_h = TAILQ_FIRST(&buf->line_history);
                    166:        else
                    167:                buf->line_h = TAILQ_NEXT(buf->line_h, hist_next);
                    168:        if (!buf->line_h)
                    169:                return RETCODE_OK;
                    170: 
                    171:        clrscrEOL(buf);
                    172:        cli_freeLine(buf);
                    173: 
                    174:        pos = buf->line_eol - buf->line_bol;
                    175: 
                    176:        buf->line_len += buf->line_h->hist_len;
                    177:        buf->line_eol += buf->line_h->hist_len;
                    178: 
                    179:        memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
                    180:        buf->line_buf[buf->line_len - 1] = 0;
                    181: 
                    182:        printfEOL(buf, -1, 1);
                    183:        return RETCODE_OK;
                    184: }
                    185: 
                    186: static int
                    187: bufDOWN(int idx, void * __restrict buffer)
                    188: {
                    189:        linebuffer_t *buf = buffer;
                    190:        int pos;
                    191: 
                    192:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    193:                return RETCODE_ERR;
                    194: 
                    195:        if (!buf->line_h)
                    196:                buf->line_h = TAILQ_LAST(&buf->line_history, tqHistoryHead);
                    197:        else
                    198:                buf->line_h = TAILQ_PREV(buf->line_h, tqHistoryHead, hist_next);
                    199:        if (!buf->line_h)
                    200:                return RETCODE_OK;
                    201: 
                    202:        clrscrEOL(buf);
                    203:        cli_freeLine(buf);
                    204: 
                    205:        pos = buf->line_eol - buf->line_bol;
                    206: 
                    207:        buf->line_len += buf->line_h->hist_len;
                    208:        buf->line_eol += buf->line_h->hist_len;
                    209: 
                    210:        memcpy(buf->line_buf + pos, buf->line_h->hist_line, buf->line_h->hist_len);
                    211:        buf->line_buf[buf->line_len - 1] = 0;
                    212: 
                    213:        printfEOL(buf, -1, 1);
                    214:        return RETCODE_OK;
                    215: }
                    216: 
                    217: static int
                    218: bufCLR(int idx, void * __restrict buffer)
                    219: {
                    220:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    221:                return RETCODE_ERR;
                    222: 
                    223:        clrscrEOL(buffer);
                    224:        cli_freeLine(buffer);
                    225: 
                    226:        printfCR(buffer, 1);
                    227:        return RETCODE_OK;
                    228: }
                    229: 
                    230: static int
                    231: bufBS(int idx, void * __restrict buffer)
                    232: {
                    233:        linebuffer_t *buf = buffer;
                    234: 
                    235:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    236:                return RETCODE_ERR;
                    237: 
                    238:        if (buf->line_bol < buf->line_eol) {
                    239:                clrscrEOL(buf);
                    240: 
                    241:                buf->line_eol--;
                    242:                buf->line_len--;
                    243:                memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
                    244:                                buf->line_buf + buf->line_eol - buf->line_bol + 1, 
                    245:                                buf->line_len - buf->line_eol);
                    246:                buf->line_buf[buf->line_len - 1] = 0;
                    247: 
                    248:                printfEOL(buf, buf->line_len - 1, 1);
                    249:                printfEOL(buf, -1, 1);
                    250:        }
                    251: 
                    252:        return RETCODE_OK;
                    253: }
                    254: 
                    255: static int
                    256: bufBTAB(int idx, void * __restrict buffer)
                    257: {
                    258:        linebuffer_t *buf = buffer;
                    259: 
                    260:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    261:                return RETCODE_ERR;
                    262: 
                    263:        if (buf->line_bol < buf->line_eol) {
                    264:                clrscrEOL(buf);
                    265: 
                    266:                buf->line_len = buf->line_eol - buf->line_bol + 1;
                    267:                buf->line_buf[buf->line_len - 1] = 0;
                    268: 
                    269:                printfEOL(buf, -1, 1);
                    270:        }
                    271: 
                    272:        return RETCODE_OK;
                    273: }
                    274: 
                    275: static int
                    276: bufMODE(int idx, void * __restrict buffer)
                    277: {
                    278:        linebuffer_t *buf = buffer;
                    279: 
                    280:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    281:                return RETCODE_ERR;
                    282: 
                    283:        buf->line_mode = !buf->line_mode ? LINEMODE_OVER : LINEMODE_INS;
                    284:        return RETCODE_OK;
                    285: }
                    286: 
                    287: static int
                    288: bufBEGIN(int idx, void * __restrict buffer)
                    289: {
                    290:        linebuffer_t *buf = buffer;
                    291: 
                    292:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    293:                return RETCODE_ERR;
                    294: 
                    295:        buf->line_eol = buf->line_bol;
                    296: 
                    297:        printfCR(buf, 1);
                    298:        return RETCODE_OK;
                    299: }
                    300: 
                    301: static int
                    302: bufEND(int idx, void * __restrict buffer)
                    303: {
                    304:        linebuffer_t *buf = buffer;
                    305: 
                    306:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    307:                return RETCODE_ERR;
                    308: 
                    309:        buf->line_eol = buf->line_len - 1;
                    310: 
                    311:        printfEOL(buf, -1, 1);
                    312:        return RETCODE_OK;
                    313: }
                    314: 
                    315: static int
                    316: bufLEFT(int idx, void * __restrict buffer)
                    317: {
                    318:        linebuffer_t *buf = buffer;
                    319: 
                    320:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    321:                return RETCODE_ERR;
                    322: 
                    323:        if (buf->line_bol < buf->line_eol)
                    324:                printfEOL(buf, --buf->line_eol - buf->line_bol, 1);
                    325: 
                    326:        return RETCODE_OK;
                    327: }
                    328: 
                    329: static int
                    330: bufRIGHT(int idx, void * __restrict buffer)
                    331: {
                    332:        linebuffer_t *buf = buffer;
                    333: 
                    334:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    335:                return RETCODE_ERR;
                    336: 
                    337:        if (buf->line_eol < buf->line_len - 1)
                    338:                printfEOL(buf, ++buf->line_eol - buf->line_bol, 1);
                    339: 
                    340:        return RETCODE_OK;
                    341: }
                    342: 
                    343: static int
                    344: bufDEL(int idx, void * __restrict buffer)
                    345: {
                    346:        linebuffer_t *buf = buffer;
                    347: 
                    348:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    349:                return RETCODE_ERR;
                    350: 
                    351:        clrscrEOL(buf);
                    352: 
                    353:        buf->line_len--;
                    354:        memmove(buf->line_buf + buf->line_eol - buf->line_bol, 
                    355:                        buf->line_buf + buf->line_eol - buf->line_bol + 1, 
                    356:                        buf->line_len - buf->line_eol);
                    357:        buf->line_buf[buf->line_len - 1] = 0;
                    358: 
                    359:        printfEOL(buf, buf->line_len - 1, 1);
                    360:        printfEOL(buf, -1, 1);
                    361: 
                    362:        return RETCODE_OK;
                    363: }
                    364: 
1.2.2.8   misho     365: static int
                    366: bufComp(int idx, void * __restrict buffer)
                    367: {
                    368:        linebuffer_t *buf = buffer;
1.2.2.12  misho     369:        char *str, *s, **app, *items[MAX_PROMPT_ITEMS], szLine[STRSIZ];
                    370:        register int i, j;
                    371:        struct tagCommand *cmd, *c;
                    372:        int pos, ret = RETCODE_OK;
1.2.2.8   misho     373: 
                    374:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    375:                return RETCODE_ERR;
                    376: 
1.2.2.9   misho     377:        str = strdup(buf->line_buf);
                    378:        if (!str)
                    379:                return RETCODE_ERR;
                    380:        else {
                    381:                s = str;
                    382:                io_TrimStr((u_char*) s);
                    383:        }
                    384: 
1.2.2.12  misho     385:        i = j = 0;
                    386:        c = NULL;
                    387:        memset(szLine, 0, STRSIZ);
1.2.2.9   misho     388:        if (*s) {
                    389:                memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
                    390:                for (app = items, i = 0; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t")); 
                    391:                                *app ? i++ : i, *app ? app++ : app);
                    392: 
1.2.2.12  misho     393:                if (i) {
1.2.2.15  misho     394:                        SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
1.2.2.12  misho     395:                                if (cmd->cmd_level == buf->line_level && 
                    396:                                                !strncmp(cmd->cmd_name, items[0], strlen(items[0]))) {
1.2.2.15  misho     397:                                        if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
                    398:                                                j++;
                    399:                                                c = cmd;
                    400:                                                strlcat(szLine, " ", STRSIZ);
                    401:                                                strlcat(szLine, cmd->cmd_name, STRSIZ);
                    402:                                        }
1.2.2.12  misho     403:                                }
1.2.2.15  misho     404:                        }
1.2.2.12  misho     405: 
1.2.2.13  misho     406:                        if (i > 1 && c) {
                    407:                                /* we are on argument of command and has complition info */
                    408:                                j++;    // always must be j > 1 ;) for arguments
                    409:                                strlcpy(szLine, c->cmd_info, STRSIZ);
1.2.2.12  misho     410:                        }
                    411:                } else {
                    412:                        /* we have valid char but i == 0, this case is illegal */
                    413:                        ret = RETCODE_ERR;
                    414:                        goto endcomp;
                    415:                }
                    416:        } else {
                    417:                /* we on 0 position of prompt, show commands for this level */
                    418:                SLIST_FOREACH(cmd, &buf->line_cmds, cmd_next) {
                    419:                        if (cmd->cmd_level == buf->line_level)
1.2.2.15  misho     420:                                if (strncmp(cmd->cmd_name, CLI_CMD_SEP, strlen(CLI_CMD_SEP))) {
                    421:                                        j++;
                    422:                                        c = cmd;
                    423:                                        strlcat(szLine, " ", STRSIZ);
                    424:                                        strlcat(szLine, cmd->cmd_name, STRSIZ);
                    425:                                }
1.2.2.12  misho     426:                }
                    427:        }
                    428: 
                    429:        /* completion show actions ... */
                    430:        if (j > 1 && c) {
                    431:                printfNL(buf, 0);
                    432:                write(buf->line_out, szLine, strlen(szLine));
                    433:                printfNL(buf, 1);
1.2.2.13  misho     434:                printfEOL(buf, buf->line_len - 1, 1);
                    435:                printfEOL(buf, -1, 1);
1.2.2.12  misho     436:        }
                    437:        if (j == 1 && c) {
                    438:                clrscrEOL(buf);
                    439:                cli_freeLine(buf);
                    440: 
                    441:                pos = buf->line_eol - buf->line_bol;
                    442: 
                    443:                buf->line_len += c->cmd_len + 1;
                    444:                buf->line_eol += c->cmd_len + 1;
                    445: 
                    446:                memcpy(buf->line_buf + pos, c->cmd_name, c->cmd_len);
                    447:                buf->line_buf[pos + c->cmd_len] = (u_char) *K_SPACE;
                    448:                buf->line_buf[buf->line_len - 1] = 0;
                    449: 
                    450:                printfEOL(buf, -1, 1);
1.2.2.9   misho     451:        }
                    452: 
1.2.2.12  misho     453: endcomp:
1.2.2.9   misho     454:        free(str);
1.2.2.12  misho     455:        return ret;
1.2.2.8   misho     456: }
                    457: 
                    458: static int
                    459: bufHelp(int idx, void * __restrict buffer)
                    460: {
                    461:        linebuffer_t *buf = buffer;
                    462: 
                    463:        if (!buffer || idx < 0 || idx > MAX_BINDKEY)
                    464:                return RETCODE_ERR;
                    465: 
                    466:        cli_Cmd_Help(buf, -1, NULL);
1.2.2.13  misho     467: 
                    468:        printfEOL(buf, buf->line_len - 1, 1);
                    469:        printfEOL(buf, -1, 1);
1.2.2.8   misho     470:        return RETCODE_OK;
                    471: }
                    472: 
1.2.2.3   misho     473: // ---------------------------------------------------------------
                    474: 
                    475: /*
1.2.2.4   misho     476:  * cli_Printf() Send message to CLI session
                    477:  * @buffer = CLI buffer
                    478:  * @fmt = printf format string
                    479:  * @... = arguments defined in fmt
                    480:  * return: none
                    481: */
                    482: inline void
                    483: cli_Printf(linebuffer_t * __restrict buffer, char *fmt, ...)
                    484: {
                    485:        va_list lst;
                    486:        FILE *f;
                    487: 
                    488:        if (fmt) {
                    489:                f = fdopen(buffer->line_out, "a");
                    490:                if (!f) {
                    491:                        LOGERR;
                    492:                        return;
                    493:                }
                    494: 
                    495:                va_start(lst, fmt);
                    496:                vfprintf(f, fmt, lst);
                    497:                va_end(lst);
                    498:        } else
                    499:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    500: }
                    501: 
                    502: /*
1.2.2.14  misho     503:  * cli_PrintHelp() Print help screen
                    504:  * @buffer = CLI buffer
                    505:  * return: none
                    506: */
                    507: inline void
                    508: cli_PrintHelp(linebuffer_t * __restrict buffer)
                    509: {
1.2.2.21! misho     510:        if (buffer) {
1.2.2.14  misho     511:                bufHelp(0, buffer);
1.2.2.21! misho     512:                clrscrEOL(buffer);
        !           513:        } else
1.2.2.14  misho     514:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    515: }
                    516: 
                    517: 
                    518: /*
1.2.2.3   misho     519:  * cli_BindKey() Bind function to key
                    520:  * @key = key structure
                    521:  * @buffer = CLI buffer
                    522:  * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
                    523: */
                    524: int
                    525: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict buffer)
                    526: {
                    527:        register int i;
                    528: 
                    529:        if (!key || !buffer) {
                    530:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    531:                return RETCODE_ERR;
                    532:        }
                    533: 
                    534:        for (i = 0; i < MAX_BINDKEY; i++)
                    535:                if (key->key_len == buffer->line_keys[i].key_len && 
                    536:                                !memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) {
                    537:                        buffer->line_keys[i].key_func = key->key_func;
                    538:                        return i;
                    539:                }
                    540: 
                    541:        return RETCODE_OK;
                    542: }
                    543: 
                    544: 
                    545: /*
1.2.2.6   misho     546:  * cli_addCommand() Add command to CLI session
                    547:  * @buffer = CLI buffer
                    548:  * @csCmd = Command name
                    549:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
                    550:  * @funcCmd = Callback function when user call command
                    551:  * @csInfo = Inline information for command
                    552:  * @csHelp = Help line when call help
                    553:  * return: RETCODE_ERR error, RETCODE_OK ok
                    554: */
                    555: int
                    556: cli_addCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd, 
1.2.2.13  misho     557:                const char *csInfo, const char *csHelp)
1.2.2.6   misho     558: {
                    559:        struct tagCommand *cmd;
                    560: 
1.2.2.14  misho     561:        if (!buffer || !csCmd) {
1.2.2.6   misho     562:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    563:                return RETCODE_ERR;
                    564:        }
                    565: 
                    566:        cmd = malloc(sizeof(struct tagCommand));
                    567:        if (!cmd) {
                    568:                LOGERR;
                    569:                return RETCODE_ERR;
                    570:        } else
                    571:                memset(cmd, 0, sizeof(struct tagCommand));
                    572: 
                    573:        cmd->cmd_level = cliLevel;
                    574:        cmd->cmd_func = funcCmd;
                    575:        cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
                    576:        if (csInfo)
                    577:                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    578:        if (csHelp)
                    579:                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
                    580:        SLIST_INSERT_HEAD(&buffer->line_cmds, cmd, cmd_next);
                    581:        return RETCODE_OK;
                    582: }
                    583: 
                    584: /*
                    585:  * cli_delCommand() Delete command from CLI session
                    586:  * @buffer = CLI buffer
                    587:  * @csCmd = Command name
                    588:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
                    589:  * return: RETCODE_ERR error, RETCODE_OK ok
                    590: */
                    591: int
                    592: cli_delCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel)
                    593: {
                    594:        struct tagCommand *cmd;
                    595:        int ret = RETCODE_OK;
                    596: 
                    597:        if (!buffer || !csCmd) {
                    598:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    599:                return RETCODE_ERR;
                    600:        }
                    601: 
                    602:        SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) 
                    603:                if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
                    604:                        ret = 1;
                    605:                        SLIST_REMOVE(&buffer->line_cmds, cmd, tagCommand, cmd_next);
                    606:                        free(cmd);
                    607:                        break;
                    608:                }
                    609: 
                    610:        return ret;
                    611: }
                    612: 
                    613: /*
                    614:  * cli_updCommand() Update command in CLI session
                    615:  * @buffer = CLI buffer
                    616:  * @csCmd = Command name
                    617:  * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
                    618:  * @funcCmd = Callback function when user call command
                    619:  * @csInfo = Inline information for command
                    620:  * @csHelp = Help line when call help
                    621:  * return: RETCODE_ERR error, RETCODE_OK ok
                    622: */
                    623: int
                    624: cli_updCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd, 
1.2.2.13  misho     625:                const char *csInfo, const char *csHelp)
1.2.2.6   misho     626: {
                    627:        struct tagCommand *cmd;
                    628:        int ret = RETCODE_OK;
                    629: 
                    630:        if (!buffer || !csCmd) {
                    631:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    632:                return RETCODE_ERR;
                    633:        }
                    634: 
                    635:        SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) 
                    636:                if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
                    637:                        ret = 1;
                    638: 
1.2.2.13  misho     639:                        if (funcCmd)
1.2.2.6   misho     640:                                cmd->cmd_func = funcCmd;
                    641:                        if (csInfo)
                    642:                                strlcpy(cmd->cmd_info, csInfo, STRSIZ);
                    643:                        if (csHelp)
                    644:                                strlcpy(cmd->cmd_help, csHelp, STRSIZ);
                    645: 
                    646:                        break;
                    647:                }
                    648: 
                    649:        return ret;
                    650: }
                    651: 
                    652: 
                    653: /*
1.2.2.3   misho     654:  * cli_addHistory() Add line to history
                    655:  * @buffer = CLI buffer
1.2.2.4   misho     656:  * @str = Add custom text or if NULL use readed line from CLI buffer
1.2.2.3   misho     657:  * return: RETCODE_ERR error, RETCODE_OK ok
                    658: */
                    659: int
                    660: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
                    661: {
                    662:        struct tagHistory *h;
                    663: 
                    664:        if (!buffer) {
                    665:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    666:                return RETCODE_ERR;
                    667:        }
                    668: 
                    669:        if (!(h = malloc(sizeof(struct tagHistory)))) {
                    670:                LOGERR;
                    671:                return RETCODE_ERR;
                    672:        } else
                    673:                memset(h, 0, sizeof(struct tagHistory));
                    674: 
                    675:        if (str) {
                    676:                if (!*str) {
                    677:                        free(h);
                    678:                        return RETCODE_OK;
                    679:                }
                    680: 
                    681:                h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
                    682:        } else {
                    683:                if (!*buffer->line_buf || buffer->line_len < 2) {
                    684:                        free(h);
                    685:                        return RETCODE_OK;
                    686:                }
                    687: 
                    688:                memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len));
                    689:                io_TrimStr((u_char*) h->hist_line);
                    690:                h->hist_len = strlen(h->hist_line);
                    691:        }
                    692: 
                    693:        TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
                    694:        return h->hist_len;
                    695: }
                    696: 
                    697: /*
                    698:  * cli_saveHistory() Save history to file
                    699:  * @buffer = CLI buffer
                    700:  * @histfile = History filename, if NULL will be use default name
                    701:  * @lines = Maximum history lines to save
                    702:  * return: RETCODE_ERR error, RETCODE_OK ok
                    703: */
                    704: int
                    705: cli_saveHistory(linebuffer_t * __restrict buffer, const char *histfile, int lines)
                    706: {
                    707:        FILE *f;
                    708:        mode_t mode;
                    709:        char szFName[MAXPATHLEN];
                    710:        struct tagHistory *h;
                    711: 
                    712:        if (!buffer) {
                    713:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    714:                return RETCODE_ERR;
                    715:        }
                    716:        if (!histfile)
                    717:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                    718:        else
                    719:                strlcpy(szFName, histfile, MAXPATHLEN);
                    720: 
                    721:        mode = umask(0177);
                    722:        f = fopen(szFName, "w");
                    723:        if (!f) {
                    724:                LOGERR;
                    725:                return RETCODE_ERR;
                    726:        }
                    727: 
                    728:        TAILQ_FOREACH(h, &buffer->line_history, hist_next) {
                    729:                fprintf(f, "%s\n", h->hist_line);
                    730: 
                    731:                if (lines)
                    732:                        lines--;
                    733:                else
                    734:                        break;
                    735:        }
                    736: 
                    737:        fclose(f);
                    738:        umask(mode);
                    739: 
                    740:        return RETCODE_OK;
                    741: }
                    742: 
                    743: /*
                    744:  * cli_loadHistory() Load history from file
                    745:  * @buffer = CLI buffer
                    746:  * @histfile = History filename, if NULL will be use default name
                    747:  * return: RETCODE_ERR error, RETCODE_OK ok
                    748: */
                    749: int
                    750: cli_loadHistory(linebuffer_t * __restrict buffer, const char *histfile)
                    751: {
                    752:        FILE *f;
                    753:        char szFName[MAXPATHLEN], buf[BUFSIZ];
                    754:        struct tagHistory *h;
                    755: 
                    756:        if (!buffer) {
                    757:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    758:                return RETCODE_ERR;
                    759:        }
                    760:        if (!histfile)
                    761:                strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
                    762:        else
                    763:                strlcpy(szFName, histfile, MAXPATHLEN);
                    764: 
                    765:        f = fopen(szFName, "r");
1.2.2.4   misho     766:        if (!f)
                    767:                return RETCODE_OK;
1.2.2.3   misho     768: 
                    769:        while (fgets(buf, BUFSIZ, f)) {
                    770:                if (!*buf || *buf == '#')
                    771:                        continue;
                    772:                else
                    773:                        io_TrimStr((u_char*) buf);
                    774: 
                    775:                if (!(h = malloc(sizeof(struct tagHistory)))) {
                    776:                        LOGERR;
                    777:                        fclose(f);
                    778:                        return RETCODE_ERR;
                    779:                } else
                    780:                        memset(h, 0, sizeof(struct tagHistory));
                    781: 
                    782:                h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
                    783:                TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next);
                    784:        }
                    785: 
                    786:        fclose(f);
                    787: 
                    788:        return RETCODE_OK;
                    789: }
                    790: 
                    791: /*
                    792:  * cli_resetHistory() Reset history search in CLI session
                    793:  * @buffer = CLI buffer
                    794:  * return: none
                    795: */
                    796: inline void
                    797: cli_resetHistory(linebuffer_t * __restrict buffer)
                    798: {
                    799:        buffer->line_h = NULL;
                    800: }
                    801: 
                    802: 
                    803: /*
                    804:  * cli_freeLine() Clear entire line
                    805:  * @buffer = CLI buffer
                    806:  * return: RETCODE_ERR error, RETCODE_OK ok
                    807: */
                    808: inline int
                    809: cli_freeLine(linebuffer_t * __restrict buffer)
                    810: {
                    811:        int code = RETCODE_ERR;
                    812: 
                    813:        if (buffer) {
                    814:                if (buffer->line_buf)
                    815:                        free(buffer->line_buf);
                    816: 
                    817:                buffer->line_buf = malloc(BUFSIZ);
                    818:                if (buffer->line_buf) {
                    819:                        memset(buffer->line_buf, 0, BUFSIZ);
                    820:                        buffer->line_eol = buffer->line_bol;
                    821:                        buffer->line_len = 1 + buffer->line_eol;
                    822: 
                    823:                        code = RETCODE_OK;
                    824:                } else
                    825:                        LOGERR;
                    826:        } else
                    827:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    828: 
                    829:        return code;
                    830: }
                    831: 
                    832: /*
                    833:  * cli_setPrompt() Set new prompt for CLI session
                    834:  * @buffer = CLI buffer
                    835:  * @prompt = new text for prompt or if NULL disable prompt
                    836:  * return: none
                    837: */
                    838: inline void
                    839: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
                    840: {
                    841:        if (buffer) {
                    842:                if (buffer->line_prompt) {
                    843:                        free(buffer->line_prompt);
                    844:                        buffer->line_prompt = NULL;
                    845:                        buffer->line_bol = 0;
                    846:                }
                    847: 
                    848:                if (prompt) {
                    849:                        buffer->line_prompt = strdup(prompt);
                    850:                        if (buffer->line_prompt) {
                    851:                                buffer->line_bol = strlen(buffer->line_prompt);
                    852:                                buffer->line_eol = buffer->line_bol;
                    853:                                buffer->line_len = 1 + buffer->line_eol;
                    854:                        } else
                    855:                                LOGERR;
                    856:                }
                    857:        } else
                    858:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    859: }
                    860: 
                    861: 
                    862: /*
                    863:  * cliEnd() Clear data, Free resources and close CLI session
                    864:  * @buffer = CLI buffer
                    865:  * return: RETCODE_ERR error, RETCODE_OK ok
                    866: */
                    867: void
                    868: cliEnd(linebuffer_t * __restrict buffer)
                    869: {
                    870:        struct tagHistory *h;
1.2.2.4   misho     871:        struct tagCommand *c;
1.2.2.3   misho     872: 
                    873:        if (buffer) {
1.2.2.4   misho     874:                while ((c = SLIST_FIRST(&buffer->line_cmds))) {
                    875:                        SLIST_REMOVE_HEAD(&buffer->line_cmds, cmd_next);
                    876:                        free(c);
                    877:                }
1.2.2.3   misho     878:                while ((h = TAILQ_FIRST(&buffer->line_history))) {
                    879:                        TAILQ_REMOVE(&buffer->line_history, h, hist_next);
                    880:                        free(h);
                    881:                }
                    882: 
                    883:                if (buffer->line_prompt)
                    884:                        free(buffer->line_prompt);
                    885: 
                    886:                if (buffer->line_keys)
                    887:                        free(buffer->line_keys);
                    888:                if (buffer->line_buf)
                    889:                        free(buffer->line_buf);
                    890: 
                    891:                free(buffer);
                    892:                buffer = NULL;
                    893:        } else
                    894:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                    895: }
                    896: 
                    897: /*
                    898:  * cliInit() Start CLI session, allocate memory for resources and bind keys
                    899:  * @fin = Input device handle
                    900:  * @fout = Output device handle
                    901:  * @prompt = text for prompt, if NULL disable prompt
                    902:  * return: NULL if error or !=NULL CLI buffer
                    903: */
                    904: linebuffer_t *
                    905: cliInit(int fin, int fout, const char *prompt)
                    906: {
                    907:        linebuffer_t *buffer;
                    908:        bindkey_t *keys;
                    909:        register int i;
                    910: 
                    911:        /* init buffer */
1.2.2.18  misho     912:        buffer = malloc(sizeof(linebuffer_t));
1.2.2.3   misho     913:        if (!buffer) {
                    914:                LOGERR;
                    915:                return NULL;
                    916:        } else {
                    917:                memset(buffer, 0, sizeof(linebuffer_t));
                    918: 
                    919:                buffer->line_in = fin;
                    920:                buffer->line_out = fout;
                    921: 
                    922:                TAILQ_INIT(&buffer->line_history);
1.2.2.4   misho     923:                SLIST_INIT(&buffer->line_cmds);
1.2.2.3   misho     924: 
                    925:                if (prompt) {
                    926:                        buffer->line_prompt = strdup(prompt);
                    927:                        if (!buffer->line_prompt) {
                    928:                                LOGERR;
                    929:                                free(buffer);
                    930:                                return NULL;
                    931:                        } else
                    932:                                buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
                    933:                }
                    934:        }
                    935:        buffer->line_buf = malloc(BUFSIZ);
                    936:        if (!buffer->line_buf) {
                    937:                LOGERR;
                    938:                if (buffer->line_prompt)
                    939:                        free(buffer->line_prompt);
                    940:                free(buffer);
                    941:                return NULL;
                    942:        } else {
                    943:                memset(buffer->line_buf, 0, BUFSIZ);
                    944:                buffer->line_len = 1 + buffer->line_eol;
                    945:        }
                    946:        keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
                    947:        if (!keys) {
                    948:                LOGERR;
                    949:                if (buffer->line_prompt)
                    950:                        free(buffer->line_prompt);
                    951:                free(buffer->line_buf);
                    952:                free(buffer);
                    953:                return NULL;
                    954:        } else
                    955:                memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
                    956: 
1.2.2.7   misho     957:        /* add helper functions */
1.2.2.13  misho     958:        cli_addCommand(buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
                    959:        cli_addCommand(buffer, "help", 0, cli_Cmd_Help, "help [command] <cr>", "Help screen");
1.2.2.15  misho     960:        cli_addCommand(buffer, "-------", 0, NULL, "-------------------------", NULL);
1.2.2.7   misho     961: 
1.2.2.3   misho     962:        /* fill key bindings */
                    963:        // ascii chars & ctrl+chars
                    964:        for (i = 0; i < 256; i++) {
                    965:                *keys[i].key_ch = (u_char) i;
                    966:                keys[i].key_len = 1;
                    967: 
                    968:                if (!i || i == *K_CTRL_D)
                    969:                        keys[i].key_func = bufEOF;
                    970:                if (i == *K_CTRL_M || i == *K_CTRL_J)
                    971:                        keys[i].key_func = bufEOL;
                    972:                if (i == *K_CTRL_H || i == *K_BACKSPACE)
                    973:                        keys[i].key_func = bufBS;
                    974:                if (i == *K_CTRL_C)
                    975:                        keys[i].key_func = bufCLR;
                    976:                if (i == *K_CTRL_A)
                    977:                        keys[i].key_func = bufBEGIN;
                    978:                if (i == *K_CTRL_E)
                    979:                        keys[i].key_func = bufEND;
1.2.2.8   misho     980:                if (i == *K_TAB)
                    981:                        keys[i].key_func = bufComp;
1.2.2.3   misho     982:                if (i >= *K_SPACE && i < *K_BACKSPACE)
                    983:                        keys[i].key_func = bufCHAR;
                    984:                if (i > *K_BACKSPACE && i < 0xff)
                    985:                        keys[i].key_func = bufCHAR;
1.2.2.8   misho     986:                if (i == '?')
                    987:                        keys[i].key_func = bufHelp;
1.2.2.3   misho     988:        }
                    989:        // alt+chars
                    990:        for (i = 256; i < 512; i++) {
                    991:                keys[i].key_ch[0] = 0x1b;
                    992:                keys[i].key_ch[1] = (u_char) i - 256;
                    993:                keys[i].key_len = 2;
                    994:        }
                    995: 
                    996:        // 3 bytes
                    997:        keys[i].key_len = sizeof K_F1 - 1;
                    998:        memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
                    999:        i++;
                   1000:        keys[i].key_len = sizeof K_F2 - 1;
                   1001:        memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
                   1002:        i++;
                   1003:        keys[i].key_len = sizeof K_F3 - 1;
                   1004:        memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
                   1005:        i++;
                   1006:        keys[i].key_len = sizeof K_F4 - 1;
                   1007:        memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
                   1008:        i++;
                   1009:        keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
                   1010:        memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
                   1011:        i++;
                   1012:        keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
                   1013:        memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
                   1014:        i++;
                   1015:        keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
                   1016:        memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
                   1017:        i++;
                   1018:        keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
                   1019:        memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
                   1020:        i++;
                   1021:        keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
                   1022:        memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
                   1023:        i++;
                   1024:        keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
                   1025:        memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
                   1026:        i++;
                   1027:        keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
                   1028:        memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
                   1029:        i++;
                   1030:        keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
                   1031:        memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
                   1032:        i++;
                   1033:        keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
                   1034:        memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
                   1035:        i++;
                   1036:        keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
                   1037:        memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
                   1038:        i++;
                   1039:        keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
                   1040:        memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
                   1041:        i++;
                   1042:        keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
                   1043:        memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
                   1044:        i++;
                   1045:        keys[i].key_len = sizeof K_CTRL_F1 - 1;
                   1046:        memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
                   1047:        i++;
                   1048:        keys[i].key_len = sizeof K_CTRL_F2 - 1;
                   1049:        memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
                   1050:        i++;
                   1051:        keys[i].key_len = sizeof K_CTRL_F3 - 1;
                   1052:        memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
                   1053:        i++;
                   1054:        keys[i].key_len = sizeof K_CTRL_F4 - 1;
                   1055:        memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
                   1056:        i++;
                   1057:        keys[i].key_len = sizeof K_CTRL_F5 - 1;
                   1058:        memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
                   1059:        i++;
                   1060:        keys[i].key_len = sizeof K_CTRL_F6 - 1;
                   1061:        memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
                   1062:        i++;
                   1063:        keys[i].key_len = sizeof K_CTRL_F7 - 1;
                   1064:        memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
                   1065:        i++;
                   1066:        keys[i].key_len = sizeof K_CTRL_F8 - 1;
                   1067:        memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
                   1068:        i++;
                   1069:        keys[i].key_len = sizeof K_CTRL_F9 - 1;
                   1070:        memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
                   1071:        i++;
                   1072:        keys[i].key_len = sizeof K_CTRL_F10 - 1;
                   1073:        memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
                   1074:        i++;
                   1075:        keys[i].key_len = sizeof K_CTRL_F11 - 1;
                   1076:        memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
                   1077:        i++;
                   1078:        keys[i].key_len = sizeof K_CTRL_F12 - 1;
                   1079:        memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
                   1080:        i++;
                   1081:        keys[i].key_len = sizeof K_HOME - 1;
                   1082:        keys[i].key_func = bufBEGIN;
                   1083:        memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
                   1084:        i++;
                   1085:        keys[i].key_len = sizeof K_END - 1;
                   1086:        keys[i].key_func = bufEND;
                   1087:        memcpy(keys[i].key_ch, K_END, keys[i].key_len);
                   1088:        i++;
                   1089:        keys[i].key_len = sizeof K_UP - 1;
                   1090:        keys[i].key_func = bufUP;
                   1091:        memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
                   1092:        i++;
                   1093:        keys[i].key_len = sizeof K_DOWN - 1;
                   1094:        keys[i].key_func = bufDOWN;
                   1095:        memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
                   1096:        i++;
                   1097:        keys[i].key_len = sizeof K_RIGHT - 1;
                   1098:        keys[i].key_func = bufRIGHT;
                   1099:        memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
                   1100:        i++;
                   1101:        keys[i].key_len = sizeof K_LEFT - 1;
                   1102:        keys[i].key_func = bufLEFT;
                   1103:        memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
                   1104:        i++;
                   1105:        keys[i].key_len = sizeof K_BTAB - 1;
                   1106:        keys[i].key_func = bufBTAB;
                   1107:        memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
                   1108:        i++;
                   1109:        // 4 bytes
                   1110:        keys[i].key_len = sizeof K_INS - 1;
                   1111:        keys[i].key_func = bufMODE;
                   1112:        memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
                   1113:        i++;
                   1114:        keys[i].key_len = sizeof K_DEL - 1;
                   1115:        keys[i].key_func = bufDEL;
                   1116:        memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
                   1117:        i++;
                   1118:        keys[i].key_len = sizeof K_PGUP - 1;
                   1119:        memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
                   1120:        i++;
                   1121:        keys[i].key_len = sizeof K_PGDN - 1;
                   1122:        memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
                   1123:        i++;
                   1124:        // 5 bytes
                   1125:        keys[i].key_len = sizeof K_F5 - 1;
                   1126:        memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
                   1127:        i++;
                   1128:        keys[i].key_len = sizeof K_F6 - 1;
                   1129:        memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
                   1130:        i++;
                   1131:        keys[i].key_len = sizeof K_F7 - 1;
                   1132:        memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
                   1133:        i++;
                   1134:        keys[i].key_len = sizeof K_F8 - 1;
                   1135:        memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
                   1136:        i++;
                   1137:        keys[i].key_len = sizeof K_F9 - 1;
                   1138:        memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
                   1139:        i++;
                   1140:        keys[i].key_len = sizeof K_F10 - 1;
                   1141:        memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
                   1142:        i++;
                   1143:        keys[i].key_len = sizeof K_F11 - 1;
                   1144:        memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
                   1145:        i++;
                   1146:        keys[i].key_len = sizeof K_F12 - 1;
                   1147:        memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
                   1148:        i++;
                   1149: 
1.2.2.18  misho    1150:        buffer->line_keys = keys;
                   1151:        return buffer;
                   1152: }
                   1153: 
                   1154: /*
                   1155:  * cliInitLine() Init CLI input line terminal
                   1156:  * @buffer = CLI buffer
                   1157:  * return: none
                   1158: */
                   1159: int
                   1160: cliInitLine(linebuffer_t * __restrict buffer)
                   1161: {
                   1162:        struct termios t;
                   1163: 
                   1164:        memset(&t, 0, sizeof t);
1.2.2.3   misho    1165:        tcgetattr(buffer->line_in, &t);
                   1166:        t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
                   1167:        t.c_iflag |= IGNBRK;
                   1168:        t.c_cc[VMIN] = 1;
                   1169:        t.c_cc[VTIME] = 0;
1.2.2.18  misho    1170:        return tcsetattr(buffer->line_in, TCSANOW, &t);
1.2.2.3   misho    1171: }
                   1172: 
1.2       misho    1173: /*
1.2.2.4   misho    1174:  * cliReadLine() Read line from opened CLI session
                   1175:  * @buffer = CLI buffer
                   1176:  * return: NULL if error or !=NULL readed line, must be free after use!
1.2       misho    1177: */
1.2.2.4   misho    1178: char *
                   1179: cliReadLine(linebuffer_t * __restrict buffer)
1.2       misho    1180: {
1.2.2.4   misho    1181:        int code, readLen;
                   1182:        register int i;
                   1183:        struct pollfd fds;
                   1184:        char buf[BUFSIZ], *str = NULL;
1.2       misho    1185: 
1.2.2.4   misho    1186:        if (!buffer) {
                   1187:                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
                   1188:                return NULL;
1.2       misho    1189:        }
                   1190: 
1.2.2.4   misho    1191:        memset(&fds, 0, sizeof fds);
                   1192:        fds.fd = buffer->line_in;
                   1193:        fds.events = POLLIN;
                   1194: 
                   1195:        printfCR(buffer, 1);
                   1196:        while (42) {
                   1197:                if (poll(&fds, 1, -1) < 1) {
                   1198:                        LOGERR;
                   1199:                        return str;
                   1200:                }
1.2       misho    1201: 
1.2.2.4   misho    1202:                memset(buf, 0, sizeof buf);
                   1203:                readLen = read(buffer->line_in, buf, BUFSIZ);
                   1204:                if (readLen == -1) {
                   1205:                        LOGERR;
                   1206:                        return str;
                   1207:                }
                   1208:                if (!readLen) {
                   1209:                        if (buffer->line_buf)
                   1210:                                str = strdup(buffer->line_buf);
                   1211:                        else
                   1212:                                cli_SetErr(EPIPE, "Error:: unknown state ...");
                   1213:                        return str;
                   1214:                }
1.2       misho    1215: 
1.2.2.4   misho    1216: recheck:
                   1217:                for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
                   1218:                        if (readLen >= buffer->line_keys[i].key_len && 
                   1219:                                        !memcmp(buffer->line_keys[i].key_ch, buf, 
                   1220:                                                buffer->line_keys[i].key_len)) {
                   1221:                                readLen -= buffer->line_keys[i].key_len;
                   1222:                                if (readLen)
                   1223:                                        memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
                   1224:                                else
                   1225:                                        memset(buf, 0, buffer->line_keys[i].key_len);
                   1226: 
                   1227:                                if (buffer->line_keys[i].key_func)
                   1228:                                        if ((code = buffer->line_keys[i].key_func(i, buffer)))
                   1229:                                                readLen = 0;
                   1230: 
                   1231:                                if (readLen)
                   1232:                                        goto recheck;
                   1233:                                else
                   1234:                                        break;
                   1235:                        }
1.2       misho    1236: 
1.2.2.4   misho    1237:                if (code)
                   1238:                        break;
                   1239:        }
                   1240: 
1.2.2.5   misho    1241:        if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
1.2.2.4   misho    1242:                str = strdup(buffer->line_buf);
                   1243:        return str;
1.2       misho    1244: }
1.2.2.4   misho    1245: 
                   1246: 
1.2       misho    1247: /*
1.2.2.4   misho    1248:  * cliNetLoop() CLI network main loop binded to socket
                   1249:  * @buffer = CLI buffer
                   1250:  * @csHistFile = History file name
1.2       misho    1251:  * @sock = client socket
1.2.2.4   misho    1252:  * return: RETCODE_ERR error, RETCODE_OK ok
1.2       misho    1253: */
1.2.2.1   misho    1254: int
1.2.2.17  misho    1255: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock)
1.2       misho    1256: {
1.2.2.4   misho    1257:        u_char buf[BUFSIZ];
1.2.2.20  misho    1258:        int pid, stat, pty, r, s, alen, flg, attrlen = 0, ret = 0;
1.2       misho    1259:        fd_set fds;
                   1260:        struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
                   1261:        struct telnetAttrs *a, Attr[10];
                   1262: 
1.2.2.20  misho    1263:        switch ((pid = forkpty(&pty, NULL, NULL, NULL))) {
1.2       misho    1264:                case -1:
                   1265:                        LOGERR;
                   1266:                        return -1;
                   1267:                case 0:
1.2.2.18  misho    1268:                        if (!buffer) {
1.2.2.8   misho    1269:                                cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1.2.2.18  misho    1270:                                return -1;
                   1271:                        } else
                   1272:                                close(sock);
1.2.2.4   misho    1273: 
1.2.2.18  misho    1274:                        ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
                   1275:                        cliEnd(buffer);
1.2.2.4   misho    1276: 
1.2.2.18  misho    1277:                        exit(ret);
1.2       misho    1278:                default:
                   1279:                        telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
                   1280:                        telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
                   1281:                        telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
                   1282:                        telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
                   1283:                        telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
                   1284:                        if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
                   1285:                                cli_Errno = telnet_GetErrno();
                   1286:                                strlcpy(cli_Error, telnet_GetError(), STRSIZ);
                   1287:                                return -1;
                   1288:                        } else
                   1289:                                flg = 0;
                   1290: 
                   1291:                        while (42) {
1.2.2.20  misho    1292:                                if (waitpid(pid, &stat, WNOHANG))
                   1293:                                        break;
                   1294: 
1.2       misho    1295:                                FD_ZERO(&fds);
                   1296:                                FD_SET(sock, &fds);
                   1297:                                FD_SET(pty, &fds);
                   1298:                                if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
                   1299:                                        if (!ret)
                   1300:                                                cli_SetErr(ETIMEDOUT, "Client session timeout ...");
                   1301: 
                   1302:                                        break;
                   1303:                                }
                   1304: 
                   1305:                                r = FD_ISSET(sock, &fds) ? sock : pty;
                   1306:                                s = FD_ISSET(sock, &fds) ? pty : sock;
                   1307: 
1.2.2.17  misho    1308:                                if (FD_ISSET(sock, &fds)) {
                   1309:                                        memset(buf, 0, BUFSIZ);
                   1310:                                        if ((ret = telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
                   1311:                                                if (a)
                   1312:                                                        free(a);
                   1313: 
                   1314:                                                if (-2 == ret)
                   1315:                                                        continue;
                   1316:                                                // EOF
                   1317:                                                if (-3 == ret)
                   1318:                                                        shutdown(sock, SHUT_RD);
                   1319:                                                else {
                   1320:                                                        cli_Errno = telnet_GetErrno();
                   1321:                                                        strlcpy(cli_Error, telnet_GetError(), STRSIZ);
                   1322:                                                }
                   1323:                                                break;
                   1324:                                        }
                   1325:                                        attrlen = 0;
                   1326:                                        if (1 == flg && alen) {
                   1327:                                                telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
                   1328:                                                telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
                   1329:                                        }
                   1330:                                        if (2 == flg && alen) {
                   1331:                                                telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
                   1332:                                                telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
                   1333:                                                                LFLOW_OFF, NULL, 0);
                   1334:                                                telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW, 
                   1335:                                                                LFLOW_RESTART_XON, NULL, 0);
                   1336:                                                telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
                   1337:                                        }
1.2       misho    1338:                                        if (a)
                   1339:                                                free(a);
                   1340: 
1.2.2.17  misho    1341:                                        if ((ret = write(pty, buf, ret)) == -1) {
                   1342:                                                LOGERR;
                   1343:                                                break;
1.2       misho    1344:                                        }
                   1345:                                }
                   1346: 
1.2.2.17  misho    1347:                                if (FD_ISSET(pty, &fds)) {
                   1348:                                        memset(buf, 0, BUFSIZ);
                   1349:                                        if ((ret = read(pty, buf, BUFSIZ)) == -1) {
                   1350:                                                LOGERR;
                   1351:                                                break;
                   1352:                                        }
                   1353: 
                   1354:                                        if ((ret = telnetSend(sock, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
                   1355:                                                cli_Errno = telnet_GetErrno();
                   1356:                                                strlcpy(cli_Error, telnet_GetError(), STRSIZ);
                   1357:                                                break;
                   1358:                                        } else
                   1359:                                                flg++;
                   1360:                                }
1.2       misho    1361:                        }
                   1362: 
                   1363:                        close(pty);
                   1364:        }
                   1365: 
                   1366:        return ret;
                   1367: }
                   1368: 
                   1369: /*
1.2.2.4   misho    1370:  * cliLoop() CLI main loop
                   1371:  * @buffer = CLI buffer
                   1372:  * @csHistFile = History file name
                   1373:  * return: RETCODE_ERR error, RETCODE_OK ok
1.1       misho    1374: */
1.2.2.4   misho    1375: int
                   1376: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
1.1       misho    1377: {
                   1378:        char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
                   1379:        register int i;
1.2.2.4   misho    1380:        int ret = RETCODE_OK;
                   1381:        struct tagCommand *cmd;
1.1       misho    1382: 
                   1383:        /* --- main body of CLI --- */
1.2.2.19  misho    1384:        cliInitLine(buffer);
1.2.2.4   misho    1385: 
                   1386:        if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
                   1387:                return RETCODE_ERR;
1.1       misho    1388: 
                   1389:        do {
1.2.2.4   misho    1390:                line = cliReadLine(buffer);
1.2.2.5   misho    1391:                if (!line) {
                   1392:                        printfNL(buffer, 0);
1.1       misho    1393:                        break;
1.2.2.5   misho    1394:                } else
1.2.2.4   misho    1395:                        cli_addHistory(buffer, NULL);
1.1       misho    1396:                // clear whitespaces
                   1397:                for (s = line; isspace(*s); s++);
                   1398:                if (*s) {
                   1399:                        for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
                   1400:                        *++t = 0;
                   1401:                }
                   1402: 
                   1403:                if (*s) {
                   1404:                        memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
                   1405:                        for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t")); 
                   1406:                                        *app ? app++ : app);
                   1407: 
                   1408:                        // exec_cmd ...
1.2.2.4   misho    1409:                        i = 0;
                   1410:                        SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
                   1411:                                if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1       misho    1412:                                        break;
1.2.2.4   misho    1413:                                else
                   1414:                                        i++;
                   1415:                        }
1.2.2.5   misho    1416: 
1.1       misho    1417:                        if (!cmd) {
1.2.2.5   misho    1418:                                cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
1.1       misho    1419:                                ret = -1;
                   1420:                        } else
1.2.2.20  misho    1421:                                if (cmd->cmd_func) {
                   1422:                                        cli_Printf(buffer, "\n");
1.2.2.15  misho    1423:                                        ret = cmd->cmd_func(buffer, i, items);
1.2.2.20  misho    1424:                                } else {
1.2.2.15  misho    1425:                                        clrscrEOL(buffer);
                   1426:                                        printfCR(buffer, 1);
                   1427:                                }
1.1       misho    1428:                }
                   1429: 
1.2.2.4   misho    1430:                cli_freeLine(buffer);
                   1431:                cli_resetHistory(buffer);
1.1       misho    1432:                free(line);
                   1433:        } while (ret < 1);
                   1434: 
1.2.2.4   misho    1435:        cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
1.1       misho    1436:        return ret;
                   1437: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>