/* Copyright (c) 2002
* Marko Boomstra (m.boomstra@chello.nl). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <conf.h>
#include <arpa/telnet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <ncurses.h>
#include <panel.h>
#include "mudix.h"
//#define CSI_DEBUG
/*
* Defines
*/
#define MAX_HISTORY 100
/*
* Locals
*/
int check_esc(char *pBuf, int *attrib);
char history [MAX_HISTORY][LINE_MAXIM];
char *pHistory [MAX_HISTORY];
char **pCurHist = pHistory;
char **pGetHist = pHistory;
bool fCharacterMode = FALSE;
void init_history(void)
{
int index;
for (index = 0; index < MAX_HISTORY; index++)
{
pHistory[index] = &history[index][0];
history[index][0] = '\0';
}
return;
}
void read_input(void)
{
static int input[LINE_MAXIM];
int *in = input, i = 0, value = 0;
while((*in = fgetc(stdin)) != EOF) {
#if KEY_DEBUG
wprintw(wInput, "<I%d>", *in);
#endif
in++;
if ((in-input) >= INPUT_MAX)
break;
}
#if KEY_DEBUG
wprintw(wInput, "<%d-%d>", *in, in-input);
#endif
if (in == input)
return;
if (input[0] == ESC)
while (i < (in-input))
value += input[i++];
#if KEY_DEBUG
wprintw(wInput, "<V%d>", value);
#endif
switch (value) {
case 0:
{
int length = in-input;
in = input;
while (length-- > 0) {
if (isprint(*in)) {
if (pEndIn >= (inbuf+INPUT_MAX)) {
beep();
break;
}
if (fCharacterMode) {
char k[2];
k[0] = (char)*in;
k[1] = '\0';
process_input(k, NULL, FALSE);
break;
}
pCursor++;
if (fEchoIn) {
waddch(wInput, *in);
}
else {
waddch(wInput, '*');
}
}
switch (*in) {
case TAB:
check_tab(inbuf, pEndIn);
break;
case BS:
case BACKSPACE:
if (pCursor == pEndIn) {
if (pEndIn > inbuf) {
pEndIn--;
pCursor--;
}
else
break;
if (pCursor >= (LINE_LENGTH + inbuf))
print_cmd_line();
else
backspace();
}
else {
char *pTemp;
if (pCursor > inbuf) {
pCursor--;
move_cursor(wInput, LEFT, 1);
}
else
break;
pTemp = pCursor;
while (pTemp != pEndIn) {
*pTemp = *(pTemp+1);
pTemp++;
}
pEndIn--;
print_cmd_line();
if (pCursor < (LINE_LENGTH + inbuf))
wmove(wInput, 0, pCursor-inbuf);
}
break;
case CR:
*pEndIn++ = '\n';
*pEndIn = '\0';
/* put command in history */
if (pEndIn - inbuf >= 4 && fEchoIn) {
char *pTempHis = *pCurHist;
char *pTempBuf = inbuf;
while(*pTempBuf != '\n')
*pTempHis++ = *pTempBuf++;
*pTempHis = '\0';
if (pCurHist == &pHistory[MAX_HISTORY-1])
pCurHist = pGetHist = &pHistory[0];
else
pGetHist = ++pCurHist;
}
process_input(inbuf, NULL, FALSE);
werase(wInput);
pEndIn = inbuf;
pCursor = inbuf;
break;
default:
*pEndIn++ = *in;
if (pCursor == pEndIn) {
if (pCursor >= (LINE_LENGTH + inbuf))
print_cmd_line();
}
else {
char *pTemp;
pCursor--;
pTemp = pEndIn-1;
while (pTemp != pCursor) {
*pTemp = *(pTemp-1);
pTemp--;
}
*pCursor++ = *in;
print_cmd_line();
if (pCursor < (LINE_LENGTH + inbuf))
wmove(wInput, 0, pCursor-inbuf);
}
break;
}
in++;
}
break;
}
case ESC:
if (panel_hidden(pMsg) == PANEL_VISIBLE)
hide_panel(pMsg);
else if (panel_hidden(pScroll) == PANEL_VISIBLE)
hide_panel(pScroll);
else if (panel_hidden(pStatus) == PANEL_VISIBLE)
hide_panel(pStatus);
break;
case F1:
case F2:
case F3:
case F4:
case F5:
case F6:
case F7:
case F8:
case F9:
case F10:
case F11:
case F12:
process_alias(value);
break;
case HOME:
if (fKeypadWalk)
process_input("u", NULL, TRUE);
else {
pCursor = inbuf;
print_cmd_line();
wmove(wInput, 0, 0);
}
break;
case END:
if (fKeypadWalk)
process_input("d", NULL, TRUE);
else {
pCursor = pEndIn;
print_cmd_line();
}
break;
case PGUP:
show_scroll(UP, SCROLL_SIZE);
break;
case PGDWN:
show_scroll(DOWN, SCROLL_SIZE);
break;
case L_ALT('1'):
show_triggers();
break;
case L_ALT('2'):
show_aliases();
break;
case L_ALT('3'):
show_paths();
break;
case L_ALT('4'):
show_tabs();
break;
case L_ALT('5'):
show_vars();
break;
case L_ALT('m'):
fCharacterMode ^= TRUE;
if (fCharacterMode) {
do_status("Character mode turned ON.", 3);
hide_panel(pBanner);
hide_panel(pInput);
wresize(wMain, LEN_ROW, LEN_COL);
}
else {
do_status("Character mode turned OFF.", 3);
show_panel(pBanner);
show_panel(pInput);
wresize(wMain, LEN_ROW-2, LEN_COL);
}
break;
case L_ALT('h'):
do_help();
break;
case L_ALT('q'):
dialog("Are you sure you want to quit? (Y/N)");
settings->state = STATE_QUIT;
break;
case L_ALT('r'):
fReconnect = TRUE;
do_status("Reconnect requested.", 3);
break;
case L_ALT('t'):
dialog("Toggle which trigger? (#)");
settings->state = STATE_TTOGGLE;
break;
case L_ALT('s'):
show_settings();
break;
case L_ALT('c'):
dialog("What text should initiate the login procedure?");
settings->state = STATE_CREATE_1;
break;
case L_ALT('i'):
fEchoIn ^= TRUE;
if (fEchoIn)
do_status("Input echo turned ON.", 3);
else
do_status("Input echo turned OFF.", 3);
break;
case L_ALT('o'):
fEchoOut ^= TRUE;
if (fEchoOut)
do_status("Command echo turned ON.", 3);
else
do_status("Command echo turned OFF.", 3);
break;
case L_ALT('p'):
fPrintTime ^= TRUE;
if (fPrintTime)
do_status("Time displayed.", 3);
else
do_status("Time display disabled.", 3);
break;
case L_ALT('k'):
fKeypadWalk ^= TRUE;
if (fKeypadWalk)
do_status("Keypad walking enabled.", 3);
else
do_status("Keypad walking disabled.", 3);
break;
case L_ALT('a'):
if (!fStatusReport) {
fStatusReport = TRUE;
do_status("Status reports enabled.", 3);
}
else {
do_status("Status reports disabled.", 3);
fStatusReport = FALSE;
}
break;
case ARROW_U:
case XARROW_U:
if (fKeypadWalk) {
process_input("n", NULL, TRUE);
break;
}
if (panel_hidden(pScroll) == PANEL_VISIBLE) {
show_scroll(UP, 1);
break;
}
if (pGetHist == &pHistory[0])
pGetHist = &pHistory[MAX_HISTORY-1];
else
pGetHist--;
werase(wInput);
if (**pGetHist != '\0') {
char *pTemp = inbuf;
char *pHtmp = *pGetHist;
while(*pHtmp != '\0')
*pTemp++ = *pHtmp++;
*pTemp = '\0';
pEndIn = pCursor = pTemp;
if (pCursor >= (LINE_LENGTH + inbuf))
print_cmd_line();
else {
waddnstr(wInput, inbuf, pTemp - inbuf);
}
}
else
pEndIn = pCursor = inbuf;
break;
case ARROW_D:
case XARROW_D:
if (fKeypadWalk) {
process_input("s", NULL, TRUE);
break;
}
if (panel_hidden(pScroll) == PANEL_VISIBLE) {
show_scroll(DOWN, 1);
break;
}
if (pGetHist == &pHistory[MAX_HISTORY-1])
pGetHist = &pHistory[0];
else
pGetHist++;
werase(wInput);
if (**pGetHist != '\0') {
char *pTemp = inbuf;
char *pHtmp = *pGetHist;
while(*pHtmp != '\0')
*pTemp++ = *pHtmp++;
*pTemp = '\0';
pEndIn = pCursor = pTemp;
if (pCursor >= (LINE_LENGTH + inbuf))
print_cmd_line();
else {
waddnstr(wInput, inbuf, pTemp - inbuf);
}
}
else
pEndIn = pCursor = inbuf;
break;
case ARROW_R:
case XARROW_R:
if (fKeypadWalk) {
process_input("e", NULL, TRUE);
break;
}
if (pCursor < pEndIn) {
pCursor++;
if (pCursor >= (LINE_LENGTH + inbuf))
print_cmd_line();
else
move_cursor(wInput, RIGHT, 1);
}
break;
case ARROW_L:
case XARROW_L:
if (fKeypadWalk) {
process_input("w", NULL, TRUE);
break;
}
if (pCursor > inbuf) {
pCursor--;
if (pCursor >= (LINE_LENGTH + inbuf))
print_cmd_line();
else
move_cursor(wInput, LEFT, 1);
}
break;
default:
break;
}
return;
}
void process_input(char *input, char *args, bool fReturn)
{
char cmd[MAX_STRING];
while (*input != '\0') {
input = parse_input(input, args, cmd, fReturn);
if (cmd[0] == '#') { /* it's a MUDix command */
do_command(&cmd[1]); /* do not pass the '#' */
continue;
}
if (process_naming(cmd))
continue;
if (!settings->state) {
if (fEchoOut) {
wattrset(wMain, COLOR_PAIR(COL_GREEN)|A_NORMAL);
waddstr(wMain, cmd);
put_in_scroll(cmd, NULL, COLOR_PAIR(COL_GREEN)|A_NORMAL);
wattrset(wMain, COLOR_PAIR(0)|A_NORMAL);
}
strcat(send_buffer, cmd);
}
else
set_settings(cmd);
}
return;
}
int fill_param(int *npar, char *pBuf, int *params)
{
char local[24];
char *pLoc = local;
if (*npar >= CSIPARAMS)
return 0;
while (pBuf < pOut) {
if (*pBuf == ';' || (*pBuf != ' ' && !isdigit(*pBuf))) {
*pLoc = '\0';
params[(*npar)++] = local[0]? atoi(local): 0;
#ifdef CSI_DEBUG
{
FILE *fp = fopen("log", "a+");
fprintf(fp, "<%d-%s-%c>\n", *npar, local, *pBuf);
fclose(fp);
}
#endif
return pLoc-local;
}
*pLoc++ = *pBuf++;
}
return 0;
}
bool iscsiseq(char c)
{
if ((c>='A' && c<='J')
|| (c>='K' && c<='M')
|| (c>='c' && c<='h')
|| (c>='l' && c<='n')
|| (c>='q' && c<='s')
|| c=='P' || c=='X' || c=='a' || c=='u' || c=='`')
return TRUE;
return FALSE;
}
int check_esc(char *pBuf, int *attrib)
{
char *pBegin = pBuf;
int params[CSIPARAMS], npar, i;
if (*pBuf++ != ESC || pBuf >= pOut) /* push character back */
return 0;
if (*pBuf++ != '[') /* only accept "ESC [" */
return 1;
npar = 0;
while (pBuf < pOut) {
if (isdigit(*pBuf))
pBuf += fill_param(&npar, pBuf, params);
if (iscsiseq(*pBuf)) {
static int x_cur, y_cur; /* cursor position for store/restore */
int x, y;
switch (*pBuf++) {
case '@':
for (i=0; i<params[0]; i++)
winsch(wMain, ' ');
break;
case 'A':
move_cursor(wMain, UP, params[0]);
break;
case 'B':
move_cursor(wMain, DOWN, params[0]);
break;
case 'C':
move_cursor(wMain, RIGHT, params[0]);
break;
case 'D':
move_cursor(wMain, LEFT, params[0]);
break;
case 'E':
move_cursor(wMain, DOWN, params[0]);
getyx(wMain, y, x);
wmove(wMain, y, 0);
break;
case 'F':
move_cursor(wMain, UP, params[0]);
getyx(wMain, y, x);
wmove(wMain, y, 0);
break;
case 'G':
getyx(wMain, y, x);
wmove(wMain, y, params[0]-1);
break;
case 'H':
wmove(wMain, params[0]-1, params[1]-1);
break;
case 'J':
if (params[0] == 0)
wclrtobot(wMain);
else if (params[0] == 2)
wclear(wMain);
break;
case 'K':
if (params[0] == 0)
wclrtoeol(wMain);
else if (params[0] == 2) {
getyx(wMain, y, x);
wmove(wMain, y, 0);
wclrtoeol(wMain);
}
break;
case 'm':
for (i=0; i<npar; i++) {
switch (params[i]) {
case ANSI_DEFAULT:
*attrib = 0;
break;
case ANSI_BOLD:
*attrib |= A_BOLD;
break;
case ANSI_REVERSE:
*attrib |= A_REVERSE;
break;
case ANSI_UNDERLINE:
*attrib |= A_UNDERLINE;
break;
case ANSI_BLINK:
*attrib |= A_BLINK;
break;
case ANSI_BOLD_OFF:
*attrib &= ~A_BOLD;
break;
case ANSI_REVERSE_OFF:
*attrib &= ~A_REVERSE;
break;
case ANSI_UNDERLINE_OFF:
*attrib &= ~A_UNDERLINE;
break;
case ANSI_BLINK_OFF:
*attrib &= ~A_BLINK;
break;
case ANSI_FG_DEFAULT:
*attrib &= ~A_COLOR;
break;
case ANSI_FG_BLACK:
case ANSI_FG_RED:
case ANSI_FG_GREEN:
case ANSI_FG_BROWN:
case ANSI_FG_BLUE:
case ANSI_FG_MAGENTA:
case ANSI_FG_CYAN:
case ANSI_FG_WHITE:
*attrib = (*attrib & ~A_COLOR) |
COLOR_PAIR(params[i]-29);
break;
default:
break;
}
}
wattrset(wMain, *attrib);
break;
case 's':
getyx(wMain, y_cur, x_cur);
break;
case 'u':
wmove(wMain, y_cur, x_cur);
break;
default:
break;
}
return pBuf-pBegin;
}
pBuf++;
}
return 0; /* push the current escape sequence back for later check */
}
void process_buffer(void)
{
static char buffer[OUTBUF_LENGTH];
static char trigbuf[OUTBUF_LENGTH];
char *pObuf = outbuf;
char *pBuf = buffer;
char *pTrg = trigbuf;
bool EscSeq = FALSE;
static int attrib;
int len;
while (pObuf < pOut) {
if (!isprint(*pObuf)) {
switch(*pObuf) {
case ESC:
if (pBuf != buffer) {
waddnstr(wMain, buffer, pBuf-buffer);
put_in_scroll(buffer, pBuf, attrib);
pBuf = buffer;
}
if ((len = check_esc(pObuf, &attrib)) <= 0) {
EscSeq = TRUE;
break;
}
pObuf += len;
continue;
case (char)IAC:
pObuf += check_iac((unsigned char *)pObuf);
continue;
case BEEP:
beep();
pObuf++;
continue;
case CR:
pObuf++;
continue;
default:
break;
}
}
if (EscSeq) {
char *pEsc = outbuf;
while (pObuf < pOut)
*pEsc++ = *pObuf++;
pOut = pEsc;
break;
}
*pTrg++ = *pBuf++ = *pObuf++;
}
if (!EscSeq)
pOut = outbuf;
if (pBuf != buffer) {
waddnstr(wMain, buffer, pBuf-buffer);
put_in_scroll(buffer, pBuf, attrib);
}
if (pTrg != trigbuf) {
*pTrg = '\0';
trigger_check(trigbuf);
}
fProcessData = FALSE;
return;
}
syntax highlighted by Code2HTML, v. 0.9.1