#include #include #include #include #include "dat.h" typedef struct Wpid Wpid; struct Wpid { int pid; Window *w; Wpid *next; }; void pipectl(void*); int pipefd; Wpid *wpid; int snarffd; void newpipewin(int pid, char *p) { Window *w; Wpid *wp; w = newwindow(); winname(w, p); wintagwrite(w, "Send ", 5); threadcreate(pipectl, w, STACK); wp = emalloc(sizeof(Wpid)); wp->pid = pid; wp->w = w; wp->next = wpid; wpid = wp; } void datapipewin(int pid, char *p, int n) { Wpid *wp; for(wp=wpid; wp!=nil; wp=wp->next){ if(wp->pid == pid){ write(wp->w->data, p, n); return; } } fprint(2, "win: can't find window %d for data message\n", pid); } void eofpipewin(int pid) { Wpid *wp, *prev; prev = nil; for(wp=wpid; wp!=nil; wp=wp->next){ if(wp->pid == pid){ winclean(wp->w); windormant(wp->w); if(prev) prev->next = wp->next; else wpid->next = wp->next; free(wp); return; } prev = wp; } fprint(2, "win: can't find window %d for eof message\n", pid); } int pipecommand(Window *w, char *s) { ulong q0, q1; char tmp[32], *t; int n, k; while(*s==' ' || *s=='\t' || *s=='\n') s++; if(strcmp(s, "Delete")==0){ windel(w, 1); threadexits(nil); return 1; } if(strcmp(s, "Del")==0){ if(windel(w, 0)) threadexits(nil); return 1; } if(strcmp(s, "Send") == 0){ if(w->addr < 0) w->addr = winopenfile(w, "addr"); ctlprint(w->ctl, "addr=dot\n"); seek(w->addr, 0UL, 0); if(read(w->addr, tmp, 2*12) == 2*12){ q0 = atol(tmp+0*12); q1 = atol(tmp+1*12); if(q0 == q1){ t = nil; k = 0; if(snarffd > 0){ seek(0, snarffd, 0); for(;;){ t = realloc(t, k+8192+1); if(t == nil) error("win: alloc failed: %r\n"); n = read(snarffd, t+k, 8192); if(n <= 0) break; k += n; } t[k] = 0; } }else{ t = emalloc((q1-q0)*UTFmax+1); winread(w, q0, q1, t); } if(t!=nil && t[0]!='\0') sendit(t); free(t); } return 1; } return 0; } void pipectl(void *v) { Window *w; Event *e; w = v; proccreate(wineventproc, w, STACK); winsetaddr(w, "0", 0); for(;;){ e = recvp(w->cevent); switch(e->c1){ default: Unknown: threadprint(2, "unknown message %c%c\n", e->c1, e->c2); break; case 'E': /* write to body; can't affect us */ break; case 'F': /* generated by our actions; ignore */ break; case 'K': /* ignore */ break; case 'M': switch(e->c2){ case 'x': case 'X': execevent(w, e, pipecommand); break; case 'l': /* reflect all searches back to acme */ case 'L': if(e->flag & 2) recvp(w->cevent); winwriteevent(w, e); break; case 'I': /* modify away; we don't care */ case 'i': case 'D': case 'd': break; default: goto Unknown; } } } } void pipeproc(void *v) { int n; char *buf; Channel *ch; ch = v; for(;;){ buf = emalloc(NPIPE+1); n = read(pipefd, buf, NPIPE); if(n < 0){ sendp(ch, nil); break; } if(n == 0) continue; buf[n] = '\0'; sendp(ch, buf); } } void pipetask(void *v) { char *buf, *datap; int pid, c; Channel *ch; ch = v; while((buf = recvp(ch)) != nil){ datap = strchr(buf, '\n'); if(datap == nil) break; datap++; pid = atoi((char*)buf+1); c = ((uchar*)buf)[0]; switch(c){ default: fprint(2, "win: unrecognized pipe command '%c'=0x%.2x\n", c, c); case 'n': newpipewin(pid, datap); break; case 'd': datapipewin(pid, datap, (buf+strlen(buf))-datap); break; case 'e': eofpipewin(pid); break; } free(buf); } } void startpipe(void) { int fd, p[2]; char *user, buf[128]; Channel *c; snarffd = open("/dev/snarf", OREAD|OCEXEC); if(pipe(p) < 0) error("can't create pipe: %r"); /* 0 will be server end, 1 will be client end */ pipefd = p[0]; user = getenv("user"); if(user == nil) user = "none"; sprint(buf, "/srv/win.%s.%d", user, getpid()); fd = create(buf, OWRITE|OCEXEC|ORCLOSE, 0600); if(fd < 0) error("can't create /srv file: %r"); if(putenv("winsrv", buf) < 0) error("can't write $winsrv: %r"); if(threadprint(fd, "%d", p[1]) <= 0) error("can't write /srv/file: %r"); /* leave fd open; ORCLOSE will take care of it */ c = chancreate(sizeof(char*), 0); proccreate(pipeproc, c, STACK); threadcreate(pipetask, c, STACK); close(p[1]); }