#include #include #include #include #include #include #include #include #include #include #include #include #define Tversion Tversion9p #define Twrite Twrite9p #include #undef Tversion #undef Twrite #include #include #include "flayer.h" #include "samterm.h" static char *exname; #define STACK 16384 void getscreen(int argc, char **argv) { int i; char *t; /* not exactly right */ for(i=0; iclipr, display->white, nil, ZP); } int screensize(int *w, int *h) { int fd, n; char buf[5*12+1]; fd = open("/dev/screen", OREAD); if(fd < 0) return 0; n = read(fd, buf, sizeof(buf)-1); close(fd); if (n != sizeof(buf)-1) return 0; buf[n] = 0; if (h) { *h = atoi(buf+4*12)-atoi(buf+2*12); if (*h < 0) return 0; } if (w) { *w = atoi(buf+3*12)-atoi(buf+1*12); if (*w < 0) return 0; } return 1; } int snarfswap(char *fromsam, int nc, char **tosam) { char *s; s = getsnarf(); putsnarf(fromsam); *tosam = s; return s ? strlen(s) : 0; } void dumperrmsg(int count, int type, int count0, int c) { fprint(2, "samterm: host mesg: count %d %ux %ux %ux %s...ignored\n", count, type, count0, c, rcvstring()); } void removeextern(void) { remove(exname); } Readbuf hostbuf[2]; Readbuf plumbbuf[2]; void extproc(void *argv) { Channel *c; int i, n, which, fd; void **arg; arg = argv; c = arg[0]; fd = (int)arg[1]; threadfdnoblock(fd); i = 0; for(;;){ i = 1-i; /* toggle */ n = threadread(fd, plumbbuf[i].data, sizeof plumbbuf[i].data); if(n <= 0){ fprint(2, "samterm: extern read error: %r\n"); threadexits("extern"); /* not a fatal error */ } plumbbuf[i].n = n; which = i; send(c, &which); } } void extstart(void) { char *user, *disp; int fd, flags; static void *arg[2]; user = getenv("USER"); if(user == nil) return; disp = getenv("DISPLAY"); if(disp) exname = smprint("/tmp/.sam.%s.%s", user, disp); else exname = smprint("/tmp/.sam.%s", user); if(exname == nil){ fprint(2, "not posting for B: out of memory\n"); return; } if(mkfifo(exname, 0600) < 0){ struct stat st; if(errno != EEXIST || stat(exname, &st) < 0) return; if(!S_ISFIFO(st.st_mode)){ removeextern(); if(mkfifo(exname, 0600) < 0) return; } } fd = open(exname, OREAD|O_NONBLOCK); if(fd == -1){ removeextern(); return; } /* * Turn off no-delay and provide ourselves as a lingering * writer so as not to get end of file on read. */ flags = fcntl(fd, F_GETFL, 0); if(flags<0 || fcntl(fd, F_SETFL, flags&~O_NONBLOCK)<0 ||open(exname, OWRITE) < 0){ close(fd); removeextern(); return; } plumbc = chancreate(sizeof(int), 0); arg[0] = plumbc; arg[1] = (void*)fd; threadcreate(extproc, arg, STACK); atexit(removeextern); } int plumbformat(Plumbmsg *m, int i) { char *addr, *data, *act; int n; data = (char*)plumbbuf[i].data; n = m->ndata; if(n == 0 || 2+n+2 >= READBUFSIZE){ plumbfree(m); return 0; } act = plumblookup(m->attr, "action"); if(act!=nil && strcmp(act, "showfile")!=0){ /* can't handle other cases yet */ plumbfree(m); return 0; } addr = plumblookup(m->attr, "addr"); if(addr){ if(addr[0] == '\0') addr = nil; else addr = strdup(addr); /* copy to safe storage; we'll overwrite data */ } memmove(data, "B ", 2); /* we know there's enough room for this */ memmove(data+2, m->data, n); n += 2; if(data[n-1] != '\n') data[n++] = '\n'; if(addr != nil){ if(n+strlen(addr)+1+1 <= READBUFSIZE) n += sprint(data+n, "%s\n", addr); free(addr); } plumbbuf[i].n = n; plumbfree(m); return 1; } void plumbproc(void *arg) { Fid *fid; int i; Plumbmsg *m; fid = arg; i = 0; for(;;){ m = plumbrecvfid(fid); if(m == nil){ fprint(2, "samterm: plumb read error: %r\n"); threadexits("plumb"); /* not a fatal error */ } if(plumbformat(m, i)){ send(plumbc, &i); i = 1-i; /* toggle */ } } } int plumbstart(void) { Fid *fid; plumbfd = plumbopen("send", OWRITE|OCEXEC); /* not open is ok */ fid = plumbopenfid("edit", OREAD|OCEXEC); if(fid == nil) return -1; plumbc = chancreate(sizeof(int), 0); if(plumbc == nil){ fsclose(fid); return -1; } threadcreate(plumbproc, fid, STACK); return 1; } void hostproc(void *arg) { Channel *c; int i, n, which; c = arg; i = 0; threadfdnoblock(hostfd[0]); for(;;){ i = 1-i; /* toggle */ n = threadread(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data); if(n <= 0){ fprint(2, "samterm: host read error: %r\n"); threadexitsall("host"); } hostbuf[i].n = n; which = i; send(c, &which); } } void hoststart(void) { hostc = chancreate(sizeof(int), 0); threadcreate(hostproc, hostc, STACK); }