Annotation of libaitcli/src/aitcli.c, revision 1.2.2.16
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.16! misho 6: * $Id: aitcli.c,v 1.2.2.15 2010/06/08 08:43:47 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: {
510: if (buffer)
511: bufHelp(0, buffer);
512: else
513: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
514: }
515:
516:
517: /*
1.2.2.3 misho 518: * cli_BindKey() Bind function to key
519: * @key = key structure
520: * @buffer = CLI buffer
521: * return: RETCODE_ERR error, RETCODE_OK ok, >0 bind at position
522: */
523: int
524: cli_BindKey(bindkey_t * __restrict key, linebuffer_t * __restrict buffer)
525: {
526: register int i;
527:
528: if (!key || !buffer) {
529: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
530: return RETCODE_ERR;
531: }
532:
533: for (i = 0; i < MAX_BINDKEY; i++)
534: if (key->key_len == buffer->line_keys[i].key_len &&
535: !memcmp(key->key_ch, buffer->line_keys[i].key_ch, key->key_len)) {
536: buffer->line_keys[i].key_func = key->key_func;
537: return i;
538: }
539:
540: return RETCODE_OK;
541: }
542:
543:
544: /*
1.2.2.6 misho 545: * cli_addCommand() Add command to CLI session
546: * @buffer = CLI buffer
547: * @csCmd = Command name
548: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
549: * @funcCmd = Callback function when user call command
550: * @csInfo = Inline information for command
551: * @csHelp = Help line when call help
552: * return: RETCODE_ERR error, RETCODE_OK ok
553: */
554: int
555: cli_addCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
1.2.2.13 misho 556: const char *csInfo, const char *csHelp)
1.2.2.6 misho 557: {
558: struct tagCommand *cmd;
559:
1.2.2.14 misho 560: if (!buffer || !csCmd) {
1.2.2.6 misho 561: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
562: return RETCODE_ERR;
563: }
564:
565: cmd = malloc(sizeof(struct tagCommand));
566: if (!cmd) {
567: LOGERR;
568: return RETCODE_ERR;
569: } else
570: memset(cmd, 0, sizeof(struct tagCommand));
571:
572: cmd->cmd_level = cliLevel;
573: cmd->cmd_func = funcCmd;
574: cmd->cmd_len = strlcpy(cmd->cmd_name, csCmd, STRSIZ);
575: if (csInfo)
576: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
577: if (csHelp)
578: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
579: SLIST_INSERT_HEAD(&buffer->line_cmds, cmd, cmd_next);
580: return RETCODE_OK;
581: }
582:
583: /*
584: * cli_delCommand() Delete command from CLI session
585: * @buffer = CLI buffer
586: * @csCmd = Command name
587: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
588: * return: RETCODE_ERR error, RETCODE_OK ok
589: */
590: int
591: cli_delCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel)
592: {
593: struct tagCommand *cmd;
594: int ret = RETCODE_OK;
595:
596: if (!buffer || !csCmd) {
597: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
598: return RETCODE_ERR;
599: }
600:
601: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
602: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
603: ret = 1;
604: SLIST_REMOVE(&buffer->line_cmds, cmd, tagCommand, cmd_next);
605: free(cmd);
606: break;
607: }
608:
609: return ret;
610: }
611:
612: /*
613: * cli_updCommand() Update command in CLI session
614: * @buffer = CLI buffer
615: * @csCmd = Command name
616: * @cliLevel = Level in CLI, -1 unprivi(view from all), 0 main config, 1 sub config ...
617: * @funcCmd = Callback function when user call command
618: * @csInfo = Inline information for command
619: * @csHelp = Help line when call help
620: * return: RETCODE_ERR error, RETCODE_OK ok
621: */
622: int
623: cli_updCommand(linebuffer_t * __restrict buffer, const char *csCmd, int cliLevel, cmd_func_t funcCmd,
1.2.2.13 misho 624: const char *csInfo, const char *csHelp)
1.2.2.6 misho 625: {
626: struct tagCommand *cmd;
627: int ret = RETCODE_OK;
628:
629: if (!buffer || !csCmd) {
630: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
631: return RETCODE_ERR;
632: }
633:
634: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next)
635: if (cmd->cmd_level == cliLevel && !strcmp(cmd->cmd_name, csCmd)) {
636: ret = 1;
637:
1.2.2.13 misho 638: if (funcCmd)
1.2.2.6 misho 639: cmd->cmd_func = funcCmd;
640: if (csInfo)
641: strlcpy(cmd->cmd_info, csInfo, STRSIZ);
642: if (csHelp)
643: strlcpy(cmd->cmd_help, csHelp, STRSIZ);
644:
645: break;
646: }
647:
648: return ret;
649: }
650:
651:
652: /*
1.2.2.3 misho 653: * cli_addHistory() Add line to history
654: * @buffer = CLI buffer
1.2.2.4 misho 655: * @str = Add custom text or if NULL use readed line from CLI buffer
1.2.2.3 misho 656: * return: RETCODE_ERR error, RETCODE_OK ok
657: */
658: int
659: cli_addHistory(linebuffer_t * __restrict buffer, const char * __restrict str)
660: {
661: struct tagHistory *h;
662:
663: if (!buffer) {
664: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
665: return RETCODE_ERR;
666: }
667:
668: if (!(h = malloc(sizeof(struct tagHistory)))) {
669: LOGERR;
670: return RETCODE_ERR;
671: } else
672: memset(h, 0, sizeof(struct tagHistory));
673:
674: if (str) {
675: if (!*str) {
676: free(h);
677: return RETCODE_OK;
678: }
679:
680: h->hist_len = strlcpy(h->hist_line, str, BUFSIZ);
681: } else {
682: if (!*buffer->line_buf || buffer->line_len < 2) {
683: free(h);
684: return RETCODE_OK;
685: }
686:
687: memcpy(h->hist_line, buffer->line_buf, (h->hist_len = buffer->line_len));
688: io_TrimStr((u_char*) h->hist_line);
689: h->hist_len = strlen(h->hist_line);
690: }
691:
692: TAILQ_INSERT_HEAD(&buffer->line_history, h, hist_next);
693: return h->hist_len;
694: }
695:
696: /*
697: * cli_saveHistory() Save history to file
698: * @buffer = CLI buffer
699: * @histfile = History filename, if NULL will be use default name
700: * @lines = Maximum history lines to save
701: * return: RETCODE_ERR error, RETCODE_OK ok
702: */
703: int
704: cli_saveHistory(linebuffer_t * __restrict buffer, const char *histfile, int lines)
705: {
706: FILE *f;
707: mode_t mode;
708: char szFName[MAXPATHLEN];
709: struct tagHistory *h;
710:
711: if (!buffer) {
712: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
713: return RETCODE_ERR;
714: }
715: if (!histfile)
716: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
717: else
718: strlcpy(szFName, histfile, MAXPATHLEN);
719:
720: mode = umask(0177);
721: f = fopen(szFName, "w");
722: if (!f) {
723: LOGERR;
724: return RETCODE_ERR;
725: }
726:
727: TAILQ_FOREACH(h, &buffer->line_history, hist_next) {
728: fprintf(f, "%s\n", h->hist_line);
729:
730: if (lines)
731: lines--;
732: else
733: break;
734: }
735:
736: fclose(f);
737: umask(mode);
738:
739: return RETCODE_OK;
740: }
741:
742: /*
743: * cli_loadHistory() Load history from file
744: * @buffer = CLI buffer
745: * @histfile = History filename, if NULL will be use default name
746: * return: RETCODE_ERR error, RETCODE_OK ok
747: */
748: int
749: cli_loadHistory(linebuffer_t * __restrict buffer, const char *histfile)
750: {
751: FILE *f;
752: char szFName[MAXPATHLEN], buf[BUFSIZ];
753: struct tagHistory *h;
754:
755: if (!buffer) {
756: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
757: return RETCODE_ERR;
758: }
759: if (!histfile)
760: strlcpy(szFName, HISTORY_FILE, MAXPATHLEN);
761: else
762: strlcpy(szFName, histfile, MAXPATHLEN);
763:
764: f = fopen(szFName, "r");
1.2.2.4 misho 765: if (!f)
766: return RETCODE_OK;
1.2.2.3 misho 767:
768: while (fgets(buf, BUFSIZ, f)) {
769: if (!*buf || *buf == '#')
770: continue;
771: else
772: io_TrimStr((u_char*) buf);
773:
774: if (!(h = malloc(sizeof(struct tagHistory)))) {
775: LOGERR;
776: fclose(f);
777: return RETCODE_ERR;
778: } else
779: memset(h, 0, sizeof(struct tagHistory));
780:
781: h->hist_len = strlcpy(h->hist_line, buf, BUFSIZ);
782: TAILQ_INSERT_TAIL(&buffer->line_history, h, hist_next);
783: }
784:
785: fclose(f);
786:
787: return RETCODE_OK;
788: }
789:
790: /*
791: * cli_resetHistory() Reset history search in CLI session
792: * @buffer = CLI buffer
793: * return: none
794: */
795: inline void
796: cli_resetHistory(linebuffer_t * __restrict buffer)
797: {
798: buffer->line_h = NULL;
799: }
800:
801:
802: /*
803: * cli_freeLine() Clear entire line
804: * @buffer = CLI buffer
805: * return: RETCODE_ERR error, RETCODE_OK ok
806: */
807: inline int
808: cli_freeLine(linebuffer_t * __restrict buffer)
809: {
810: int code = RETCODE_ERR;
811:
812: if (buffer) {
813: if (buffer->line_buf)
814: free(buffer->line_buf);
815:
816: buffer->line_buf = malloc(BUFSIZ);
817: if (buffer->line_buf) {
818: memset(buffer->line_buf, 0, BUFSIZ);
819: buffer->line_eol = buffer->line_bol;
820: buffer->line_len = 1 + buffer->line_eol;
821:
822: code = RETCODE_OK;
823: } else
824: LOGERR;
825: } else
826: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
827:
828: return code;
829: }
830:
831: /*
832: * cli_setPrompt() Set new prompt for CLI session
833: * @buffer = CLI buffer
834: * @prompt = new text for prompt or if NULL disable prompt
835: * return: none
836: */
837: inline void
838: cli_setPrompt(linebuffer_t * __restrict buffer, const char *prompt)
839: {
840: if (buffer) {
841: if (buffer->line_prompt) {
842: free(buffer->line_prompt);
843: buffer->line_prompt = NULL;
844: buffer->line_bol = 0;
845: }
846:
847: if (prompt) {
848: buffer->line_prompt = strdup(prompt);
849: if (buffer->line_prompt) {
850: buffer->line_bol = strlen(buffer->line_prompt);
851: buffer->line_eol = buffer->line_bol;
852: buffer->line_len = 1 + buffer->line_eol;
853: } else
854: LOGERR;
855: }
856: } else
857: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
858: }
859:
860:
861: /*
862: * cliEnd() Clear data, Free resources and close CLI session
863: * @buffer = CLI buffer
864: * return: RETCODE_ERR error, RETCODE_OK ok
865: */
866: void
867: cliEnd(linebuffer_t * __restrict buffer)
868: {
869: struct tagHistory *h;
1.2.2.4 misho 870: struct tagCommand *c;
1.2.2.3 misho 871:
872: if (buffer) {
1.2.2.4 misho 873: while ((c = SLIST_FIRST(&buffer->line_cmds))) {
874: SLIST_REMOVE_HEAD(&buffer->line_cmds, cmd_next);
875: free(c);
876: }
1.2.2.3 misho 877: while ((h = TAILQ_FIRST(&buffer->line_history))) {
878: TAILQ_REMOVE(&buffer->line_history, h, hist_next);
879: free(h);
880: }
881:
882: if (buffer->line_prompt)
883: free(buffer->line_prompt);
884:
885: if (buffer->line_keys)
886: free(buffer->line_keys);
887: if (buffer->line_buf)
888: free(buffer->line_buf);
889:
890: free(buffer);
891: buffer = NULL;
892: } else
893: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
894: }
895:
896: /*
897: * cliInit() Start CLI session, allocate memory for resources and bind keys
898: * @fin = Input device handle
899: * @fout = Output device handle
900: * @prompt = text for prompt, if NULL disable prompt
901: * return: NULL if error or !=NULL CLI buffer
902: */
903: linebuffer_t *
904: cliInit(int fin, int fout, const char *prompt)
905: {
906: linebuffer_t *buffer;
907: bindkey_t *keys;
908: register int i;
909: struct termios t;
910:
911: memset(&t, 0, sizeof t);
912: /* init buffer */
913: buffer = malloc(sizeof (linebuffer_t));
914: if (!buffer) {
915: LOGERR;
916: return NULL;
917: } else {
918: memset(buffer, 0, sizeof(linebuffer_t));
919:
920: buffer->line_in = fin;
921: buffer->line_out = fout;
922:
923: TAILQ_INIT(&buffer->line_history);
1.2.2.4 misho 924: SLIST_INIT(&buffer->line_cmds);
1.2.2.3 misho 925:
926: if (prompt) {
927: buffer->line_prompt = strdup(prompt);
928: if (!buffer->line_prompt) {
929: LOGERR;
930: free(buffer);
931: return NULL;
932: } else
933: buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
934: }
935: }
936: buffer->line_buf = malloc(BUFSIZ);
937: if (!buffer->line_buf) {
938: LOGERR;
939: if (buffer->line_prompt)
940: free(buffer->line_prompt);
941: free(buffer);
942: return NULL;
943: } else {
944: memset(buffer->line_buf, 0, BUFSIZ);
945: buffer->line_len = 1 + buffer->line_eol;
946: }
947: keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
948: if (!keys) {
949: LOGERR;
950: if (buffer->line_prompt)
951: free(buffer->line_prompt);
952: free(buffer->line_buf);
953: free(buffer);
954: return NULL;
955: } else
956: memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
957:
1.2.2.7 misho 958: /* add helper functions */
1.2.2.13 misho 959: cli_addCommand(buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
960: cli_addCommand(buffer, "help", 0, cli_Cmd_Help, "help [command] <cr>", "Help screen");
1.2.2.15 misho 961: cli_addCommand(buffer, "-------", 0, NULL, "-------------------------", NULL);
1.2.2.7 misho 962:
1.2.2.3 misho 963: /* fill key bindings */
964: // ascii chars & ctrl+chars
965: for (i = 0; i < 256; i++) {
966: *keys[i].key_ch = (u_char) i;
967: keys[i].key_len = 1;
968:
969: if (!i || i == *K_CTRL_D)
970: keys[i].key_func = bufEOF;
971: if (i == *K_CTRL_M || i == *K_CTRL_J)
972: keys[i].key_func = bufEOL;
973: if (i == *K_CTRL_H || i == *K_BACKSPACE)
974: keys[i].key_func = bufBS;
975: if (i == *K_CTRL_C)
976: keys[i].key_func = bufCLR;
977: if (i == *K_CTRL_A)
978: keys[i].key_func = bufBEGIN;
979: if (i == *K_CTRL_E)
980: keys[i].key_func = bufEND;
1.2.2.8 misho 981: if (i == *K_TAB)
982: keys[i].key_func = bufComp;
1.2.2.3 misho 983: if (i >= *K_SPACE && i < *K_BACKSPACE)
984: keys[i].key_func = bufCHAR;
985: if (i > *K_BACKSPACE && i < 0xff)
986: keys[i].key_func = bufCHAR;
1.2.2.8 misho 987: if (i == '?')
988: keys[i].key_func = bufHelp;
1.2.2.3 misho 989: }
990: // alt+chars
991: for (i = 256; i < 512; i++) {
992: keys[i].key_ch[0] = 0x1b;
993: keys[i].key_ch[1] = (u_char) i - 256;
994: keys[i].key_len = 2;
995: }
996:
997: // 3 bytes
998: keys[i].key_len = sizeof K_F1 - 1;
999: memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
1000: i++;
1001: keys[i].key_len = sizeof K_F2 - 1;
1002: memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
1003: i++;
1004: keys[i].key_len = sizeof K_F3 - 1;
1005: memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
1006: i++;
1007: keys[i].key_len = sizeof K_F4 - 1;
1008: memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
1009: i++;
1010: keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
1011: memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
1012: i++;
1013: keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
1014: memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
1015: i++;
1016: keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
1017: memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
1018: i++;
1019: keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
1020: memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
1021: i++;
1022: keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
1023: memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
1024: i++;
1025: keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
1026: memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
1027: i++;
1028: keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
1029: memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
1030: i++;
1031: keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
1032: memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
1033: i++;
1034: keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
1035: memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
1036: i++;
1037: keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
1038: memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
1039: i++;
1040: keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
1041: memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
1042: i++;
1043: keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
1044: memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
1045: i++;
1046: keys[i].key_len = sizeof K_CTRL_F1 - 1;
1047: memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
1048: i++;
1049: keys[i].key_len = sizeof K_CTRL_F2 - 1;
1050: memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
1051: i++;
1052: keys[i].key_len = sizeof K_CTRL_F3 - 1;
1053: memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
1054: i++;
1055: keys[i].key_len = sizeof K_CTRL_F4 - 1;
1056: memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
1057: i++;
1058: keys[i].key_len = sizeof K_CTRL_F5 - 1;
1059: memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
1060: i++;
1061: keys[i].key_len = sizeof K_CTRL_F6 - 1;
1062: memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
1063: i++;
1064: keys[i].key_len = sizeof K_CTRL_F7 - 1;
1065: memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
1066: i++;
1067: keys[i].key_len = sizeof K_CTRL_F8 - 1;
1068: memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
1069: i++;
1070: keys[i].key_len = sizeof K_CTRL_F9 - 1;
1071: memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
1072: i++;
1073: keys[i].key_len = sizeof K_CTRL_F10 - 1;
1074: memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
1075: i++;
1076: keys[i].key_len = sizeof K_CTRL_F11 - 1;
1077: memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
1078: i++;
1079: keys[i].key_len = sizeof K_CTRL_F12 - 1;
1080: memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
1081: i++;
1082: keys[i].key_len = sizeof K_HOME - 1;
1083: keys[i].key_func = bufBEGIN;
1084: memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
1085: i++;
1086: keys[i].key_len = sizeof K_END - 1;
1087: keys[i].key_func = bufEND;
1088: memcpy(keys[i].key_ch, K_END, keys[i].key_len);
1089: i++;
1090: keys[i].key_len = sizeof K_UP - 1;
1091: keys[i].key_func = bufUP;
1092: memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
1093: i++;
1094: keys[i].key_len = sizeof K_DOWN - 1;
1095: keys[i].key_func = bufDOWN;
1096: memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
1097: i++;
1098: keys[i].key_len = sizeof K_RIGHT - 1;
1099: keys[i].key_func = bufRIGHT;
1100: memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
1101: i++;
1102: keys[i].key_len = sizeof K_LEFT - 1;
1103: keys[i].key_func = bufLEFT;
1104: memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
1105: i++;
1106: keys[i].key_len = sizeof K_BTAB - 1;
1107: keys[i].key_func = bufBTAB;
1108: memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1109: i++;
1110: // 4 bytes
1111: keys[i].key_len = sizeof K_INS - 1;
1112: keys[i].key_func = bufMODE;
1113: memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1114: i++;
1115: keys[i].key_len = sizeof K_DEL - 1;
1116: keys[i].key_func = bufDEL;
1117: memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1118: i++;
1119: keys[i].key_len = sizeof K_PGUP - 1;
1120: memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1121: i++;
1122: keys[i].key_len = sizeof K_PGDN - 1;
1123: memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1124: i++;
1125: // 5 bytes
1126: keys[i].key_len = sizeof K_F5 - 1;
1127: memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1128: i++;
1129: keys[i].key_len = sizeof K_F6 - 1;
1130: memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1131: i++;
1132: keys[i].key_len = sizeof K_F7 - 1;
1133: memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1134: i++;
1135: keys[i].key_len = sizeof K_F8 - 1;
1136: memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1137: i++;
1138: keys[i].key_len = sizeof K_F9 - 1;
1139: memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1140: i++;
1141: keys[i].key_len = sizeof K_F10 - 1;
1142: memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1143: i++;
1144: keys[i].key_len = sizeof K_F11 - 1;
1145: memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1146: i++;
1147: keys[i].key_len = sizeof K_F12 - 1;
1148: memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1149: i++;
1150:
1151: tcgetattr(buffer->line_in, &t);
1152: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1153: t.c_iflag |= IGNBRK;
1154: t.c_cc[VMIN] = 1;
1155: t.c_cc[VTIME] = 0;
1156: tcsetattr(buffer->line_in, TCSANOW, &t);
1157:
1158: buffer->line_keys = keys;
1159: return buffer;
1160: }
1161:
1.2 misho 1162: /*
1.2.2.4 misho 1163: * cliReadLine() Read line from opened CLI session
1164: * @buffer = CLI buffer
1165: * return: NULL if error or !=NULL readed line, must be free after use!
1.2 misho 1166: */
1.2.2.4 misho 1167: char *
1168: cliReadLine(linebuffer_t * __restrict buffer)
1.2 misho 1169: {
1.2.2.4 misho 1170: int code, readLen;
1171: register int i;
1172: struct pollfd fds;
1173: char buf[BUFSIZ], *str = NULL;
1.2 misho 1174:
1.2.2.4 misho 1175: if (!buffer) {
1176: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1177: return NULL;
1.2 misho 1178: }
1179:
1.2.2.4 misho 1180: memset(&fds, 0, sizeof fds);
1181: fds.fd = buffer->line_in;
1182: fds.events = POLLIN;
1183:
1184: printfCR(buffer, 1);
1185: while (42) {
1186: if (poll(&fds, 1, -1) < 1) {
1187: LOGERR;
1188: return str;
1189: }
1.2 misho 1190:
1.2.2.4 misho 1191: memset(buf, 0, sizeof buf);
1192: readLen = read(buffer->line_in, buf, BUFSIZ);
1193: if (readLen == -1) {
1194: LOGERR;
1195: return str;
1196: }
1197: if (!readLen) {
1198: if (buffer->line_buf)
1199: str = strdup(buffer->line_buf);
1200: else
1201: cli_SetErr(EPIPE, "Error:: unknown state ...");
1202: return str;
1203: }
1.2 misho 1204:
1.2.2.4 misho 1205: recheck:
1206: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
1207: if (readLen >= buffer->line_keys[i].key_len &&
1208: !memcmp(buffer->line_keys[i].key_ch, buf,
1209: buffer->line_keys[i].key_len)) {
1210: readLen -= buffer->line_keys[i].key_len;
1211: if (readLen)
1212: memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
1213: else
1214: memset(buf, 0, buffer->line_keys[i].key_len);
1215:
1216: if (buffer->line_keys[i].key_func)
1217: if ((code = buffer->line_keys[i].key_func(i, buffer)))
1218: readLen = 0;
1219:
1220: if (readLen)
1221: goto recheck;
1222: else
1223: break;
1224: }
1.2 misho 1225:
1.2.2.4 misho 1226: if (code)
1227: break;
1228: }
1229:
1.2.2.5 misho 1230: if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
1.2.2.4 misho 1231: str = strdup(buffer->line_buf);
1232: return str;
1.2 misho 1233: }
1.2.2.4 misho 1234:
1235:
1.2 misho 1236: /*
1.2.2.4 misho 1237: * cliNetLoop() CLI network main loop binded to socket
1238: * @buffer = CLI buffer
1239: * @csHistFile = History file name
1.2 misho 1240: * @sock = client socket
1241: * @term = stdin termios
1242: * @win = window size of tty
1.2.2.4 misho 1243: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1244: */
1.2.2.1 misho 1245: int
1.2.2.4 misho 1246: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock,
1247: struct termios *term, struct winsize *win)
1.2 misho 1248: {
1.2.2.4 misho 1249: u_char buf[BUFSIZ];
1250: int pty, r, s, alen, attrlen, flg, ret = 0;
1.2 misho 1251: fd_set fds;
1252: struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
1253: struct telnetAttrs *a, Attr[10];
1254:
1255: switch (forkpty(&pty, NULL, term, win)) {
1256: case -1:
1257: LOGERR;
1258: return -1;
1259: case 0:
1260: close(sock);
1261:
1.2.2.14 misho 1262: if (buffer)
1.2.2.8 misho 1263: ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
1.2.2.14 misho 1264: else
1.2.2.8 misho 1265: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1.2.2.4 misho 1266:
1.2 misho 1267: /* spawn Shell mode */
1.2.2.16! misho 1268: //execl("/bin/tcsh", "tcsh", NULL);
1.2.2.4 misho 1269:
1.2 misho 1270: _exit(ret);
1271: default:
1272: telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
1273: telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
1274: telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
1275: telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
1276: telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
1277: if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
1278: cli_Errno = telnet_GetErrno();
1279: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1280: return -1;
1281: } else
1282: flg = 0;
1283:
1284: while (42) {
1285: FD_ZERO(&fds);
1286: FD_SET(sock, &fds);
1287: FD_SET(pty, &fds);
1288: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
1289: if (!ret)
1290: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
1291:
1292: break;
1293: }
1294:
1295: r = FD_ISSET(sock, &fds) ? sock : pty;
1296: s = FD_ISSET(sock, &fds) ? pty : sock;
1297:
1298: if ((ret = telnetRecv(r, &a, &alen, buf, BUFSIZ)) < 0) {
1299: if (a)
1300: free(a);
1301:
1302: if (-2 == ret)
1303: continue;
1304: // EOF
1305: if (-3 == ret)
1306: shutdown(r, SHUT_RD);
1307: else {
1308: cli_Errno = telnet_GetErrno();
1309: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1310: }
1311: break;
1312: }
1313: attrlen = 0;
1314: if (1 == flg && alen) {
1315: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
1316: telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1317: }
1318: if (2 == flg && alen) {
1319: telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
1320: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1321: LFLOW_OFF, NULL, 0);
1322: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1323: LFLOW_RESTART_XON, NULL, 0);
1324: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1325: }
1326: if (a)
1327: free(a);
1328:
1329: if ((ret = telnetSend(s, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
1330: cli_Errno = telnet_GetErrno();
1331: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1332: break;
1333: } else
1334: flg++;
1335: }
1336:
1337: close(pty);
1338: }
1339:
1340: return ret;
1341: }
1342:
1343: /*
1.2.2.4 misho 1344: * cliLoop() CLI main loop
1345: * @buffer = CLI buffer
1346: * @csHistFile = History file name
1347: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 1348: */
1.2.2.4 misho 1349: int
1350: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
1.1 misho 1351: {
1352: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
1353: register int i;
1.2.2.4 misho 1354: int ret = RETCODE_OK;
1355: struct tagCommand *cmd;
1.1 misho 1356:
1357: /* --- main body of CLI --- */
1.2.2.4 misho 1358:
1359: if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
1360: return RETCODE_ERR;
1.1 misho 1361:
1362: do {
1.2.2.4 misho 1363: line = cliReadLine(buffer);
1.2.2.5 misho 1364: if (!line) {
1365: printfNL(buffer, 0);
1.1 misho 1366: break;
1.2.2.5 misho 1367: } else
1.2.2.4 misho 1368: cli_addHistory(buffer, NULL);
1.1 misho 1369: // clear whitespaces
1370: for (s = line; isspace(*s); s++);
1371: if (*s) {
1372: for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
1373: *++t = 0;
1374: }
1375:
1376: if (*s) {
1377: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1378: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
1379: *app ? app++ : app);
1380:
1381: // exec_cmd ...
1.2.2.4 misho 1382: i = 0;
1383: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
1384: if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1 misho 1385: break;
1.2.2.4 misho 1386: else
1387: i++;
1388: }
1.2.2.5 misho 1389:
1.1 misho 1390: if (!cmd) {
1.2.2.5 misho 1391: cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
1.1 misho 1392: ret = -1;
1393: } else
1.2.2.15 misho 1394: if (cmd->cmd_func)
1395: ret = cmd->cmd_func(buffer, i, items);
1396: else {
1397: clrscrEOL(buffer);
1398: printfCR(buffer, 1);
1399: }
1.1 misho 1400: }
1401:
1.2.2.4 misho 1402: cli_freeLine(buffer);
1403: cli_resetHistory(buffer);
1.1 misho 1404: free(line);
1405: } while (ret < 1);
1406:
1.2.2.4 misho 1407: cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
1.1 misho 1408: return ret;
1409: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>