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