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