#include #include #include #include #include #include #ifdef BSD extern "C" { int socketpair(int, int, int, int *); } #include #endif /* BSD */ #ifdef i386 extern "C" { int grantpt(int); int unlockpt(int); char *ptsname(int); } #endif /* i386 */ SRCFILE("term.c") static void mallocerr() { PadsError("Pads library: malloc failed"); } void Pick( char *s, Action a, long o ) { Index ix; trace("Pick(%d,%d)", a, o); ix = ICache->place(Item(s, a, o)); R->pktstart( P_PICK ); R->sendlong( ix.indx ); R->pktend(); } char *JerqTERM[] = { "/usr/jerq/bin/32ld /usr/jerq/mbin/pads.m", "5620", "jerq", "JERQ", "Jerq", "DMD", "DMD5620", 0 }; char *BlitTERM[] = { "/usr/blit/bin/68ld /usr/blit/mbin/pads.m", "blit", "BLIT", "Blit", 0 }; char *XTERM[] = { "pads", "xterm", "sun", 0 }; char **MapTERM[] = { XTERM, JerqTERM, BlitTERM, 0 }; static char *pipeconnect(int argc, char **argv, char *cmd, int *afildes) { char *termargv[20]; int targc = 0; int pid; termargv[targc++] = cmd; while( argc > 1 ){ if( !strcmp("-font", argv[1]) || !strcmp("-foreground", argv[1]) || !strcmp("-background", argv[1]) || !strcmp("-geometry", argv[1]) ){ termargv[targc++] = argv[1]; termargv[targc++] = argv[2]; --argc, argv++; } --argc, argv++; } termargv[targc] = 0; #ifdef i386 if((afildes[1] = open("/dev/ptmx", 2)) == -1) return "can't create opne /dev/ptmx\n"; grantpt(afildes[1]); unlockpt(afildes[1]); if((afildes[0] = open(ptsname(afildes[1]), 2)) == -1) { close(afildes[1]); return "can't create pipe to terminal process\n"; } #else #ifdef BSD if( socketpair(AF_UNIX, SOCK_STREAM, 0, afildes)==-1 ) #else if( pipe(afildes)==-1 ) #endif /* BSD */ return "can't open pipe\n"; #endif /* i386 */ if( (pid=fork())==0 ){ close(afildes[1]); close(0); dup(afildes[0]); close(1); dup(afildes[0]); close(afildes[0]); execvp(termargv[0], termargv); _exit(1); } if(pid==-1) return "terminal fork failed"; return 0; } char *PadsInit(int argc, char **argv) { char *TERM = getenv("TERM"), ***map, **term; char *loadcmd = MapTERM[0][0]; for( map = MapTERM; TERM && *map; ++map ) for( term = *map, ++term; *term; ++term ) if( !strcmp(TERM, *term) ) loadcmd = **map; if( loadcmd == XTERM[0] ){ int afildes[2]; char *c = pipeconnect(argc, argv, loadcmd, afildes); if (c) return c; close(afildes[0]); R = new Remote(afildes[1]); } else { if ( system(loadcmd) ) return "terminal download failed"; R = new Remote("/dev/tty"); } set_new_handler(mallocerr); R->pktstart(P_VERSION); R->sendlong(PADS_VERSION); R->pktend(); R->pktstart(P_BUSY); R->pktend(); ICache = new ItemCache; CCache = new CarteCache; close(2); return 0; } char *PadsTermInit(int argc, char **argv, char *machine) { int afildes[2]; char *c = pipeconnect(argc, argv, XTERM[0], afildes); if (c) return c; close(0); dup(afildes[1]); close(1); dup(afildes[1]); close(2); dup(afildes[1]); close(afildes[0]); close(afildes[1]); c = strrchr(*argv, '/'); char *base = c ? c + 1 : *argv; char *dir = getenv("JTOOLSBIN"); if (!dir) dir = "/usr/jtools/bin"; char *s = new char[30 + strlen(base) + strlen(dir)]; sprintf(s, "exec %s/%s -R", dir, base); #if i386 execlp("rshl", machine, s, 0); #else execlp("rsh", machine, s, 0); #endif /*i386*/ exit(127); return 0; } void PadsRemInit() { R = new Remote(0); set_new_handler(mallocerr); R->pktstart(P_VERSION); R->sendlong(PADS_VERSION); R->pktend(); R->pktstart(P_BUSY); R->pktend(); ICache = new ItemCache; CCache = new CarteCache; } char *TapTo; void WireTap(PRINTF_ARGS) { PRINTF_PROLOGUE; static int fd = -1; static long t0; struct stat s; long t; if( !TapTo ) return; t = time(0); if( ::stat("/usr/tmp/.logpads", &s) || ctime(&t)[23]!='6' ) goto BailOut; if( t0 ) t -= t0; else t0 = t; char buf[256]; sprintf(buf, "%x:", t); sprintf(buf+strlen(buf), PRINTF_COPY); if( fd < 0 ){ if( ::stat(TapTo, &s) ) creat(TapTo, 0777); fd = open(TapTo, 1); } #define PILOGSIZE 32000 if( fd<0 || fstat(fd, &s) || s.st_size > PILOGSIZE ) goto BailOut; lseek(fd, s.st_size, 0); write(fd, buf, strlen(buf)); return; BailOut: TapTo = 0; } int BothValid(PadRcv *p, PadRcv *o) { return p && o; } void TermAction(PadRcv *parent, PadRcv *obj, int pick) { Item *item; Index ix((int)R->rcvlong()); trace( "TermAction(%d,%d,%d)", parent, obj, pick ); if( ix.null() ) return; item = ICache->take(ix); if( !BothValid(parent,obj) || (pick && !obj->accept(item->action)) ) return; if( item->action ) (obj->*item->action)(item->opand, 0, 0); } char *DoKbd(PadRcv *obj, char *buf) { // WireTap("%x->%x(%x) %s\n", obj, &obj->kbd, strlen(buf), buf); char *e = obj->kbd(buf); if( e ) PadsWarn("%s", e); return e; } void Shell() { char cmd[256]; R->rcvstring(cmd); FILE *fp = Popen(cmd, "w"); for( long lines = R->rcvlong(); lines>0; --lines ){ char data[256]; if( fp ) fprintf(fp, "%s\n", R->rcvstring(data)); } if( !fp ){ PadsWarn("cannot write to pipe"); return; } int x = Pclose(fp); if( x ) PadsWarn( "exit(%d): %s", x, cmd ); } void ShKbd(PadRcv *obj, char *cmd) { trace( "ShKbd(%d,%s)", obj, buf ); FILE *fp = Popen(cmd, "r"); if( !fp ){ PadsWarn("cannot read from pipe"); return; } char buf[256]; while( fgets(buf, sizeof buf, fp) ){ buf[strlen(buf)-1] = 0; if( DoKbd(obj, buf) ) break; } int x = Pclose(fp); if( x ) PadsWarn( "exit(%d): %s", x, cmd ); } void Kbd(PadRcv *parent, PadRcv *obj) { char buf[256]; R->rcvstring(buf); trace( "Kbd %d %s", obj, buf ); if( !BothValid(parent,obj) ) return; if( !strcmp( buf, "?" ) ){ obj->showhelp(HELP_KEY); } else if( buf[0] == '<' ){ ShKbd(obj, buf+1); } else DoKbd(obj, buf); } void TermServe() { Protocol p; long n, to, pick = 0; trace("TermServe()"); R->pktstart(P_IDLE); R->pktflush(); p = (Protocol) R->get(); if( p == P_PICK ) { pick = 1; p = (Protocol) R->get(); } PadRcv *par = R->rcvobj(); PadRcv *obj = R->rcvobj(); if( p != P_CYCLE ) { R->pktstart(P_BUSY); R->pktflush(); } switch( (int) p ){ case P_ACTION: TermAction(par, obj, (int)pick); break; case P_KBDSTR: Kbd(par, obj); break; case P_SHELL: Shell(); break; case P_NUMERIC: case P_CYCLE: case P_USERCLOSE: case P_USERCUT: n = R->rcvlong(); if( !BothValid(par,obj) ) return; switch( (int) p ){ case P_NUMERIC: // WireTap("%x->%x(%x)\n", obj, &obj->numeric, n); obj->numeric(n); break; case P_CYCLE: obj->cycle(); break; case P_USERCLOSE: // WireTap("%x->%x(0)\n", obj, &obj->userclose); obj->userclose(); break; case P_USERCUT : // WireTap("%x->%x(0)\n", obj, &obj->usercut); obj->usercut(); break; default: R->err(); } break; case P_LINEREQ: n = R->rcvlong(); to = R->rcvlong(); trace("P_LINEREQ %d %d %d", p, n, to); if( !BothValid(par,obj) ) return; // WireTap("%x->%x(%x)", obj, &obj->linereq, to-n+1); while( n <= to ) obj->linereq((long) n++, 0); break; default: R->err(); } } void PadsServe(long n) { if( n ){ while( n-->0 ) TermServe(); } else { for( ;; ) TermServe(); } } void PadsWarn(PRINTF_ARGS) { PRINTF_PROLOGUE; char t[256]; sprintf( t, PRINTF_COPY ); R->pktstart( P_HELPSTR ); R->sendstring( t ); R->pktend(); } void PadsError(PRINTF_ARGS) { PRINTF_PROLOGUE; char t[256]; sprintf(t, PRINTF_COPY); R->pktstart( P_ERROR ); R->sendstring( t ); R->pktflush(); exit(1); } void PadsQuit() { R->pktstart( P_QUIT ); R->pktflush(); exit(0); }