xref: /inferno-os/appl/svc/httpd/imagemap.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement imagemap;
2
3include "sys.m";
4	sys : Sys;
5
6include "bufio.m";
7	bufio: Bufio;
8	Iobuf: 	import bufio;
9
10include "draw.m";
11	draw: Draw;
12
13include "cache.m";
14include "contents.m";
15
16include "httpd.m";
17	Private_info: import Httpd;
18	OnlySearch, BadSearch, NotFound: import Httpd;
19	g : ref Private_info;
20
21include "parser.m";
22	parser : Parser;
23
24include "daytime.m";
25	daytime: Daytime;
26
27include "string.m";
28	str : String;
29
30imagemap : module
31{
32	init: fn(g : ref Private_info, req: Httpd->Request);
33};
34
35Point : adt {
36	x,y : int;
37};
38
39me : string;
40
41badmod(p: string)
42{
43	sys->fprint(sys->fildes(2), "imagemap: cannot load %s: %r\n", p);
44	raise "fail:bad module";
45}
46
47init(k : ref Private_info, req: Httpd->Request)
48{
49	dest, s : string;
50	sys = load Sys "$Sys";
51	draw = load Draw "$Draw";
52
53	daytime = load Daytime Daytime->PATH;
54	if(daytime == nil) badmod(Daytime->PATH);
55
56	parser = load Parser Parser->PATH;
57	if(parser == nil) badmod(Parser->PATH);
58
59	str = load String String->PATH;
60	if (str == nil) badmod(String->PATH);
61
62	me = "imagemap";
63
64	g=k;
65	bufio=g.bufio;
66	parser->init();
67	parser->httpheaders(g,req.version);
68	dest = translate(req.uri, req.search);
69	if(dest == nil){
70		if(req.version!= ""){
71			parser->okheaders(g);
72			g.bout.puts(sys->sprint("Date: %s\r\n", daytime->time()));
73			g.bout.puts("Content-type: text/html\r\n");
74			g.bout.puts("\r\n");
75		}
76		g.bout.puts("<head><title>Nothing Found</title></head><body>\n");
77		g.bout.puts("Nothing satisfying your search request could be found.\n</body>\n");
78		return;
79	}
80
81	g.bout.puts(sys->sprint("%s 301 Moved Permanently\r\n", g.version));
82	g.bout.puts(sys->sprint("Date: %s\r\n", daytime->time()));
83	g.bout.puts("Server: Charon\r\n");
84	g.bout.puts("MIME-version: 1.0\r\n");
85	g.bout.puts("Content-type: text/html\r\n");
86	(s,nil)=str->splitl(dest, ":");
87	if(s!=nil){
88		g.bout.puts(sys->sprint("URI: <%s>\r\n", parser->urlconv(dest)));
89		g.bout.puts(sys->sprint("Location: %s\r\n", parser->urlconv(dest)));
90	}else if(dest[0] == '/'){
91		g.bout.puts(sys->sprint("URI: <%s>\r\n",parser->urlconv(dest)));
92		g.bout.puts(sys->sprint("Location: http://%s%s\r\n", parser->urlconv(g.mydomain), parser->urlconv(dest)));
93	} else {
94		(req.uri,s) = str->splitr(req.uri, "/");
95		g.bout.puts(sys->sprint("URI: <%s/%s>\r\n", parser->urlconv(req.uri), parser->urlconv(dest)));
96		g.bout.puts(sys->sprint("Location: http://%s%s/%s\r\n", parser->urlconv(g.mydomain), parser->urlconv(req.uri), parser->urlconv(dest)));
97	}
98	g.bout.puts("\r\n");
99	g.bout.puts("<head><title>Object Moved</title></head>\r\n");
100	g.bout.puts("<body><h1>Object Moved</h1></body>\r\n");
101	if(dest[0] == '/')
102		g.bout.puts(sys->sprint("Your selection mapped to <a href=\"%s\"> here</a>.<p>\r\n", parser->urlconv(dest)));
103	else
104		g.bout.puts(sys->sprint("Your selection mapped to <a href=\"%s/%s\"> here</a>.<p>\r\n", parser->urlconv(req.uri), parser->urlconv(dest)));
105}
106
107
108translate(uri, search : string) : string
109{
110	b : ref Iobuf;
111	p, c, q, start : Point;
112	close, d : real;
113	line, To, def, s : string;
114	ok, n, inside, r : int;
115	(pth,nil):=str->splitr(uri,"/");
116	# sys->print("pth is %s",pth);
117	if(search == nil)
118		parser->fail(g,OnlySearch, me);
119	(p, ok) = pt(search);
120	if(!ok)
121		parser->fail(g,BadSearch, me);
122
123	b = bufio->open(uri, bufio->OREAD);
124	if(b == nil){
125		sys->fprint(sys->fildes(2), "imagemap: cannot open %s: %r\n", uri);
126		parser->fail(g, NotFound, uri);
127	}
128	To = "";
129	def = "";
130	close = 0.;
131	while((line = b.gets('\n'))!=nil){
132		line=line[0:len line-1];
133
134		(s, line) = getfield(line);
135		if(s== "rect"){
136			(s, line) = getfield(line);
137			(q, ok) = pt(s);
138			if(!ok || q.x > p.x || q.y > p.y)
139				continue;
140			(s, line) = getfield(line);
141			(q, ok) = pt(s);
142			if(!ok || q.x < p.x || q.y < p.y)
143				continue;
144			(s, nil) = getfield(line);
145			return pth+s;
146		}else if(s== "circle"){
147			(s, line) = getfield(line);
148			(c, ok) = pt(s);
149			if(!ok)
150				continue;
151			(s, line) = getfield(line);
152			(r,nil) = str->toint(s,10);
153			(s, line) = getfield(line);
154			d = real (r * r);
155			if(d >= dist(p, c))
156				return pth+s;
157		}else if(s=="poly"){
158			(s, line) = getfield(line);
159			(start, ok) = pt(s);
160			if(!ok)
161				continue;
162			inside = 0;
163			c = start;
164			for(n = 1; ; n++){
165				(s, line) = getfield(line);
166				(q, ok) = pt(s);
167				if(!ok)
168					break;
169				inside = polytest(inside, p, c, q);
170				c = q;
171			}
172			inside = polytest(inside, p, c, start);
173			if(n >= 3 && inside)
174				return pth+s;
175		}else if(s== "point"){
176			(s, line) = getfield(line);
177			(q, ok) = pt(s);
178			if(!ok)
179				continue;
180			d = dist(p, q);
181			(s, line) = getfield(line);
182			if(d == 0.)
183				return pth+s;
184			if(close == 0. || d < close){
185				close = d;
186				To = s;
187			}
188		}else if(s ==  "default"){
189			(def, line) = getfield(line);
190		}
191	}
192	if(To == nil)
193		To = def;
194	return pth+To;
195}
196
197
198polytest(inside : int,p, b, a : Point) : int{
199	pa, ba : Point;
200
201	if(b.y>a.y){
202		pa=sub(p, a);
203		ba=sub(b, a);
204	}else{
205		pa=sub(p, b);
206		ba=sub(a, b);
207	}
208	if(0<=pa.y && pa.y<ba.y && pa.y*ba.x<=pa.x*ba.y)
209		inside = !inside;
210	return inside;
211}
212
213
214sub(p, q : Point) : Point {
215	return (Point)(p.x-q.x, p.y-q.y);
216}
217
218
219dist(p, q : Point) : real {
220	p.x -= q.x;
221	p.y -= q.y;
222	return real (p.x * p.x + p.y *p.y);
223}
224
225
226pt(s : string) : (Point, int) {
227	p : Point;
228	x, y : string;
229
230	if(s[0] == '(')
231		s=s[1:];
232	(s,nil)=str->splitl(s, ")");
233	p = Point(0, 0);
234	(x,y) = str->splitl(s, ",");
235	if(x == s)
236		return (p, 0);
237	(p.x,nil) = str->toint(x,10);
238	if(y==nil)
239		return (p, 0);
240	y=y[1:];
241	(p.y,nil) = str->toint(y, 10);
242	return (p, 1);
243}
244
245
246getfield(s : string) : (string,string) {
247	i:=0;
248	while(s[i] == '\t' || s[i] == ' ')
249		i++;
250	return str->splitl(s[i:],"\t ");
251}
252