/* * copyright David J. Binette * ALL RIGHTS RESERVED */ /* ------------------------------------------------------------------------ */ /* tab stops are set to 4 */ /* ------------------------------------------------------------------------ */ #include "nix.h" /* ------------------------------------------------------------------------ */ static SESSION * GlobalSessionHook = NULL; /* ------------------------------------------------------------------------ */ /* a mini line edit * 'hide' is a mask * bit 0 = no echo * bit 1 = erase all text and prompt after input */ #define WRITEBKSPC(h) write(h ,"\b \b" ,3) char *Ask(SESSION *sess ,const char *prompt ,char *buf ,int n ,short hide) { char c = 0; int r; int hi = fileno(sess->i); int ho = fileno(sess->o); int col = 0; /* output the prompt */ fflush(sess->o); write(ho ,prompt ,strlen(prompt)); /* raw mode means read without waiting * we want to wait now, so set the char timing interval * to wait for each character, forever if neccessary */ sess->tsetup.c_cc[VMIN ]= (char)1; sess->tsetup.c_cc[VTIME]= (char)0; SETTERMINALSTATE(hi,&sess->tsetup); while (!sess->quit) { r = read(hi ,&c ,1); if ((r < 1) || (c == CTRL('D'))) /* EOF */ { sess->quit = 1; col = 0; break; } if (c=='\033') /* esc */ { write(1 ,"\a" ,1); /* beep */ if(!(hide & 1)) /* if visible text */ for( ;col ;col--) /* delete all text */ WRITEBKSPC(ho); col = 0; /* reset for hidden text */ continue; } if (c == '\t') /* convert tab to space */ c=' '; if ((c == '\0') || (c == '\177')) /* brk and del are bkspc */ c='\b'; if ((c == '\r') || (c == '\n')) /* end of line */ break; if ((c == '\b') && (col == 0)) /* no bkspc past origin */ continue; if (c == '\b') /* do bkspc */ { col--; if(!(hide & 1)) WRITEBKSPC(ho); continue; } if (!(isprint(c) || isspace(c))) /* safe printable only */ continue; if (col >= (n-1)) /* stop at limit */ break; if(!(hide & 1)) write(ho ,&c ,1); /* output this char */ buf[col++] = c; /* add to text */ } buf[col] = EOS; if(hide & 2) { r = col + strlen(prompt); while(r-- > 0) WRITEBKSPC(ho); } else write(ho ,"\n" ,1); sess->tsetup.c_cc[VMIN ]= (char)0; sess->tsetup.c_cc[VTIME]= (char)0; SETTERMINALSTATE(hi,&sess->tsetup); return buf; } /* ------------------------------------------------------------------------ */ /* the waiting is done in the select for the socket, not here */ /* if the input stream is cooked, select only returns true after CRNL */ /* we want raw checking here, so we put the terminal into raw mode */ BOOL KeybDataAvailable(SESSION *sess) { struct timeval tv; fd_set fds; int fh = fileno(sess->i); /* look for a key */ tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(fh ,&fds); return (select(fh+1 ,&fds ,NULL ,NULL ,&tv) > 0); } /* ------------------------------------------------------------------------ */ void ClearScreen(SESSION *sess) { if(sess->ansi) fprintf(sess->o ,"\033[h\033[2J"); } /* ------------------------------------------------------------------------ */ /* Linux version of a signal handler * traps ^C brk intr term etc */ static void control_c_handler(int whathappened) { write(2,"*whap*",6); if(GlobalSessionHook->sock != INVALID_SOCKET) { closesocket(GlobalSessionHook->sock); GlobalSessionHook->sock = INVALID_SOCKET; GlobalSessionHook->quit = 1; } } /* ------------------------------------------------------------------------ */ int SessionHook(SESSION *sess ,short state ,short argc ,void* args) { int r = TRUE; switch(state) { /* the program has started */ /* user data has not yet been entered */ case SHOOK_PROG: GlobalSessionHook = sess; sess->i = stdin; sess->o = stdout; /* fetch and remember the current terminal state */ GETTERMINALSTATE(fileno(sess->i),&sess->tstate); /* make a copy that will be our new input mode */ sess->tsetup = sess->tstate; /* make that copy a raw mode version */ sess->tsetup.c_lflag &= ~(ECHO|ECHOKE|ECHONL|ICANON|IEXTEN); /* set the terminal to raw mode */ SETTERMINALSTATE(fileno(sess->i),&sess->tsetup); /* trap interupt and terminate so we can restore the modes later */ signal(SIGINT ,control_c_handler); signal(SIGTERM ,control_c_handler); break; /* user data is complete */ /* prepare to start networking */ /* login follows this */ case SHOOK_NET: break; /* login was successful */ /* next is login to chat */ case SHOOK_CHAT: break; /* connected to chat */ /* ready to start receiving data */ case SHOOK_RECV: fprintf(sess->o ,"waiting for yahoo greeting (wait a bit)\n"); break; /* yahoo data packet has arrived */ case SHOOK_DATA: /* on a login packet ,do a room join */ if(sess->yin.type == 0x01) { fprintf(sess->o ,"Chat started, type /help for help\n"); YahooTextCommand(sess ,"join " ,sess->room); /* set the return value for the program */ sess->rval = 0; } break; /* an optional hook fron the parser/decoder */ /* return TRUE if we displayed it here */ /* return FALSE for the default display handler */ case SHOOK_DECODE: r = FALSE; break; /* the user has entered chat text * args points to the NULL delimited string * if you return FALSE it wont be sent * this would be a good place to make macro * substitutions etc. */ case SHOOK_INPUT: break; /* the chat session is ending */ /* socket will be closed after this */ case SHOOK_CHATEND: break; /* all sockets closed */ /* end all networking */ case SHOOK_NETEND: break; /* program is exiting */ case SHOOK_EXIT: /* restore the default signal handlers */ signal(SIGINT ,SIG_DFL); signal(SIGTERM ,SIG_DFL); /* restore any saved terminal attributes */ SETTERMINALSTATE(fileno(sess->i),&sess->tstate); fprintf(sess->o ,"done\n"); /* set a return value for the program */ r= sess->rval; break; } return r; } /* ------------------------------------------------------------------------ */ /* end */