Annotation of libaitcli/src/aitcli.c, revision 1.2.2.18
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.18! misho 6: * $Id: aitcli.c,v 1.2.2.17 2010/06/09 09:32:30 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:
910: /* init buffer */
1.2.2.18! misho 911: buffer = malloc(sizeof(linebuffer_t));
1.2.2.3 misho 912: if (!buffer) {
913: LOGERR;
914: return NULL;
915: } else {
916: memset(buffer, 0, sizeof(linebuffer_t));
917:
918: buffer->line_in = fin;
919: buffer->line_out = fout;
920:
921: TAILQ_INIT(&buffer->line_history);
1.2.2.4 misho 922: SLIST_INIT(&buffer->line_cmds);
1.2.2.3 misho 923:
924: if (prompt) {
925: buffer->line_prompt = strdup(prompt);
926: if (!buffer->line_prompt) {
927: LOGERR;
928: free(buffer);
929: return NULL;
930: } else
931: buffer->line_eol = buffer->line_bol = strlen(buffer->line_prompt);
932: }
933: }
934: buffer->line_buf = malloc(BUFSIZ);
935: if (!buffer->line_buf) {
936: LOGERR;
937: if (buffer->line_prompt)
938: free(buffer->line_prompt);
939: free(buffer);
940: return NULL;
941: } else {
942: memset(buffer->line_buf, 0, BUFSIZ);
943: buffer->line_len = 1 + buffer->line_eol;
944: }
945: keys = calloc(MAX_BINDKEY + 1, sizeof(bindkey_t));
946: if (!keys) {
947: LOGERR;
948: if (buffer->line_prompt)
949: free(buffer->line_prompt);
950: free(buffer->line_buf);
951: free(buffer);
952: return NULL;
953: } else
954: memset(keys, 0, sizeof(bindkey_t) * (MAX_BINDKEY + 1));
955:
1.2.2.7 misho 956: /* add helper functions */
1.2.2.13 misho 957: cli_addCommand(buffer, "exit", 0, cli_Cmd_Exit, "exit <cr>", "Exit from console");
958: cli_addCommand(buffer, "help", 0, cli_Cmd_Help, "help [command] <cr>", "Help screen");
1.2.2.15 misho 959: cli_addCommand(buffer, "-------", 0, NULL, "-------------------------", NULL);
1.2.2.7 misho 960:
1.2.2.3 misho 961: /* fill key bindings */
962: // ascii chars & ctrl+chars
963: for (i = 0; i < 256; i++) {
964: *keys[i].key_ch = (u_char) i;
965: keys[i].key_len = 1;
966:
967: if (!i || i == *K_CTRL_D)
968: keys[i].key_func = bufEOF;
969: if (i == *K_CTRL_M || i == *K_CTRL_J)
970: keys[i].key_func = bufEOL;
971: if (i == *K_CTRL_H || i == *K_BACKSPACE)
972: keys[i].key_func = bufBS;
973: if (i == *K_CTRL_C)
974: keys[i].key_func = bufCLR;
975: if (i == *K_CTRL_A)
976: keys[i].key_func = bufBEGIN;
977: if (i == *K_CTRL_E)
978: keys[i].key_func = bufEND;
1.2.2.8 misho 979: if (i == *K_TAB)
980: keys[i].key_func = bufComp;
1.2.2.3 misho 981: if (i >= *K_SPACE && i < *K_BACKSPACE)
982: keys[i].key_func = bufCHAR;
983: if (i > *K_BACKSPACE && i < 0xff)
984: keys[i].key_func = bufCHAR;
1.2.2.8 misho 985: if (i == '?')
986: keys[i].key_func = bufHelp;
1.2.2.3 misho 987: }
988: // alt+chars
989: for (i = 256; i < 512; i++) {
990: keys[i].key_ch[0] = 0x1b;
991: keys[i].key_ch[1] = (u_char) i - 256;
992: keys[i].key_len = 2;
993: }
994:
995: // 3 bytes
996: keys[i].key_len = sizeof K_F1 - 1;
997: memcpy(keys[i].key_ch, K_F1, keys[i].key_len);
998: i++;
999: keys[i].key_len = sizeof K_F2 - 1;
1000: memcpy(keys[i].key_ch, K_F2, keys[i].key_len);
1001: i++;
1002: keys[i].key_len = sizeof K_F3 - 1;
1003: memcpy(keys[i].key_ch, K_F3, keys[i].key_len);
1004: i++;
1005: keys[i].key_len = sizeof K_F4 - 1;
1006: memcpy(keys[i].key_ch, K_F4, keys[i].key_len);
1007: i++;
1008: keys[i].key_len = sizeof K_CTRL_SH_F1 - 1;
1009: memcpy(keys[i].key_ch, K_CTRL_SH_F1, keys[i].key_len);
1010: i++;
1011: keys[i].key_len = sizeof K_CTRL_SH_F2 - 1;
1012: memcpy(keys[i].key_ch, K_CTRL_SH_F2, keys[i].key_len);
1013: i++;
1014: keys[i].key_len = sizeof K_CTRL_SH_F3 - 1;
1015: memcpy(keys[i].key_ch, K_CTRL_SH_F3, keys[i].key_len);
1016: i++;
1017: keys[i].key_len = sizeof K_CTRL_SH_F4 - 1;
1018: memcpy(keys[i].key_ch, K_CTRL_SH_F4, keys[i].key_len);
1019: i++;
1020: keys[i].key_len = sizeof K_CTRL_SH_F5 - 1;
1021: memcpy(keys[i].key_ch, K_CTRL_SH_F5, keys[i].key_len);
1022: i++;
1023: keys[i].key_len = sizeof K_CTRL_SH_F6 - 1;
1024: memcpy(keys[i].key_ch, K_CTRL_SH_F6, keys[i].key_len);
1025: i++;
1026: keys[i].key_len = sizeof K_CTRL_SH_F7 - 1;
1027: memcpy(keys[i].key_ch, K_CTRL_SH_F7, keys[i].key_len);
1028: i++;
1029: keys[i].key_len = sizeof K_CTRL_SH_F8 - 1;
1030: memcpy(keys[i].key_ch, K_CTRL_SH_F8, keys[i].key_len);
1031: i++;
1032: keys[i].key_len = sizeof K_CTRL_SH_F9 - 1;
1033: memcpy(keys[i].key_ch, K_CTRL_SH_F9, keys[i].key_len);
1034: i++;
1035: keys[i].key_len = sizeof K_CTRL_SH_F10 - 1;
1036: memcpy(keys[i].key_ch, K_CTRL_SH_F10, keys[i].key_len);
1037: i++;
1038: keys[i].key_len = sizeof K_CTRL_SH_F11 - 1;
1039: memcpy(keys[i].key_ch, K_CTRL_SH_F11, keys[i].key_len);
1040: i++;
1041: keys[i].key_len = sizeof K_CTRL_SH_F12 - 1;
1042: memcpy(keys[i].key_ch, K_CTRL_SH_F12, keys[i].key_len);
1043: i++;
1044: keys[i].key_len = sizeof K_CTRL_F1 - 1;
1045: memcpy(keys[i].key_ch, K_CTRL_F1, keys[i].key_len);
1046: i++;
1047: keys[i].key_len = sizeof K_CTRL_F2 - 1;
1048: memcpy(keys[i].key_ch, K_CTRL_F2, keys[i].key_len);
1049: i++;
1050: keys[i].key_len = sizeof K_CTRL_F3 - 1;
1051: memcpy(keys[i].key_ch, K_CTRL_F3, keys[i].key_len);
1052: i++;
1053: keys[i].key_len = sizeof K_CTRL_F4 - 1;
1054: memcpy(keys[i].key_ch, K_CTRL_F4, keys[i].key_len);
1055: i++;
1056: keys[i].key_len = sizeof K_CTRL_F5 - 1;
1057: memcpy(keys[i].key_ch, K_CTRL_F5, keys[i].key_len);
1058: i++;
1059: keys[i].key_len = sizeof K_CTRL_F6 - 1;
1060: memcpy(keys[i].key_ch, K_CTRL_F6, keys[i].key_len);
1061: i++;
1062: keys[i].key_len = sizeof K_CTRL_F7 - 1;
1063: memcpy(keys[i].key_ch, K_CTRL_F7, keys[i].key_len);
1064: i++;
1065: keys[i].key_len = sizeof K_CTRL_F8 - 1;
1066: memcpy(keys[i].key_ch, K_CTRL_F8, keys[i].key_len);
1067: i++;
1068: keys[i].key_len = sizeof K_CTRL_F9 - 1;
1069: memcpy(keys[i].key_ch, K_CTRL_F9, keys[i].key_len);
1070: i++;
1071: keys[i].key_len = sizeof K_CTRL_F10 - 1;
1072: memcpy(keys[i].key_ch, K_CTRL_F10, keys[i].key_len);
1073: i++;
1074: keys[i].key_len = sizeof K_CTRL_F11 - 1;
1075: memcpy(keys[i].key_ch, K_CTRL_F11, keys[i].key_len);
1076: i++;
1077: keys[i].key_len = sizeof K_CTRL_F12 - 1;
1078: memcpy(keys[i].key_ch, K_CTRL_F12, keys[i].key_len);
1079: i++;
1080: keys[i].key_len = sizeof K_HOME - 1;
1081: keys[i].key_func = bufBEGIN;
1082: memcpy(keys[i].key_ch, K_HOME, keys[i].key_len);
1083: i++;
1084: keys[i].key_len = sizeof K_END - 1;
1085: keys[i].key_func = bufEND;
1086: memcpy(keys[i].key_ch, K_END, keys[i].key_len);
1087: i++;
1088: keys[i].key_len = sizeof K_UP - 1;
1089: keys[i].key_func = bufUP;
1090: memcpy(keys[i].key_ch, K_UP, keys[i].key_len);
1091: i++;
1092: keys[i].key_len = sizeof K_DOWN - 1;
1093: keys[i].key_func = bufDOWN;
1094: memcpy(keys[i].key_ch, K_DOWN, keys[i].key_len);
1095: i++;
1096: keys[i].key_len = sizeof K_RIGHT - 1;
1097: keys[i].key_func = bufRIGHT;
1098: memcpy(keys[i].key_ch, K_RIGHT, keys[i].key_len);
1099: i++;
1100: keys[i].key_len = sizeof K_LEFT - 1;
1101: keys[i].key_func = bufLEFT;
1102: memcpy(keys[i].key_ch, K_LEFT, keys[i].key_len);
1103: i++;
1104: keys[i].key_len = sizeof K_BTAB - 1;
1105: keys[i].key_func = bufBTAB;
1106: memcpy(keys[i].key_ch, K_BTAB, keys[i].key_len);
1107: i++;
1108: // 4 bytes
1109: keys[i].key_len = sizeof K_INS - 1;
1110: keys[i].key_func = bufMODE;
1111: memcpy(keys[i].key_ch, K_INS, keys[i].key_len);
1112: i++;
1113: keys[i].key_len = sizeof K_DEL - 1;
1114: keys[i].key_func = bufDEL;
1115: memcpy(keys[i].key_ch, K_DEL, keys[i].key_len);
1116: i++;
1117: keys[i].key_len = sizeof K_PGUP - 1;
1118: memcpy(keys[i].key_ch, K_PGUP, keys[i].key_len);
1119: i++;
1120: keys[i].key_len = sizeof K_PGDN - 1;
1121: memcpy(keys[i].key_ch, K_PGDN, keys[i].key_len);
1122: i++;
1123: // 5 bytes
1124: keys[i].key_len = sizeof K_F5 - 1;
1125: memcpy(keys[i].key_ch, K_F5, keys[i].key_len);
1126: i++;
1127: keys[i].key_len = sizeof K_F6 - 1;
1128: memcpy(keys[i].key_ch, K_F6, keys[i].key_len);
1129: i++;
1130: keys[i].key_len = sizeof K_F7 - 1;
1131: memcpy(keys[i].key_ch, K_F7, keys[i].key_len);
1132: i++;
1133: keys[i].key_len = sizeof K_F8 - 1;
1134: memcpy(keys[i].key_ch, K_F8, keys[i].key_len);
1135: i++;
1136: keys[i].key_len = sizeof K_F9 - 1;
1137: memcpy(keys[i].key_ch, K_F9, keys[i].key_len);
1138: i++;
1139: keys[i].key_len = sizeof K_F10 - 1;
1140: memcpy(keys[i].key_ch, K_F10, keys[i].key_len);
1141: i++;
1142: keys[i].key_len = sizeof K_F11 - 1;
1143: memcpy(keys[i].key_ch, K_F11, keys[i].key_len);
1144: i++;
1145: keys[i].key_len = sizeof K_F12 - 1;
1146: memcpy(keys[i].key_ch, K_F12, keys[i].key_len);
1147: i++;
1148:
1.2.2.18! misho 1149: buffer->line_keys = keys;
! 1150: return buffer;
! 1151: }
! 1152:
! 1153: /*
! 1154: * cliInitLine() Init CLI input line terminal
! 1155: * @buffer = CLI buffer
! 1156: * return: none
! 1157: */
! 1158: int
! 1159: cliInitLine(linebuffer_t * __restrict buffer)
! 1160: {
! 1161: struct termios t;
! 1162:
! 1163: memset(&t, 0, sizeof t);
1.2.2.3 misho 1164: tcgetattr(buffer->line_in, &t);
1165: t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
1166: t.c_iflag |= IGNBRK;
1167: t.c_cc[VMIN] = 1;
1168: t.c_cc[VTIME] = 0;
1.2.2.18! misho 1169: return tcsetattr(buffer->line_in, TCSANOW, &t);
1.2.2.3 misho 1170: }
1171:
1.2 misho 1172: /*
1.2.2.4 misho 1173: * cliReadLine() Read line from opened CLI session
1174: * @buffer = CLI buffer
1175: * return: NULL if error or !=NULL readed line, must be free after use!
1.2 misho 1176: */
1.2.2.4 misho 1177: char *
1178: cliReadLine(linebuffer_t * __restrict buffer)
1.2 misho 1179: {
1.2.2.4 misho 1180: int code, readLen;
1181: register int i;
1182: struct pollfd fds;
1183: char buf[BUFSIZ], *str = NULL;
1.2 misho 1184:
1.2.2.4 misho 1185: if (!buffer) {
1186: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1187: return NULL;
1.2 misho 1188: }
1189:
1.2.2.4 misho 1190: memset(&fds, 0, sizeof fds);
1191: fds.fd = buffer->line_in;
1192: fds.events = POLLIN;
1193:
1194: printfCR(buffer, 1);
1195: while (42) {
1196: if (poll(&fds, 1, -1) < 1) {
1197: LOGERR;
1198: return str;
1199: }
1.2 misho 1200:
1.2.2.4 misho 1201: memset(buf, 0, sizeof buf);
1202: readLen = read(buffer->line_in, buf, BUFSIZ);
1203: if (readLen == -1) {
1204: LOGERR;
1205: return str;
1206: }
1207: if (!readLen) {
1208: if (buffer->line_buf)
1209: str = strdup(buffer->line_buf);
1210: else
1211: cli_SetErr(EPIPE, "Error:: unknown state ...");
1212: return str;
1213: }
1.2 misho 1214:
1.2.2.4 misho 1215: recheck:
1216: for (code = RETCODE_OK, i = MAX_BINDKEY - 1; i > -1; i--)
1217: if (readLen >= buffer->line_keys[i].key_len &&
1218: !memcmp(buffer->line_keys[i].key_ch, buf,
1219: buffer->line_keys[i].key_len)) {
1220: readLen -= buffer->line_keys[i].key_len;
1221: if (readLen)
1222: memmove(buf, buf + buffer->line_keys[i].key_len, readLen);
1223: else
1224: memset(buf, 0, buffer->line_keys[i].key_len);
1225:
1226: if (buffer->line_keys[i].key_func)
1227: if ((code = buffer->line_keys[i].key_func(i, buffer)))
1228: readLen = 0;
1229:
1230: if (readLen)
1231: goto recheck;
1232: else
1233: break;
1234: }
1.2 misho 1235:
1.2.2.4 misho 1236: if (code)
1237: break;
1238: }
1239:
1.2.2.5 misho 1240: if (code != RETCODE_ERR && code != RETCODE_EOF && buffer->line_buf)
1.2.2.4 misho 1241: str = strdup(buffer->line_buf);
1242: return str;
1.2 misho 1243: }
1.2.2.4 misho 1244:
1245:
1.2 misho 1246: /*
1.2.2.4 misho 1247: * cliNetLoop() CLI network main loop binded to socket
1248: * @buffer = CLI buffer
1249: * @csHistFile = History file name
1.2 misho 1250: * @sock = client socket
1.2.2.4 misho 1251: * return: RETCODE_ERR error, RETCODE_OK ok
1.2 misho 1252: */
1.2.2.1 misho 1253: int
1.2.2.17 misho 1254: cliNetLoop(linebuffer_t * __restrict buffer, const char *csHistFile, int sock)
1.2 misho 1255: {
1.2.2.4 misho 1256: u_char buf[BUFSIZ];
1.2.2.17 misho 1257: int pty, r, s, alen, flg, attrlen = 0, ret = 0;
1.2 misho 1258: fd_set fds;
1259: struct timeval tv = { DEFAULT_SOCK_TIMEOUT, 0 };
1260: struct telnetAttrs *a, Attr[10];
1261:
1.2.2.17 misho 1262: switch (forkpty(&pty, NULL, NULL, NULL)) {
1.2 misho 1263: case -1:
1264: LOGERR;
1265: return -1;
1266: case 0:
1.2.2.18! misho 1267: if (!buffer) {
1.2.2.8 misho 1268: cli_SetErr(EINVAL, "Error:: invalid input parameters ...");
1.2.2.18! misho 1269: return -1;
! 1270: } else
! 1271: close(sock);
1.2.2.4 misho 1272:
1.2.2.18! misho 1273: cliInitLine(buffer);
! 1274: ret = cliLoop(buffer, csHistFile) < 0 ? 1 : 0;
! 1275: cliEnd(buffer);
1.2.2.4 misho 1276:
1.2.2.18! misho 1277: exit(ret);
1.2 misho 1278: default:
1279: telnet_SetCmd(Attr + 0, DO, TELOPT_TTYPE);
1280: telnet_SetCmd(Attr + 1, WILL, TELOPT_ECHO);
1281: telnet_Set_SubOpt(Attr + 2, TELOPT_LFLOW, LFLOW_OFF, NULL, 0);
1282: telnet_Set_SubOpt(Attr + 3, TELOPT_LFLOW, LFLOW_RESTART_XON, NULL, 0);
1283: telnet_SetCmd(Attr + 4, DO, TELOPT_LINEMODE);
1284: if ((ret = telnetSend(sock, Attr, 5, NULL, 0, 0)) == -1) {
1285: cli_Errno = telnet_GetErrno();
1286: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1287: return -1;
1288: } else
1289: flg = 0;
1290:
1291: while (42) {
1292: FD_ZERO(&fds);
1293: FD_SET(sock, &fds);
1294: FD_SET(pty, &fds);
1295: if ((ret = select(FD_SETSIZE, &fds, NULL, NULL, &tv)) < 1) {
1296: if (!ret)
1297: cli_SetErr(ETIMEDOUT, "Client session timeout ...");
1298:
1299: break;
1300: }
1301:
1302: r = FD_ISSET(sock, &fds) ? sock : pty;
1303: s = FD_ISSET(sock, &fds) ? pty : sock;
1304:
1.2.2.17 misho 1305: if (FD_ISSET(sock, &fds)) {
1306: memset(buf, 0, BUFSIZ);
1307: if ((ret = telnetRecv(sock, &a, &alen, buf, BUFSIZ)) < 0) {
1308: if (a)
1309: free(a);
1310:
1311: if (-2 == ret)
1312: continue;
1313: // EOF
1314: if (-3 == ret)
1315: shutdown(sock, SHUT_RD);
1316: else {
1317: cli_Errno = telnet_GetErrno();
1318: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1319: }
1320: break;
1321: }
1322: attrlen = 0;
1323: if (1 == flg && alen) {
1324: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_SGA);
1325: telnet_SetCmd(&Attr[attrlen++], DO, TELOPT_ECHO);
1326: }
1327: if (2 == flg && alen) {
1328: telnet_SetCmd(&Attr[attrlen++], WILL, TELOPT_ECHO);
1329: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1330: LFLOW_OFF, NULL, 0);
1331: telnet_Set_SubOpt(&Attr[attrlen++], TELOPT_LFLOW,
1332: LFLOW_RESTART_XON, NULL, 0);
1333: telnet_SetCmd(&Attr[attrlen++], DONT, TELOPT_LINEMODE);
1334: }
1.2 misho 1335: if (a)
1336: free(a);
1337:
1.2.2.17 misho 1338: if ((ret = write(pty, buf, ret)) == -1) {
1339: LOGERR;
1340: break;
1.2 misho 1341: }
1342: }
1343:
1.2.2.17 misho 1344: if (FD_ISSET(pty, &fds)) {
1345: memset(buf, 0, BUFSIZ);
1346: if ((ret = read(pty, buf, BUFSIZ)) == -1) {
1347: LOGERR;
1348: break;
1349: }
1350:
1351: if ((ret = telnetSend(sock, Attr, pty == s ? 0 : attrlen, buf, ret, 0)) == -1) {
1352: cli_Errno = telnet_GetErrno();
1353: strlcpy(cli_Error, telnet_GetError(), STRSIZ);
1354: break;
1355: } else
1356: flg++;
1357: }
1.2 misho 1358: }
1359:
1360: close(pty);
1361: }
1362:
1363: return ret;
1364: }
1365:
1366: /*
1.2.2.4 misho 1367: * cliLoop() CLI main loop
1368: * @buffer = CLI buffer
1369: * @csHistFile = History file name
1370: * return: RETCODE_ERR error, RETCODE_OK ok
1.1 misho 1371: */
1.2.2.4 misho 1372: int
1373: cliLoop(linebuffer_t * __restrict buffer, const char *csHistFile)
1.1 misho 1374: {
1375: char *line, *s, *t, **app, *items[MAX_PROMPT_ITEMS];
1376: register int i;
1.2.2.4 misho 1377: int ret = RETCODE_OK;
1378: struct tagCommand *cmd;
1.1 misho 1379:
1380: /* --- main body of CLI --- */
1.2.2.4 misho 1381:
1382: if (cli_loadHistory(buffer, csHistFile) == RETCODE_ERR)
1383: return RETCODE_ERR;
1.1 misho 1384:
1385: do {
1.2.2.4 misho 1386: line = cliReadLine(buffer);
1.2.2.5 misho 1387: if (!line) {
1388: printfNL(buffer, 0);
1.1 misho 1389: break;
1.2.2.5 misho 1390: } else
1.2.2.4 misho 1391: cli_addHistory(buffer, NULL);
1.1 misho 1392: // clear whitespaces
1393: for (s = line; isspace(*s); s++);
1394: if (*s) {
1395: for (t = s + strlen(s) - 1; t > s && isspace(*t); t--);
1396: *++t = 0;
1397: }
1398:
1399: if (*s) {
1400: memset(items, 0, sizeof(char*) * MAX_PROMPT_ITEMS);
1401: for (app = items; app < items + MAX_PROMPT_ITEMS - 1 && (*app = strsep(&s, " \t"));
1402: *app ? app++ : app);
1403:
1404: // exec_cmd ...
1.2.2.4 misho 1405: i = 0;
1406: SLIST_FOREACH(cmd, &buffer->line_cmds, cmd_next) {
1407: if (*items[0] && !strncmp(cmd->cmd_name, items[0], strlen(items[0])))
1.1 misho 1408: break;
1.2.2.4 misho 1409: else
1410: i++;
1411: }
1.2.2.5 misho 1412:
1.1 misho 1413: if (!cmd) {
1.2.2.5 misho 1414: cli_Printf(buffer, "\nCommand '%s' not found!\n", items[0]);
1.1 misho 1415: ret = -1;
1416: } else
1.2.2.15 misho 1417: if (cmd->cmd_func)
1418: ret = cmd->cmd_func(buffer, i, items);
1419: else {
1420: clrscrEOL(buffer);
1421: printfCR(buffer, 1);
1422: }
1.1 misho 1423: }
1424:
1.2.2.4 misho 1425: cli_freeLine(buffer);
1426: cli_resetHistory(buffer);
1.1 misho 1427: free(line);
1428: } while (ret < 1);
1429:
1.2.2.4 misho 1430: cli_saveHistory(buffer, csHistFile, HISTORY_LINES);
1.1 misho 1431: return ret;
1432: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>