fs_cli.c 51 KB

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