xref: /plan9/sys/src/cmd/ip/httpd/imagemap.c (revision 80ee5cbfe36716af62da8896207e9763b8e3d760)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "httpd.h"
5 #include "httpsrv.h"
6 
7 typedef struct Point	Point;
8 typedef struct OkPoint	OkPoint;
9 typedef struct Strings	Strings;
10 
11 struct Point
12 {
13 	int	x;
14 	int	y;
15 };
16 
17 struct OkPoint
18 {
19 	Point	p;
20 	int	ok;
21 };
22 
23 struct Strings
24 {
25 	char	*s1;
26 	char	*s2;
27 };
28 
29 static	char *me;
30 
31 int		polytest(int, Point, Point, Point);
32 Strings		getfield(char*);
33 OkPoint		pt(char*);
34 char*		translate(HConnect*, char*, char*);
35 Point		sub(Point, Point);
36 float		dist(Point, Point);
37 
38 void
main(int argc,char ** argv)39 main(int argc, char **argv)
40 {
41 	HConnect *c;
42 	Hio *hout;
43 	char *dest;
44 
45 	me = "imagemap";
46 	c = init(argc, argv);
47 	hout = &c->hout;
48 	if(hparseheaders(c, HSTIMEOUT) < 0)
49 		exits("failed");
50 	anonymous(c);
51 
52 	if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0){
53 		hunallowed(c, "GET, HEAD");
54 		exits("unallowed");
55 	}
56 	if(c->head.expectother || c->head.expectcont){
57 		hfail(c, HExpectFail, nil);
58 		exits("failed");
59 	}
60 	dest = translate(c, c->req.uri, c->req.search);
61 
62 	if(dest == nil){
63 		if(c->req.vermaj){
64 			hokheaders(c);
65 			hprint(hout, "Content-type: text/html\r\n");
66 			hprint(hout, "\r\n");
67 		}
68 		hprint(hout, "<head><title>Nothing Found</title></head><body>\n");
69 		hprint(hout, "Nothing satisfying your search request could be found.\n</body>\n");
70 		hflush(hout);
71 		writelog(c, "Reply: 200 imagemap %ld %ld\n", hout->seek, hout->seek);
72 		exits(nil);
73 	}
74 
75 	if(http11(c) && strcmp(c->req.meth, "POST") == 0)
76 		hredirected(c, "303 See Other", dest);
77 	else
78 		hredirected(c, "302 Found", dest);
79 	exits(nil);
80 }
81 
82 char*
translate(HConnect * c,char * uri,char * search)83 translate(HConnect *c, char *uri, char *search)
84 {
85 	Biobuf *b;
86 	Strings ss;
87 	OkPoint okp;
88 	Point p, cen, q, start;
89 	float close, d;
90 	char *line, *to, *def, *s, *dst;
91 	int n, inside, r, ncsa;
92 
93 	if(search == nil){
94 		hfail(c, HNoData, me);
95 		exits("failed");
96 	}
97 	okp = pt(search);
98 	if(!okp.ok){
99 		hfail(c, HBadSearch, me);
100 		exits("failed");
101 	}
102 	p = okp.p;
103 
104 	b = Bopen(uri, OREAD);
105 	if(b == nil){
106 		hfail(c, HNotFound, uri);
107 		exits("failed");
108 	}
109 
110 	to = nil;
111 	def = nil;
112 	dst = nil;
113 	close = 0.;
114 	ncsa = 1;
115 	while(line = Brdline(b, '\n')){
116 		line[Blinelen(b)-1] = 0;
117 
118 		ss = getfield(line);
119 		s = ss.s1;
120 		line = ss.s2;
121 		if(ncsa){
122 			ss = getfield(line);
123 			dst = ss.s1;
124 			line = ss.s2;
125 		}
126 		if(strcmp(s, "#cern") == 0){
127 			ncsa = 0;
128 			continue;
129 		}
130 		if(strcmp(s, "rect") == 0){
131 			ss = getfield(line);
132 			s = ss.s1;
133 			line = ss.s2;
134 			okp = pt(s);
135 			q = okp.p;
136 			if(!okp.ok || q.x > p.x || q.y > p.y)
137 				continue;
138 			ss = getfield(line);
139 			s = ss.s1;
140 			line = ss.s2;
141 			okp = pt(s);
142 			q = okp.p;
143 			if(!okp.ok || q.x < p.x || q.y < p.y)
144 				continue;
145 			if(!ncsa){
146 				ss = getfield(line);
147 				dst = ss.s1;
148 			}
149 			return dst;
150 		}else if(strcmp(s, "circle") == 0){
151 			ss = getfield(line);
152 			s = ss.s1;
153 			line = ss.s2;
154 			okp = pt(s);
155 			cen = okp.p;
156 			if(!okp.ok)
157 				continue;
158 			ss = getfield(line);
159 			s = ss.s1;
160 			line = ss.s2;
161 			if(ncsa){
162 				okp = pt(s);
163 				if(!okp.ok)
164 					continue;
165 				if(dist(okp.p, cen) >= dist(p, cen))
166 					return dst;
167 			}else{
168 				r = strtol(s, nil, 10);
169 				ss = getfield(line);
170 				dst = ss.s1;
171 				d = (float)r * r;
172 				if(d >= dist(p, cen))
173 					return dst;
174 			}
175 		}else if(strcmp(s, "poly") == 0){
176 			ss = getfield(line);
177 			s = ss.s1;
178 			line = ss.s2;
179 			okp = pt(s);
180 			start = okp.p;
181 			if(!okp.ok)
182 				continue;
183 			inside = 0;
184 			cen = start;
185 			for(n = 1; ; n++){
186 				ss = getfield(line);
187 				s = ss.s1;
188 				line = ss.s2;
189 				okp = pt(s);
190 				q = okp.p;
191 				if(!okp.ok)
192 					break;
193 				inside = polytest(inside, p, cen, q);
194 				cen = q;
195 			}
196 			inside = polytest(inside, p, cen, start);
197 			if(!ncsa)
198 				dst = s;
199 			if(n >= 3 && inside)
200 				return dst;
201 		}else if(strcmp(s, "point") == 0){
202 			ss = getfield(line);
203 			s = ss.s1;
204 			line = ss.s2;
205 			okp = pt(s);
206 			q = okp.p;
207 			if(!okp.ok)
208 				continue;
209 			d = dist(p, q);
210 			if(!ncsa){
211 				ss = getfield(line);
212 				dst = ss.s1;
213 			}
214 			if(d == 0.)
215 				return dst;
216 			if(close == 0. || d < close){
217 				close = d;
218 				to = dst;
219 			}
220 		}else if(strcmp(s, "default") == 0){
221 			if(!ncsa){
222 				ss = getfield(line);
223 				dst = ss.s1;
224 			}
225 			def = dst;
226 		}
227 	}
228 	if(to == nil)
229 		to = def;
230 	return to;
231 }
232 
233 int
polytest(int inside,Point p,Point b,Point a)234 polytest(int inside, Point p, Point b, Point a)
235 {
236 	Point pa, ba;
237 
238 	if(b.y>a.y){
239 		pa=sub(p, a);
240 		ba=sub(b, a);
241 	}else{
242 		pa=sub(p, b);
243 		ba=sub(a, b);
244 	}
245 	if(0<=pa.y && pa.y<ba.y && pa.y*ba.x<=pa.x*ba.y)
246 		inside = !inside;
247 	return inside;
248 }
249 
250 Point
sub(Point p,Point q)251 sub(Point p, Point q)
252 {
253 	p.x -= q.x;
254 	p.y -= q.y;
255 	return p;
256 }
257 
258 float
dist(Point p,Point q)259 dist(Point p, Point q)
260 {
261 	p.x -= q.x;
262 	p.y -= q.y;
263 	return (float)p.x * p.x + (float)p.y * p.y;
264 }
265 
266 OkPoint
pt(char * s)267 pt(char *s)
268 {
269 	OkPoint okp;
270 	Point p;
271 	char *t, *e;
272 
273 	if(*s == '(')
274 		s++;
275 	t = strchr(s, ')');
276 	if(t != nil)
277 		*t = 0;
278 	p.x = 0;
279 	p.y = 0;
280 	t = strchr(s, ',');
281 	if(t == nil){
282 		okp.p = p;
283 		okp.ok = 0;
284 		return okp;
285 	}
286 	e = nil;
287 	p.x = strtol(s, &e, 10);
288 	if(e != t){
289 		okp.p = p;
290 		okp.ok = 0;
291 		return okp;
292 	}
293 	p.y = strtol(t+1, &e, 10);
294 	if(e == nil || *e != 0){
295 		okp.p = p;
296 		okp.ok = 0;
297 		return okp;
298 	}
299 	okp.p = p;
300 	okp.ok = 1;
301 	return okp;
302 }
303 
304 Strings
getfield(char * s)305 getfield(char *s)
306 {
307 	Strings ss;
308 	char *f;
309 
310 	while(*s == '\t' || *s == ' ')
311 		s++;
312 	f = s;
313 	while(*s && *s != '\t' && *s != ' ')
314 		s++;
315 	if(*s)
316 		*s++ = 0;
317 	ss.s1 = f;
318 	ss.s2 = s;
319 	return ss;
320 }
321