16 int verbose=0; /* -v flag causes html errors to be written to file-descriptor 2 */
17 int defdisplay=1; /* is the default (initial) display visible? */
18 Panel *root; /* the whole display */
19 Panel *alt; /* the alternate display */
20 Panel *alttext; /* the alternate text window */
21 Panel *cmd; /* command entry */
22 Panel *cururl; /* label giving the url of the visible text */
23 Panel *list; /* list of previously acquired www pages */
24 Panel *msg; /* message display */
25 Panel *menu3; /* button 3 menu */
26 char mothra[] = "mothra!";
29 0x01, 0x80, 0x03, 0xC0, 0x07, 0xE0, 0x07, 0xe0,
30 0x07, 0xe0, 0x07, 0xe0, 0x03, 0xc0, 0x0F, 0xF0,
31 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
32 0x0F, 0xF0, 0x1F, 0xF8, 0x3F, 0xFC, 0x3F, 0xFC,
34 0x01, 0x80, 0x03, 0xC0, 0x07, 0xE0, 0x04, 0x20,
35 0x04, 0x20, 0x06, 0x60, 0x02, 0x40, 0x0C, 0x30,
36 0x10, 0x08, 0x14, 0x08, 0x14, 0x28, 0x12, 0x28,
37 0x0A, 0x50, 0x16, 0x68, 0x20, 0x04, 0x3F, 0xFC,
41 0x0F, 0xBF, 0x0F, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF,
42 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE,
43 0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF,
44 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
46 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F,
47 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C,
48 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
49 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90
53 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F, 0xF0,
54 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x1F, 0xF0,
55 0x3F, 0xF0, 0x7F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
56 0xFB, 0xFF, 0xF3, 0xFF, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0,
59 0x07, 0xE0, 0x01, 0xE0, 0x03, 0xE0, 0x07, 0x60,
60 0x0E, 0x60, 0x1C, 0x00, 0x38, 0x00, 0x71, 0xB6,
61 0x61, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 {0x00, 0x00, 0x60, 0x06, 0xf8, 0x1f, 0xfc, 0x3f,
66 0xfe, 0x7f, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfe,
67 0x7f, 0xfe, 0x3f, 0xfc, 0x3f, 0xfc, 0x1f, 0xf8,
68 0x1f, 0xf8, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00, },
69 {0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x58, 0x1a,
70 0x5c, 0x3a, 0x64, 0x26, 0x27, 0xe4, 0x37, 0xec,
71 0x37, 0xec, 0x17, 0xe8, 0x1b, 0xd8, 0x0e, 0x70,
72 0x0c, 0x30, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, }
80 void docmd(Panel *, char *);
81 void doprev(Panel *, int, int);
83 void setcurrent(int, char *);
84 char *genwww(Panel *, int);
86 void dolink(Panel *, int, Rtext *);
88 void mothon(Www *, int);
105 return &a[index % NWWW];
108 return wwwtop<NWWW ? wwwtop : NWWW;
111 int subpanel(Panel *obj, Panel *subj){
113 if(obj==subj) return 1;
114 for(obj=obj->child;obj;obj=obj->next)
115 if(subpanel(obj, subj)) return 1;
119 * Make sure that the keyboard focus is on-screen, by adjusting it to
120 * be the cmd entry if necessary.
126 yoffs=text->r.min.y-plgetpostextview(text);
127 for(t=current->text;t;t=t->next) if(!eqrect(t->r, Rect(0,0,0,0))){
128 if(t->r.max.y+yoffs>=text->r.min.y
129 && t->r.min.y+yoffs<text->r.max.y
131 && subpanel(t->p, plkbfocus))
139 void scrolltext(int dy, int whence)
143 s = plgetscroll(text);
152 s.pos.y = s.size.y+dy;
157 if(s.pos.y > s.size.y)
159 plsetscroll(text, s);
163 Panel *p, *bar, *swap;
165 menu3=plmenu(0, 0, buttons, PACKN|FILLX, hit3);
166 root=plpopup(root, EXPAND, 0, 0, menu3);
167 p=plgroup(root, PACKN|FILLX);
168 msg=pllabel(p, PACKN|FILLX, mothra);
169 plplacelabel(msg, PLACEW);
170 pllabel(p, PACKW, "Go:");
171 cmd=plentry(p, PACKN|FILLX, 0, "", docmd);
172 p=plgroup(root, PACKN|FILLX);
173 bar=plscrollbar(p, PACKW);
174 list=pllist(p, PACKN|FILLX, genwww, 8, doprev);
175 plscroll(list, 0, bar);
176 p=plgroup(root, PACKN|FILLX);
177 pllabel(p, PACKW, "Url:");
178 cururl=pllabel(p, PACKE|EXPAND, "---");
179 plplacelabel(cururl, PLACEW);
180 p=plgroup(root, PACKN|EXPAND);
181 bar=plscrollbar(p, PACKW|USERFL);
182 text=pltextview(p, PACKE|EXPAND, Pt(0, 0), 0, dolink);
183 plscroll(text, 0, bar);
185 alt=plpopup(0, PACKE|EXPAND, 0, 0, menu3);
186 bar=plscrollbar(alt, PACKW|USERFL);
187 alttext=pltextview(alt, PACKE|EXPAND, Pt(0, 0), 0, dolink);
188 plscroll(alttext, 0, bar);
200 void killcohort(void){
202 for(i=0;i!=3;i++){ /* It's a long way to the kitchen */
203 postnote(PNGROUP, cohort, "kill\n");
207 void catch(void*, char*){
210 void dienow(void*, char*){
215 static char *home; /* where to put files */
222 tmp = smprint("%s/lib", henv);
223 f=create(tmp, OREAD, DMDIR|0777);
227 home = smprint("%s/lib/mothra", henv);
228 f=create(home, OREAD, DMDIR|0777);
233 home = strdup("/tmp");
239 if(current && current->alldone==0)
240 esetcursor(&readingcurs);
242 esetcursor(&mothcurs);
247 void drawlock(int dolock){
251 lockdisplay(display);
254 unlockdisplay(display);
258 void scrollto(char *tag);
261 extern char *mtpt; /* url */
263 void main(int argc, char *argv[]){
265 enum { Eplumb = 128, Ekick = 256 };
273 fmtinstall('U', Ufmt);
276 case 'd': debug=1; break;
277 case 'v': verbose=1; break;
281 case 'a': defdisplay=0; break;
286 * so that we can stop all subprocesses with a note,
287 * and to isolate rendezvous from other processes
289 if(cohort=rfork(RFPROC|RFNOTEG|RFNAMEG|RFREND)){
301 fprint(2, "Usage: %s [-dva] [-m mtpt] [url]\n", argv0);
306 case 1: url=argv[0]; break;
308 if(initdraw(0, 0, mothra) < 0)
309 sysfatal("initdraw: %r");
310 display->locking = 1;
311 chrwidth=stringwidth(font, "0");
312 pltabsize(chrwidth, 8*chrwidth);
313 einit(Emouse|Ekeyboard);
314 eplumb(Eplumb, "web");
315 if(pipe(kickpipe) < 0)
316 sysfatal("pipe: %r");
317 estart(Ekick, kickpipe[0], 256);
318 plinit(screen->depth);
319 if(debug) notify(dienow);
321 hrule=allocimage(display, Rect(0, 0, 2048, 5), screen->chan, 0, DWhite);
323 sysfatal("can't allocimage!");
324 draw(hrule, Rect(0,1,1280,3), display->black, 0, ZP);
325 linespace=allocimage(display, Rect(0, 0, 2048, 5), screen->chan, 0, DWhite);
327 sysfatal("can't allocimage!");
328 bullet=allocimage(display, Rect(0,0,25, 8), screen->chan, 0, DWhite);
329 fillellipse(bullet, Pt(4,4), 3, 3, display->black, ZP);
331 unlockdisplay(display);
336 geturl(url, -1, 1, 0);
340 if(mouse.buttons==0 && current){
341 if(current->finished){
343 if(current->url->tag[0])
344 scrollto(current->url->tag);
353 flushimage(display, 1);
360 if(mouse.buttons==0 && current && current->changed){
361 if(!current->finished)
376 scrolltext(-text->size.y/4, 1);
379 scrolltext(-text->size.y/2, 1);
382 scrolltext(text->size.y/4, 1);
385 scrolltext(text->size.y/2, 1);
388 scrolltext(-text->size.y, 2);
397 if(mouse.buttons & (8|16)){
398 if(mouse.buttons & 8)
399 scrolltext(-text->size.y/24, 1);
401 scrolltext(text->size.y/24, 1);
404 plmouse(root, &mouse);
409 geturl(pm->data, -1, 1, 0);
415 Cursor confirmcursor={
417 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
418 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
419 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
420 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
422 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F,
423 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C,
424 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
425 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90,
429 esetcursor(&confirmcursor);
430 do down=emouse(); while(!down.buttons);
431 do up=emouse(); while(up.buttons);
433 return down.buttons==(1<<(b-1));
435 void message(char *s, ...){
436 static char buf[1024];
440 out = buf + vsnprint(buf, sizeof(buf), s, args);
443 plinitlabel(msg, PACKN|FILLX, buf);
444 if(defdisplay) pldraw(msg, screen);
446 void htmlerror(char *name, int line, char *m, ...){
447 static char buf[1024];
452 out=buf+snprint(buf, sizeof(buf), "%s: line %d: ", name, line);
453 out+=vsnprint(out, sizeof(buf)-(out-buf)-1, m, args);
456 fprint(2, "%s\n", buf);
459 void eresized(int new){
463 if(new && getwindow(display, Refnone) == -1) {
464 fprint(2, "getwindow: %r\n");
470 pldraw(cmd, screen); /* put cmd box on screen for alt display */
471 pldraw(root, screen);
472 flushimage(display, 1);
475 void *emalloc(int n){
479 sysfatal("out of memory");
481 setmalloctag(v, getcallerpc(&n));
484 void nstrcpy(char *to, char *from, int len){
485 strncpy(to, from, len);
489 char *genwww(Panel *, int index){
490 static char buf[1024];
500 if(w->title[0]!='\0'){
502 snprint(buf, sizeof(buf), "%2d %s", i+1, w->title);
504 snprint(buf, sizeof(buf), "%2d %s", i+1, urlstr(w->url));
508 void scrollto(char *tag){
511 if(current == nil || text == nil)
514 for(tp=current->text;tp;tp=tp->next){
516 if(ap && ap->name && strcmp(ap->name, tag)==0){
517 current->yoffs=tp->topy;
522 plsetpostextview(text, current->yoffs);
523 flushimage(display, 1);
527 * selected text should be a url.
529 void setcurrent(int index, char *tag){
533 if(new==current && (tag==0 || tag[0]==0)) return;
535 current->yoffs=plgetpostextview(text);
537 plinitlabel(cururl, PACKE|EXPAND, current->url->fullname);
538 if(defdisplay) pldraw(cururl, screen);
539 plinittextview(text, PACKE|EXPAND, Pt(0, 0), current->text, dolink);
541 if((i = open("/dev/label", OWRITE)) >= 0){
542 fprint(i, "%s %s", mothra, current->url->fullname);
548 do ++s; while(*s==' ' || *s=='\t');
551 void save(int ifd, char *name){
555 message("save: %s: %r", name);
558 ofd=create(name, OWRITE, 0666);
560 message("save: %s: %r", name);
563 switch(rfork(RFNOTEG|RFNAMEG|RFFDG|RFMEM|RFPROC|RFNOWAIT)){
565 message("Can't fork: %r");
573 snprint(buf, sizeof(buf),
574 "{tput -p || cat} |[2] {aux/statusmsg -k %q >/dev/null || cat >/dev/null}", name);
575 execl("/bin/rc", "rc", "-c", buf, nil);
582 void screendump(char *name, int full){
585 fd=create(name, OWRITE, 0666);
587 message("can't create %s", name);
591 writeimage(fd, screen, 0);
593 if((b=allocimage(display, text->r, screen->chan, 0, DNofill)) == nil){
594 message("can't allocate image");
598 draw(b, b->r, screen, 0, b->r.min);
599 writeimage(fd, b, 0);
606 * convert a url into a local file name.
608 char *urltofile(Url *url){
612 if(url->fullname[0] || url->reltext[0])
616 if(slash = strrchr(name, '/'))
624 * user typed a command.
626 void docmd(Panel *p, char *s){
631 while(*s==' ' || *s=='\t') s++;
633 * Non-command does a get on the url
635 if(s[0]!='\0' && s[1]!='\0' && s[1]!=' ')
637 else switch(c = s[0]){
639 message("Unknown command %s", s);
643 if(*s=='\0' && selection)
651 s = urlstr(selection);
653 message("no url selected");
660 doprev(nil, 1, wwwtop-atoi(s));
662 message("Usage: j index");
665 mothon(current, !mothmode);
673 if(s==0 || *s=='\0'){
674 snprint(buf, sizeof(buf), "dump.bit");
675 if(eenter("Screendump to", buf, sizeof(buf), &mouse) <= 0)
679 screendump(s, c == 'W');
684 message("no url selected");
687 if(s==0 || *s=='\0'){
688 snprint(buf, sizeof(buf), "%s", urltofile(selection));
689 if(eenter("Save to", buf, sizeof(buf), &mouse) <= 0)
693 save(urlget(selection, -1), s);
698 plinitentry(cmd, EXPAND, 0, "", docmd);
699 pldraw(root, screen);
703 static char last[256];
709 if(current == nil || current->text == nil || text == nil)
711 strncpy(buf, last, sizeof(buf)-1);
712 if(eenter("Search for", buf, sizeof(buf), &mouse) <= 0)
717 strncpy(last, buf, sizeof(buf)-1);
718 for(tp=current->text;tp;tp=tp->next)
719 if(tp->flags & PL_SEL)
724 tp->flags &= ~PL_SEL;
728 tp->flags &= ~PL_SEL;
729 if(tp->text && *tp->text)
730 if(regexec(re, tp->text, nil, 0)){
732 plsetpostextview(text, tp->topy);
742 void hiturl(int buttons, char *url, int map){
744 case 1: geturl(url, -1, 0, map); break;
745 case 2: selurl(url); break;
746 case 4: message("Button 3 hit on url can't happen!"); break;
751 * user selected from the list of available pages
753 void doprev(Panel *p, int buttons, int index){
756 if(index < 0 || index >= nwww())
760 case 1: setcurrent(i, 0); /* no break ... */
761 case 2: selurl(www(i)->url->fullname); break;
762 case 4: message("Button 3 hit on page can't happen!"); break;
767 * Follow an html link
769 void dolink(Panel *p, int buttons, Rtext *word){
770 char *file, mapurl[NNAME];
775 /* really a button, hit it */
776 if(word->p != nil && word->p != p && strcmp(word->p->kind, "button") == 0){
777 extern void pl_buttonhit(Panel *p, int buttons, int check);
778 pl_buttonhit(word->p, buttons, 0);
783 if(a == nil || (a->link == nil && a->image == nil))
786 hiturl(buttons, a->image ? a->image : a->link, 0);
789 yoffs=plgetpostextview(p);
790 coord=subpt(subpt(mouse.xy, word->r.min), p->r.min);
791 snprint(mapurl, sizeof(mapurl), "%s?%d,%d", a->link, coord.x, coord.y+yoffs);
792 hiturl(buttons, mapurl, 1);
794 hiturl(buttons, a->link, 0);
798 void filter(int fd, char *cmd){
799 switch(rfork(RFFDG|RFPROC|RFMEM|RFREND|RFNOWAIT|RFNOTEG)){
801 message("Can't fork!");
804 dupfds(fd, 1, 2, -1);
805 execl("/bin/rc", "rc", "-c", cmd, 0);
810 void gettext(Www *w, int fd, int type){
811 switch(rfork(RFFDG|RFPROC|RFMEM|RFNOWAIT)){
813 message("Can't fork, please wait");
817 plrdhtml(w->url->fullname, fd, w);
819 plrdplain(w->url->fullname, fd, w);
825 void freetext(Rtext *t){
830 for(; t!=0; t = t->next){
853 for(mfd = 0; fd >= 0; fd = va_arg(arg, int), mfd++)
858 if((fd = open("/fd", OREAD)) < 0)
859 sysfatal("open: %r");
860 n = dirreadall(fd, &dir);
862 if(strstr(dir[i].name, "ctl"))
864 fd = atoi(dir[i].name);
871 int pipeline(int fd, char *fmt, ...)
873 char buf[80], *argv[4];
878 vsnprint(buf, sizeof buf, fmt, arg);
884 werrstr("pipeline for %s failed: %r", buf);
887 switch(rfork(RFPROC|RFMEM|RFFDG|RFREND|RFNOWAIT)){
893 dupfds(fd, pfd[1], 2, -1);
898 exec("/bin/rc", argv);
909 return url->fullname;
912 Url* selurl(char *urlname){
914 seturl(&url, urlname, current ? current->url->fullname : "");
916 message("selected: %s", urlstr(selection));
917 plgrabkb(cmd); /* for snarf */
920 void seturl(Url *url, char *urlname, char *base){
921 nstrcpy(url->reltext, urlname, sizeof(url->reltext));
922 nstrcpy(url->basename, base, sizeof(url->basename));
923 url->fullname[0] = 0;
927 Url *copyurl(Url *u){
929 v=emalloc(sizeof(Url));
933 void freeurl(Url *u){
938 * get the file at the given url
940 void geturl(char *urlname, int post, int plumb, int map){
941 int i, fd, typ, pfd[2];
946 if(*urlname == '#' && post < 0){
954 message("getting %s", selection->reltext);
955 esetcursor(&patientcurs);
957 if((fd=urlget(selection, post)) < 0){
961 message("getting %s", selection->fullname);
962 if(mothmode && !plumb)
969 message("unknown file type");
973 snprint(cmd, sizeof(cmd), "%s", urltofile(selection));
974 if(eenter("Save to", cmd, sizeof(cmd), &mouse) <= 0){
981 fd = pipeline(fd, "exec uhtml");
984 for(i=wwwtop-1; i>=0 && i!=(wwwtop-NWWW-1); i--){
986 n += countpix(w->pix);
987 if(n >= NPIXMB*1024*1024)
990 w = www(i = wwwtop++);
992 /* wait for the reader to finish the document */
993 while(!w->finished && !w->alldone){
1002 memset(w, 0, sizeof(*w));
1005 w->url=copyurl(current->url);
1007 w->url=copyurl(selection);
1010 gettext(w, fd, typ);
1011 if(rfork(RFPROC|RFMEM|RFNOWAIT) == 0){
1014 if(w->finished || w->alldone)
1017 write(kickpipe[1], "C", 1);
1021 plinitlist(list, PACKN|FILLX, genwww, 8, doprev);
1022 if(defdisplay) pldraw(list, screen);
1023 setcurrent(i, selection->tag);
1030 filter(fd, "exec page -w");
1037 void updtext(Www *w){
1040 if(defdisplay && w->gottitle==0 && w->title[0]!='\0')
1041 pldraw(list, screen);
1042 for(t=w->text;t;t=t->next){
1052 w->yoffs=plgetpostextview(text);
1053 plinittextview(text, PACKE|EXPAND, Pt(0, 0), w->text, dolink);
1054 plsetpostextview(text, w->yoffs);
1055 pldraw(text, screen);
1058 void finish(Www *w){
1060 write(kickpipe[1], "F", 1);
1064 mothon(Www *w, int on)
1069 if(w==0 || mothmode==on)
1072 message("moth mode!");
1076 * insert or remove artificial links to the href for
1077 * images that are also links
1079 for(t=w->text;t;t=t->next){
1081 if(a == nil || a->image == nil)
1087 t->flags &= ~PL_HOT;
1093 ap=emalloc(sizeof(Action));
1094 ap->link = strdup(a->link);
1095 plrtstr(&t->next, 0, 0, t->font, strdup("->"), PL_HOT, ap);
1109 void killpix(Www *w){
1112 if(w==0 || !w->finished && !w->alldone)
1114 for(t=w->text; t; t=t->next)
1121 void snarf(Panel *p){
1124 plputsnarf(urlstr(selection));
1127 message("no url selected");
1131 void paste(Panel *p){
1135 void hit3(int button, int item){
1147 current->yoffs=plgetpostextview(text);
1151 defdisplay=!defdisplay;
1152 plpack(root, screen->r);
1154 plinittextview(text, PACKE|EXPAND, Pt(0, 0), current->text, dolink);
1155 plsetpostextview(text, current->yoffs);
1157 pldraw(root, screen);
1160 mothon(current, !mothmode);
1173 message("no url selected");
1176 snprint(name, sizeof(name), "%s/hit.html", mkhome());
1177 fd=open(name, OWRITE);
1179 fd=create(name, OWRITE, 0666);
1181 message("can't open %s", name);
1184 fprint(fd, "<html><head><title>Hit List</title></head>\n");
1185 fprint(fd, "<body><h1>Hit list</h1>\n");
1188 fprint(fd, "<p><a href=\"%s\">%s</a>\n", urlstr(selection), urlstr(selection));
1192 snprint(name, sizeof(name), "file:%s/hit.html", mkhome());
1193 geturl(name, -1, 1, 0);