"http://cat-v.org/",
"",
"",
- HTML,
};
Url badurl={
"",
"No file loaded",
"",
"",
- HTML,
};
Cursor patientcurs={
0, 0,
0x0E, 0x60, 0x1C, 0x00, 0x38, 0x00, 0x71, 0xB6,
0x61, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
+Cursor mothcurs={
+ {-7, -7},
+ {0x00, 0x00, 0x60, 0x06, 0xf8, 0x1f, 0xfc, 0x3f,
+ 0xfe, 0x7f, 0xff, 0xff, 0x7f, 0xfe, 0x7f, 0xfe,
+ 0x7f, 0xfe, 0x3f, 0xfc, 0x3f, 0xfc, 0x1f, 0xf8,
+ 0x1f, 0xf8, 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00, },
+ {0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x58, 0x1a,
+ 0x5c, 0x3a, 0x64, 0x26, 0x27, 0xe4, 0x37, 0xec,
+ 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;
void docmd(Panel *, char *);
void doprev(Panel *, int, int);
+char *urlstr(Url *);
void selurl(char *);
void setcurrent(int, char *);
char *genwww(Panel *, int);
void hit3(int, int);
char *buttons[]={
"alt display",
+ "moth mode",
"snarf url",
"paste",
- "save url",
"save hit",
"hit list",
"exit",
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.max.y) break;
+ if(t->r.min.y+yoffs>=text->r.min.y
+ && t->b==0
+ && subpanel(t->p, pl_kbfocus)) return;
+ }
}
plgrabkb(cmd);
}
f=create(stem, OWRITE, mode);
return f;
}
+
+void donecurs(void){
+ if(current == nil)
+ return;
+ if(mothmode)
+ esetcursor(&mothcurs);
+ else
+ esetcursor(current->alldone ? 0 : &readingcurs);
+}
+
+void scrollto(char *tag);
+
void main(int argc, char *argv[]){
Event e;
enum { Eplumb = 128 };
Plumbmsg *pm;
Www *new;
+ Action *a;
char *url;
int errfile;
int i;
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);
- esetcursor(0);
+ donecurs();
}
else if(current->changed){
updtext(current);
}
}
}
+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;
plinitlabel(curttl, PACKE|EXPAND, "---");
plinitlabel(cururl, PACKE|EXPAND, "---");
plpack(root, r);
+ plpack(alt, r);
if(current){
plinitlabel(curttl, PACKE|EXPAND, current->title);
plinitlabel(cururl, PACKE|EXPAND, current->url->fullname);
return buf;
}
-void donecurs(void){
- 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;
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;
- }
- }
- }
- plsetpostextview(text, current->yoffs);
+ scrollto(tag);
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;
+void save(int ifd, char *name){
char buf[4096];
- ofd=create(name, OWRITE, 0666);
- if(ofd==-1){
+ int 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, OEXCL|OWRITE, 0666);
+ if(ofd < 0){
+ message("save: %s: %r", name);
+ return;
}
- switch(rfork(RFNOTEG|RFFDG|RFPROC|RFNOWAIT)){
+ switch(rfork(RFNOTEG|RFNAMEG|RFFDG|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);
+ snprint(buf, sizeof(buf), "-pid %d", getpid());
+ if(newwindow(buf) != -1){
+ int blk, cfd, n;
+ vlong off;
+
+ close(1); open("/dev/cons", OWRITE);
+ if((cfd = open("/dev/label", OWRITE)) >= 0){
+ fprint(cfd, "save %s", name);
+ close(cfd);
+ }
+ if((cfd = open("/dev/wctl", OWRITE)) >= 0){
+ fprint(cfd, "scroll\n");
+ close(cfd);
+ }
+ off = 0;
+ blk = 0;
+ werrstr("");
+ for(;;){
+ if((blk++ % 4) == 0){
+ if(off > 0)
+ print("\n");
+ print("%s: ", name);
+ }
+ if((n=read(ifd, buf, sizeof(buf))) <= 0)
+ break;
+ if(write(ofd, buf, n) != n)
+ break;
+ off += n;
+ print("%lldK... ", off/1024);
+ }
+ print("%r\n");
+ }
+ exits(0);
}
close(ifd);
close(ofd);
+ donecurs();
}
void screendump(char *name, int full){
Image *b;
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.
*/
* Non-command does a get on the url
*/
if(s[0]!='\0' && s[1]!='\0' && s[1]!=' ')
- geturl(s, GET, 0, 1, 0);
+ geturl(s, GET, 0, 0, 0);
else switch(s[0]){
default:
message("Unknown command %s, type h for help", 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, GET, 0, 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);
- break;
case 'W':
s = arg(s);
if(s=='\0'){
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");
- break;
- }
+ if(!selection){
+ message("no url selected");
+ break;
+ }
+ if(s==0 || *s=='\0')
+ s = urltofile(selection);
+ if(s==0 || *s=='\0'){
+ message("Usage: s file");
+ break;
}
- save(selection, s);
+ save(urlopen(selection, GET, 0), s);
break;
case 'q':
draw(screen, screen->r, display->white, 0, ZP);
}
void hiturl(int buttons, char *url, int map){
switch(buttons){
- case 1: geturl(url, GET, 0, 1, map); break;
+ case 1: geturl(url, GET, 0, 0, map); break;
case 2: selurl(url); break;
case 4: message("Button 3 hit on url can't happen!"); break;
}
* Follow an html link
*/
void dolink(Panel *p, int buttons, Rtext *word){
- char mapurl[NNAME];
- Action *a;
+ char *file, mapurl[NNAME];
Point coord;
int yoffs;
- USED(p);
+ Action *a;
+
a=word->user;
- if(a && 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
- hiturl(buttons, a->link, 0);
- }
+ if(a == nil || a->image == nil && a->link == nil)
+ return;
+ if(mothmode)
+ hiturl(buttons, a->image ? a->image : a->link, 0);
+ else 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
+ hiturl(buttons, a->link ? a->link : a->image, 0);
}
+
void filter(char *cmd, int fd){
flushimage(display, 1);
switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFMEM)){
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)
-{
- 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;
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 readstr(char *buf, int nbuf, char *base, char *name){
+ char path[128];
+ int n, fd;
+
+ n = 0;
+ snprint(path, sizeof path, "%s/%s", base, name);
+ if((fd = open(path, OREAD)) >= 0){
+ if((n = read(fd, buf, nbuf-1)) < 0)
+ n = 0;
+ close(fd);
+ }
+ buf[n] = 0;
+ return n;
+}
+
int urlopen(Url *url, int method, char *body){
int conn, ctlfd, fd, n;
char buf[1024+1], *p;
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;
}
buf[n] = 0;
conn = atoi(buf);
-
if(url->basename[0]){
n = snprint(buf, sizeof buf, "baseurl %s", url->basename);
write(ctlfd, buf, n);
close(ctlfd);
return -1;
}
-
if(method == POST && body){
snprint(buf, sizeof buf, "%s/%d/postbody", mtpt, conn);
if((fd = open(buf, OWRITE)) < 0)
}
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;
}
return pfd[1];
}
-/*
- * select the file at the given url
- */
+char*
+urlstr(Url *url){
+ if(url->fullname[0])
+ return url->fullname;
+ if(url->reltext[0])
+ return url->reltext;
+ return nil;
+}
void selurl(char *urlname){
static Url url;
seturl(&url, urlname, current?
current->url->fullname :
defurl.fullname);
selection=&url;
- message("selected: %s", selection->fullname[0] ? selection->fullname : selection->reltext);
+ message("selected: %s", urlstr(selection));
}
void seturl(Url *url, char *urlname, char *base){
strncpy(url->reltext, urlname, sizeof(url->reltext));
strncpy(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){
/*
* get the file at the given url
*/
-void geturl(char *urlname, int method, char *body, int cache, int map){
- int i, fd;
- char cmd[NNAME];
+void geturl(char *urlname, int method, char *body, int plumb, int map){
+ int i, fd, typ;
+ char *file, cmd[NNAME];
int pfd[2];
Www *w;
+ if(*urlname == '#'){
+ scrollto(urlname+1);
+ return;
+ }
+
selurl(urlname);
selection->map=map;
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);
+ if(typ == GUNZIP){
+ fd=pipeline("/bin/gunzip", fd);
+ typ = snooptype(fd);
+ }
+ if(typ == COMPRESS){
+ fd=pipeline("/bin/uncompress", fd);
+ typ = snooptype(fd);
+ }
+ }
+ switch(typ){
default:
- message("Bad type %x in geturl", selection->type);
+ if(plumb){
+ message("unknown file type");
+ close(fd);
+ break;
+ }
+ file = urltofile(selection);
+ if(!mothmode){
+ message("save to '%s' ?", file);
+ if(!confirm(1)){
+ message(mothra);
+ close(fd);
+ break;
+ }
+ }
+ save(fd, file);
break;
case HTML:
- snprint(cmd, sizeof(cmd), selection->charset[0] ?
- "/bin/uhtml -c %s" : "/bin/uhtml", selection->charset);
- fd = pipeline(cmd, fd);
+ fd = pipeline("/bin/uhtml", fd);
case PLAIN:
w = www(i = wwwtop++);
if(i >= NWWW){
w->url=copyurl(selection);
w->finished = 0;
w->alldone = 0;
- gettext(w, fd, selection->type&~COMPRESSION);
+ gettext(w, fd, typ);
plinitlist(list, PACKN|FILLX, genwww, 8, doprev);
if(defdisplay) pldraw(list, screen);
setcurrent(i, selection->tag);
break;
- case POSTSCRIPT:
case GIF:
+ if(rfork(RFFDG|RFNOTEG|RFPROC|RFNAMEG|RFNOWAIT) == 0){
+ snprint(cmd, sizeof(cmd), "-pid %d", getpid());
+ if(newwindow(cmd) != -1){
+ close(1); open("/dev/cons", OWRITE);
+ print("reading gif...\n");
+ filter("gif", fd);
+ }
+ exits(0);
+ }
+ close(fd);
+ break;
case JPEG:
case PNG:
- case PDF:
+ case BMP:
+ case PAGE:
filter("page -w", fd);
break;
- case TIFF:
- filter("/sys/lib/mothra/tiffview", fd);
- break;
- case XBM:
- filter("fb/xbm2pic|fb/9v", fd);
- break;
}
break;
}
plsetpostextview(text, w->yoffs);
pldraw(root, 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
+mothon(Www *w, int on)
+{
+ Rtext *t, *x;
+ Action *a, *ap;
+
+ if(current == nil || 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 || a->link == nil)
+ continue;
+ x = t->next;
+ if(on){
+ t->next = nil;
+ ap=mallocz(sizeof(Action), 1);
+ ap->link = strdup(a->link);
+ plrtstr(&t->next, 0, 0, t->font, strdup("->"), 1, ap);
+ t->next->next = x;
+ } else {
+ t->next = x->next;
+ x->next = nil;
+ freetext(x);
+ }
+ }
+ updtext(w);
donecurs();
- return down.buttons==(1<<(b-1));
}
+
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);
+ fprint(fd, "%s", urlstr(selection));
close(fd);
}
}
pldraw(root, screen);
break;
case 1:
- snarf(cmd);
+ mothon(current, !mothmode);
break;
case 2:
- paste(cmd);
+ snarf(cmd);
break;
case 3:
- if(strrchr(selection->reltext, '/')){
- snprint(file, sizeof(file), "%s", strrchr(selection->reltext, '/')+1);
- if(file[0]==0)
- strcpy(file, "index");
- } else
- snprint(file, sizeof(file), "%s", selection->reltext);
- save(selection, file);
- message("saved %s", file);
+ paste(cmd);
break;
case 4:
snprint(name, sizeof(name), "%s/hit.html", home);
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: