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 draw(screen, screen->clipr, display->white, nil, ZP);
59 }
61 int
62 screensize(int *w, int *h)
63 {
64 int fd, n;
65 char buf[5*12+1];
67 fd = open("/dev/screen", OREAD);
68 if(fd < 0)
69 return 0;
70 n = read(fd, buf, sizeof(buf)-1);
71 close(fd);
72 if (n != sizeof(buf)-1)
73 return 0;
74 buf[n] = 0;
75 if (h) {
76 *h = atoi(buf+4*12)-atoi(buf+2*12);
77 if (*h < 0)
78 return 0;
79 }
80 if (w) {
81 *w = atoi(buf+3*12)-atoi(buf+1*12);
82 if (*w < 0)
83 return 0;
84 }
85 return 1;
86 }
88 int
89 snarfswap(char *fromsam, int nc, char **tosam)
90 {
91 char *s;
93 s = getsnarf();
94 putsnarf(fromsam);
95 *tosam = s;
96 return s ? strlen(s) : 0;
97 }
99 void
100 dumperrmsg(int count, int type, int count0, int c)
102 fprint(2, "samterm: host mesg: count %d %ux %ux %ux %s...ignored\n",
103 count, type, count0, c, rcvstring());
106 void
107 removeextern(void)
109 remove(exname);
112 Readbuf hostbuf[2];
113 Readbuf plumbbuf[2];
115 void
116 extproc(void *argv)
118 Channel *c;
119 int i, n, which, fd;
120 void **arg;
122 arg = argv;
123 c = arg[0];
124 fd = (int)(uintptr)arg[1];
126 i = 0;
127 for(;;){
128 i = 1-i; /* toggle */
129 n = read(fd, plumbbuf[i].data, sizeof plumbbuf[i].data);
130 if(0) fprint(2, "ext %d\n", n);
131 if(n <= 0){
132 fprint(2, "samterm: extern read error: %r\n");
133 threadexits("extern"); /* not a fatal error */
135 plumbbuf[i].n = n;
136 which = i;
137 send(c, &which);
141 void
142 extstart(void)
144 char *user, *disp;
145 int fd, flags;
146 static void *arg[2];
148 user = getenv("USER");
149 if(user == nil)
150 return;
151 disp = getenv("DISPLAY");
152 if(disp)
153 exname = smprint("/tmp/.sam.%s.%s", user, disp);
154 else
155 exname = smprint("/tmp/.sam.%s", user);
156 if(exname == nil){
157 fprint(2, "not posting for B: out of memory\n");
158 return;
161 if(mkfifo(exname, 0600) < 0){
162 struct stat st;
163 if(errno != EEXIST || stat(exname, &st) < 0)
164 return;
165 if(!S_ISFIFO(st.st_mode)){
166 removeextern();
167 if(mkfifo(exname, 0600) < 0)
168 return;
172 fd = open(exname, OREAD|ONONBLOCK);
173 if(fd == -1){
174 removeextern();
175 return;
178 /*
179 * Turn off no-delay and provide ourselves as a lingering
180 * writer so as not to get end of file on read.
181 */
182 flags = fcntl(fd, F_GETFL, 0);
183 if(flags<0 || fcntl(fd, F_SETFL, flags&~O_NONBLOCK)<0
184 ||open(exname, OWRITE) < 0){
185 close(fd);
186 removeextern();
187 return;
190 plumbc = chancreate(sizeof(int), 0);
191 chansetname(plumbc, "plumbc");
192 arg[0] = plumbc;
193 arg[1] = (void*)(uintptr)fd;
194 proccreate(extproc, arg, STACK);
195 atexit(removeextern);
198 int
199 plumbformat(Plumbmsg *m, int i)
201 char *addr, *data, *act;
202 int n;
204 data = (char*)plumbbuf[i].data;
205 n = m->ndata;
206 if(n == 0 || 2+n+2 >= READBUFSIZE){
207 plumbfree(m);
208 return 0;
210 act = plumblookup(m->attr, "action");
211 if(act!=nil && strcmp(act, "showfile")!=0){
212 /* can't handle other cases yet */
213 plumbfree(m);
214 return 0;
216 addr = plumblookup(m->attr, "addr");
217 if(addr){
218 if(addr[0] == '\0')
219 addr = nil;
220 else
221 addr = strdup(addr); /* copy to safe storage; we'll overwrite data */
223 memmove(data, "B ", 2); /* we know there's enough room for this */
224 memmove(data+2, m->data, n);
225 n += 2;
226 if(data[n-1] != '\n')
227 data[n++] = '\n';
228 if(addr != nil){
229 if(n+strlen(addr)+1+1 <= READBUFSIZE)
230 n += sprint(data+n, "%s\n", addr);
231 free(addr);
233 plumbbuf[i].n = n;
234 plumbfree(m);
235 return 1;
238 void
239 plumbproc(void *arg)
241 CFid *fid;
242 int i;
243 Plumbmsg *m;
245 fid = arg;
246 i = 0;
247 for(;;){
248 m = plumbrecvfid(fid);
249 if(m == nil){
250 fprint(2, "samterm: plumb read error: %r\n");
251 threadexits("plumb"); /* not a fatal error */
253 if(plumbformat(m, i)){
254 send(plumbc, &i);
255 i = 1-i; /* toggle */
260 int
261 plumbstart(void)
263 CFid *fid;
265 plumbfd = plumbopen("send", OWRITE|OCEXEC); /* not open is ok */
266 fid = plumbopenfid("edit", OREAD|OCEXEC);
267 if(fid == nil)
268 return -1;
269 plumbc = chancreate(sizeof(int), 0);
270 chansetname(plumbc, "plumbc");
271 if(plumbc == nil){
272 fsclose(fid);
273 return -1;
275 threadcreate(plumbproc, fid, STACK);
276 return 1;
279 void
280 hostproc(void *arg)
282 Channel *c;
283 int i, n, which;
285 c = arg;
287 i = 0;
288 for(;;){
289 i = 1-i; /* toggle */
290 n = read(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data);
291 if(0) fprint(2, "hostproc %d\n", n);
292 if(n <= 0){
293 if(n == 0){
294 if(exiting)
295 threadexits(nil);
296 werrstr("unexpected eof");
298 fprint(2, "samterm: host read error: %r\n");
299 threadexitsall("host");
301 hostbuf[i].n = n;
302 which = i;
303 if(0) fprint(2, "hostproc send %d\n", which);
304 send(c, &which);
308 void
309 hoststart(void)
311 hostc = chancreate(sizeof(int), 0);
312 chansetname(hostc, "hostc");
313 proccreate(hostproc, hostc, STACK);