#include <plumb.h>
#include <cursor.h>
#include <panel.h>
+#include <regexp.h>
#include "mothra.h"
#include "rtext.h"
-int verbose=0; /* -v flag causes html errors to appear in error log */
+int debug=0;
+int verbose=0; /* -v flag causes html errors to be written to file-descriptor 2 */
int defdisplay=1; /* is the default (initial) display visible? */
Panel *root; /* the whole display */
Panel *alt; /* the alternate display */
Panel *alttext; /* the alternate text window */
Panel *cmd; /* command entry */
-Panel *curttl; /* label giving the title of the visible text */
Panel *cururl; /* label giving the url of the visible text */
Panel *list; /* list of previously acquired www pages */
Panel *msg; /* message display */
Panel *menu3; /* button 3 menu */
-Mouse mouse; /* current mouse data */
char mothra[] = "mothra!";
-Url defurl={
- "http://cat-v.org/",
- "",
- "http://cat-v.org/",
- "",
- "",
- HTML,
-};
-Url badurl={
- "",
- "",
- "No file loaded",
- "",
- "",
- HTML,
-};
Cursor patientcurs={
0, 0,
0x01, 0x80, 0x03, 0xC0, 0x07, 0xE0, 0x07, 0xe0,
0x37, 0xec, 0x17, 0xe8, 0x1b, 0xd8, 0x0e, 0x70,
0x0c, 0x30, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, }
};
-char *mtpt="/mnt/web";
+
Www *current=0;
Url *selection=0;
-int logfile;
int mothmode;
+int kickpipe[2];
+
void docmd(Panel *, char *);
void doprev(Panel *, int, int);
-void selurl(char *);
+char *urlstr(Url *);
void setcurrent(int, char *);
char *genwww(Panel *, int);
void updtext(Www *);
void dolink(Panel *, int, Rtext *);
void hit3(int, int);
+void mothon(Www *, int);
+void killpix(Www *w);
char *buttons[]={
"alt display",
"moth mode",
- "snarf url",
+ "snarf",
"paste",
+ "search",
"save hit",
"hit list",
"exit",
int wwwtop=0;
Www *www(int index){
- static Www a[1+NWWW];
- return &a[1+(index % NWWW)];
+ static Www a[NWWW];
+ return &a[index % NWWW];
}
int nwww(void){
return wwwtop<NWWW ? wwwtop : NWWW;
}
-void err(Display *, char *msg){
- fprint(2, "err: %s (%r)\n", msg);
- abort();
-}
int subpanel(Panel *obj, Panel *subj){
if(obj==0) return 0;
if(obj==subj) return 1;
* Make sure that the keyboard focus is on-screen, by adjusting it to
* be the cmd entry if necessary.
*/
-void adjkb(void){
+int adjkb(void){
Rtext *t;
int yoffs;
- extern Panel *pl_kbfocus; /* this is a secret panel library name */
- yoffs=text->r.min.y-plgetpostextview(text);
- for(t=current->text;t;t=t->next) if(!eqrect(t->r, Rect(0,0,0,0))){
- if(t->r.max.y+yoffs>text->r.max.y) break;
- if(t->r.min.y+yoffs>=text->r.min.y
- && t->b==0
- && subpanel(t->p, pl_kbfocus)) return;
+ if(current){
+ yoffs=text->r.min.y-plgetpostextview(text);
+ for(t=current->text;t;t=t->next) if(!eqrect(t->r, Rect(0,0,0,0))){
+ if(t->r.max.y+yoffs>=text->r.min.y
+ && t->r.min.y+yoffs<text->r.max.y
+ && t->b==0
+ && subpanel(t->p, plkbfocus))
+ return 1;
+ }
}
plgrabkb(cmd);
+ return 0;
}
void scrolltext(int dy, int whence)
if(s.pos.y > s.size.y)
s.pos.y = s.size.y;
plsetscroll(text, s);
- pldraw(root, screen);
}
void mkpanels(void){
- Panel *p, *bar;
+ Panel *p, *bar, *swap;
+
menu3=plmenu(0, 0, buttons, PACKN|FILLX, hit3);
root=plpopup(root, EXPAND, 0, 0, menu3);
p=plgroup(root, PACKN|FILLX);
bar=plscrollbar(p, PACKW);
list=pllist(p, PACKN|FILLX, genwww, 8, doprev);
plscroll(list, 0, bar);
- p=plgroup(root, PACKN|FILLX);
- pllabel(p, PACKW, "Title:");
- curttl=pllabel(p, PACKE|EXPAND, "Initializing");
- plplacelabel(curttl, PLACEW);
p=plgroup(root, PACKN|FILLX);
pllabel(p, PACKW, "Url:");
cururl=pllabel(p, PACKE|EXPAND, "---");
plplacelabel(cururl, PLACEW);
p=plgroup(root, PACKN|EXPAND);
- bar=plscrollbar(p, PACKW);
+ bar=plscrollbar(p, PACKW|USERFL);
text=pltextview(p, PACKE|EXPAND, Pt(0, 0), 0, dolink);
plscroll(text, 0, bar);
plgrabkb(cmd);
alt=plpopup(0, PACKE|EXPAND, 0, 0, menu3);
- bar=plscrollbar(alt, PACKW);
+ bar=plscrollbar(alt, PACKW|USERFL);
alttext=pltextview(alt, PACKE|EXPAND, Pt(0, 0), 0, dolink);
plscroll(alttext, 0, bar);
+
+ if(!defdisplay){
+ swap=root;
+ root=alt;
+ alt=swap;
+ swap=text;
+ text=alttext;
+ alttext=swap;
+ }
}
+int cohort = -1;
void killcohort(void){
int i;
for(i=0;i!=3;i++){ /* It's a long way to the kitchen */
- postnote(PNGROUP, getpid(), "kill\n");
+ postnote(PNGROUP, cohort, "kill\n");
sleep(1);
}
}
+void catch(void*, char*){
+ noted(NCONT);
+}
void dienow(void*, char*){
noted(NDFLT);
}
-int mkmfile(char *stem, int mode){
- char *henv;
- char filename[NNAME];
+
+char* mkhome(void){
+ static char *home; /* where to put files */
+ char *henv, *tmp;
int f;
- if(home[0]=='\0'){
+
+ if(home == nil){
henv=getenv("home");
if(henv){
- sprint(home, "%s/lib", henv);
- f=create(home, OREAD, DMDIR|0777);
+ tmp = smprint("%s/lib", henv);
+ f=create(tmp, OREAD, DMDIR|0777);
if(f!=-1) close(f);
- sprint(home, "%s/lib/mothra", henv);
+ free(tmp);
+
+ home = smprint("%s/lib/mothra", henv);
f=create(home, OREAD, DMDIR|0777);
if(f!=-1) close(f);
free(henv);
}
else
- strcpy(home, "/tmp");
+ home = strdup("/tmp");
+ }
+ return home;
+}
+
+void donecurs(void){
+ if(current && current->alldone==0)
+ esetcursor(&readingcurs);
+ else if(mothmode)
+ esetcursor(&mothcurs);
+ else
+ esetcursor(0);
+}
+
+void drawlock(int dolock){
+ static int ref = 0;
+ if(dolock){
+ if(ref++ == 0)
+ lockdisplay(display);
+ } else {
+ if(--ref == 0)
+ unlockdisplay(display);
}
- snprint(filename, sizeof(filename), "%s/%s", home, stem);
- f=create(filename, OWRITE, mode);
- if(f==-1)
- f=create(stem, OWRITE, mode);
- return f;
}
+
+void scrollto(char *tag);
+void search(void);
+
+extern char *mtpt; /* url */
+
void main(int argc, char *argv[]){
Event e;
- enum { Eplumb = 128 };
+ enum { Eplumb = 128, Ekick = 256 };
Plumbmsg *pm;
Www *new;
Action *a;
char *url;
- int errfile;
int i;
+
+ quotefmtinstall();
+ fmtinstall('U', Ufmt);
+
ARGBEGIN{
- case 'd': debug++; break;
+ case 'd': debug=1; break;
case 'v': verbose=1; break;
case 'm':
if(mtpt = ARGF())
break;
+ case 'a': defdisplay=0; break;
default: goto Usage;
}ARGEND
* so that we can stop all subprocesses with a note,
* and to isolate rendezvous from other processes
*/
- rfork(RFNOTEG|RFNAMEG|RFREND);
+ if(cohort=rfork(RFPROC|RFNOTEG|RFNAMEG|RFREND)){
+ atexit(killcohort);
+ notify(catch);
+ waitpid();
+ exits(0);
+ }
+ cohort = getpid();
atexit(killcohort);
+
switch(argc){
default:
Usage:
- fprint(2, "Usage: %s [-d] [-m mtpt] [url]\n", argv[0]);
+ fprint(2, "Usage: %s [-dva] [-m mtpt] [url]\n", argv0);
exits("usage");
case 0:
url=getenv("url");
- if(url==0 || url[0]=='\0')
- url=defurl.fullname;
break;
case 1: url=argv[0]; break;
}
- errfile=mkmfile("mothra.err", 0666);
- if(errfile!=-1){
- dup(errfile, 2);
- close(errfile);
- }
- logfile=mkmfile("mothra.log", 0666|DMAPPEND);
-
- initdraw(err,0,"mothra");
+ if(initdraw(0, 0, mothra) < 0)
+ sysfatal("initdraw: %r");
display->locking = 1;
chrwidth=stringwidth(font, "0");
pltabsize(chrwidth, 8*chrwidth);
einit(Emouse|Ekeyboard);
eplumb(Eplumb, "web");
- etimer(0, 1000);
+ if(pipe(kickpipe) < 0)
+ sysfatal("pipe: %r");
+ estart(Ekick, kickpipe[0], 256);
plinit(screen->depth);
if(debug) notify(dienow);
getfonts();
hrule=allocimage(display, Rect(0, 0, 2048, 5), screen->chan, 0, DWhite);
- if(hrule==0){
- fprint(2, "%s: can't allocimage!\n", argv[0]);
- exits("no mem");
- }
+ if(hrule==0)
+ sysfatal("can't allocimage!");
draw(hrule, Rect(0,1,1280,3), display->black, 0, ZP);
linespace=allocimage(display, Rect(0, 0, 2048, 5), screen->chan, 0, DWhite);
- if(linespace==0){
- fprint(2, "%s: can't allocimage!\n", argv[0]);
- exits("no mem");
- }
+ if(linespace==0)
+ sysfatal("can't allocimage!");
bullet=allocimage(display, Rect(0,0,25, 8), screen->chan, 0, DWhite);
fillellipse(bullet, Pt(4,4), 3, 3, display->black, ZP);
- new = www(-1);
- new->url=&badurl;
- strcpy(new->title, "See error message above");
- plrtstr(&new->text, 0, 0, font, "See error message above", 0, 0);
- new->alldone=1;
mkpanels();
-
unlockdisplay(display);
eresized(0);
- lockdisplay(display);
+ drawlock(1);
- geturl(url, GET, 0, 1, 0);
+ if(url && url[0])
+ geturl(url, -1, 1, 0);
- if(logfile==-1) message("Can't open log file");
mouse.buttons=0;
for(;;){
if(mouse.buttons==0 && current){
if(current->finished){
updtext(current);
+ if(current->url->tag[0])
+ scrollto(current->url->tag);
current->finished=0;
current->changed=0;
current->alldone=1;
message(mothra);
- if(mothmode==0)
- esetcursor(0);
- }
- else if(current->changed){
- updtext(current);
- current->changed=0;
+ donecurs();
}
}
- unlockdisplay(display);
+ flushimage(display, 1);
+ drawlock(0);
i=event(&e);
- lockdisplay(display);
+ drawlock(1);
switch(i){
+ case Ekick:
+ if(mouse.buttons==0 && current && current->changed){
+ if(!current->finished)
+ updtext(current);
+ current->changed=0;
+ }
+ break;
case Ekeyboard:
switch(e.kbdc){
default:
case Kend:
scrolltext(-text->size.y, 2);
break;
+ case Kack:
+ search();
+ break;
}
break;
case Emouse:
mouse=e.mouse;
- if(mouse.buttons > 1){
- mothmode = 0;
- esetcursor(current && current->alldone?0:&readingcurs);
- message(mothra);
+ if(mouse.buttons & (8|16) && ptinrect(mouse.xy, text->r)){
+ if(mouse.buttons & 8)
+ scrolltext(text->r.min.y - mouse.xy.y, 1);
+ else
+ scrolltext(mouse.xy.y - text->r.min.y, 1);
+ break;
}
- plmouse(root, e.mouse);
+ plmouse(root, &mouse);
break;
case Eplumb:
pm=e.v;
if(pm->ndata > 0)
- geturl(pm->data, GET, 0, 1, 0);
+ geturl(pm->data, -1, 1, 0);
plumbfree(pm);
break;
}
}
}
+Cursor confirmcursor={
+ 0, 0,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+
+ 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F,
+ 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C,
+ 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
+ 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90,
+};
+int confirm(int b){
+ Mouse down, up;
+ esetcursor(&confirmcursor);
+ do down=emouse(); while(!down.buttons);
+ do up=emouse(); while(up.buttons);
+ donecurs();
+ return down.buttons==(1<<(b-1));
+}
void message(char *s, ...){
static char buf[1024];
char *out;
void eresized(int new){
Rectangle r;
- lockdisplay(display);
+ drawlock(1);
if(new && getwindow(display, Refnone) == -1) {
fprint(2, "getwindow: %r\n");
exits("getwindow");
}
r=screen->r;
- plinitlabel(curttl, PACKE|EXPAND, "---");
- plinitlabel(cururl, PACKE|EXPAND, "---");
plpack(root, r);
- if(current){
- plinitlabel(curttl, PACKE|EXPAND, current->title);
- plinitlabel(cururl, PACKE|EXPAND, current->url->fullname);
- }
- draw(screen, r, display->white, 0, ZP);
+ plpack(alt, r);
+ pldraw(cmd, screen); /* put cmd box on screen for alt display */
pldraw(root, screen);
- unlockdisplay(display);
+ flushimage(display, 1);
+ drawlock(0);
}
void *emalloc(int n){
void *v;
v=malloc(n);
- if(v==0){
- fprint(2, "out of space\n");
- exits("no mem");
- }
+ if(v==0)
+ sysfatal("out of memory");
+ memset(v, 0, n);
+ setmalloctag(v, getcallerpc(&n));
return v;
}
-void *emallocz(int n, int z){
- void *v;
- v = emalloc(n);
- if(z)
- memset(v, 0, n);
- return v;
+void nstrcpy(char *to, char *from, int len){
+ strncpy(to, from, len);
+ to[len-1] = 0;
}
char *genwww(Panel *, int index){
static char buf[1024];
+ Www *w;
int i;
if(index >= nwww())
return 0;
i = wwwtop-index-1;
- snprint(buf, sizeof(buf), "%2d %s", i+1, www(i)->title);
+ w = www(i);
+ if(!w->url)
+ return 0;
+ if(w->title[0]!='\0'){
+ w->gottitle=1;
+ snprint(buf, sizeof(buf), "%2d %s", i+1, w->title);
+ } else
+ snprint(buf, sizeof(buf), "%2d %s", i+1, urlstr(w->url));
return buf;
}
-void donecurs(void){
- if(mothmode)
- esetcursor(current && current->alldone?0:&mothcurs);
- else
- esetcursor(current && current->alldone?0:&readingcurs);
+void scrollto(char *tag){
+ Rtext *tp;
+ Action *ap;
+ if(current == nil || text == nil)
+ return;
+ if(tag && tag[0]){
+ for(tp=current->text;tp;tp=tp->next){
+ ap=tp->user;
+ if(ap && ap->name && strcmp(ap->name, tag)==0){
+ current->yoffs=tp->topy;
+ break;
+ }
+ }
+ }
+ plsetpostextview(text, current->yoffs);
+ flushimage(display, 1);
}
/*
* selected text should be a url.
- * get the document, scroll to the given tag
*/
void setcurrent(int index, char *tag){
Www *new;
- Rtext *tp;
- Action *ap;
int i;
new=www(index);
if(new==current && (tag==0 || tag[0]==0)) return;
if(current)
current->yoffs=plgetpostextview(text);
current=new;
- plinitlabel(curttl, PACKE|EXPAND, current->title);
- if(defdisplay) pldraw(curttl, screen);
plinitlabel(cururl, PACKE|EXPAND, current->url->fullname);
if(defdisplay) pldraw(cururl, screen);
plinittextview(text, PACKE|EXPAND, Pt(0, 0), current->text, dolink);
- if(tag && tag[0]){
- for(tp=current->text;tp;tp=tp->next){
- ap=tp->user;
- if(ap && ap->name && strcmp(ap->name, tag)==0){
- current->yoffs=tp->topy;
- break;
- }
- }
+ scrollto(tag);
+ if((i = open("/dev/label", OWRITE)) >= 0){
+ fprint(i, "%s %s", mothra, current->url->fullname);
+ close(i);
}
- plsetpostextview(text, current->yoffs);
donecurs();
- flushimage(display, 1);
}
char *arg(char *s){
do ++s; while(*s==' ' || *s=='\t');
return s;
}
-void save(Url *url, char *name){
- int ofd, ifd, n;
- char buf[4096];
- ofd=create(name, OWRITE, 0666);
- if(ofd==-1){
+void save(int ifd, char *name){
+ char buf[NNAME+64];
+ int cfd, ofd;
+ if(ifd < 0){
message("save: %s: %r", name);
return;
}
- esetcursor(&patientcurs);
- ifd=urlopen(url, GET, 0);
- donecurs();
- if(ifd==-1){
- message("save: %s: %r", selection->fullname);
- close(ofd);
+ ofd=create(name, OWRITE, 0666);
+ if(ofd < 0){
+ message("save: %s: %r", name);
+ return;
}
- switch(rfork(RFNOTEG|RFFDG|RFPROC|RFNOWAIT)){
+ switch(rfork(RFNOTEG|RFNAMEG|RFFDG|RFMEM|RFPROC|RFNOWAIT)){
case -1:
- message("Can't fork -- please wait");
- esetcursor(&patientcurs);
- while((n=read(ifd, buf, 4096))>0)
- write(ofd, buf, n);
- donecurs();
+ message("Can't fork: %r");
break;
case 0:
- while((n=read(ifd, buf, 4096))>0)
- write(ofd, buf, n);
- if(n==-1) fprint(2, "save: %s: %r\n", url->fullname);
- _exits(0);
+ dup(ifd, 0);
+ close(ifd);
+ dup(ofd, 1);
+ close(ofd);
+
+ snprint(buf, sizeof(buf),
+ "{tput -p || cat} |[2] {aux/statusmsg -k %q >/dev/null || cat >/dev/null}", name);
+ execl("/bin/rc", "rc", "-c", buf, nil);
+ exits("exec");
}
close(ifd);
close(ofd);
+ donecurs();
}
void screendump(char *name, int full){
Image *b;
int fd;
- fd=create(name, OWRITE|OTRUNC, 0666);
+ fd=create(name, OWRITE, 0666);
if(fd==-1){
message("can't create %s", name);
return;
close(fd);
}
+/*
+ * convert a url into a local file name.
+ */
+char *urltofile(Url *url){
+ char *name, *slash;
+ if(url == nil)
+ return nil;
+ if(url->fullname[0] || url->reltext[0])
+ name = urlstr(url);
+ else
+ name = "/";
+ if(slash = strrchr(name, '/'))
+ name = slash+1;
+ if(name[0] == 0)
+ name = "index";
+ return name;
+}
+
/*
* user typed a command.
*/
void docmd(Panel *p, char *s){
+ char buf[NNAME];
+ int c;
+
USED(p);
while(*s==' ' || *s=='\t') s++;
/*
* Non-command does a get on the url
*/
if(s[0]!='\0' && s[1]!='\0' && s[1]!=' ')
- geturl(s, GET, 0, 1, 0);
- else switch(s[0]){
+ geturl(s, -1, 0, 0);
+ else switch(c = s[0]){
default:
- message("Unknown command %s, type h for help", s);
+ message("Unknown command %s", s);
break;
case 'a':
s = arg(s);
case 'g':
s = arg(s);
if(*s=='\0'){
+ case 'r':
if(selection)
- geturl(selection->fullname, GET, 0, 1, 0);
+ s = urlstr(selection);
else
message("no url selected");
}
- else geturl(s, GET, 0, 1, 0);
+ geturl(s, -1, 0, 0);
break;
case 'j':
s = arg(s);
else
message("Usage: j index");
break;
- case 'r':
- s = arg(s);
- if(*s=='\0' && selection)
- geturl(selection->fullname, GET, 0, 0, 0);
+ case 'm':
+ mothon(current, !mothmode);
break;
- case 'W':
- s = arg(s);
- if(s=='\0'){
- message("Usage: W file");
- break;
- }
- screendump(s, 1);
+ case 'k':
+ killpix(current);
break;
case 'w':
+ case 'W':
s = arg(s);
- if(s=='\0'){
- message("Usage: w file");
- break;
+ if(s==0 || *s=='\0'){
+ snprint(buf, sizeof(buf), "dump.bit");
+ if(eenter("Screendump to", buf, sizeof(buf), &mouse) <= 0)
+ break;
+ s = buf;
}
- screendump(s, 0);
+ screendump(s, c == 'W');
break;
case 's':
s = arg(s);
- if(*s=='\0'){
- if(selection){
- s=strrchr(selection->fullname, '/');
- if(s) s++;
- }
- if(s==0 || *s=='\0'){
- message("Usage: s file");
+ if(!selection){
+ message("no url selected");
+ break;
+ }
+ if(s==0 || *s=='\0'){
+ snprint(buf, sizeof(buf), "%s", urltofile(selection));
+ if(eenter("Save to", buf, sizeof(buf), &mouse) <= 0)
break;
- }
+ s = buf;
}
- save(selection, s);
+ save(urlget(selection, -1), s);
break;
case 'q':
- draw(screen, screen->r, display->white, 0, ZP);
exits(0);
}
plinitentry(cmd, EXPAND, 0, "", docmd);
- if(defdisplay) pldraw(cmd, screen);
+ pldraw(root, screen);
}
+
+void search(void){
+ static char last[256];
+ char buf[256];
+ Reprog *re;
+ Rtext *tp;
+
+ for(;;){
+ if(current == nil || current->text == nil || text == nil)
+ return;
+ strncpy(buf, last, sizeof(buf)-1);
+ if(eenter("Search for", buf, sizeof(buf), &mouse) <= 0)
+ return;
+ re = regcompnl(buf);
+ if(re == nil)
+ return;
+ strncpy(last, buf, sizeof(buf)-1);
+ for(tp=current->text;tp;tp=tp->next)
+ if(tp->flags & PL_SEL)
+ break;
+ if(tp == nil)
+ tp = current->text;
+ else {
+ tp->flags &= ~PL_SEL;
+ tp = tp->next;
+ }
+ while(tp != nil){
+ tp->flags &= ~PL_SEL;
+ if(tp->text && *tp->text)
+ if(regexec(re, tp->text, nil, 0)){
+ tp->flags |= PL_SEL;
+ plsetpostextview(text, tp->topy);
+ break;
+ }
+ tp = tp->next;
+ }
+ free(re);
+ updtext(current);
+ }
+}
+
void hiturl(int buttons, char *url, int map){
switch(buttons){
- case 1: geturl(url, GET, 0, 1, map); break;
+ case 1: geturl(url, -1, 0, map); break;
case 2: selurl(url); break;
case 4: message("Button 3 hit on url can't happen!"); break;
}
}
+
/*
* user selected from the list of available pages
*/
}
}
-/*
- * convert a url into a local file name.
- */
-char *urltofile(char *url){
- static char file[128];
- if(strrchr(url, '/')){
- snprint(file, sizeof(file), "%s", strrchr(url, '/')+1);
- if(file[0]==0)
- strcpy(file, "index");
- }else
- snprint(file, sizeof(file), "%s", url);
- return file;
-}
/*
* Follow an html link
*/
void dolink(Panel *p, int buttons, Rtext *word){
- char file[128], mapurl[NNAME];
- Action *a;
- Url u;
+ char *file, mapurl[NNAME];
Point coord;
- int fd, yoffs;
- USED(p);
+ int yoffs;
+ Action *a;
+
+ /* really a button, hit it */
+ if(word->p != nil && word->p != p && strcmp(word->p->kind, "button") == 0){
+ extern void pl_buttonhit(Panel *p, int buttons, int check);
+ pl_buttonhit(word->p, buttons, 0);
+ return;
+ }
+
a=word->user;
- if(mothmode && a){
- if(a->image){
- seturl(&u, a->image, current->url->fullname);
- snprint(file, sizeof(file), "%s", urltofile(a->image));
- }else{
- seturl(&u, a->link, current->url->fullname);
- snprint(file, sizeof(file), "%s", urltofile(a->link));
- }
- save(&u, file);
- message("saved %s", file);
- esetcursor(&mothcurs);
- }else if(a && a->link){
+ if(a == nil || (a->link == nil && a->image == nil))
+ return;
+ if(mothmode)
+ hiturl(buttons, a->image ? a->image : a->link, 0);
+ else if(a->link){
if(a->ismap){
yoffs=plgetpostextview(p);
coord=subpt(subpt(mouse.xy, word->r.min), p->r.min);
snprint(mapurl, sizeof(mapurl), "%s?%d,%d", a->link, coord.x, coord.y+yoffs);
hiturl(buttons, mapurl, 1);
- }else
+ } else
hiturl(buttons, a->link, 0);
}
}
-void filter(char *cmd, int fd){
- flushimage(display, 1);
- switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
+
+void filter(int fd, char *cmd){
+ switch(rfork(RFFDG|RFPROC|RFMEM|RFREND|RFNOWAIT|RFNOTEG)){
case -1:
message("Can't fork!");
break;
case 0:
- close(0);
- dup(fd, 0);
- close(fd);
+ dupfds(fd, 1, 2, -1);
execl("/bin/rc", "rc", "-c", cmd, 0);
- message("Can't exec /bin/rc!");
_exits(0);
- default:
- break;
}
close(fd);
}
void gettext(Www *w, int fd, int type){
- flushimage(display, 1);
- switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFMEM)){
+ switch(rfork(RFFDG|RFPROC|RFMEM|RFNOWAIT)){
case -1:
message("Can't fork, please wait");
- if(type==HTML)
- plrdhtml(w->url->fullname, fd, w);
- else
- plrdplain(w->url->fullname, fd, w);
break;
case 0:
if(type==HTML)
plrtfree(tt);
}
-void popwin(char *cmd){
- flushimage(display, 1);
- switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
- case -1:
- message("sorry, can't fork to %s", cmd);
- break;
- case 0:
- execl("/bin/window", "window", "100 100 800 800", "rc", "-c", cmd, 0);
- _exits(0);
- }
-}
-
-int readstr(char *buf, int nbuf, char *base, char *name)
+void
+dupfds(int fd, ...)
{
- char path[128];
- int n, fd;
-
- snprint(path, sizeof path, "%s/%s", base, name);
- if((fd = open(path, OREAD)) < 0){
- ErrOut:
- memset(buf, 0, nbuf);
- return 0;
- }
- n = read(fd, buf, nbuf-1);
- close(fd);
- if(n <= 0){
- close(fd);
- goto ErrOut;
- }
- buf[n] = 0;
- return n;
-}
-
-int fileurlopen(Url *url){
- char *rel, *base, *x;
- int fd;
-
- rel = base = nil;
- if(cistrncmp(url->basename, "file:", 5) == 0)
- base = url->basename+5;
- if(cistrncmp(url->reltext, "file:", 5) == 0)
- rel = url->reltext+5;
- if(rel == nil && base == nil)
- return -1;
- if(rel == nil)
- rel = url->reltext;
- if(base && base[0] == '/' && rel[0] != '/'){
- if(x = strrchr(base, '/'))
- *x = 0;
- snprint(url->fullname, sizeof(url->fullname), "%s/%s", base, rel);
- if(x) *x = '/';
- }else
- snprint(url->fullname, sizeof(url->fullname), "%s", rel);
- url->tag[0] = 0;
- if(x = strrchr(url->fullname, '#')){
- *x++ = 0;
- strncpy(url->tag, x, sizeof(url->tag));
- }
- fd = open(cleanname(url->fullname), OREAD);
- if(fd < 0)
- return -1;
- memset(url->fullname, 0, sizeof(url->fullname));
- strcpy(url->fullname, "file:");
- fd2path(fd, url->fullname+5, sizeof(url->fullname)-6);
- url->type = content2type("application/octet-stream", url->fullname);
- return fd;
-}
-
-int urlopen(Url *url, int method, char *body){
- int conn, ctlfd, fd, n;
- char buf[1024+1], *p;
+ int mfd, n, i;
+ va_list arg;
+ Dir *dir;
- if(debug) fprint(2, "urlopen %s (%s)\n", url->reltext, url->basename);
-
- if(method == GET)
- if((fd = fileurlopen(url)) >= 0)
- return fd;
-
- snprint(buf, sizeof buf, "%s/clone", mtpt);
- if((ctlfd = open(buf, ORDWR)) < 0)
- return -1;
- if((n = read(ctlfd, buf, sizeof buf-1)) <= 0){
- close(ctlfd);
- return -1;
- }
- buf[n] = 0;
- conn = atoi(buf);
-
- if(url->basename[0]){
- n = snprint(buf, sizeof buf, "baseurl %s", url->basename);
- write(ctlfd, buf, n);
- }
- n = snprint(buf, sizeof buf, "url %s", url->reltext);
- if(write(ctlfd, buf, n) != n){
- ErrOut:
- close(ctlfd);
- return -1;
- }
-
- if(method == POST && body){
- snprint(buf, sizeof buf, "%s/%d/postbody", mtpt, conn);
- if((fd = open(buf, OWRITE)) < 0)
- goto ErrOut;
- n = strlen(body);
- if(write(fd, body, n) != n){
+ va_start(arg, fd);
+ for(mfd = 0; fd >= 0; fd = va_arg(arg, int), mfd++)
+ if(fd != mfd)
+ if(dup(fd, mfd) < 0)
+ sysfatal("dup: %r");
+ va_end(arg);
+ if((fd = open("/fd", OREAD)) < 0)
+ sysfatal("open: %r");
+ n = dirreadall(fd, &dir);
+ for(i=0; i<n; i++){
+ if(strstr(dir[i].name, "ctl"))
+ continue;
+ fd = atoi(dir[i].name);
+ if(fd >= mfd)
close(fd);
- goto ErrOut;
- }
- close(fd);
}
-
- snprint(buf, sizeof buf, "%s/%d/body", mtpt, conn);
- if((fd = open(buf, OREAD)) < 0)
- goto ErrOut;
-
- snprint(buf, sizeof buf, "%s/%d/parsed", mtpt, conn);
- readstr(url->fullname, sizeof(url->fullname), buf, "url");
- readstr(url->tag, sizeof(url->tag), buf, "fragment");
-
- snprint(buf, sizeof buf, "%s/%d", mtpt, conn);
- readstr(buf, sizeof buf, buf, "contenttype");
- url->charset[0] = 0;
- if(p = cistrstr(buf, "charset=")){
- p += 8;
- strncpy(url->charset, p, sizeof(url->charset));
- if(p = strchr(url->charset, ';'))
- *p = 0;
- }
- if(p = strchr(buf, ';'))
- *p = 0;
- url->type = content2type(buf, url->fullname);
-
- close(ctlfd);
- return fd;
+ free(dir);
}
-int pipeline(char *cmd, int fd)
+int pipeline(int fd, char *fmt, ...)
{
+ char buf[80], *argv[4];
+ va_list arg;
int pfd[2];
- if(pipe(pfd)==-1){
-Err:
+ va_start(arg, fmt);
+ vsnprint(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+
+ if(pipe(pfd) < 0){
+ Err:
close(fd);
- werrstr("pipeline for %s failed: %r", cmd);
+ werrstr("pipeline for %s failed: %r", buf);
return -1;
}
- switch(fork()){
+ switch(rfork(RFPROC|RFMEM|RFFDG|RFREND|RFNOWAIT)){
case -1:
close(pfd[0]);
close(pfd[1]);
goto Err;
case 0:
- dup(fd, 0);
- dup(pfd[0], 1);
- close(pfd[0]);
- close(pfd[1]);
- execl("/bin/rc", "rc", "-c", cmd, 0);
+ dupfds(fd, pfd[1], 2, -1);
+ argv[0] = "rc";
+ argv[1] = "-c";
+ argv[2] = buf;
+ argv[3] = nil;
+ exec("/bin/rc", argv);
_exits(0);
}
- close(pfd[0]);
close(fd);
- return pfd[1];
+ close(pfd[1]);
+ return pfd[0];
}
-/*
- * select the file at the given url
- */
-void selurl(char *urlname){
+char*
+urlstr(Url *url){
+ if(url->fullname[0])
+ return url->fullname;
+ return url->reltext;
+}
+Url* selurl(char *urlname){
static Url url;
- seturl(&url, urlname, current?
- current->url->fullname :
- defurl.fullname);
+ seturl(&url, urlname, current ? current->url->fullname : "");
selection=&url;
- message("selected: %s", selection->fullname[0] ? selection->fullname : selection->reltext);
+ message("selected: %s", urlstr(selection));
+ plgrabkb(cmd); /* for snarf */
+ return selection;
}
void seturl(Url *url, char *urlname, char *base){
- strncpy(url->reltext, urlname, sizeof(url->reltext));
- strncpy(url->basename, base, sizeof(url->basename));
+ nstrcpy(url->reltext, urlname, sizeof(url->reltext));
+ nstrcpy(url->basename, base, sizeof(url->basename));
url->fullname[0] = 0;
- url->charset[0] = 0;
url->tag[0] = 0;
- url->type = 0;
url->map = 0;
}
Url *copyurl(Url *u){
return v;
}
void freeurl(Url *u){
- if(u!=&defurl && u!=&badurl)
- free(u);
+ free(u);
}
/*
* get the file at the given url
*/
-void geturl(char *urlname, int method, char *body, int cache, int map){
- int i, fd;
+void geturl(char *urlname, int post, int plumb, int map){
+ int i, fd, typ, pfd[2];
char cmd[NNAME];
- int pfd[2];
+ ulong n;
Www *w;
+ if(*urlname == '#' && post < 0){
+ scrollto(urlname+1);
+ return;
+ }
+
selurl(urlname);
selection->map=map;
message("getting %s", selection->reltext);
esetcursor(&patientcurs);
for(;;){
- if((fd=urlopen(selection, method, body)) < 0){
+ if((fd=urlget(selection, post)) < 0){
message("%r");
- setcurrent(-1, 0);
break;
}
message("getting %s", selection->fullname);
- if(selection->type&COMPRESS)
- fd=pipeline("/bin/uncompress", fd);
- else if(selection->type&GUNZIP)
- fd=pipeline("/bin/gunzip", fd);
- switch(selection->type&~COMPRESSION){
+ if(mothmode && !plumb)
+ typ = -1;
+ else
+ typ = snooptype(fd);
+ switch(typ){
default:
- message("Bad type %x in geturl", selection->type);
+ if(plumb){
+ message("unknown file type");
+ close(fd);
+ break;
+ }
+ snprint(cmd, sizeof(cmd), "%s", urltofile(selection));
+ if(eenter("Save to", cmd, sizeof(cmd), &mouse) <= 0){
+ close(fd);
+ break;
+ }
+ save(fd, cmd);
break;
case HTML:
- snprint(cmd, sizeof(cmd), selection->charset[0] ?
- "/bin/uhtml -c %s" : "/bin/uhtml", selection->charset);
- fd = pipeline(cmd, fd);
+ fd = pipeline(fd, "exec uhtml");
case PLAIN:
+ n=0;
+ for(i=wwwtop-1; i>=0 && i!=(wwwtop-NWWW-1); i--){
+ w = www(i);
+ n += countpix(w->pix);
+ if(n >= NPIXMB*1024*1024)
+ killpix(w);
+ }
w = www(i = wwwtop++);
if(i >= NWWW){
- extern void freeform(void *p);
- extern void freepix(void *p);
-
/* wait for the reader to finish the document */
while(!w->finished && !w->alldone){
- unlockdisplay(display);
+ drawlock(0);
sleep(10);
- lockdisplay(display);
+ drawlock(1);
}
-
freetext(w->text);
freeform(w->form);
freepix(w->pix);
w->url=copyurl(selection);
w->finished = 0;
w->alldone = 0;
- gettext(w, fd, selection->type&~COMPRESSION);
+ gettext(w, fd, typ);
+ if(rfork(RFPROC|RFMEM|RFNOWAIT) == 0){
+ for(;;){
+ sleep(1000);
+ if(w->finished || w->alldone)
+ break;
+ if(w->changed)
+ write(kickpipe[1], "C", 1);
+ }
+ _exits(0);
+ }
plinitlist(list, PACKN|FILLX, genwww, 8, doprev);
if(defdisplay) pldraw(list, screen);
setcurrent(i, selection->tag);
break;
- case POSTSCRIPT:
case GIF:
case JPEG:
case PNG:
- case PDF:
- filter("page -w", fd);
- break;
- case TIFF:
- filter("/sys/lib/mothra/tiffview", fd);
- break;
- case XBM:
- filter("fb/xbm2pic|fb/9v", fd);
+ case BMP:
+ case PAGE:
+ filter(fd, "exec page -w");
break;
}
break;
void updtext(Www *w){
Rtext *t;
Action *a;
+ if(defdisplay && w->gottitle==0 && w->title[0]!='\0')
+ pldraw(list, screen);
for(t=w->text;t;t=t->next){
a=t->user;
if(a){
a->field=0;
}
}
+ if(w != current)
+ return;
w->yoffs=plgetpostextview(text);
plinittextview(text, PACKE|EXPAND, Pt(0, 0), w->text, dolink);
plsetpostextview(text, w->yoffs);
- pldraw(root, screen);
+ pldraw(text, screen);
}
-Cursor confirmcursor={
- 0, 0,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x0E, 0x07, 0x1F, 0x03, 0x17, 0x73, 0x6F,
- 0xFB, 0xCE, 0xDB, 0x8C, 0xDB, 0xC0, 0xFB, 0x6C,
- 0x77, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
- 0x94, 0xA6, 0x63, 0x3C, 0x63, 0x18, 0x94, 0x90,
-};
-int confirm(int b){
- Mouse down, up;
- esetcursor(&confirmcursor);
- do down=emouse(); while(!down.buttons);
- do up=emouse(); while(up.buttons);
+void finish(Www *w){
+ w->finished = 1;
+ write(kickpipe[1], "F", 1);
+}
+
+void
+mothon(Www *w, int on)
+{
+ Rtext *t, *x;
+ Action *a, *ap;
+
+ if(w==0 || mothmode==on)
+ return;
+ if(mothmode = on)
+ message("moth mode!");
+ else
+ message(mothra);
+ /*
+ * insert or remove artificial links to the href for
+ * images that are also links
+ */
+ for(t=w->text;t;t=t->next){
+ a=t->user;
+ if(a == nil || a->image == nil)
+ continue;
+ if(a->link == nil){
+ if(on)
+ t->flags |= PL_HOT;
+ else
+ t->flags &= ~PL_HOT;
+ continue;
+ }
+ x = t->next;
+ if(on){
+ t->next = nil;
+ ap=emalloc(sizeof(Action));
+ ap->link = strdup(a->link);
+ plrtstr(&t->next, 0, 0, t->font, strdup("->"), PL_HOT, ap);
+ t->next->next = x;
+ } else {
+ if(x) {
+ t->next = x->next;
+ x->next = nil;
+ freetext(x);
+ }
+ }
+ }
+ updtext(w);
donecurs();
- return down.buttons==(1<<(b-1));
+}
+
+void killpix(Www *w){
+ Rtext *t;
+
+ if(w==0 || !w->finished && !w->alldone)
+ return;
+ for(t=w->text; t; t=t->next)
+ if(t->b && t->user)
+ t->b=0;
+ freepix(w->pix);
+ w->pix=0;
+ updtext(w);
}
void snarf(Panel *p){
- int fd;
- fd=create("/dev/snarf", OWRITE, 0666);
- if(fd>=0){
- fprint(fd, "%s", selection->fullname[0] ? selection->fullname : selection->reltext);
- close(fd);
- }
+ if(p==0 || p==cmd){
+ if(selection){
+ plputsnarf(urlstr(selection));
+ plsnarf(text);
+ }else
+ message("no url selected");
+ }else
+ plsnarf(p);
}
void paste(Panel *p){
- char buf[1024];
- int n, len, fd;
- fd=open("/dev/snarf", OREAD);
- strncpy(buf, plentryval(p), sizeof(buf));
- len=strlen(buf);
- n=read(fd, buf+len, sizeof(buf)-len-1);
- if(n>0){
- buf[len+n]='\0';
- plinitentry(cmd, PACKE|EXPAND, 0, buf, docmd);
- pldraw(cmd, screen);
- }
- close(fd);
+ if(p==0) p=cmd;
+ plpaste(p);
}
void hit3(int button, int item){
char name[NNAME];
swap=root;
root=alt;
alt=swap;
- current->yoffs=plgetpostextview(text);
+ if(current)
+ current->yoffs=plgetpostextview(text);
swap=text;
text=alttext;
alttext=swap;
defdisplay=!defdisplay;
plpack(root, screen->r);
- plinittextview(text, PACKE|EXPAND, Pt(0, 0), current->text, dolink);
- plsetpostextview(text, current->yoffs);
+ if(current){
+ plinittextview(text, PACKE|EXPAND, Pt(0, 0), current->text, dolink);
+ plsetpostextview(text, current->yoffs);
+ }
pldraw(root, screen);
break;
case 1:
- mothmode = 1;
- message("moth mode");
- esetcursor(&mothcurs);
+ mothon(current, !mothmode);
break;
case 2:
- snarf(cmd);
+ snarf(plkbfocus);
break;
case 3:
- paste(cmd);
+ paste(plkbfocus);
break;
case 4:
- snprint(name, sizeof(name), "%s/hit.html", home);
+ search();
+ break;
+ case 5:
+ if(!selection){
+ message("no url selected");
+ break;
+ }
+ snprint(name, sizeof(name), "%s/hit.html", mkhome());
fd=open(name, OWRITE);
if(fd==-1){
fd=create(name, OWRITE, 0666);
message("can't open %s", name);
return;
}
- fprint(fd, "<head><title>Hit List</title></head>\n");
+ fprint(fd, "<html><head><title>Hit List</title></head>\n");
fprint(fd, "<body><h1>Hit list</h1>\n");
}
seek(fd, 0, 2);
- fprint(fd, "<p><a href=\"%s\">%s</a>\n",
- selection->fullname, selection->fullname);
+ fprint(fd, "<p><a href=\"%s\">%s</a>\n", urlstr(selection), urlstr(selection));
close(fd);
break;
- case 5:
- snprint(name, sizeof(name), "file:%s/hit.html", home);
- geturl(name, GET, 0, 1, 0);
- break;
case 6:
- if(confirm(3)){
- draw(screen, screen->r, display->white, 0, ZP);
+ snprint(name, sizeof(name), "file:%s/hit.html", mkhome());
+ geturl(name, -1, 1, 0);
+ break;
+ case 7:
+ if(confirm(3))
exits(0);
- }
break;
}
}