pkg://splitscreen-1.4.1.tar.gz:10904/
splitscreen-1.4.1/splitscreen.c
downloads
/* Splitscreen telnet client */
/* Uses ncurses, so hopefully compatible with much */
/* dave brown n2rjt (dcb@vectorbd.com) wrote this */
#define VERSION "V1.4.1 5/18/96 - N2RJT"
#include <ncurses/curses.h>
#include "sockserv.h"
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#define SERVICE "ttylink"
#define ALLOWCOLOR has_colors()
#define ENTRYROWS 2
#define BUFFERSIZE 256
#define SCROLLSIZE (LINES/4*3+1)
#define DEFAULTLOGLINES 500
WINDOW *sclwin, *entwin;
int currow;
int curcol;
FILE *logfile = NULL;
FILE *debugfile = NULL;
int maxloglines = DEFAULTLOGLINES;
int attr[3];
int color[3][2];
int curattr = 0;
#define NORMAL_ATTR 0
#define MINE_ATTR 1
#define ENTRY_ATTR 2
int insmode = TRUE;
struct logline {
struct logline *next;
struct logline *prev;
char *text;
int attr;
} *loghead = NULL, *logtail = NULL, *viewing = NULL;
int loglines = 0;
#define STATE_EDITING 0
#define STATE_VIEWING 1
int view_state = STATE_EDITING;
char input_buffer[BUFFERSIZE];
void addlog(char *s)
{
struct logline *temp;
if (logfile)
fprintf(logfile,"%s\n",s);
if (loglines >= maxloglines) {
temp = loghead;
loghead = loghead->next;
loghead->prev = NULL;
if (viewing == temp){
viewing = loghead;
}
free(temp->text);
} else {
temp = (struct logline *) malloc (sizeof(struct logline));
}
loglines++;
temp->next = NULL;
temp->text = strdup(s);
temp->attr = curattr;
if (loghead) {
logtail->next = temp;
temp->prev = logtail;
} else {
loghead = temp;
temp->prev = NULL;
}
logtail = temp;
}
int logattr(void)
{
if (!viewing)
return 0;
else
return viewing->attr;
}
char *firstlog(void)
{
viewing = loghead;
view_state = STATE_VIEWING;
if (debugfile) fprintf(debugfile,"firstlog: view_state = STATE_VIEWING: %s\n",viewing->text);
return viewing->text;
}
char *lastlog(void)
{
viewing = logtail;
view_state = STATE_VIEWING;
if (debugfile) fprintf(debugfile,"lastlog: view_state = STATE_VIEWING: %s\n", viewing->text);
return viewing->text;
}
char *nextlog(void)
{
if (view_state == STATE_EDITING)
viewing = loghead;
else if (viewing)
viewing = viewing->next;
if (viewing) {
view_state = STATE_VIEWING;
if (debugfile) fprintf(debugfile,"nextlog: view_state = STATE_VIEWING: %s\n",viewing->text);
return viewing->text;
} else {
viewing = logtail;
if (debugfile) fprintf(debugfile,"nextlog: AT BOTTOM\n");
return NULL;
}
}
char *prevlog(void)
{
if (view_state == STATE_EDITING)
viewing = logtail;
else if (viewing)
viewing = viewing->prev;
if (viewing) {
view_state = STATE_VIEWING;
if (debugfile) fprintf(debugfile,"prevlog: view_state = STATE_VIEWING: %s\n",viewing->text);
return viewing->text;
} else {
viewing = loghead;
if (debugfile) fprintf(debugfile,"prevlog: AT TOP\n");
return NULL;
}
}
void start_editing(void)
{
werase(entwin);
currow = curcol = 0;
viewing = NULL;
view_state = STATE_EDITING;
if (debugfile) fprintf(debugfile,"start_editing: view_state = STATE_EDITING\n");
}
void delete_prev_char(void)
{ int i,j;
int c,cc;
if (currow != 0 || curcol != 0) {
if (curcol-- == 0) {
curcol = COLS-1;
currow--;
}
c = ' ';
for (i=ENTRYROWS-1,j=COLS-1;i>currow || j>=curcol; j--) {
if (j<0) {
j = COLS-1;
i--;
}
cc = mvwinch(entwin,i,j);
waddch(entwin,c);
c = cc;
}
wmove(entwin,currow,curcol);
}
}
void right_arrow(void)
{
if (++curcol >= COLS) {
curcol = 0;
if (++currow >= ENTRYROWS){
currow = ENTRYROWS-1;
curcol = COLS-1;
}
}
wmove(entwin,currow,curcol);
}
void left_arrow(void)
{
if (--curcol < 0) {
curcol = COLS-1;
if (--currow < 0) {
currow = curcol = 0;
}
}
wmove(entwin,currow,curcol);
}
void move_eol(void)
{
currow = ENTRYROWS-1;
curcol = COLS-1;
while ((A_CHARTEXT & mvwinch(entwin,currow,curcol))==' ') {
curcol--;
if (curcol<0) {
if (currow>0) {
currow--;
curcol = COLS-1;
} else {
break;
}
}
}
right_arrow();
}
void gather_input(char *s)
{ int l = 0;
int i,j;
for (i=j=0;i<ENTRYROWS;j++) {
if (j>=COLS) {
j = 0;
i++;
}
if (i<ENTRYROWS)
s[l++] = A_CHARTEXT & mvwinch(entwin,i,j);
}
while (--l>=0) {
if (s[l]!=' ')
break;
else
s[l] = '\0';
}
/*s[++l] = '\n';*/
}
int attop = 0;
int walkup(void)
{ int i;
if (attop)
return 0;
if (debugfile) fprintf(debugfile,"walkup start\n");
attop = TRUE;
for (i=0; i<LINES-ENTRYROWS-1; i++) {
if (prevlog()==NULL){ /* Not enough to view .. you already see it all */
beep();
if (debugfile) fprintf(debugfile,"walkup beep done\n");
return 1;
}
}
if (debugfile) fprintf(debugfile,"walkup done\n");
return 0;
}
int walkdn(void)
{ int i;
if (!attop)
return 0;
if (debugfile) fprintf(debugfile,"walkdn start\n");
attop = FALSE;
for (i=0; i<LINES-ENTRYROWS-1; i++) {
if (nextlog()==NULL){ /* Not enough to view */
beep();
if (debugfile) fprintf(debugfile,"walkdn beep done\n");
return 1;
}
}
if (debugfile) fprintf(debugfile,"walkdn done\n");
return 0;
}
int pageup(int lines)
{
int i;
char *s = NULL;
if (debugfile) fprintf(debugfile,"pageup(%d) start\n",lines);
walkup();
for (i=0; i<lines; i++) {
wmove(sclwin,0,0);
s = prevlog();
if (s == NULL){
beep();
break;
}
winsertln(sclwin);
wattrset(sclwin, logattr());
mvwaddstr(sclwin,0,0,s);
}
wrefresh(sclwin);
if (debugfile) fprintf(debugfile,"pageup end %s\n",s != NULL ? "TRUE":"FALSE");
return (s != NULL);
}
int pagedn(int lines)
{
int i;
char *s = NULL;
if (debugfile) fprintf(debugfile,"pagedn(%d) start\n",lines);
walkdn();
for (i=0; i<lines; i++) {
s = nextlog();
if (s == NULL){
beep();
break;
}
scroll(sclwin);
wattrset(sclwin, logattr());
mvwprintw(sclwin,LINES-ENTRYROWS-1,0,"%s",s);
}
wrefresh(sclwin);
if (debugfile) fprintf(debugfile,"pagedn end %s\n",s != NULL ? "TRUE":"FALSE");
return (s != NULL);
}
char entry_text[BUFFERSIZE];
void viewbottom(void)
{
int i;
char *s;
if (debugfile) fprintf(debugfile,"viewbottom start\n");
for (i=0; i<LINES-ENTRYROWS; i++) {
if (i==0)
s = lastlog();
else
s = prevlog();
if (s == NULL)
break;
}
werase(sclwin);
while (1) {
s = nextlog();
if (s == NULL)
break;
wattrset(sclwin, logattr());
wprintw(sclwin,"%s\n",s);
}
if (strlen(input_buffer)>0)
wprintw(sclwin,"%s",input_buffer);
wrefresh(sclwin);
attop = FALSE;
if (debugfile) fprintf(debugfile,"viewbottom end\n");
}
void viewtop(void)
{
int i;
char *s;
if (debugfile) fprintf(debugfile,"viewbottom start\n");
werase(sclwin);
for (i=0; i<LINES-ENTRYROWS; i++) {
if (i == 0)
s = firstlog();
else
s = nextlog();
if (s == NULL)
break;
wattrset(sclwin, logattr());
wprintw(sclwin,"%s\n",s);
}
wrefresh(sclwin);
attop = FALSE;
if (debugfile) fprintf(debugfile,"viewbottom end\n");
}
void resume_editing(void)
{
viewbottom();
wattrset(sclwin, curattr);
werase(entwin);
mvwprintw(entwin,0,0,entry_text);
wmove(entwin,currow,curcol);
viewing = NULL;
view_state = STATE_EDITING;
if (debugfile) fprintf(debugfile,"resume_editing: view_state = STATE_EDITING\n");
wrefresh(entwin);
}
void viewlog(void)
{
if (debugfile) fprintf(debugfile,"viewlog start\n");
attop = FALSE;
if (walkup()){
view_state = STATE_EDITING;
viewing = NULL;
return;
}
gather_input(entry_text);
werase(entwin);
mvwprintw(entwin,0,0,"Viewing data... hit ENTER to return\n");
pageup(SCROLLSIZE);
if (debugfile) fprintf(debugfile,"viewlog end\n");
}
int litflag = FALSE;
int edit_line(int c)
{
if (view_state != STATE_EDITING) {
if (c == '\n')
resume_editing();
else if (c == KEY_PPAGE)
pageup(SCROLLSIZE);
else if (c == KEY_NPAGE)
pagedn(SCROLLSIZE);
else if (c == KEY_UP)
pageup(1);
else if (c == KEY_DOWN)
pagedn(1);
else if (c == KEY_HOME)
viewtop();
else if (c == KEY_END)
viewbottom();
} else {
if (litflag) {
wprintw(sclwin,"Keycode = %o octal\n", c);
wrefresh(sclwin);
litflag = FALSE;
return 0;
}
if (c == erasechar() || c == KEY_BACKSPACE)
delete_prev_char();
else if (c == killchar() || c == KEY_CLEAR)
start_editing();
else if (c == '\n')
return 1;
else if (c == KEY_IC)
insmode = TRUE;
else if (c == KEY_EIC)
insmode = FALSE;
else if (c == KEY_F(10))
insmode = !insmode;
else if (c == KEY_DOWN) {
if (currow < ENTRYROWS)
currow++;
wmove(entwin,currow,curcol);
} else if (c == KEY_UP) {
if (currow > 0)
currow--;
wmove(entwin,currow,curcol);
} else if (c == KEY_PPAGE) {
viewlog();
} else if (c == KEY_LEFT) {
left_arrow();
} else if (c == KEY_RIGHT) {
right_arrow();
} else if (c == KEY_HOME || c == '\001') {
currow = curcol = 0;
wmove(entwin,currow,curcol);
} else if (c == KEY_END || c == '\005') {
move_eol();
} else if (c == KEY_DC) {
right_arrow();
delete_prev_char();
} else if (c == KEY_EOS) {
wclrtobot(entwin);
} else if (c == KEY_EOL) {
wclrtoeol(entwin);
} else if (c == KEY_F(9)) {
litflag = TRUE;
}
else if (c == (c & A_CHARTEXT)){
if (insmode) {
if (currow < ENTRYROWS-1) {
int i;
i = A_CHARTEXT & mvwinch(entwin,currow,COLS-1);
mvwinsch(entwin,currow+1,0,i);
}
mvwinsch(entwin,currow,curcol,c);
} else {
waddch(entwin,c);
}
curcol++;
if (curcol == COLS && currow < ENTRYROWS-1){
curcol = 0;
currow++;
}
wmove(entwin,currow,curcol);
}
}
return 0;
}
void sanitize(unsigned char *s)
{
char *t;
for (t=s; *s!='\0'; s++) {
if (*s == '\007')
beep();
else if (*s == '\015')
;
else if (*s > 127)
*t++ = *s - 128;
else
*t++ = *s;
}
*t = '\0';
}
void addtext(char *s)
{
int i,l;
l = strlen(input_buffer);
if (view_state == STATE_EDITING){
wprintw(sclwin,"%s",s);
wrefresh(sclwin);
}
for (i=0; i<strlen(s); i++) {
if (s[i]=='\n' || i+l+1 >= COLS) {
addlog(input_buffer);
l = -i-1;
} else {
input_buffer[i+l] = s[i];
}
input_buffer[i+l+1] = '\0';
}
}
int setattr(char *name)
{
if (!strcasecmp(name,"normal")) return A_NORMAL;
else if (!strcasecmp(name,"standout")) return A_STANDOUT;
else if (!strcasecmp(name,"underline")) return A_UNDERLINE;
else if (!strcasecmp(name,"reverse")) return A_REVERSE;
else if (!strcasecmp(name,"blink")) return A_BLINK;
else if (!strcasecmp(name,"dim")) return A_DIM;
else if (!strcasecmp(name,"bold")) return A_BOLD;
else return 0;
}
int setcolor(char *name)
{
if (!strcasecmp(name,"black")) return COLOR_BLACK;
else if (!strcasecmp(name,"red")) return COLOR_RED;
else if (!strcasecmp(name,"green")) return COLOR_GREEN;
else if (!strcasecmp(name,"yellow")) return COLOR_YELLOW;
else if (!strcasecmp(name,"blue")) return COLOR_BLUE;
else if (!strcasecmp(name,"magenta")) return COLOR_MAGENTA;
else if (!strcasecmp(name,"cyan")) return COLOR_CYAN;
else if (!strcasecmp(name,"white")) return COLOR_WHITE;
else return -1;
}
int setattrs(int pairnum, char *name)
{
int i,j,attrib,n;
int icolor;
char attrname[20];
color[pairnum][0] = COLOR_WHITE;
color[pairnum][1] = COLOR_BLACK;
i = icolor = 0;
attrib = 0;
for (j=0; j<=strlen(name);j++) {
if (name[j] == ':' || j == strlen(name)) {
attrname[i] = '\0';
i = 0;
if ((n = setcolor(attrname)) != -1) {
if (icolor < 2)
color[pairnum][icolor++] = n;
} else
attrib |= setattr(attrname);
} else {
if (i<20)
attrname[i++] = name[j];
}
}
if (icolor){
attrib |= COLOR_PAIR((pairnum+1));
}
return attrib;
}
int main(int argc,char *argv[])
{
int sock;
char line[BUFFERSIZE];
int i;
int c;
struct servent *svc;
int portnum = 0;
char *service = SERVICE;
int argn, addrarg;
int whydie = 0;
input_buffer[0] = '\0';
attr[NORMAL_ATTR] = A_NORMAL;
attr[MINE_ATTR] = A_BOLD;
attr[ENTRY_ATTR] = A_BOLD;
addrarg = 0;
argn = 0;
for (i=1; i<argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'n':
c = atoi(argv[i]+2);
if (c || argv[i][2]=='0')
maxloglines = c;
else{
fprintf(stderr,"arg value must be numeric: %s\n",argv[i]);
sleep(2);
}
break;
case 'd':
if ((debugfile = fopen(argv[i]+2,"w")) == NULL) {
perror(argv[i]+2);
sleep(2);
}
break;
case 'l':
if ((logfile = fopen(argv[i]+2,"a+")) == NULL) {
perror(argv[i]+2);
sleep(2);
}
break;
case 't':
attr[NORMAL_ATTR] = setattrs(NORMAL_ATTR,argv[i]+2);
break;
case 's':
attr[MINE_ATTR] = setattrs(MINE_ATTR,argv[i]+2);
break;
case 'e':
attr[ENTRY_ATTR] = setattrs(ENTRY_ATTR,argv[i]+2);
break;
default:
fprintf(stderr,"Invalid argument '%s'\n",argv[i]);
sleep(2);
}
} else if (!argn++) {
addrarg = i;
} else {
service = argv[i];
}
}
if (argn < 1) {
fprintf(stderr,"Usage: %s hostname [port]; default port is %s\n",
argv[0], SERVICE);
fprintf(stderr,"optional arguments:\n");
fprintf(stderr," -n<saved lines> -- how many lines to remember\n");
fprintf(stderr," -l<logfile name> -- enable logging to a file\n");
fprintf(stderr," -t<attributes> -- set received text attributes\n");
fprintf(stderr," -s<attributes> -- set sent text attributes\n");
fprintf(stderr," -e<attributes> -- set edit text attributes\n");
fprintf(stderr," -d<debug file> -- enable debugging\n");
fprintf(stderr,"attributes = fgcolor:bgcolor:attr, where\n");
fprintf(stderr," attr = bold, underline, reverse, etc\n");
fprintf(stderr," color = black red green yellow blue magenta cyan or white\n");
exit(1);
}
svc = getservbyname(service,NULL);
if (svc) {
portnum = ntohs(svc->s_port);
} else {
portnum = atoi(service);
}
if (portnum == 0) {
fprintf(stderr,"Service %s unknown\n",service);
exit(1);
}
if (initscr() == NULL) {
fprintf(stderr,"Cannot initialize ncurses\n");
exit(1);
}
if (ALLOWCOLOR) {
start_color();
for (i=0; i<3; i++) {
init_pair(i+1,color[i][0],color[i][1]);
}
}
sclwin = newwin(LINES-ENTRYROWS, COLS, 0, 0); /* Create main window */
entwin = newwin(ENTRYROWS, COLS, LINES-ENTRYROWS, 0); /* Data entry window */
scrollok(sclwin,TRUE); /* scroll window scrolls, */
scrollok(entwin,FALSE); /* entry window doesn't */
keypad(entwin,TRUE); /* Enable function key recognition */
intrflush(entwin,FALSE);
wattrset(sclwin, attr[NORMAL_ATTR]); /* Make the scroll window normal video. */
wattrset(entwin, attr[ENTRY_ATTR]); /* Make the entry window reverse video. */
mvwprintw(sclwin,0,0,"Splitscreen %s\n",VERSION);
noecho();
cbreak();
wtimeout(entwin,0);
wrefresh(sclwin);
start_editing();
curattr = attr[NORMAL_ATTR];
wprintw(sclwin,"Trying %s:%d ... ",argv[addrarg], portnum);
wrefresh(sclwin);
if ((sock=startcli(argv[addrarg],portnum)) < 0){
whydie = errno;
wprintw(sclwin,"failed %d\n", sock);
wrefresh(sclwin);
goto cleanup;
} else {
/*setlinemode(sock,TRUE);*/
wprintw(sclwin,"connected.\n");
}
wrefresh(sclwin);
socktimeout(30);
while(1){
wrefresh(entwin);
while ((c = wgetch(entwin))==-1){
i = recvline(&sock,line,BUFFERSIZE-1);
if (i == -1) {
whydie = errno;
goto cleanup;
} else if (i != -2){
line[i] = '\0';
if (debugfile) fprintf(debugfile,"Received %d bytes: %s\n",i,line);
if (debugfile) fprintf(debugfile,"Portnum = %d\n",portnum);
sanitize(line);
addtext(line);
}
}
if (edit_line(c)) {
gather_input(line);
curattr = attr[MINE_ATTR];
wattrset(sclwin, curattr);
strcat(line,"\n");
usputs(sock,line);
addtext(line);
curattr = attr[NORMAL_ATTR];
wattrset(sclwin, curattr);
wrefresh(sclwin);
start_editing();
}
}
cleanup:
wattrset(entwin,A_NORMAL);
wclear(entwin);
wmove(entwin,1,0);
wrefresh(entwin);
vidattr(A_NORMAL);
endwin();
if (sock > 0)
close_s(sock);
if (whydie == ENOENT)
fprintf(stderr,"Connection reset by peer.\n");
else if (whydie)
perror(argv[addrarg]);
if (logfile)
fclose(logfile);
if (debugfile)
fclose(debugfile);
return 0;
}