1implement Query; 2 3# 4# Copyright © 2003 Vita Nuova Holdings Limited. All rights reserved. 5# 6 7 8include "sys.m"; 9 sys : Sys; 10include "draw.m"; 11 draw: Draw; 12 Display, Rect, Image: import draw; 13include "tk.m"; 14 tk: Tk; 15include "tkclient.m"; 16 tkclient: Tkclient; 17include "readdir.m"; 18 readdir: Readdir; 19include "sh.m"; 20include "workdir.m"; 21include "registries.m"; 22 registries: Registries; 23 Service: import registries; 24include "grid/pathreader.m"; 25 reader: PathReader; 26include "grid/browser.m"; 27 browser: Browser; 28 Browse, File: import browser; 29include "grid/srvbrowse.m"; 30 srvbrowse: Srvbrowse; 31include "grid/fbrowse.m"; 32include "grid/announce.m"; 33 announce: Announce; 34 35srvfilter : list of list of (string, string); 36 37Query : module { 38 init : fn (context : ref Draw->Context, nil : list of string); 39 readpath: fn (dir: File): (array of ref sys->Dir, int); 40}; 41 42realinit() 43{ 44 sys = load Sys Sys->PATH; 45 if (sys == nil) 46 badmod(Sys->PATH); 47 readdir = load Readdir Readdir->PATH; 48 if (readdir == nil) 49 badmod(Readdir->PATH); 50 draw = load Draw Draw->PATH; 51 if (draw == nil) 52 badmod(Draw->PATH); 53 tk = load Tk Tk->PATH; 54 if (tk == nil) 55 badmod(Tk->PATH); 56 tkclient = load Tkclient Tkclient->PATH; 57 if (tkclient == nil) 58 badmod(Tkclient->PATH); 59 tkclient->init(); 60 workdir := load Workdir Workdir->PATH; 61 if (workdir == nil) 62 badmod(Workdir->PATH); 63 registries = load Registries Registries->PATH; 64 if (registries == nil) 65 badmod(Registries->PATH); 66 registries->init(); 67 browser = load Browser Browser->PATH; 68 if (browser == nil) 69 badmod(Browser->PATH); 70 browser->init(); 71 srvbrowse = load Srvbrowse Srvbrowse->PATH; 72 if (srvbrowse == nil) 73 badmod(Srvbrowse->PATH); 74 srvbrowse->init(); 75 announce = load Announce Announce->PATH; 76 if (announce == nil) 77 badmod(Announce->PATH); 78 announce->init(); 79 reader = load PathReader "$self"; 80 if (reader == nil) 81 badmod("PathReader"); 82} 83 84init(ctxt : ref Draw->Context, nil: list of string) 85{ 86 realinit(); 87 spawn start(ctxt, 1); 88} 89 90start(ctxt: ref Draw->Context, standalone: int) 91{ 92 sys->pctl(sys->FORKNS | sys->NEWPGRP, nil); 93 if (ctxt == nil) 94 ctxt = tkclient->makedrawcontext(); 95 96 if (standalone) 97 sys->create("/tmp/query", sys->OREAD, sys->DMDIR | 8r777); 98 root := "/"; 99 (top, titlebar) := tkclient->toplevel(ctxt,"","Query", tkclient->Appl); 100 butchan := chan of string; 101 tk->namechan(top, butchan, "butchan"); 102 browsechan := chan of string; 103 tk->namechan(top, browsechan, "browsechan"); 104 br := Browse.new(top, "browsechan", "services/", "Services", 1, reader); 105 br.addopened(File ("services/", nil), 1); 106 srvbrowse->refreshservices(srvfilter); 107 br.refresh(); 108 109 for (ik := 0; ik < len mainscreen; ik++) 110 tkcmd(top,mainscreen[ik]); 111 112 tkcmd(top, "pack .f -fill both -expand 1; pack propagate . 0"); 113 released := 1; 114 title := ""; 115 resize(top, 400,400); 116 tkclient->onscreen(top, nil); 117 tkclient->startinput(top, "kbd"::"ptr"::nil); 118 tkpath: string; 119 main: for (;;) { 120 alt { 121 s := <-top.ctxt.kbd => 122 tk->keyboard(top, s); 123 s := <-top.ctxt.ptr => 124 tk->pointer(top, *s); 125 inp := <-browsechan => 126 (nil, lst) := sys->tokenize(inp, " \n\t"); 127 if (len lst > 1) 128 tkpath = hd tl lst; 129 selected := br.getselected(0); 130 br.defaultaction(lst, nil); 131 if (!File.eq(selected, br.getselected(0))) 132 actionbutton(top, br.selected[0].file.path, br.selected[0].tkpath); 133 tkcmd(top, "update"); 134 inp := <-butchan => 135 # sys->print("inp: %s\n",inp); 136 (nil, lst) := sys->tokenize(inp, " \n\t"); 137 if (len lst > 1) 138 tkpath = hd tl lst; 139 case hd lst { 140 "search" => 141 if (tl lst == nil) 142 spawn srvbrowse->searchwin(ctxt, butchan, nil); 143 else { 144 if (hd tl lst == "select") { 145 file := hd tl tl lst; 146 for (tmp := tl tl tl lst; tl tmp != nil; tmp = tl tmp) 147 file += " "+hd tmp; 148 qid := hd tmp; 149 br.gotoselectfile(File (file, qid)); 150 actionbutton(top, br.selected[0].file.path, br.selected[0].tkpath); 151 } 152 else if (hd tl lst == "search") { 153 srvbrowse->refreshservices(srvfilter); 154 br.refresh(); 155 } 156 } 157 "refresh" => 158 # ! check to see if anything is mounted first 159 srvbrowse->refreshservices(srvfilter); 160 br.refresh(); 161 "mount" => 162 file := *br.getpath(tkpath); 163 (nsrv, lsrv) := sys->tokenize(file.path, "/"); 164 if (nsrv == 3) 165 spawn mountsrv(ctxt, file, getcoords(top)); 166 } 167 tkcmd(top, "update"); 168 169 title = <-top.ctxt.ctl or 170 title = <-top.wreq or 171 title = <-titlebar => 172 if (title == "exit") 173 break main; 174 e := tkclient->wmctl(top, title); 175 if (e == nil && title[0] == '!') 176 (nil, lst) := sys->tokenize(title, " \t\n"); 177 } 178 } 179 killg(sys->pctl(0,nil)); 180} 181 182resize(top: ref Tk->Toplevel, w, h: int) 183{ 184 tkcmd(top, ". configure -x 0 -width "+string min(top.screenr.dx(), w)); 185 tkcmd(top, ". configure -y 0 -height "+string min(top.screenr.dy(), h)); 186} 187 188min(a, b: int): int 189{ 190 if (a < b) 191 return a; 192 return b; 193} 194 195nactionbuttons := 0; 196actionbutton(top: ref Tk->Toplevel, path, tkpath: string) 197{ 198 for (i := 0; i < nactionbuttons; i++) { 199 tkcmd(top, "grid forget .f.ftop.baction"+string i); 200 tkcmd(top, "destroy .f.ftop.baction"+string i); 201 } 202 if (path == nil) { 203 nactionbuttons = 0; 204 return; 205 } 206 (n, nil) := sys->tokenize(path, "/"); 207 buttons : list of (string, string) = nil; 208 if (n == 3) 209 buttons = ("Mount", "mount "+tkpath) :: buttons; 210 211 nactionbuttons = len buttons; 212 for (i = 0; i < nactionbuttons; i++) { 213 name := ".f.ftop.baction"+string i+" "; 214 (text,cmd) := hd buttons; 215 tkcmd(top, "button "+name+"-text {"+text+"} "+ 216 "-font /fonts/charon/bold.normal.font "+ 217 "-command {send butchan "+cmd+"}"); 218 tkcmd(top, "grid "+name+" -row 0 -column "+string (4+i)); 219 buttons = tl buttons; 220 } 221} 222 223kill(pid: int) 224{ 225 if ((fd := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE)) != nil) 226 sys->fprint(fd, "kill"); 227} 228 229killg(pid: int) 230{ 231 if ((fd := sys->open("/prog/" + string pid + "/ctl", Sys->OWRITE)) != nil) 232 sys->fprint(fd, "killgrp"); 233} 234 235mainscreen := array[] of { 236 "frame .f", 237 "frame .f.ftop", 238 "variable opt command", 239 "button .f.ftop.br -text {Refresh} -command {send butchan refresh} -font /fonts/charon/bold.normal.font", 240 "button .f.ftop.bs -text {Search} -command {send butchan search} -font /fonts/charon/bold.normal.font", 241 "grid .f.ftop.br .f.ftop.bs -row 0", 242 "grid columnconfigure .f.ftop 3 -minsize 30", 243 "label .f.l -text { } -height 1 -bg red", 244 "grid .f.l -row 1 -column 0 -sticky ew", 245 "grid .f.ftop -row 0 -column 0 -pady 2 -sticky w", 246 "grid .fbrowse -in .f -row 2 -column 0 -sticky nsew", 247 248 "grid columnconfigure .f 0 -weight 1", 249 "grid rowconfigure .f 2 -weight 1", 250 251 "bind .Wm_t <Button-1> +{focus .Wm_t}", 252 "bind .Wm_t.title <Button-1> +{focus .Wm_t}", 253 "focus .Wm_t", 254}; 255 256readpath(dir: File): (array of ref sys->Dir, int) 257{ 258 return srvbrowse->servicepath2Dir(dir.path, int dir.qid); 259} 260 261badmod(path: string) 262{ 263 sys->print("Query: failed to load %s: %r\n",path); 264 exit; 265} 266 267mountscr := array[] of { 268 "frame .f -borderwidth 2 -relief raised", 269 "text .f.t -width 200 -height 60 -borderwidth 1 -bg white -font /fonts/charon/plain.normal.font", 270 "button .f.b -text {Cancel} -command {send butchan cancel} -width 70 -font /fonts/charon/plain.normal.font", 271 "grid .f.t -row 0 -column 0 -padx 10 -pady 10", 272 "grid .f.b -row 1 -column 0 -sticky n", 273 "grid rowconfigure .f 1 -minsize 30", 274}; 275 276mountsrv(ctxt: ref Draw->Context, srvfile: File, coords: draw->Rect) 277{ 278 (top, nil) := tkclient->toplevel(ctxt, "", nil, tkclient->Plain); 279 ctlchan := chan of string; 280 butchan := chan of string; 281 tk->namechan(top, butchan, "butchan"); 282 tkcmds(top, mountscr); 283 tkcmd(top, ". configure "+getcentre(top, coords)+"; pack .f; update"); 284 spawn mountit(ctxt, srvfile, ctlchan); 285 pid := int <-ctlchan; 286 tkclient->onscreen(top, "exact"); 287 tkclient->startinput(top, "kbd"::"ptr"::nil); 288 for (;;) { 289 alt { 290 s := <-top.ctxt.kbd => 291 tk->keyboard(top, s); 292 s := <-top.ctxt.ptr => 293 tk->pointer(top, *s); 294 e := <- ctlchan => 295 if (e[0] == '!') { 296 tkcmd(top, ".f.t insert end {"+e[1:]+"}"); 297 tkcmd(top, ".f.b configure -text {close}; update"); 298 pid = -1; 299 } 300 else if (e == "ok") 301 return; 302 else 303 tkcmd(top, ".f.t insert end {"+e+"}; update"); 304 <- butchan => 305 if (pid != -1) 306 kill(pid); 307 return; 308 } 309 } 310} 311 312mountit(ctxt: ref Draw->Context, srvfile: File, ctlchan: chan of string) 313{ 314 ctlchan <-= string sys->pctl(0,nil); 315 316 n := 0; 317 (nil, lst) := sys->tokenize(srvfile.path, "/"); 318 stype := hd tl lst; 319 name := hd tl tl lst; 320 addr := ""; 321 ctlchan <-= "Connecting...\n"; 322 lsrv := srvbrowse->servicepath2Service(srvfile.path, srvfile.qid); 323 if (len lsrv < 1) { 324 ctlchan <-= "!could not find service"; 325 return; 326 } 327 srvc := hd lsrv; 328 329 ctlchan <-= "Mounting...\n"; 330 331 id := 0; 332 dir : string; 333 for (;;) { 334 dir = "/tmp/query/"+string id; 335 (n2, nil) := sys->stat(dir); 336 if (n2 == -1) { 337 fdtmp := sys->create(dir, sys->OREAD, sys->DMDIR | 8r777); 338 if (fdtmp != nil) 339 break; 340 } 341 else { 342 (dirs2, nil) := readdir->init(dir, readdir->NAME | readdir->COMPACT); 343 if (len dirs2 == 0) 344 break; 345 } 346 id++; 347 } 348 attached := srvc.attach(nil, nil); 349 if (attached == nil) { 350 ctlchan <-= sys->sprint("!could not connect: %r"); 351 return; 352 } 353 if (sys->mount(attached.fd, nil, dir, sys->MREPL, nil) != -1) { 354 ctlchan <-= "ok"; 355 fbrowse := load FBrowse FBrowse->PATH; 356 if (fbrowse == nil) 357 badmod(FBrowse->PATH); 358 fbrowse->init(ctxt, srvfile.path, dir, dir); 359 sys->unmount(nil, dir); 360 attached = nil; 361 } 362 else 363 ctlchan <-= sys->sprint("!mount failed: %r"); 364} 365 366getcoords(top: ref Tk->Toplevel): draw->Rect 367{ 368 h := int tkcmd(top, ". cget -height"); 369 w := int tkcmd(top, ". cget -width"); 370 x := int tkcmd(top, ". cget -actx"); 371 y := int tkcmd(top, ". cget -acty"); 372 r := draw->Rect((x,y),(x+w,y+h)); 373 return r; 374} 375 376getcentre(top: ref Tk->Toplevel, winr: draw->Rect): string 377{ 378 h := int tkcmd(top, ".f cget -height"); 379 w := int tkcmd(top, ".f cget -width"); 380 midx := winr.min.x + (winr.dx() / 2); 381 midy := winr.min.y + (winr.dy() / 2); 382 newx := midx - (w/2); 383 newy := midy - (h/2); 384 return "-x "+string newx+" -y "+string newy; 385} 386 387tkcmd(top: ref Tk->Toplevel, cmd: string): string 388{ 389 e := tk->cmd(top, cmd); 390 if (e != "" && e[0] == '!') 391 sys->print("Tk error: '%s': %s\n",cmd,e); 392 return e; 393} 394 395tkcmds(top: ref Tk->Toplevel, a: array of string) 396{ 397 for (j := 0; j < len a; j++) 398 tkcmd(top, a[j]); 399} 400