Blob


1 #include <u.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <errno.h>
6 #include <u.h>
7 #include <libc.h>
8 #include <draw.h>
9 #include <thread.h>
10 #include <mouse.h>
11 #include <cursor.h>
12 #include <keyboard.h>
13 #include <frame.h>
14 #define Tversion Tversion9p
15 #define Twrite Twrite9p
16 #include <fcall.h>
17 #undef Tversion
18 #undef Twrite
19 #include <9pclient.h>
20 #include <plumb.h>
21 #include "flayer.h"
22 #include "samterm.h"
24 static char *exname;
26 #define STACK 16384
28 void
29 usage(void)
30 {
31 fprint(2, "usage: samterm -a -W winsize\n");
32 threadexitsall("usage");
33 }
35 void
36 getscreen(int argc, char **argv)
37 {
38 char *t;
40 ARGBEGIN{
41 case 'a':
42 autoindent = 1;
43 break;
44 case 'W':
45 winsize = EARGF(usage());
46 break;
47 default:
48 usage();
49 }ARGEND
51 if(initdraw(panic1, nil, "sam") < 0){
52 fprint(2, "samterm: initdraw: %r\n");
53 threadexitsall("init");
54 }
55 t = getenv("tabstop");
56 if(t != nil){
57 maxtab = strtoul(t, nil, 0);
58 free(t);
59 }
60 draw(screen, screen->clipr, display->white, nil, ZP);
61 }
63 int
64 screensize(int *w, int *h)
65 {
66 int fd, n;
67 char buf[5*12+1];
69 fd = open("/dev/screen", OREAD);
70 if(fd < 0)
71 return 0;
72 n = read(fd, buf, sizeof(buf)-1);
73 close(fd);
74 if (n != sizeof(buf)-1)
75 return 0;
76 buf[n] = 0;
77 if (h) {
78 *h = atoi(buf+4*12)-atoi(buf+2*12);
79 if (*h < 0)
80 return 0;
81 }
82 if (w) {
83 *w = atoi(buf+3*12)-atoi(buf+1*12);
84 if (*w < 0)
85 return 0;
86 }
87 return 1;
88 }
90 int
91 snarfswap(char *fromsam, int nc, char **tosam)
92 {
93 char *s;
95 s = getsnarf();
96 putsnarf(fromsam);
97 *tosam = s;
98 return s ? strlen(s) : 0;
99 }
101 void
102 dumperrmsg(int count, int type, int count0, int c)
104 fprint(2, "samterm: host mesg: count %d %ux %ux %ux %s...ignored\n",
105 count, type, count0, c, rcvstring());
108 void
109 removeextern(void)
111 remove(exname);
114 Readbuf hostbuf[2];
115 Readbuf plumbbuf[2];
117 void
118 extproc(void *argv)
120 Channel *c;
121 int i, n, which, fd;
122 void **arg;
124 arg = argv;
125 c = arg[0];
126 fd = (int)(uintptr)arg[1];
128 i = 0;
129 for(;;){
130 i = 1-i; /* toggle */
131 n = read(fd, plumbbuf[i].data, sizeof plumbbuf[i].data);
132 if(0) fprint(2, "ext %d\n", n);
133 if(n <= 0){
134 fprint(2, "samterm: extern read error: %r\n");
135 threadexits("extern"); /* not a fatal error */
137 plumbbuf[i].n = n;
138 which = i;
139 send(c, &which);
143 void
144 extstart(void)
146 char *user, *disp;
147 int fd, flags;
148 static void *arg[2];
150 user = getenv("USER");
151 if(user == nil)
152 return;
153 disp = getenv("DISPLAY");
154 if(disp){
155 exname = smprint("/tmp/.sam.%s.%s", user, disp);
156 free(disp);
158 else
159 exname = smprint("/tmp/.sam.%s", user);
160 free(user);
161 if(exname == nil){
162 fprint(2, "not posting for B: out of memory\n");
163 return;
166 if(mkfifo(exname, 0600) < 0){
167 struct stat st;
168 if(errno != EEXIST || stat(exname, &st) < 0)
169 return;
170 if(!S_ISFIFO(st.st_mode)){
171 removeextern();
172 if(mkfifo(exname, 0600) < 0)
173 return;
177 fd = open(exname, OREAD|ONONBLOCK);
178 if(fd == -1){
179 removeextern();
180 return;
183 /*
184 * Turn off no-delay and provide ourselves as a lingering
185 * writer so as not to get end of file on read.
186 */
187 flags = fcntl(fd, F_GETFL, 0);
188 if(flags<0 || fcntl(fd, F_SETFL, flags&~O_NONBLOCK)<0
189 ||open(exname, OWRITE) < 0){
190 close(fd);
191 removeextern();
192 return;
195 plumbc = chancreate(sizeof(int), 0);
196 chansetname(plumbc, "plumbc");
197 arg[0] = plumbc;
198 arg[1] = (void*)(uintptr)fd;
199 proccreate(extproc, arg, STACK);
200 atexit(removeextern);
203 int
204 plumbformat(Plumbmsg *m, int i)
206 char *addr, *data, *act;
207 int n;
209 data = (char*)plumbbuf[i].data;
210 n = m->ndata;
211 if(n == 0 || 2+n+2 >= READBUFSIZE){
212 plumbfree(m);
213 return 0;
215 act = plumblookup(m->attr, "action");
216 if(act!=nil && strcmp(act, "showfile")!=0){
217 /* can't handle other cases yet */
218 plumbfree(m);
219 return 0;
221 addr = plumblookup(m->attr, "addr");
222 if(addr){
223 if(addr[0] == '\0')
224 addr = nil;
225 else
226 addr = strdup(addr); /* copy to safe storage; we'll overwrite data */
228 memmove(data, "B ", 2); /* we know there's enough room for this */
229 memmove(data+2, m->data, n);
230 n += 2;
231 if(data[n-1] != '\n')
232 data[n++] = '\n';
233 if(addr != nil){
234 if(n+strlen(addr)+1+1 <= READBUFSIZE)
235 n += sprint(data+n, "%s\n", addr);
236 free(addr);
238 plumbbuf[i].n = n;
239 plumbfree(m);
240 return 1;
243 void
244 plumbproc(void *arg)
246 CFid *fid;
247 int i;
248 Plumbmsg *m;
250 fid = arg;
251 i = 0;
252 for(;;){
253 m = plumbrecvfid(fid);
254 if(m == nil){
255 fprint(2, "samterm: plumb read error: %r\n");
256 threadexits("plumb"); /* not a fatal error */
258 if(plumbformat(m, i)){
259 send(plumbc, &i);
260 i = 1-i; /* toggle */
265 int
266 plumbstart(void)
268 CFid *fid;
270 plumbfd = plumbopen("send", OWRITE|OCEXEC); /* not open is ok */
271 fid = plumbopenfid("edit", OREAD|OCEXEC);
272 if(fid == nil)
273 return -1;
274 plumbc = chancreate(sizeof(int), 0);
275 chansetname(plumbc, "plumbc");
276 if(plumbc == nil){
277 fsclose(fid);
278 return -1;
280 threadcreate(plumbproc, fid, STACK);
281 return 1;
284 void
285 hostproc(void *arg)
287 Channel *c;
288 int i, n, which;
290 c = arg;
292 i = 0;
293 for(;;){
294 i = 1-i; /* toggle */
295 n = read(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data);
296 if(0) fprint(2, "hostproc %d\n", n);
297 if(n <= 0){
298 if(n == 0){
299 if(exiting)
300 threadexits(nil);
301 werrstr("unexpected eof");
303 fprint(2, "samterm: host read error: %r\n");
304 threadexitsall("host");
306 hostbuf[i].n = n;
307 which = i;
308 if(0) fprint(2, "hostproc send %d\n", which);
309 send(c, &which);
313 void
314 hoststart(void)
316 hostc = chancreate(sizeof(int), 0);
317 chansetname(hostc, "hostc");
318 proccreate(hostproc, hostc, STACK);