| #include <u.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <errno.h> |
| |
| #include <u.h> |
| #include <libc.h> |
| #include <draw.h> |
| #include <thread.h> |
| #include <mouse.h> |
| #include <cursor.h> |
| #include <keyboard.h> |
| #include <frame.h> |
| #define Tversion Tversion9p |
| #define Twrite Twrite9p |
| #include <fcall.h> |
| #undef Tversion |
| #undef Twrite |
| #include <9pclient.h> |
| #include <plumb.h> |
| #include "flayer.h" |
| #include "samterm.h" |
| |
| static char *exname; |
| |
| #define STACK 16384 |
| |
| void |
| usage(void) |
| { |
| fprint(2, "usage: samterm -a -W winsize\n"); |
| threadexitsall("usage"); |
| } |
| |
| void |
| getscreen(int argc, char **argv) |
| { |
| char *t; |
| |
| ARGBEGIN{ |
| case 'a': |
| autoindent = 1; |
| break; |
| case 'W': |
| winsize = EARGF(usage()); |
| break; |
| default: |
| usage(); |
| }ARGEND |
| |
| if(initdraw(panic1, nil, "sam") < 0){ |
| fprint(2, "samterm: initdraw: %r\n"); |
| threadexitsall("init"); |
| } |
| t = getenv("tabstop"); |
| if(t != nil) |
| maxtab = strtoul(t, nil, 0); |
| draw(screen, screen->clipr, 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)(uintptr)arg[1]; |
| |
| i = 0; |
| for(;;){ |
| i = 1-i; /* toggle */ |
| n = read(fd, plumbbuf[i].data, sizeof plumbbuf[i].data); |
| if(0) fprint(2, "ext %d\n", n); |
| 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|ONONBLOCK); |
| 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); |
| chansetname(plumbc, "plumbc"); |
| arg[0] = plumbc; |
| arg[1] = (void*)(uintptr)fd; |
| proccreate(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) |
| { |
| CFid *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) |
| { |
| CFid *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); |
| chansetname(plumbc, "plumbc"); |
| 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; |
| for(;;){ |
| i = 1-i; /* toggle */ |
| n = read(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data); |
| if(0) fprint(2, "hostproc %d\n", n); |
| if(n <= 0){ |
| if(n == 0){ |
| if(exiting) |
| threadexits(nil); |
| werrstr("unexpected eof"); |
| } |
| fprint(2, "samterm: host read error: %r\n"); |
| threadexitsall("host"); |
| } |
| hostbuf[i].n = n; |
| which = i; |
| if(0) fprint(2, "hostproc send %d\n", which); |
| send(c, &which); |
| } |
| } |
| |
| void |
| hoststart(void) |
| { |
| hostc = chancreate(sizeof(int), 0); |
| chansetname(hostc, "hostc"); |
| proccreate(hostproc, hostc, STACK); |
| } |