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

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

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