#line 43 "telnet.c-nw" static char copyright[] = "Copyright NBBI, Den Haag, 1995"; #include #include #include #include #include #include #include #include #include #include #include #include #include #define UseScrolledWindow typedef struct { Widget ansiterm; Strip host; pid_t child; int fd; /* Child's input & output */ } *Info; typedef struct _Assoc { long id; Info b; struct _Assoc *next; } *Assoc; static Assoc assoclist = NULL; /* store -- store an ID/Buffer combination */ static void store(Info b, long id) { Assoc h; new(h); h->id = id; h->b = b; h->next = assoclist; assoclist = h; } /* delete -- delete an ID/Buffer combination */ static void delete(long id) { Assoc g, h; assert(assoclist); if (assoclist->id == id) { h = assoclist; assoclist = assoclist->next; dispose(h); } else { assert(h->next); for (h = assoclist; h->next->id != id; h = h->next) assert(h->next); g = h->next; h->next = g->next; dispose(g); } } /* find -- find the Buffer associated with an ID */ static Info find(long id) { Assoc h; assert(assoclist); for (h = assoclist; h->id != id; h = h->next) assert(h->next); return h->b; } static void syserr(char *s) { perror(s); exit(1); } #line 118 "telnet.c-nw" #define SUFFIX1 "pqrstuvwxyzabcdefghijklmno" /* Tried in order (major) */ #define SUFFIX2 "0123456789abcdef" /* Tried in order (minor) */ #define DEVPTY1 "/dev/pty??" /* Name template of pty's */ #define DEVPTY2 "/dev/tty??" /* Template of slave pty's */ static Bool openpty(master_return, slave_return) int *master_return, *slave_return; { static char suffix1[] = SUFFIX1, suffix2[] = SUFFIX2; static char mastername[] = DEVPTY1, slavename[] = DEVPTY2; char *p, *q; for (p = suffix1; *p; p++) { mastername[sizeof(DEVPTY1)-3] = *p; slavename[sizeof(DEVPTY2)-3] = *p; for (q = suffix2; *q; q++) { mastername[sizeof(DEVPTY1)-2] = *q; slavename[sizeof(DEVPTY2)-2] = *q; if ((*master_return = open(mastername, O_RDWR)) == -1) continue; if ((*slave_return = open(slavename, O_RDWR)) != -1) return TRUE; close(*master_return); } } return FALSE; } #line 153 "telnet.c-nw" static void out_cb(XtPointer client_data, int *fid, XtInputId *id) { Widget term = (Widget) client_data; char buf[BUFSIZ]; int nbytes; if ((nbytes = read(*fid, buf, sizeof(buf))) == -1) XtAppWarning(XtWidgetToApplicationContext(term), "Read error"); else XfwfAnsiWrite(term, buf, nbytes); } #line 171 "telnet.c-nw" static void key_cb(Widget w, XtPointer client_data, XtPointer call_data) { int fd = (int) client_data; char *data = (char *) call_data; if (write(fd, data, 1) == -1) { debug("errno = %d (%s)\n", errno, strerror(errno)); XtAppWarning(XtWidgetToApplicationContext(w), "Couldn't send key"); } } /* resize_cb -- callback for when the AnsiTerm changes size */ static void resize_cb(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { /* XfwfResizeInfo *size = (XfwfResizeInfo *) call_data; */ pid_t *child = (pid_t *) client_data; kill(*child, SIGWINCH); } /* initTelnet -- initialize class variables for the Telnet viewer */ EXPORT Bool initTelnet(char ***mime_types, int *nrtypes, float **qual) { static char *types[] = {"application/x-telnet"}; static float pref[] = {1.0}; *mime_types = types; *nrtypes = 1; *qual = pref; return TRUE; /* Nothing to initialize */ } /* openTelnet -- open a viewer for a Telnet connection, return an ID */ EXPORT Bool openTelnet(const W3ADocumentInfo doc, W3AWindow area, long id) { int master, slave; long c, tblsiz; Widget scrwin; pid_t child; Info info; URI uri; if (! URL_parse(doc.url, &uri)) {errno = EURL; return -1;} if (! openpty(&master, &slave)) return FALSE; switch ((child = fork())) { case -1: return FALSE; /* NOTREACHED */ case 0: #if 0 setsid(); /* Dissociate from terminal */ #endif if (close(0) == -1) syserr("close"); if (dup(slave) != 0) syserr("dup failed\n"); if (close(1) == -1) syserr("close"); if (dup(slave) != 1) syserr("dup failed\n"); if (close(2) == -1) syserr("close"); if (dup(slave) != 2) syserr("dup failed\n"); /* Close all other files */ tblsiz = sysconf(_SC_OPEN_MAX); for (c = 3; c < tblsiz; c++) (void) close(c); putenv("TERM=ansi"); execlp("telnet", "telnet", strip2str(uri.host), uri.port ? strip2str(uri.port) : NULL, NULL); syserr("execl failed"); /* NOTREACHED */ } if (close(slave) == -1) return FALSE; new(info); store(info, id); info->child = child; info->fd = master; info->host = uri.host; #ifdef UseScrolledWindow scrwin = XtVaCreateManagedWidget ("telnet-board", xmScrolledWindowWidgetClass, area, XmNscrollingPolicy, XmAUTOMATIC, NULL); info->ansiterm = XtVaCreateManagedWidget ("telnet", xmAnsiTermWidgetClass, scrwin, NULL); XtVaSetValues(scrwin, XmNinitialFocus, info->ansiterm, NULL); #else info->ansiterm = XtVaCreateManagedWidget ("telnet", xmAnsiTermWidgetClass, area, NULL); #endif /* Install input handler to read pfdout[0] pipe */ XtAppAddInput(XtWidgetToApplicationContext(info->ansiterm), master, (XtPointer) XtInputReadMask, out_cb, info->ansiterm); /* Install callback to pass key presses on to pfdin[1] */ XtAddCallback(info->ansiterm, XtNkeyCallback, key_cb, (XtPointer) master); /* Install callback to notify child of size change */ XtAddCallback(info->ansiterm, XtNresizeCallback, resize_cb, &info->child); (void) XmProcessTraversal(info->ansiterm, XmTRAVERSE_CURRENT); return TRUE; } /* writeTelnet -- do nothing (Telnet viewer gets input from elsewhere) */ EXPORT int writeTelnet(long id, const char *buf, size_t nbytes) { return nbytes; } /* closeTelnet -- close Telnet viewer, close connection */ EXPORT Bool closeTelnet(long id) { Info info = find(id); (void) close(info->fd); #ifdef UseScrolledWindow XtDestroyWidget(XtParent(info->ansiterm)); #else XtDestroyWidget(info->ansiterm); #endif kill(info->child, SIGKILL); dispose(info); return TRUE; } /* infoTelnet -- suggest a title if no title has been set */ EXPORT Bool infoTelnet(long id, W3ADocumentInfo *doc) { Info info = find(id); char s[256]; if (doc->title == NULL || doc->title[0] == '\0') { sprintf(s, "Telnet %s", strip2str(info->host)); dispose(doc->title); doc->title = newstring(s); } return TRUE; } /* eventTelnet -- do nothing in response to W3A events */ EXPORT void eventTelnet(long id, long source_id, long type, void *params) { /* Doesn't handle W3A events */ }