1 #include <u.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <errno.h>
5
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"
23
24 static char *exname;
25
26 #define STACK 16384
27
28 void
usage(void)29 usage(void)
30 {
31 fprint(2, "usage: samterm -a -W winsize\n");
32 threadexitsall("usage");
33 }
34
35 void
getscreen(int argc,char ** argv)36 getscreen(int argc, char **argv)
37 {
38 char *t;
39
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
50
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 }
62
63 int
screensize(int * w,int * h)64 screensize(int *w, int *h)
65 {
66 int fd, n;
67 char buf[5*12+1];
68
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 }
89
90 int
snarfswap(char * fromsam,int nc,char ** tosam)91 snarfswap(char *fromsam, int nc, char **tosam)
92 {
93 char *s;
94
95 s = getsnarf();
96 putsnarf(fromsam);
97 *tosam = s;
98 return s ? strlen(s) : 0;
99 }
100
101 void
dumperrmsg(int count,int type,int count0,int c)102 dumperrmsg(int count, int type, int count0, int c)
103 {
104 fprint(2, "samterm: host mesg: count %d %ux %ux %ux %s...ignored\n",
105 count, type, count0, c, rcvstring());
106 }
107
108 void
removeextern(void)109 removeextern(void)
110 {
111 remove(exname);
112 }
113
114 Readbuf hostbuf[2];
115 Readbuf plumbbuf[2];
116
117 void
extproc(void * argv)118 extproc(void *argv)
119 {
120 Channel *c;
121 int i, n, which, fd;
122 void **arg;
123
124 arg = argv;
125 c = arg[0];
126 fd = (int)(uintptr)arg[1];
127
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 */
136 }
137 plumbbuf[i].n = n;
138 which = i;
139 send(c, &which);
140 }
141 }
142
143 void
extstart(void)144 extstart(void)
145 {
146 char *user, *disp;
147 int fd, flags;
148 static void *arg[2];
149
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);
157 }
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;
164 }
165
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;
174 }
175 }
176
177 fd = open(exname, OREAD|ONONBLOCK);
178 if(fd == -1){
179 removeextern();
180 return;
181 }
182
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;
193 }
194
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);
201 }
202
203 int
plumbformat(Plumbmsg * m,int i)204 plumbformat(Plumbmsg *m, int i)
205 {
206 char *addr, *data, *act;
207 int n;
208
209 data = (char*)plumbbuf[i].data;
210 n = m->ndata;
211 if(n == 0 || 2+n+2 >= READBUFSIZE){
212 plumbfree(m);
213 return 0;
214 }
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;
220 }
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 */
227 }
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);
237 }
238 plumbbuf[i].n = n;
239 plumbfree(m);
240 return 1;
241 }
242
243 void
plumbproc(void * arg)244 plumbproc(void *arg)
245 {
246 CFid *fid;
247 int i;
248 Plumbmsg *m;
249
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 */
257 }
258 if(plumbformat(m, i)){
259 send(plumbc, &i);
260 i = 1-i; /* toggle */
261 }
262 }
263 }
264
265 int
plumbstart(void)266 plumbstart(void)
267 {
268 CFid *fid;
269
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;
279 }
280 threadcreate(plumbproc, fid, STACK);
281 return 1;
282 }
283
284 void
hostproc(void * arg)285 hostproc(void *arg)
286 {
287 Channel *c;
288 int i, n, which;
289
290 c = arg;
291
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");
302 }
303 fprint(2, "samterm: host read error: %r\n");
304 threadexitsall("host");
305 }
306 hostbuf[i].n = n;
307 which = i;
308 if(0) fprint(2, "hostproc send %d\n", which);
309 send(c, &which);
310 }
311 }
312
313 void
hoststart(void)314 hoststart(void)
315 {
316 hostc = chancreate(sizeof(int), 0);
317 chansetname(hostc, "hostc");
318 proccreate(hostproc, hostc, STACK);
319 }
320