2
0

fs_cli.c 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801
  1. #if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
  2. #define _XOPEN_SOURCE 600
  3. #endif
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <esl.h>
  7. #include <signal.h>
  8. #include <getopt.h>
  9. #define CMD_BUFLEN 1024
  10. #ifndef WIN32
  11. #include <esl_config_auto.h>
  12. #include <sys/select.h>
  13. #include <unistd.h>
  14. #include <time.h>
  15. #else
  16. #define strdup(src) _strdup(src)
  17. #define fileno _fileno
  18. #define read _read
  19. #include <io.h>
  20. #define CC_NORM 0
  21. #define CC_NEWLINE 1
  22. #define CC_EOF 2
  23. #define CC_ARGHACK 3
  24. #define CC_REFRESH 4
  25. #define CC_CURSOR 5
  26. #define CC_ERROR 6
  27. #define CC_FATAL 7
  28. #define CC_REDISPLAY 8
  29. #define CC_REFRESH_BEEP 9
  30. #define HISTLEN 10
  31. #define KEY_UP 1
  32. #define KEY_DOWN 2
  33. #define KEY_TAB 3
  34. #define CLEAR_OP 4
  35. #define DELETE_REFRESH_OP 5
  36. #define KEY_LEFT 6
  37. #define KEY_RIGHT 7
  38. #define KEY_INSERT 8
  39. #define PROMPT_OP 9
  40. #define KEY_DELETE 10
  41. static int console_bufferInput (char *buf, int len, char *cmd, int key);
  42. static unsigned char esl_console_complete(const char *buffer, const char *cursor, const char *lastchar);
  43. #endif
  44. #ifdef HAVE_LIBEDIT
  45. #include <histedit.h>
  46. #endif
  47. typedef struct {
  48. char name[128];
  49. char host[128];
  50. esl_port_t port;
  51. char user[256];
  52. char pass[128];
  53. int debug;
  54. const char *console_fnkeys[12];
  55. const char *console_fnkeys_toggle[12];
  56. int console_fnkeys_state[12];
  57. char loglevel[128];
  58. int log_uuid;
  59. int log_uuid_length;
  60. int quiet;
  61. int use_history_file;
  62. int batch_mode;
  63. char prompt_color[12];
  64. char input_text_color[12];
  65. char output_text_color[12];
  66. } cli_profile_t;
  67. static const int log_uuid_short_length = 8;
  68. static int is_color = 1;
  69. static int warn_stop = 0;
  70. static int connected = 0;
  71. static int allow_ctl_c = 0;
  72. static char bare_prompt_str[512] = "";
  73. static int bare_prompt_str_len = 0;
  74. static char prompt_str[512] = "";
  75. static char prompt_color[12] = {ESL_SEQ_DEFAULT_COLOR};
  76. static char input_text_color[12] = {ESL_SEQ_DEFAULT_COLOR};
  77. static char output_text_color[12] = {ESL_SEQ_DEFAULT_COLOR};
  78. static int feature_level = 0;
  79. static cli_profile_t profiles[128] = {{{0}}};
  80. static cli_profile_t internal_profile = {{ 0 }};
  81. static int pcount = 0;
  82. static esl_handle_t *global_handle;
  83. static cli_profile_t *global_profile;
  84. static int running = 1;
  85. static int thread_running = 0;
  86. static char *filter_uuid;
  87. static char *logfilter;
  88. static int timeout = 0;
  89. static int connect_timeout = 0;
  90. #ifdef HAVE_LIBEDIT
  91. static EditLine *el;
  92. static History *myhistory;
  93. static HistEvent ev;
  94. #endif
  95. static esl_mutex_t *MUTEX = NULL;
  96. static void _sleep_ns(int secs, long nsecs) {
  97. #ifndef WIN32
  98. if (nsecs > 999999999) {
  99. secs += nsecs/1000000000;
  100. nsecs = nsecs % 1000000000;
  101. }
  102. {
  103. struct timespec ts = { secs, nsecs };
  104. nanosleep(&ts, NULL);
  105. }
  106. #else
  107. Sleep(secs*1000 + nsecs/1000000);
  108. #endif
  109. }
  110. static void sleep_ns(long nsecs) { _sleep_ns(0, nsecs); }
  111. static void sleep_ms(int msecs) { sleep_ns(msecs*1000000); }
  112. static void sleep_s(int secs) { _sleep_ns(secs, 0); }
  113. static int process_command(esl_handle_t *handle, const char *cmd);
  114. #if defined(HAVE_LIBEDIT) || defined(WIN32)
  115. static void clear_cli(void) {
  116. if (global_profile->batch_mode) return;
  117. putchar('\r');
  118. printf("\033[%dC", bare_prompt_str_len);
  119. printf("\033[K");
  120. fflush(stdout);
  121. }
  122. #endif
  123. static void screen_size(int *x, int *y)
  124. {
  125. #ifdef WIN32
  126. CONSOLE_SCREEN_BUFFER_INFO csbi;
  127. int ret;
  128. if ((ret = GetConsoleScreenBufferInfo(GetStdHandle( STD_OUTPUT_HANDLE ), &csbi))) {
  129. if (x) *x = csbi.dwSize.X;
  130. if (y) *y = csbi.dwSize.Y;
  131. }
  132. #elif defined(TIOCGWINSZ)
  133. struct winsize w;
  134. if ( (ioctl(0, TIOCGWINSZ, &w)) >= 0 ) {
  135. if (x) *x = w.ws_col;
  136. if (y) *y = w.ws_row;
  137. }
  138. #else
  139. if (x) *x = 80;
  140. if (y) *y = 24;
  141. #endif
  142. }
  143. #if defined(HAVE_LIBEDIT) || defined(WIN32)
  144. /* If a fnkey is configured then process the command */
  145. static unsigned char console_fnkey_pressed(int i)
  146. {
  147. const char *c;
  148. int fnkey;
  149. assert((i > 0) && (i <= 12));
  150. fnkey = i - 1;
  151. if ((c = global_profile->console_fnkeys_toggle[fnkey]) && global_profile->console_fnkeys_state[fnkey]) {
  152. global_profile->console_fnkeys_state[fnkey] = 0;
  153. } else if ((c = global_profile->console_fnkeys[fnkey])) {
  154. global_profile->console_fnkeys_state[fnkey] = 1;
  155. } else {
  156. printf("\n");
  157. esl_log(ESL_LOG_ERROR, "FUNCTION KEY F%d IS NOT BOUND, please edit your config.\n", i);
  158. return CC_REDISPLAY;
  159. }
  160. clear_cli();
  161. printf("%s\n", c);
  162. if (process_command(global_handle, c)) {
  163. running = thread_running = 0;
  164. }
  165. return CC_REDISPLAY;
  166. }
  167. #endif
  168. #ifdef HAVE_LIBEDIT
  169. static char *prompt(EditLine *e) { return prompt_str; }
  170. static unsigned char console_f1key(EditLine *el, int ch) { return console_fnkey_pressed(1); }
  171. static unsigned char console_f2key(EditLine *el, int ch) { return console_fnkey_pressed(2); }
  172. static unsigned char console_f3key(EditLine *el, int ch) { return console_fnkey_pressed(3); }
  173. static unsigned char console_f4key(EditLine *el, int ch) { return console_fnkey_pressed(4); }
  174. static unsigned char console_f5key(EditLine *el, int ch) { return console_fnkey_pressed(5); }
  175. static unsigned char console_f6key(EditLine *el, int ch) { return console_fnkey_pressed(6); }
  176. static unsigned char console_f7key(EditLine *el, int ch) { return console_fnkey_pressed(7); }
  177. static unsigned char console_f8key(EditLine *el, int ch) { return console_fnkey_pressed(8); }
  178. static unsigned char console_f9key(EditLine *el, int ch) { return console_fnkey_pressed(9); }
  179. static unsigned char console_f10key(EditLine *el, int ch) { return console_fnkey_pressed(10); }
  180. static unsigned char console_f11key(EditLine *el, int ch) { return console_fnkey_pressed(11); }
  181. static unsigned char console_f12key(EditLine *el, int ch) { return console_fnkey_pressed(12); }
  182. static unsigned char console_eofkey(EditLine *el, int ch)
  183. {
  184. LineInfo *line;
  185. /* only exit if empty line */
  186. line = (LineInfo *)el_line(el);
  187. if (line->buffer == line->lastchar) {
  188. printf("/exit\n\n");
  189. running = thread_running = 0;
  190. return CC_EOF;
  191. } else {
  192. if (line->cursor != line->lastchar) {
  193. line->cursor++;
  194. el_deletestr(el, 1);
  195. }
  196. return CC_REDISPLAY;
  197. }
  198. }
  199. #else
  200. #ifdef _MSC_VER
  201. char history[HISTLEN][CMD_BUFLEN+1];
  202. int iHistory = 0;
  203. int iHistorySel = 0;
  204. static int console_history (char *cmd, int direction)
  205. {
  206. int i;
  207. static int first;
  208. if (direction == 0) {
  209. first = 1;
  210. if (iHistory < HISTLEN) {
  211. if (iHistory && strcmp(history[iHistory-1], cmd)) {
  212. iHistorySel = iHistory;
  213. strcpy(history[iHistory++], cmd);
  214. }
  215. else if (iHistory == 0) {
  216. iHistorySel = iHistory;
  217. strcpy(history[iHistory++], cmd);
  218. }
  219. }
  220. else {
  221. iHistory = HISTLEN-1;
  222. for (i = 0; i < HISTLEN-1; i++) {
  223. strcpy(history[i], history[i+1]);
  224. }
  225. iHistorySel = iHistory;
  226. strcpy(history[iHistory++], cmd);
  227. }
  228. }
  229. else {
  230. if (!first) {
  231. iHistorySel += direction;
  232. }
  233. first = 0;
  234. if (iHistorySel < 0) {
  235. iHistorySel = 0;
  236. }
  237. if (iHistory && iHistorySel >= iHistory) {
  238. iHistorySel = iHistory-1;
  239. }
  240. strcpy(cmd, history[iHistorySel]);
  241. }
  242. return (0);
  243. }
  244. static int console_bufferInput (char *addchars, int len, char *cmd, int key)
  245. {
  246. static int iCmdBuffer = 0;
  247. static int iCmdCursor = 0;
  248. static int ignoreNext = 0;
  249. static int insertMode = 1;
  250. static COORD orgPosition;
  251. static char prompt [80];
  252. int iBuf;
  253. int i;
  254. HANDLE hOut;
  255. CONSOLE_SCREEN_BUFFER_INFO info;
  256. COORD position;
  257. hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  258. GetConsoleScreenBufferInfo(hOut, &info);
  259. position = info.dwCursorPosition;
  260. if (iCmdCursor == 0) {
  261. orgPosition = position;
  262. }
  263. if (key == PROMPT_OP) {
  264. if (strlen(cmd) < sizeof(prompt)) {
  265. strcpy(prompt, cmd);
  266. }
  267. return 0;
  268. }
  269. if (key == KEY_TAB) {
  270. esl_console_complete(cmd, cmd+iCmdBuffer, cmd+iCmdBuffer);
  271. return 0;
  272. }
  273. if (key == KEY_UP || key == KEY_DOWN || key == CLEAR_OP) {
  274. SetConsoleCursorPosition(hOut, orgPosition);
  275. for (i = 0; i < (int)strlen(cmd); i++) {
  276. printf(" ");
  277. }
  278. SetConsoleCursorPosition(hOut, orgPosition);
  279. iCmdBuffer = 0;
  280. iCmdCursor = 0;
  281. memset(cmd, 0, CMD_BUFLEN);
  282. }
  283. if (key == DELETE_REFRESH_OP) {
  284. int l = len < (int)strlen(cmd) ? len : (int)strlen(cmd);
  285. for (i = 0; i < l; i++) {
  286. cmd[--iCmdBuffer] = 0;
  287. }
  288. iCmdCursor = (int)strlen(cmd);
  289. printf("%s", prompt);
  290. GetConsoleScreenBufferInfo(hOut, &info);
  291. orgPosition = info.dwCursorPosition;
  292. printf("%s", cmd);
  293. return 0;
  294. }
  295. if (key == KEY_LEFT) {
  296. if (iCmdCursor) {
  297. if (position.X == 0) {
  298. position.Y -= 1;
  299. position.X = info.dwSize.X-1;
  300. }
  301. else {
  302. position.X -= 1;
  303. }
  304. SetConsoleCursorPosition(hOut, position);
  305. iCmdCursor--;
  306. }
  307. }
  308. if (key == KEY_RIGHT) {
  309. if (iCmdCursor < (int)strlen(cmd)) {
  310. if (position.X == info.dwSize.X-1) {
  311. position.Y += 1;
  312. position.X = 0;
  313. }
  314. else {
  315. position.X += 1;
  316. }
  317. SetConsoleCursorPosition(hOut, position);
  318. iCmdCursor++;
  319. }
  320. }
  321. if (key == KEY_INSERT) {
  322. insertMode = !insertMode;
  323. }
  324. if (key == KEY_DELETE) {
  325. if (iCmdCursor < iCmdBuffer) {
  326. int pos;
  327. for (pos = iCmdCursor; pos < iCmdBuffer; pos++) {
  328. cmd[pos] = cmd[pos + 1];
  329. }
  330. cmd[pos] = 0;
  331. iCmdBuffer--;
  332. for (pos = iCmdCursor; pos < iCmdBuffer; pos++) {
  333. printf("%c", cmd[pos]);
  334. }
  335. printf(" ");
  336. SetConsoleCursorPosition(hOut, position);
  337. }
  338. }
  339. for (iBuf = 0; iBuf < len; iBuf++) {
  340. switch (addchars[iBuf]) {
  341. case '\r':
  342. case '\n':
  343. if (ignoreNext) {
  344. ignoreNext = 0;
  345. }
  346. else {
  347. int ret = iCmdBuffer;
  348. if (iCmdBuffer == 0) {
  349. strcpy(cmd, "Empty");
  350. ret = (int)strlen(cmd);
  351. }
  352. else {
  353. console_history(cmd, 0);
  354. cmd[iCmdBuffer] = 0;
  355. }
  356. iCmdBuffer = 0;
  357. iCmdCursor = 0;
  358. printf("\n");
  359. return (ret);
  360. }
  361. break;
  362. case '\b':
  363. if (iCmdCursor) {
  364. if (position.X == 0) {
  365. position.Y -= 1;
  366. position.X = info.dwSize.X-1;
  367. SetConsoleCursorPosition(hOut, position);
  368. }
  369. else {
  370. position.X -= 1;
  371. SetConsoleCursorPosition(hOut, position);
  372. }
  373. printf(" ");
  374. if (iCmdCursor < iCmdBuffer) {
  375. int pos;
  376. iCmdCursor--;
  377. for (pos = iCmdCursor; pos < iCmdBuffer; pos++) {
  378. cmd[pos] = cmd[pos+1];
  379. }
  380. cmd[pos] = 0;
  381. iCmdBuffer--;
  382. SetConsoleCursorPosition(hOut, position);
  383. for (pos = iCmdCursor; pos < iCmdBuffer; pos++) {
  384. printf("%c", cmd[pos]);
  385. }
  386. printf(" ");
  387. SetConsoleCursorPosition(hOut, position);
  388. }
  389. else {
  390. SetConsoleCursorPosition(hOut, position);
  391. iCmdBuffer--;
  392. iCmdCursor--;
  393. cmd[iCmdBuffer] = 0;
  394. }
  395. }
  396. break;
  397. default:
  398. if (!ignoreNext) {
  399. if (iCmdCursor < iCmdBuffer) {
  400. int pos;
  401. if (position.X == info.dwSize.X-1) {
  402. position.Y += 1;
  403. position.X = 0;
  404. }
  405. else {
  406. position.X += 1;
  407. }
  408. if (insertMode) {
  409. for (pos = iCmdBuffer-1; pos >= iCmdCursor; pos--) {
  410. cmd[pos+1] = cmd[pos];
  411. }
  412. }
  413. iCmdBuffer++;
  414. cmd[iCmdCursor++] = addchars[iBuf];
  415. printf("%c", addchars[iBuf]);
  416. for (pos = iCmdCursor; pos < iCmdBuffer; pos++) {
  417. GetConsoleScreenBufferInfo(hOut, &info);
  418. if (info.dwCursorPosition.X == info.dwSize.X-1 && info.dwCursorPosition.Y == info.dwSize.Y-1) {
  419. orgPosition.Y -= 1;
  420. position.Y -= 1;
  421. }
  422. printf("%c", cmd[pos]);
  423. }
  424. SetConsoleCursorPosition(hOut, position);
  425. }
  426. else {
  427. if (position.X == info.dwSize.X-1 && position.Y == info.dwSize.Y-1) {
  428. orgPosition.Y -= 1;
  429. }
  430. cmd[iCmdBuffer++] = addchars[iBuf];
  431. iCmdCursor++;
  432. printf("%c", addchars[iBuf]);
  433. }
  434. }
  435. }
  436. if (iCmdBuffer == CMD_BUFLEN) {
  437. printf("Read Console... BUFFER OVERRUN\n");
  438. iCmdBuffer = 0;
  439. ignoreNext = 1;
  440. }
  441. }
  442. return (0);
  443. }
  444. static BOOL console_readConsole(HANDLE conIn, char *buf, int len, int *pRed, int *key)
  445. {
  446. DWORD recordIndex, bufferIndex, toRead, red;
  447. PINPUT_RECORD pInput;
  448. if (GetNumberOfConsoleInputEvents(conIn, &toRead) == 0) {
  449. return(FALSE);
  450. }
  451. if (len < (int)toRead) {
  452. toRead = len;
  453. }
  454. if (toRead == 0) {
  455. return(FALSE);
  456. }
  457. if ((pInput = (PINPUT_RECORD) malloc(toRead * sizeof(INPUT_RECORD))) == NULL) {
  458. return (FALSE);
  459. }
  460. *key = 0;
  461. ReadConsoleInput(conIn, pInput, toRead, &red);
  462. for (recordIndex = bufferIndex = 0; recordIndex < red; recordIndex++) {
  463. KEY_EVENT_RECORD keyEvent = pInput[recordIndex].Event.KeyEvent;
  464. if (pInput[recordIndex].EventType == KEY_EVENT && keyEvent.bKeyDown) {
  465. if (keyEvent.wVirtualKeyCode == 38 && keyEvent.wVirtualScanCode == 72) {
  466. buf[0] = 0;
  467. console_history(buf, -1);
  468. *key = KEY_UP;
  469. bufferIndex += (DWORD)strlen(buf);
  470. }
  471. if (keyEvent.wVirtualKeyCode == 40 && keyEvent.wVirtualScanCode == 80) {
  472. buf[0] = 0;
  473. console_history(buf, 1);
  474. *key = KEY_DOWN;
  475. bufferIndex += (DWORD)strlen(buf);
  476. }
  477. if (keyEvent.wVirtualKeyCode == 112 && keyEvent.wVirtualScanCode == 59) {
  478. console_fnkey_pressed(1);
  479. }
  480. if (keyEvent.wVirtualKeyCode == 113 && keyEvent.wVirtualScanCode == 60) {
  481. console_fnkey_pressed(2);
  482. }
  483. if (keyEvent.wVirtualKeyCode == 114 && keyEvent.wVirtualScanCode == 61) {
  484. console_fnkey_pressed(3);
  485. }
  486. if (keyEvent.wVirtualKeyCode == 115 && keyEvent.wVirtualScanCode == 62) {
  487. console_fnkey_pressed(4);
  488. }
  489. if (keyEvent.wVirtualKeyCode == 116 && keyEvent.wVirtualScanCode == 63) {
  490. console_fnkey_pressed(5);
  491. }
  492. if (keyEvent.wVirtualKeyCode == 117 && keyEvent.wVirtualScanCode == 64) {
  493. console_fnkey_pressed(6);
  494. }
  495. if (keyEvent.wVirtualKeyCode == 118 && keyEvent.wVirtualScanCode == 65) {
  496. console_fnkey_pressed(7);
  497. }
  498. if (keyEvent.wVirtualKeyCode == 119 && keyEvent.wVirtualScanCode == 66) {
  499. console_fnkey_pressed(8);
  500. }
  501. if (keyEvent.wVirtualKeyCode == 120 && keyEvent.wVirtualScanCode == 67) {
  502. console_fnkey_pressed(9);
  503. }
  504. if (keyEvent.wVirtualKeyCode == 121 && keyEvent.wVirtualScanCode == 68) {
  505. console_fnkey_pressed(10);
  506. }
  507. if (keyEvent.wVirtualKeyCode == 122 && keyEvent.wVirtualScanCode == 87) {
  508. console_fnkey_pressed(11);
  509. }
  510. if (keyEvent.wVirtualKeyCode == 123 && keyEvent.wVirtualScanCode == 88) {
  511. console_fnkey_pressed(12);
  512. }
  513. if (keyEvent.uChar.AsciiChar == 9) {
  514. *key = KEY_TAB;
  515. break;
  516. }
  517. if (keyEvent.uChar.AsciiChar == 27) {
  518. *key = CLEAR_OP;
  519. break;
  520. }
  521. if (keyEvent.wVirtualKeyCode == 37 && keyEvent.wVirtualScanCode == 75) {
  522. *key = KEY_LEFT;
  523. }
  524. if (keyEvent.wVirtualKeyCode == 39 && keyEvent.wVirtualScanCode == 77) {
  525. *key = KEY_RIGHT;
  526. }
  527. if (keyEvent.wVirtualKeyCode == 45 && keyEvent.wVirtualScanCode == 82) {
  528. *key = KEY_INSERT;
  529. }
  530. if (keyEvent.wVirtualKeyCode == 46 && keyEvent.wVirtualScanCode == 83) {
  531. *key = KEY_DELETE;
  532. }
  533. while (keyEvent.wRepeatCount && keyEvent.uChar.AsciiChar) {
  534. buf[bufferIndex] = keyEvent.uChar.AsciiChar;
  535. if (buf[bufferIndex] == '\r') {
  536. buf[bufferIndex] = '\n';
  537. }
  538. bufferIndex++;
  539. keyEvent.wRepeatCount--;
  540. }
  541. }
  542. }
  543. free(pInput);
  544. *pRed = bufferIndex;
  545. return (TRUE);
  546. }
  547. #endif
  548. #endif
  549. static void handle_SIGINT(int sig)
  550. {
  551. if (!connected || allow_ctl_c) {
  552. fprintf(stdout, "Interrupted.\n");
  553. exit(1);
  554. }
  555. warn_stop = 1;
  556. signal(SIGINT, handle_SIGINT);
  557. #ifdef SIGTSTP
  558. signal(SIGTSTP, handle_SIGINT);
  559. #endif
  560. return;
  561. }
  562. static void handle_SIGQUIT(int sig)
  563. {
  564. fprintf(stdout, "Caught SIGQUIT\n");
  565. return;
  566. }
  567. #ifdef WIN32
  568. static HANDLE hStdout;
  569. static WORD wOldColorAttrs;
  570. static CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
  571. #endif
  572. #ifdef WIN32
  573. static WORD colors[]
  574. #else
  575. static const char *colors[]
  576. #endif
  577. = {
  578. ESL_SEQ_DEFAULT_COLOR, ESL_SEQ_FRED, ESL_SEQ_FRED, ESL_SEQ_FRED,
  579. ESL_SEQ_FMAGEN, ESL_SEQ_FCYAN, ESL_SEQ_FGREEN, ESL_SEQ_FYELLOW
  580. };
  581. static const char *usage_str =
  582. "Usage: %s [-H <host>] [-P <port>] [-p <secret>] [-d <level>] [-x command] [-t <timeout_ms>] [profile]\n\n"
  583. " -?,-h --help Usage Information\n"
  584. " -H, --host=hostname Host to connect\n"
  585. " -P, --port=port Port to connect (1 - 65535)\n"
  586. " -u, --user=user@domain user@domain\n"
  587. " -p, --password=password Password\n"
  588. " -i, --interrupt Allow Control-c to interrupt\n"
  589. " -x, --execute=command Execute Command and Exit\n"
  590. " -l, --loglevel=command Log Level\n"
  591. " -U, --log-uuid Include UUID in log output\n"
  592. " -S, --log-uuid-short Include shortened UUID in log output\n"
  593. " -q, --quiet Disable logging\n"
  594. " -r, --retry Retry connection on failure\n"
  595. " -R, --reconnect Reconnect if disconnected\n"
  596. " -d, --debug=level Debug Level (0 - 7)\n"
  597. " -b, --batchmode Batch mode\n"
  598. " -t, --timeout Timeout for API commands (in miliseconds)\n"
  599. " -T, --connect-timeout Timeout for socket connection (in miliseconds)\n"
  600. " -n, --no-color Disable color\n\n";
  601. static int usage(char *name){
  602. printf(usage_str, name);
  603. return 1;
  604. }
  605. static int stdout_writable(void)
  606. {
  607. #ifndef WIN32
  608. fd_set set;
  609. int fd = fileno(stdout);
  610. struct timeval to;
  611. memset(&to, 0, sizeof(to));
  612. FD_ZERO(&set);
  613. FD_SET(fd, &set);
  614. to.tv_sec = 0;
  615. to.tv_usec = 100000;
  616. if (select(fd + 1, NULL, &set, NULL, &to) > 0) {
  617. return FD_ISSET(fd, &set);
  618. } else {
  619. return 0;
  620. }
  621. #else
  622. return 1;
  623. #endif
  624. }
  625. static void clear_line(void)
  626. {
  627. if (global_profile->batch_mode) return;
  628. putchar('\r');
  629. printf("\033[K");
  630. fflush(stdout);
  631. return;
  632. }
  633. static void redisplay(void)
  634. {
  635. #ifdef HAVE_LIBEDIT
  636. #ifdef HAVE_DECL_EL_REFRESH
  637. #ifdef HAVE_EL_WSET
  638. /* Current libedit versions don't implement EL_REFRESH in eln.c so
  639. * use the wide version instead. */
  640. el_wset(el, EL_REFRESH);
  641. #else
  642. /* This will work on future libedit versions and versions built
  643. * without wide character support. */
  644. el_set(el, EL_REFRESH);
  645. #endif
  646. #else
  647. /* Old libedit versions don't implement EL_REFRESH at all so use
  648. * our own implementation instead. */
  649. const LineInfo *lf = el_line(el);
  650. const char *c = lf->buffer;
  651. if (global_profile->batch_mode) return;
  652. printf("%s",prompt_str);
  653. while (c < lf->lastchar && *c) {
  654. putchar(*c);
  655. c++;
  656. }
  657. {
  658. int pos = (int)(lf->cursor - lf->buffer);
  659. char s1[12], s2[12];
  660. putchar('\r');
  661. snprintf(s1, sizeof(s1), "\033[%dC", bare_prompt_str_len);
  662. snprintf(s2, sizeof(s2), "\033[%dC", pos);
  663. printf("%s%s",s1,s2);
  664. }
  665. fflush(stdout);
  666. return;
  667. #endif
  668. #endif
  669. }
  670. static int output_printf(const char *fmt, ...)
  671. {
  672. va_list ap;
  673. int r;
  674. va_start(ap, fmt);
  675. #ifndef WIN32
  676. if (!(global_profile->batch_mode)) {
  677. printf("%s", output_text_color);
  678. }
  679. #endif
  680. r = vprintf(fmt, ap);
  681. va_end(ap);
  682. return r;
  683. }
  684. static void *msg_thread_run(esl_thread_t *me, void *obj)
  685. {
  686. esl_handle_t *handle = (esl_handle_t *) obj;
  687. thread_running = 1;
  688. while(thread_running && handle->connected) {
  689. int aok = 1;
  690. esl_status_t status;
  691. esl_mutex_lock(MUTEX);
  692. status = esl_recv_event_timed(handle, 10, 1, NULL);
  693. esl_mutex_unlock(MUTEX);
  694. if (status == ESL_BREAK) {
  695. sleep_ms(1);
  696. } else if (status == ESL_FAIL) {
  697. esl_log(ESL_LOG_WARNING, "Disconnected.\n");
  698. running = -1; thread_running = 0;
  699. } else if (status == ESL_SUCCESS) {
  700. aok = stdout_writable();
  701. if (handle->last_event) {
  702. int known = 1;
  703. const char *type = esl_event_get_header(handle->last_event, "content-type");
  704. if (!esl_strlen_zero(type)) {
  705. if (!strcasecmp(type, "log/data")) {
  706. const char *userdata = esl_event_get_header(handle->last_event, "user-data");
  707. if (esl_strlen_zero(userdata) || esl_strlen_zero(filter_uuid) || !strcasecmp(filter_uuid, userdata)) {
  708. int level = 0;
  709. const char *lname = esl_event_get_header(handle->last_event, "log-level");
  710. #ifdef WIN32
  711. DWORD len = (DWORD) strlen(handle->last_event->body);
  712. DWORD outbytes = 0;
  713. #endif
  714. if (logfilter) {
  715. if (!strstr(handle->last_event->body, logfilter)) {
  716. continue;
  717. }
  718. }
  719. if (lname) {
  720. level = atoi(lname);
  721. }
  722. #ifndef WIN32
  723. if (aok) {
  724. if (feature_level) clear_line();
  725. if(!(global_profile->batch_mode)) {
  726. printf("%s", colors[level]);
  727. }
  728. if (global_profile->log_uuid && !esl_strlen_zero(userdata)) {
  729. if (global_profile->log_uuid_length) {
  730. int len = strlen(userdata);
  731. int i = (global_profile->log_uuid_length < len) ? global_profile->log_uuid_length : len;
  732. if (fwrite(userdata, sizeof(char), i, stdout) < i) {
  733. // don't care
  734. }
  735. printf(" ");
  736. } else {
  737. printf("%s ", userdata);
  738. }
  739. }
  740. if (strcmp("\n",handle->last_event->body)) {
  741. char *c = handle->last_event->body;
  742. printf("%s", handle->last_event->body);
  743. if (*c) {
  744. while (*c) ++c; c--;
  745. if (*c != '\n')
  746. printf("\n");
  747. }
  748. }
  749. if(!(global_profile->batch_mode)) {
  750. if (!feature_level) printf("%s", ESL_SEQ_DEFAULT_COLOR);
  751. }
  752. if (feature_level) redisplay();
  753. }
  754. #else
  755. if (aok) {
  756. if(!(global_profile->batch_mode)) {
  757. SetConsoleTextAttribute(hStdout, colors[level]);
  758. }
  759. if (global_profile->log_uuid && !esl_strlen_zero(userdata)) {
  760. WriteFile(hStdout, userdata, (DWORD)strlen(userdata), &outbytes, NULL);
  761. WriteFile(hStdout, " ", (DWORD)strlen(" "), &outbytes, NULL);
  762. }
  763. WriteFile(hStdout, handle->last_event->body, len, &outbytes, NULL);
  764. if(!(global_profile->batch_mode)) {
  765. SetConsoleTextAttribute(hStdout, wOldColorAttrs);
  766. }
  767. }
  768. #endif
  769. }
  770. } else if (!strcasecmp(type, "text/disconnect-notice")) {
  771. running = -1; thread_running = 0;
  772. } else if (!strcasecmp(type, "text/event-plain")) {
  773. char *s;
  774. esl_event_serialize(handle->last_ievent, &s, ESL_FALSE);
  775. if (aok) {
  776. clear_line();
  777. output_printf("RECV EVENT\n%s\n", s);
  778. redisplay();
  779. }
  780. free(s);
  781. } else {
  782. known = 0;
  783. }
  784. }
  785. if (aok && !known) {
  786. char *s;
  787. output_printf("INCOMING DATA [%s]\n%s\n", type, handle->last_event->body ? handle->last_event->body : "");
  788. esl_event_serialize(handle->last_event, &s, ESL_FALSE);
  789. output_printf("RECV EVENT\n%s\n", s);
  790. redisplay();
  791. free(s);
  792. }
  793. }
  794. }
  795. if (warn_stop) {
  796. if (aok) {
  797. clear_line();
  798. output_printf("Type control-D or /exit or /quit or /bye to exit.\n\n");
  799. redisplay();
  800. }
  801. warn_stop = 0;
  802. }
  803. //sleep_ms(1);
  804. }
  805. thread_running = 0;
  806. esl_log(ESL_LOG_DEBUG, "Thread Done\n");
  807. return NULL;
  808. }
  809. static const char *cli_usage =
  810. "Command \tDescription\n"
  811. "-----------------------------------------------\n"
  812. "/help \tHelp\n"
  813. "/exit, /quit, /bye, ... \tExit the program.\n"
  814. "/event, /noevents, /nixevent\tEvent commands.\n"
  815. "/log, /nolog \tLog commands.\n"
  816. "/uuid \tFilter logs for a single call uuid\n"
  817. "/filter \tFilter commands.\n"
  818. "/logfilter \tFilter Log for a single string.\n"
  819. "/debug [0-7] \tSet debug level.\n"
  820. "\n";
  821. static int process_command(esl_handle_t *handle, const char *cmd)
  822. {
  823. int r = 0;
  824. while (*cmd == ' ') cmd++;
  825. esl_mutex_lock(MUTEX);
  826. if ((*cmd == '/' && cmd++) || !strncasecmp(cmd, "...", 3)) {
  827. if (!strcasecmp(cmd, "help")) {
  828. output_printf("%s", cli_usage);
  829. goto end;
  830. }
  831. if (!strcasecmp(cmd, "exit") ||
  832. !strcasecmp(cmd, "quit") ||
  833. !strcasecmp(cmd, "...") ||
  834. !strcasecmp(cmd, "bye")
  835. ) {
  836. esl_log(ESL_LOG_INFO, "Goodbye!\nSee you at ClueCon http://www.cluecon.com/\n");
  837. r = -1; goto end;
  838. } else if (!strncasecmp(cmd, "logfilter", 9)) {
  839. cmd += 9;
  840. while (*cmd && *cmd == ' ') {
  841. cmd++;
  842. }
  843. if (!esl_strlen_zero(cmd)) {
  844. esl_safe_free(logfilter);
  845. logfilter = strdup(cmd);
  846. } else {
  847. esl_safe_free(logfilter);
  848. }
  849. output_printf("Logfilter %s\n", logfilter ? "enabled" : "disabled");
  850. } else if (!strncasecmp(cmd, "uuid", 4)) {
  851. cmd += 4;
  852. while (*cmd && *cmd == ' ') {
  853. cmd++;
  854. }
  855. if (!esl_strlen_zero(cmd)) {
  856. filter_uuid = strdup(cmd);
  857. } else {
  858. esl_safe_free(filter_uuid);
  859. }
  860. output_printf("UUID filtering %s\n", filter_uuid ? "enabled" : "disabled");
  861. } else if (!strncasecmp(cmd, "event", 5) ||
  862. !strncasecmp(cmd, "noevents", 8) ||
  863. !strncasecmp(cmd, "nixevent", 8) ||
  864. !strncasecmp(cmd, "log", 3) ||
  865. !strncasecmp(cmd, "nolog", 5) ||
  866. !strncasecmp(cmd, "filter", 6)
  867. ) {
  868. esl_send_recv(handle, cmd);
  869. printf("%s\n", handle->last_sr_reply);
  870. } else if (!strncasecmp(cmd, "debug", 5)) {
  871. int tmp_debug = atoi(cmd+6);
  872. if (tmp_debug > -1 && tmp_debug < 8) {
  873. esl_global_set_default_logger(tmp_debug);
  874. output_printf("fs_cli debug level set to %d\n", tmp_debug);
  875. } else {
  876. output_printf("fs_cli debug level must be 0 - 7\n");
  877. }
  878. } else {
  879. output_printf("Unknown command [%s]\n", cmd);
  880. }
  881. } else {
  882. char cmd_str[1024] = "";
  883. const char *err = NULL;
  884. if (!strncasecmp(cmd, "console loglevel ", 17)) {
  885. snprintf(cmd_str, sizeof(cmd_str), "log %s", cmd + 17);
  886. esl_send_recv(handle, cmd_str);
  887. printf("%s\n", handle->last_sr_reply);
  888. }
  889. snprintf(cmd_str, sizeof(cmd_str), "api %s\nconsole_execute: true\n\n", cmd);
  890. if (esl_send_recv(handle, cmd_str)) {
  891. output_printf("Socket interrupted, bye!\n");
  892. r = -1; goto end;
  893. }
  894. if (handle->last_sr_event) {
  895. if (handle->last_sr_event->body) {
  896. output_printf("%s\n", handle->last_sr_event->body);
  897. } else if ((err = esl_event_get_header(handle->last_sr_event, "reply-text")) && !strncasecmp(err, "-err", 3)) {
  898. output_printf("Error: %s!\n", err + 4);
  899. }
  900. }
  901. }
  902. end:
  903. esl_mutex_unlock(MUTEX);
  904. return r;
  905. }
  906. static int get_profile(const char *name, cli_profile_t **profile)
  907. {
  908. int x;
  909. for (x = 0; x < pcount; x++) {
  910. if (!strcmp(profiles[x].name, name)) {
  911. *profile = &profiles[x];
  912. return 0;
  913. }
  914. }
  915. return -1;
  916. }
  917. static char command_buf[CMD_BUFLEN+1] = "";
  918. static const char *basic_gets(int *cnt)
  919. {
  920. int x = 0;
  921. #ifdef _MSC_VER
  922. int read, key;
  923. char keys[CMD_BUFLEN];
  924. HANDLE stdinHandle;
  925. if (global_profile->batch_mode) {
  926. #endif
  927. printf("%s", prompt_str);
  928. if (global_profile->batch_mode) fflush(stdout);
  929. memset(&command_buf, 0, sizeof(command_buf));
  930. for (x = 0; x < (sizeof(command_buf) - 1); x++) {
  931. int c = getchar();
  932. if (c < 0) {
  933. if (fgets(command_buf, sizeof(command_buf) - 1, stdin) != command_buf) {
  934. break;
  935. }
  936. command_buf[strlen(command_buf)-1] = '\0'; /* remove endline */
  937. break;
  938. }
  939. command_buf[x] = (char) c;
  940. if (command_buf[x] == '\n') {
  941. command_buf[x] = '\0';
  942. break;
  943. }
  944. }
  945. *cnt = x;
  946. #ifdef _MSC_VER
  947. } else {
  948. stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
  949. console_bufferInput (0, 0, prompt_str, PROMPT_OP);
  950. printf("%s", prompt_str);
  951. if (global_profile->batch_mode) fflush(stdout);
  952. *cnt = 0;
  953. memset(&command_buf, 0, sizeof(command_buf));
  954. while (!*cnt) {
  955. if (console_readConsole(stdinHandle, keys, (int)sizeof(keys), &read, &key)) {
  956. *cnt = console_bufferInput(keys, read, command_buf, key);
  957. if (global_profile->batch_mode) fflush(stdout);
  958. if (!strcmp(command_buf, "Empty")) {
  959. command_buf[0] = 0;
  960. }
  961. }
  962. sleep_ms(20);
  963. }
  964. }
  965. #endif
  966. return command_buf;
  967. }
  968. static const char *banner =
  969. ".=======================================================.\n"
  970. "| _____ ____ ____ _ ___ |\n"
  971. "| | ___/ ___| / ___| | |_ _| |\n"
  972. "| | |_ \\___ \\ | | | | | | |\n"
  973. "| | _| ___) | | |___| |___ | | |\n"
  974. "| |_| |____/ \\____|_____|___| |\n"
  975. "| |\n"
  976. ".=======================================================.\n"
  977. "| Anthony Minessale II, Ken Rice, |\n"
  978. "| Michael Jerris, Travis Cross |\n"
  979. "| FreeSWITCH (http://www.freeswitch.org) |\n"
  980. "| Paypal Donations Appreciated: paypal@freeswitch.org |\n"
  981. "| Brought to you by ClueCon http://www.cluecon.com/ |\n"
  982. ".=======================================================.\n"
  983. "\n";
  984. static const char *inf = "Type /help <enter> to see a list of commands\n\n\n";
  985. static void print_banner(FILE *stream, int color)
  986. {
  987. int x = 0;
  988. const char *use = NULL;
  989. #include <cc.h>
  990. screen_size(&x, NULL);
  991. use = (x > 100) ? cc : cc_s;
  992. #ifdef WIN32
  993. /* Print banner in yellow with blue background */
  994. if (color) {
  995. SetConsoleTextAttribute(hStdout, ESL_SEQ_FYELLOW | BACKGROUND_BLUE);
  996. }
  997. WriteFile(hStdout, banner, (DWORD) strlen(banner), NULL, NULL);
  998. WriteFile(hStdout, use, (DWORD) strlen(use), NULL, NULL);
  999. if (color) {
  1000. SetConsoleTextAttribute(hStdout, wOldColorAttrs);
  1001. }
  1002. /* Print the rest info in default colors */
  1003. fprintf(stream, "\n%s\n", inf);
  1004. #else
  1005. if (color) {
  1006. fprintf(stream, "%s%s%s", ESL_SEQ_DEFAULT_COLOR, ESL_SEQ_FYELLOW, ESL_SEQ_BBLUE);
  1007. }
  1008. #ifndef DISABLE_CC
  1009. fprintf(stream, "%s%s", banner, use);
  1010. #else
  1011. fprintf(stream, "%s", banner);
  1012. #endif
  1013. if (color) {
  1014. fprintf(stream, "%s", ESL_SEQ_DEFAULT_COLOR);
  1015. }
  1016. fprintf(stream, "\n%s\n", inf);
  1017. if (color) {
  1018. fprintf(stream, "%s", output_text_color);
  1019. }
  1020. #endif
  1021. if (x < 160) {
  1022. fprintf(stream, "\n[This app Best viewed at 160x60 or more..]\n");
  1023. }
  1024. }
  1025. static void set_fn_keys(cli_profile_t *profile)
  1026. {
  1027. profile->console_fnkeys[0] = "help";
  1028. profile->console_fnkeys[1] = "status";
  1029. profile->console_fnkeys[2] = "show channels";
  1030. profile->console_fnkeys[3] = "show calls";
  1031. profile->console_fnkeys[4] = "sofia status";
  1032. profile->console_fnkeys[5] = "reloadxml";
  1033. profile->console_fnkeys[6] = "/log console";
  1034. profile->console_fnkeys[7] = "/log debug";
  1035. profile->console_fnkeys[8] = "sofia status profile internal";
  1036. profile->console_fnkeys[9] = "fsctl pause";
  1037. profile->console_fnkeys[10] = "fsctl resume";
  1038. profile->console_fnkeys[11] = "version";
  1039. }
  1040. #if defined(HAVE_LIBEDIT) || defined(WIN32)
  1041. static char* end_of_str(char *s) { return (*s == '\0' ? s : s + strlen(s) - 1); }
  1042. static char* _strndup(const char *s, int n)
  1043. {
  1044. char *r = (char*)malloc(n + 1), *d=r;
  1045. while (n > 0 && *s) {
  1046. *d = *s;
  1047. d++; s++; n--;
  1048. }
  1049. *d = 0;
  1050. return r;
  1051. }
  1052. static unsigned char esl_console_complete(const char *buffer, const char *cursor, const char *lastchar)
  1053. {
  1054. char cmd_str[2048] = "";
  1055. unsigned char ret = CC_REDISPLAY;
  1056. char *dup = _strndup(buffer, (int)(lastchar - buffer));
  1057. char *buf = dup;
  1058. int sc = 0, offset = (int)(cursor - buffer), pos = (offset > 0) ? offset : 0;
  1059. char *p;
  1060. if (pos > 0) {
  1061. *(buf + pos) = '\0';
  1062. }
  1063. if ((p = strchr(buf, '\r')) || (p = strchr(buf, '\n'))) {
  1064. *p = '\0';
  1065. }
  1066. while (*buf == ' ') {
  1067. buf++;
  1068. sc++;
  1069. }
  1070. #ifdef HAVE_LIBEDIT
  1071. if (!*buf && sc) {
  1072. el_deletestr(el, sc);
  1073. sc = 0;
  1074. }
  1075. #endif
  1076. p = end_of_str(buf);
  1077. while(p >= buf && *p == ' ') {
  1078. sc++;
  1079. p--;
  1080. }
  1081. #ifdef HAVE_LIBEDIT
  1082. if (sc > 1) {
  1083. el_deletestr(el, sc - 1);
  1084. *(p + 2) = '\0';
  1085. }
  1086. #endif
  1087. if (*cursor) {
  1088. snprintf(cmd_str, sizeof(cmd_str), "api console_complete c=%ld;%s\n\n", (long)pos, buf);
  1089. } else {
  1090. snprintf(cmd_str, sizeof(cmd_str), "api console_complete %s\n\n", buf);
  1091. }
  1092. esl_send_recv(global_handle, cmd_str);
  1093. if (global_handle->last_sr_event && global_handle->last_sr_event->body) {
  1094. char *r = global_handle->last_sr_event->body;
  1095. char *w, *p1;
  1096. if (r) {
  1097. if ((w = strstr(r, "\n\nwrite="))) {
  1098. int len = 0;
  1099. *w = '\0';
  1100. w += 8;
  1101. len = atoi(w);
  1102. if ((p1= strchr(w, ':'))) {
  1103. w = p1+ 1;
  1104. }
  1105. printf("%s\n\n\n", r);
  1106. #ifdef HAVE_LIBEDIT
  1107. el_deletestr(el, len);
  1108. el_insertstr(el, w);
  1109. #else
  1110. #ifdef _MSC_VER
  1111. console_bufferInput(0, len, (char*)buffer, DELETE_REFRESH_OP);
  1112. console_bufferInput(w, (int)strlen(w), (char*)buffer, 0);
  1113. #endif
  1114. #endif
  1115. } else {
  1116. printf("%s\n", r);
  1117. #ifdef _MSC_VER
  1118. console_bufferInput(0, 0, (char*)buffer, DELETE_REFRESH_OP);
  1119. #endif
  1120. }
  1121. }
  1122. fflush(stdout);
  1123. }
  1124. esl_safe_free(dup);
  1125. return ret;
  1126. }
  1127. #endif /* if defined(HAVE_LIBEDIT) || defined(WIN32) */
  1128. #ifdef HAVE_LIBEDIT
  1129. static unsigned char complete(EditLine *el, int ch)
  1130. {
  1131. const LineInfo *lf = el_line(el);
  1132. int r;
  1133. esl_mutex_lock(MUTEX);
  1134. r = esl_console_complete(lf->buffer, lf->cursor, lf->lastchar);
  1135. esl_mutex_unlock(MUTEX);
  1136. return r;
  1137. }
  1138. #endif
  1139. struct color_map_el {
  1140. char name[32];
  1141. char seq[12];
  1142. };
  1143. struct color_map_el color_map[] = {
  1144. {"black", ESL_SEQ_FBLACK}, {"bold-black", ESL_SEQ_BBLACK},
  1145. {"red", ESL_SEQ_FRED}, {"bold-red", ESL_SEQ_BRED},
  1146. {"green", ESL_SEQ_FGREEN}, {"bold-green", ESL_SEQ_BGREEN},
  1147. {"yellow", ESL_SEQ_FYELLOW}, {"bold-yellow", ESL_SEQ_BYELLOW},
  1148. {"blue", ESL_SEQ_FBLUE}, {"bold-blue", ESL_SEQ_BBLUE},
  1149. {"magenta", ESL_SEQ_FMAGEN}, {"bold-magenta", ESL_SEQ_BMAGEN},
  1150. {"cyan", ESL_SEQ_FCYAN}, {"bold-cyan", ESL_SEQ_BCYAN},
  1151. {"white", ESL_SEQ_FWHITE}, {"bold-white", ESL_SEQ_BWHITE},
  1152. {{0}}};
  1153. static const char* match_color(const char *s) {
  1154. struct color_map_el *map = color_map;
  1155. while (*map->name) {
  1156. if (!(strcasecmp(s, map->name))) {
  1157. return map->seq;
  1158. }
  1159. map++;
  1160. }
  1161. #ifdef WIN32
  1162. return "white";
  1163. #else
  1164. return ESL_SEQ_DEFAULT_COLOR;
  1165. #endif
  1166. }
  1167. static void read_config(const char *dft_cfile, const char *cfile) {
  1168. esl_config_t cfg;
  1169. if (esl_config_open_file(&cfg, cfile) ||
  1170. esl_config_open_file(&cfg, dft_cfile)) {
  1171. char *var, *val;
  1172. char cur_cat[128] = "";
  1173. while (esl_config_next_pair(&cfg, &var, &val)) {
  1174. if (strcmp(cur_cat, cfg.category)) {
  1175. esl_set_string(cur_cat, cfg.category);
  1176. esl_set_string(profiles[pcount].name, cur_cat);
  1177. esl_set_string(profiles[pcount].host, "127.0.0.1");
  1178. esl_set_string(profiles[pcount].pass, "ClueCon");
  1179. profiles[pcount].port = 8021;
  1180. set_fn_keys(&profiles[pcount]);
  1181. esl_set_string(profiles[pcount].prompt_color, prompt_color);
  1182. esl_set_string(profiles[pcount].input_text_color, input_text_color);
  1183. esl_set_string(profiles[pcount].output_text_color, output_text_color);
  1184. profiles[pcount].use_history_file = 1;
  1185. esl_log(ESL_LOG_DEBUG, "Found Profile [%s]\n", profiles[pcount].name);
  1186. pcount++;
  1187. }
  1188. if (!strcasecmp(var, "host")) {
  1189. esl_set_string(profiles[pcount-1].host, val);
  1190. } else if (!strcasecmp(var, "user")) {
  1191. esl_set_string(profiles[pcount-1].user, val);
  1192. } else if (!strcasecmp(var, "password")) {
  1193. esl_set_string(profiles[pcount-1].pass, val);
  1194. } else if (!strcasecmp(var, "port")) {
  1195. int pt = atoi(val);
  1196. if (pt > 0) {
  1197. profiles[pcount-1].port = (esl_port_t)pt;
  1198. }
  1199. } else if (!strcasecmp(var, "batchmode")) {
  1200. profiles[pcount-1].batch_mode = esl_true(val);
  1201. } else if (!strcasecmp(var, "debug")) {
  1202. int dt = atoi(val);
  1203. if (dt > -1 && dt < 8){
  1204. profiles[pcount-1].debug = dt;
  1205. }
  1206. } else if(!strcasecmp(var, "loglevel")) {
  1207. esl_set_string(profiles[pcount-1].loglevel, val);
  1208. } else if(!strcasecmp(var, "log-uuid")) {
  1209. profiles[pcount-1].log_uuid = esl_true(val);
  1210. } else if(!strcasecmp(var, "log-uuid-short")) {
  1211. profiles[pcount-1].log_uuid = esl_true(val);
  1212. profiles[pcount-1].log_uuid_length = (esl_true(val) ? log_uuid_short_length : 0);
  1213. } else if(!strcasecmp(var, "log-uuid-length")) {
  1214. int i;
  1215. if ((i = atoi(val)) > -1) {
  1216. profiles[pcount-1].log_uuid_length = i;
  1217. }
  1218. } else if(!strcasecmp(var, "quiet")) {
  1219. profiles[pcount-1].quiet = esl_true(val);
  1220. } else if(!strcasecmp(var, "no-history-file")) {
  1221. profiles[pcount-1].use_history_file = !esl_true(val);
  1222. } else if(!strcasecmp(var, "prompt-color")) {
  1223. esl_set_string(profiles[pcount-1].prompt_color, match_color(val));
  1224. } else if(!strcasecmp(var, "input-text-color")) {
  1225. esl_set_string(profiles[pcount-1].input_text_color, match_color(val));
  1226. } else if(!strcasecmp(var, "output-text-color")) {
  1227. esl_set_string(profiles[pcount-1].output_text_color, match_color(val));
  1228. } else if (!strncasecmp(var, "key_F", 5)) {
  1229. char *key = var + 5;
  1230. if (key) {
  1231. int i = atoi(key);
  1232. if (i > 0 && i < 13) {
  1233. profiles[pcount-1].console_fnkeys[i - 1] = strdup(val);
  1234. }
  1235. }
  1236. } else if (!strncasecmp(var, "key_toggle_F", 12)) {
  1237. char *key = var + 12;
  1238. if (key) {
  1239. int i = atoi(key);
  1240. if (i > 0 && i < 13) {
  1241. profiles[pcount-1].console_fnkeys_toggle[i - 1] = strdup(val);
  1242. }
  1243. }
  1244. } else if (!strcasecmp(var, "timeout")) {
  1245. timeout = atoi(val);
  1246. } else if (!strcasecmp(var, "connect-timeout")) {
  1247. connect_timeout = atoi(val);
  1248. }
  1249. }
  1250. esl_config_close_file(&cfg);
  1251. }
  1252. }
  1253. static void clear_el_buffer(void) {
  1254. #ifdef HAVE_LIBEDIT
  1255. const LineInfo *lf = el_line(el);
  1256. int len = (int)(lf->cursor - lf->buffer);
  1257. if (global_profile->batch_mode) return;
  1258. el_deletestr(el, len);
  1259. memset((char*)lf->buffer, 0, len);
  1260. #endif
  1261. }
  1262. int main(int argc, char *argv[])
  1263. {
  1264. esl_handle_t handle = {{0}};
  1265. int count = 0;
  1266. const char *line = NULL;
  1267. char cmd_str[1024] = "";
  1268. cli_profile_t *profile = NULL;
  1269. int argv_use_history_file = 1;
  1270. int use_history_file = 0;
  1271. #ifndef WIN32
  1272. char hfile[512] = "/tmp/fs_cli_history";
  1273. char cfile[512] = "/etc/fs_cli.conf";
  1274. char dft_cfile[512] = "/etc/fs_cli.conf";
  1275. #else
  1276. char hfile[512] = "fs_cli_history";
  1277. char cfile[512] = "fs_cli.conf";
  1278. char dft_cfile[512] = "fs_cli.conf";
  1279. #endif
  1280. char *home = getenv("HOME");
  1281. /* Vars for optargs */
  1282. int opt;
  1283. static struct option options[] = {
  1284. {"help", 0, 0, 'h'},
  1285. {"no-color", 0, 0, 'n'},
  1286. {"host", 1, 0, 'H'},
  1287. {"port", 1, 0, 'P'},
  1288. {"user", 1, 0, 'u'},
  1289. {"password", 1, 0, 'p'},
  1290. {"debug", 1, 0, 'd'},
  1291. {"execute", 1, 0, 'x'},
  1292. {"loglevel", 1, 0, 'l'},
  1293. {"log-uuid", 0, 0, 'U'},
  1294. {"log-uuid-short", 0, 0, 'S'},
  1295. {"quiet", 0, 0, 'q'},
  1296. {"batchmode", 0, 0, 'b'},
  1297. {"no-history-file", 0, 0, 'Q'},
  1298. {"retry", 0, 0, 'r'},
  1299. {"interrupt", 0, 0, 'i'},
  1300. {"reconnect", 0, 0, 'R'},
  1301. {"timeout", 1, 0, 't'},
  1302. {"connect-timeout", 1, 0, 'T'},
  1303. {0, 0, 0, 0}
  1304. };
  1305. char temp_host[128];
  1306. int argv_host = 0;
  1307. char temp_user[256];
  1308. char temp_pass[128];
  1309. int argv_pass = 0 ;
  1310. int argv_user = 0 ;
  1311. int temp_port = 0;
  1312. int argv_port = 0;
  1313. int temp_log = -1;
  1314. int argv_error = 0;
  1315. int argv_exec = 0;
  1316. char argv_command[1024] = "";
  1317. char argv_loglevel[128] = "";
  1318. int argv_log_uuid = 0;
  1319. int argv_log_uuid_short = 0;
  1320. int argv_quiet = 0;
  1321. int argv_batch = 0;
  1322. int loops = 2, reconnect = 0;
  1323. char *ccheck;
  1324. esl_mutex_create(&MUTEX);
  1325. #if HAVE_DECL_EL_PROMPT_ESC
  1326. feature_level = 1;
  1327. #else
  1328. {
  1329. char *term = getenv("TERM");
  1330. if (term && (!strncasecmp("screen", term, 6) ||
  1331. !strncasecmp("vt100", term, 5))) {
  1332. feature_level = 1;
  1333. } else {
  1334. feature_level = 0;
  1335. }
  1336. }
  1337. #endif
  1338. #ifdef WIN32
  1339. feature_level = 0;
  1340. #endif
  1341. if ((ccheck = getenv("FS_CLI_COLOR"))) {
  1342. is_color = esl_true(ccheck);
  1343. }
  1344. strncpy(internal_profile.host, "127.0.0.1", sizeof(internal_profile.host));
  1345. strncpy(internal_profile.pass, "ClueCon", sizeof(internal_profile.pass));
  1346. strncpy(internal_profile.name, "internal", sizeof(internal_profile.name));
  1347. internal_profile.port = 8021;
  1348. set_fn_keys(&internal_profile);
  1349. esl_set_string(internal_profile.prompt_color, prompt_color);
  1350. esl_set_string(internal_profile.input_text_color, input_text_color);
  1351. esl_set_string(internal_profile.output_text_color, output_text_color);
  1352. internal_profile.use_history_file = 1;
  1353. if (home) {
  1354. snprintf(hfile, sizeof(hfile), "%s/.fs_cli_history", home);
  1355. snprintf(cfile, sizeof(cfile), "%s/.fs_cli_conf", home);
  1356. }
  1357. signal(SIGINT, handle_SIGINT);
  1358. #ifdef SIGTSTP
  1359. signal(SIGTSTP, handle_SIGINT);
  1360. #endif
  1361. #ifdef SIGQUIT
  1362. signal(SIGQUIT, handle_SIGQUIT);
  1363. #endif
  1364. esl_global_set_default_logger(6); /* default debug level to 6 (info) */
  1365. for(;;) {
  1366. int option_index = 0;
  1367. opt = getopt_long(argc, argv, "H:P:u:p:d:x:l:USt:T:qQrRhib?n", options, &option_index);
  1368. if (opt == -1) break;
  1369. switch (opt) {
  1370. case 'H':
  1371. esl_set_string(temp_host, optarg);
  1372. argv_host = 1;
  1373. break;
  1374. case 'P':
  1375. temp_port= atoi(optarg);
  1376. if (temp_port > 0 && temp_port < 65536) {
  1377. argv_port = 1;
  1378. } else {
  1379. printf("ERROR: Port must be in range 1 - 65535\n");
  1380. argv_error = 1;
  1381. }
  1382. break;
  1383. case 'n':
  1384. is_color = 0;
  1385. break;
  1386. case 'u':
  1387. esl_set_string(temp_user, optarg);
  1388. argv_user = 1;
  1389. break;
  1390. case 'p':
  1391. esl_set_string(temp_pass, optarg);
  1392. argv_pass = 1;
  1393. break;
  1394. case 'd':
  1395. temp_log=atoi(optarg);
  1396. if (temp_log < 0 || temp_log > 7) {
  1397. printf("ERROR: Debug level should be 0 - 7.\n");
  1398. argv_error = 1;
  1399. } else {
  1400. esl_global_set_default_logger(temp_log);
  1401. }
  1402. break;
  1403. case 'x':
  1404. argv_exec = 1;
  1405. esl_set_string(argv_command, optarg);
  1406. break;
  1407. case 'l':
  1408. esl_set_string(argv_loglevel, optarg);
  1409. break;
  1410. case 'U':
  1411. argv_log_uuid = 1;
  1412. break;
  1413. case 'S':
  1414. argv_log_uuid_short = 1;
  1415. break;
  1416. case 'q':
  1417. argv_quiet = 1;
  1418. break;
  1419. case 'b':
  1420. argv_batch = 1;
  1421. break;
  1422. case 'Q':
  1423. argv_use_history_file = 0;
  1424. break;
  1425. case 'i':
  1426. allow_ctl_c = 1;
  1427. break;
  1428. case 'r':
  1429. loops += 120;
  1430. break;
  1431. case 'R':
  1432. reconnect = 1;
  1433. break;
  1434. case 't':
  1435. timeout = atoi(optarg);
  1436. break;
  1437. case 'T':
  1438. connect_timeout = atoi(optarg);
  1439. break;
  1440. case 'h':
  1441. case '?':
  1442. print_banner(stdout, is_color);
  1443. usage(argv[0]);
  1444. return 0;
  1445. }
  1446. }
  1447. if (argv_error) {
  1448. printf("\n");
  1449. return usage(argv[0]);
  1450. }
  1451. read_config(dft_cfile, cfile);
  1452. if (optind < argc) {
  1453. get_profile(argv[optind], &profile);
  1454. }
  1455. if (!profile) {
  1456. if (get_profile("default", &profile)) {
  1457. esl_log(ESL_LOG_DEBUG, "profile default does not exist using builtin profile\n");
  1458. profile = &internal_profile;
  1459. }
  1460. }
  1461. if (temp_log < 0 ) {
  1462. esl_global_set_default_logger(profile->debug);
  1463. }
  1464. if (argv_host) {
  1465. esl_set_string(profile->host, temp_host);
  1466. }
  1467. if (argv_port) {
  1468. profile->port = (esl_port_t)temp_port;
  1469. }
  1470. if (argv_user) {
  1471. esl_set_string(profile->user, temp_user);
  1472. }
  1473. if (argv_pass) {
  1474. esl_set_string(profile->pass, temp_pass);
  1475. }
  1476. if (argv_batch || profile->batch_mode) {
  1477. profile->batch_mode = 1;
  1478. feature_level=0;
  1479. }
  1480. if (argv_use_history_file && profile->use_history_file) {
  1481. use_history_file = 1;
  1482. }
  1483. if (*argv_loglevel) {
  1484. esl_set_string(profile->loglevel, argv_loglevel);
  1485. profile->quiet = 0;
  1486. }
  1487. if (argv_log_uuid) {
  1488. profile->log_uuid = 1;
  1489. }
  1490. if (argv_log_uuid_short) {
  1491. profile->log_uuid = 1;
  1492. profile->log_uuid_length = log_uuid_short_length;
  1493. }
  1494. esl_log(ESL_LOG_DEBUG, "Using profile %s [%s]\n", profile->name, profile->host);
  1495. esl_set_string(prompt_color, profile->prompt_color);
  1496. esl_set_string(input_text_color, profile->input_text_color);
  1497. esl_set_string(output_text_color, profile->output_text_color);
  1498. if (argv_host) {
  1499. if (argv_port && profile->port != 8021) {
  1500. snprintf(bare_prompt_str, sizeof(bare_prompt_str), "freeswitch@%s:%u@%s> ", profile->host, profile->port, profile->name);
  1501. } else {
  1502. snprintf(bare_prompt_str, sizeof(bare_prompt_str), "freeswitch@%s@%s> ", profile->host, profile->name);
  1503. }
  1504. } else {
  1505. snprintf(bare_prompt_str, sizeof(bare_prompt_str), "freeswitch@%s> ", profile->name);
  1506. }
  1507. bare_prompt_str_len = (int)strlen(bare_prompt_str);
  1508. if (feature_level) {
  1509. #if HAVE_DECL_EL_PROMPT_ESC
  1510. snprintf(prompt_str, sizeof(prompt_str), "\1%s\1%s\1%s\1", prompt_color, bare_prompt_str, input_text_color);
  1511. #else
  1512. snprintf(prompt_str, sizeof(prompt_str), "%s%s%s", prompt_color, bare_prompt_str, input_text_color);
  1513. #endif
  1514. } else {
  1515. snprintf(prompt_str, sizeof(prompt_str), "%s", bare_prompt_str);
  1516. }
  1517. connect:
  1518. connected = 0;
  1519. while (--loops > 0) {
  1520. memset(&handle, 0, sizeof(handle));
  1521. if (esl_connect_timeout(&handle, profile->host, profile->port, profile->user, profile->pass, connect_timeout)) {
  1522. esl_global_set_default_logger(7);
  1523. esl_log(ESL_LOG_ERROR, "Error Connecting [%s]\n", handle.err);
  1524. if (loops == 1) {
  1525. if (!argv_exec) usage(argv[0]);
  1526. return -1;
  1527. } else {
  1528. sleep_s(1);
  1529. esl_log(ESL_LOG_INFO, "Retrying\n");
  1530. }
  1531. } else {
  1532. connected = 1;
  1533. if (temp_log < 0 ) {
  1534. esl_global_set_default_logger(profile->debug);
  1535. } else {
  1536. esl_global_set_default_logger(temp_log);
  1537. }
  1538. break;
  1539. }
  1540. }
  1541. if (argv_exec) {
  1542. const char *err = NULL;
  1543. snprintf(cmd_str, sizeof(cmd_str), "api %s\nconsole_execute: true\n\n", argv_command);
  1544. if (timeout) {
  1545. esl_status_t status = esl_send_recv_timed(&handle, cmd_str, timeout);
  1546. if (status != ESL_SUCCESS) {
  1547. printf("Request timed out.\n");
  1548. esl_disconnect(&handle);
  1549. return -2;
  1550. }
  1551. } else {
  1552. esl_send_recv(&handle, cmd_str);
  1553. }
  1554. if (handle.last_sr_event) {
  1555. if (handle.last_sr_event->body) {
  1556. printf("%s\n", handle.last_sr_event->body);
  1557. } else if ((err = esl_event_get_header(handle.last_sr_event, "reply-text")) && !strncasecmp(err, "-err", 3)) {
  1558. printf("Error: %s!\n", err + 4);
  1559. }
  1560. }
  1561. esl_disconnect(&handle);
  1562. return 0;
  1563. }
  1564. global_handle = &handle;
  1565. global_profile = profile;
  1566. if (esl_thread_create_detached(msg_thread_run, &handle) != ESL_SUCCESS) {
  1567. printf("Error starting thread!\n");
  1568. esl_disconnect(&handle);
  1569. return 0;
  1570. }
  1571. #ifdef HAVE_LIBEDIT
  1572. el = el_init(__FILE__, stdin, stdout, stderr);
  1573. #if HAVE_DECL_EL_PROMPT_ESC
  1574. el_set(el, EL_PROMPT_ESC, &prompt, '\1');
  1575. #else
  1576. el_set(el, EL_PROMPT, &prompt);
  1577. #endif
  1578. el_set(el, EL_EDITOR, "emacs");
  1579. el_set(el, EL_ADDFN, "f1-key", "F1 KEY PRESS", console_f1key);
  1580. el_set(el, EL_ADDFN, "f2-key", "F2 KEY PRESS", console_f2key);
  1581. el_set(el, EL_ADDFN, "f3-key", "F3 KEY PRESS", console_f3key);
  1582. el_set(el, EL_ADDFN, "f4-key", "F4 KEY PRESS", console_f4key);
  1583. el_set(el, EL_ADDFN, "f5-key", "F5 KEY PRESS", console_f5key);
  1584. el_set(el, EL_ADDFN, "f6-key", "F6 KEY PRESS", console_f6key);
  1585. el_set(el, EL_ADDFN, "f7-key", "F7 KEY PRESS", console_f7key);
  1586. el_set(el, EL_ADDFN, "f8-key", "F8 KEY PRESS", console_f8key);
  1587. el_set(el, EL_ADDFN, "f9-key", "F9 KEY PRESS", console_f9key);
  1588. el_set(el, EL_ADDFN, "f10-key", "F10 KEY PRESS", console_f10key);
  1589. el_set(el, EL_ADDFN, "f11-key", "F11 KEY PRESS", console_f11key);
  1590. el_set(el, EL_ADDFN, "f12-key", "F12 KEY PRESS", console_f12key);
  1591. el_set(el, EL_ADDFN, "EOF-key", "EOF (^D) KEY PRESS", console_eofkey);
  1592. el_set(el, EL_BIND, "\033OP", "f1-key", NULL);
  1593. el_set(el, EL_BIND, "\033OQ", "f2-key", NULL);
  1594. el_set(el, EL_BIND, "\033OR", "f3-key", NULL);
  1595. el_set(el, EL_BIND, "\033OS", "f4-key", NULL);
  1596. el_set(el, EL_BIND, "\033OT", "f5-key", NULL);
  1597. el_set(el, EL_BIND, "\033OU", "f6-key", NULL);
  1598. el_set(el, EL_BIND, "\033OV", "f7-key", NULL);
  1599. el_set(el, EL_BIND, "\033OW", "f8-key", NULL);
  1600. el_set(el, EL_BIND, "\033OX", "f9-key", NULL);
  1601. el_set(el, EL_BIND, "\033OY", "f10-key", NULL);
  1602. el_set(el, EL_BIND, "\033OZ", "f11-key", NULL);
  1603. el_set(el, EL_BIND, "\033O[", "f12-key", NULL);
  1604. el_set(el, EL_BIND, "\033[11~", "f1-key", NULL);
  1605. el_set(el, EL_BIND, "\033[12~", "f2-key", NULL);
  1606. el_set(el, EL_BIND, "\033[13~", "f3-key", NULL);
  1607. el_set(el, EL_BIND, "\033[14~", "f4-key", NULL);
  1608. el_set(el, EL_BIND, "\033[15~", "f5-key", NULL);
  1609. el_set(el, EL_BIND, "\033[17~", "f6-key", NULL);
  1610. el_set(el, EL_BIND, "\033[18~", "f7-key", NULL);
  1611. el_set(el, EL_BIND, "\033[19~", "f8-key", NULL);
  1612. el_set(el, EL_BIND, "\033[20~", "f9-key", NULL);
  1613. el_set(el, EL_BIND, "\033[21~", "f10-key", NULL);
  1614. el_set(el, EL_BIND, "\033[23~", "f11-key", NULL);
  1615. el_set(el, EL_BIND, "\033[24~", "f12-key", NULL);
  1616. el_set(el, EL_BIND, "\004", "EOF-key", NULL);
  1617. el_set(el, EL_ADDFN, "ed-complete", "Complete argument", complete);
  1618. el_set(el, EL_BIND, "^I", "ed-complete", NULL);
  1619. /* "Delete" key. */
  1620. el_set(el, EL_BIND, "\033[3~", "ed-delete-next-char", NULL);
  1621. if (!(myhistory = history_init())) {
  1622. esl_log(ESL_LOG_ERROR, "history could not be initialized\n");
  1623. goto done;
  1624. }
  1625. history(myhistory, &ev, H_SETSIZE, 800);
  1626. /* Ignore duplicate lines */
  1627. history(myhistory, &ev, H_SETUNIQUE, 1);
  1628. el_set(el, EL_HIST, history, myhistory);
  1629. if (use_history_file) history(myhistory, &ev, H_LOAD, hfile);
  1630. el_source(el, NULL);
  1631. #endif
  1632. #ifdef WIN32
  1633. hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  1634. if (hStdout != INVALID_HANDLE_VALUE && GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) {
  1635. wOldColorAttrs = csbiInfo.wAttributes;
  1636. }
  1637. #endif
  1638. if (!argv_quiet && !profile->quiet) {
  1639. snprintf(cmd_str, sizeof(cmd_str), "log %s\n\n", profile->loglevel);
  1640. esl_send_recv(&handle, cmd_str);
  1641. }
  1642. if (global_profile->batch_mode) {
  1643. setvbuf(stdout, (char*)NULL, _IONBF, 0);
  1644. }
  1645. print_banner(stdout, is_color);
  1646. esl_log(ESL_LOG_INFO, "FS CLI Ready.\nenter /help for a list of commands.\n");
  1647. output_printf("%s\n", handle.last_sr_reply);
  1648. while (running > 0) {
  1649. int r;
  1650. #ifdef HAVE_LIBEDIT
  1651. if (!(global_profile->batch_mode)) {
  1652. line = el_gets(el, &count);
  1653. } else {
  1654. #endif
  1655. line = basic_gets(&count);
  1656. #ifdef HAVE_LIBEDIT
  1657. }
  1658. #endif
  1659. if (count > 1 && !esl_strlen_zero(line)) {
  1660. char *p, *cmd = strdup(line);
  1661. assert(cmd);
  1662. if ((p = strrchr(cmd, '\r')) || (p = strrchr(cmd, '\n'))) {
  1663. *p = '\0';
  1664. }
  1665. #ifdef HAVE_LIBEDIT
  1666. history(myhistory, &ev, H_ENTER, line);
  1667. #endif
  1668. if ((r = process_command(&handle, cmd))) {
  1669. running = r;
  1670. }
  1671. free(cmd);
  1672. clear_el_buffer();
  1673. }
  1674. sleep_ms(1);
  1675. }
  1676. if (running < 0 && reconnect) {
  1677. running = 1;
  1678. loops = 120;
  1679. goto connect;
  1680. }
  1681. #ifdef HAVE_LIBEDIT
  1682. done:
  1683. if (use_history_file) history(myhistory, &ev, H_SAVE, hfile);
  1684. history_end(myhistory);
  1685. el_end(el);
  1686. #endif
  1687. esl_disconnect(&handle);
  1688. global_handle = NULL;
  1689. thread_running = 0;
  1690. esl_mutex_destroy(&MUTEX);
  1691. return 0;
  1692. }
  1693. /* For Emacs:
  1694. * Local Variables:
  1695. * mode:c
  1696. * indent-tabs-mode:t
  1697. * tab-width:4
  1698. * c-basic-offset:4
  1699. * End:
  1700. * For VIM:
  1701. * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
  1702. */