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