ref: aa9097b4bbf566504c80689fa45b2e82aad56c36
parent: 1a10c36b88d9acdd7edcb33a09525b74875cc1fa
author: cinap_lenrek <cinap_lenrek@centraldogma>
date: Sun Sep 4 23:29:26 EDT 2011
mothra: remove ftp,gopher,file and http code and use /mnt/web instead
--- a/sys/src/cmd/mothra/auth.c
+++ /dev/null
@@ -1,68 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <panel.h>
-#include <bio.h>
-#include "mothra.h"
-
-static int
-basicauth(char *arg, char *str, int n)
-{
- int i;
- char *p;
- char buf[1024];
- Biobuf *b;
-
- if(strncmp(arg, "realm=", 6) == 0)
- arg += 6;
- if(*arg == '"'){
- arg++;
- for(p = arg; *p && *p != '"'; p++);
- *p = 0;
- } else {
- for(p = arg; *p && *p != ' ' && *p != '\t'; p++);
- *p = 0;
- }
-
- p = getenv("home");
- if(p == 0){
- werrstr("$home not set");
- return -1;
- }
- snprint(buf, sizeof(buf), "%s/lib/mothra/insecurity", p);
- b = Bopen(buf, OREAD);
- if(b == 0){
- werrstr("www password file %s: %r", buf);
- return -1;
- }
-
- i = strlen(arg);
- while(p = Brdline(b, '\n'))
- if(strncmp(arg, p, i) == 0 && p[i] == '\t')
- break;
- if(p == 0){
- Bterm(b);
- werrstr("no basic password for domain `%s'", arg);
- return -1;
- }
-
- p[Blinelen(b)-1] = 0;
- for(p += i; *p == '\t'; p++);
- if (enc64(buf, sizeof buf, (uchar*)p, strlen(p)) < 0) {
- Bterm(b);
- werrstr("password too long: %s", p);
- return -1;
- }
- snprint(str, n, "Authorization: Basic %s\r\n", buf);
- return 0;
-}
-
-int
-auth(Url *url, char *str, int n)
-{
- if(cistrcmp(url->authtype, "basic") == 0)
- return basicauth(url->autharg, str, n);
- werrstr("unknown auth method %s", url->authtype);
- return -1;
-}
--- a/sys/src/cmd/mothra/cistr.c
+++ /dev/null
@@ -1,29 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <panel.h>
-#include <ctype.h>
-#include "mothra.h"
-int cistrcmp(char *s1, char *s2){
- int c1, c2;
-
- for(; *s1; s1++, s2++){
- c1 = isupper(*s1) ? tolower(*s1) : *s1;
- c2 = isupper(*s2) ? tolower(*s2) : *s2;
- if (c1 < c2) return -1;
- if (c1 > c2) return 1;
- }
- return 0;
-}
-int cistrncmp(char *s1, char *s2, int n){
- int c1, c2;
-
- for(; *s1 && n!=0; s1++, s2++, --n){
- c1 = isupper(*s1) ? tolower(*s1) : *s1;
- c2 = isupper(*s2) ? tolower(*s2) : *s2;
- if (c1 < c2) return -1;
- if (c1 > c2) return 1;
- }
- return 0;
-}
--- a/sys/src/cmd/mothra/crackurl.c
+++ /dev/null
@@ -1,188 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <panel.h>
-#include <ctype.h>
-#include "mothra.h"
-enum{
- IP=1, /* url can contain //ipaddress[:port] */
- REL=2, /* fill in ip address & root of name from current, if necessary */
- SSL=4, /* use SSL/TLS encryption */
-};
-Scheme scheme[]={
- "http:", HTTP, IP|REL, 80,
- "https:", HTTP, IP|REL|SSL, 443,
- "ftp:", FTP, IP|REL, 21,
- "file:", FILE, REL, 0,
- "telnet:", TELNET, IP, 0,
- "mailto:", MAILTO, 0, 0,
- "gopher:", GOPHER, IP, 70,
- 0, HTTP, IP|REL, 80,
-};
-int endaddr(int c){
- return c=='/' || c==':' || c=='?' || c=='#' || c=='\0';
-}
-/*
- * Remove ., mu/.. and empty components from path names.
- * Empty last components of urls are significant, and
- * therefore preserved.
- */
-void urlcanon(char *name){
- char *s, *t;
- char **comp, **p, **q;
- int rooted;
- rooted=name[0]=='/';
- /*
- * Break the name into a list of components
- */
- comp=emalloc((strlen(name)+2)*sizeof(char *));
- p=comp;
- *p++=name;
- for(s=name;;s++){
- if(*s=='/'){
- *p++=s+1;
- *s='\0';
- }
- else if(*s=='\0' || *s=='?')
- break;
- }
- *p=0;
- /*
- * go through the component list, deleting components that are empty (except
- * the last component) or ., and any .. and its non-.. predecessor.
- */
- p=q=comp;
- while(*p){
- if(strcmp(*p, "")==0 && p[1]!=0
- || strcmp(*p, ".")==0)
- p++;
- else if(strcmp(*p, "..")==0 && q!=comp && strcmp(q[-1], "..")!=0){
- --q;
- p++;
- }
- else
- *q++=*p++;
- }
- *q=0;
- /*
- * rebuild the path name
- */
- s=name;
- if(rooted) *s++='/';
- for(p=comp;*p;p++){
- t=*p;
- while(*t) *s++=*t++;
- if(p[1]!=0) *s++='/';
- }
- *s='\0';
- free(comp);
-}
-/*
- * True url parsing is a nightmare.
- * This assumes that there are two basic syntaxes
- * for url's -- with and without an ip address.
- * If the type identifier or the ip address and port number
- * or the relative address is missing from urlname or is empty,
- * it is copied from cur.
- */
-void crackurl(Url *url, char *urlname, Url *cur){
- char *relp, *tagp, *httpname;
- int len;
- Scheme *up;
- char buf[30];
- /*
- * The following lines `fix' the most egregious urlname syntax errors
- */
- while(*urlname==' ' || *urlname=='\t' || *urlname=='\n') urlname++;
- relp=strchr(urlname, '\n');
- if(relp) *relp='\0';
- /*
- * In emulation of Netscape, attach a free "http://"
- * to names beginning with "www.".
- */
- if(strncmp(urlname, "www.", 4)==0){
- httpname=emalloc(strlen(urlname)+8);
- strcpy(httpname, "http://");
- strcat(httpname, urlname);
- crackurl(url, httpname, cur);
- free(httpname);
- return;
- }
- url->port=cur->port;
- strncpy(url->ipaddr, cur->ipaddr, sizeof(url->ipaddr));
- strncpy(url->reltext, cur->reltext, sizeof(url->reltext));
- if(strchr(urlname, ':')==0){
- up=cur->scheme;
- if(up==0){
- up=&scheme[0];
- cur->scheme=up;
- }
- }
- else{
- for(up=scheme;up->name;up++){
- len=strlen(up->name);
- if(strncmp(urlname, up->name, len)==0){
- urlname+=len;
- break;
- }
- }
- if(up->name==0) up=&scheme[0]; /* default to http: */
- }
- url->access=up->type;
- url->scheme=up;
- if(up!=cur->scheme)
- url->reltext[0]='\0';
- if(up->flags&IP && strncmp(urlname, "//", 2)==0){
- urlname+=2;
- for(relp=urlname;!endaddr(*relp);relp++);
- len=relp-urlname;
- strncpy(url->ipaddr, urlname, len);
- url->ipaddr[len]='\0';
- urlname=relp;
- if(*urlname==':'){
- urlname++;
- url->port=atoi(urlname);
- while(!endaddr(*urlname)) urlname++;
- }
- else
- url->port=up->port;
- if(*urlname=='\0') urlname="/";
- }
- url->ssl = up->flags&SSL;
-
- tagp=strchr(urlname, '#');
- if(tagp){
- *tagp='\0';
- strncpy(url->tag, tagp+1, sizeof(url->tag));
- }
- else
- url->tag[0]='\0';
- if(!(up->flags&REL) || *urlname=='/')
- strncpy(url->reltext, urlname, sizeof(url->reltext));
- else if(urlname[0]){
- relp=strrchr(url->reltext, '/');
- if(relp==0)
- strncpy(url->reltext, urlname, sizeof(url->reltext));
- else
- strcpy(relp+1, urlname);
- }
- urlcanon(url->reltext);
- if(tagp) *tagp='#';
- /*
- * The following mess of strcpys and strcats
- * can't be changed to a few sprints because
- * urls are not necessarily composed of legal utf
- */
- strcpy(url->fullname, up->name);
- if(up->flags&IP){
- strncat(url->fullname, "//", sizeof(url->fullname));
- strncat(url->fullname, url->ipaddr, sizeof(url->fullname));
- if(url->port!=up->port){
- snprint(buf, sizeof(buf), ":%d", url->port);
- strncat(url->fullname, buf, sizeof(url->fullname));
- }
- }
- strcat(url->fullname, url->reltext);
- url->map=0;
-}
--- a/sys/src/cmd/mothra/file.c
+++ /dev/null
@@ -1,48 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <panel.h>
-#include "mothra.h"
-/*
- * fd is the result of a successful open(name, OREAD),
- * where name is the name of a directory. We convert
- * this into an html page containing links to the files
- * in the directory.
- */
-int dir2html(char *name, int fd){
- int p[2], first;
- Dir *dir;
- int i, n;
- if(pipe(p)==-1){
- close(fd);
- return -1;
- }
- switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
- case -1:
- close(fd);
- return -1;
- case 0:
- close(p[1]);
- fprint(p[0], "<head>\n");
- fprint(p[0], "<title>Directory %s</title>\n", name);
- fprint(p[0], "</head>\n");
- fprint(p[0], "<body>\n");
- fprint(p[0], "<h1>%s</h1>\n", name);
- fprint(p[0], "<ul>\n");
- first=1;
- while((n = dirread(fd, &dir)) > 0) {
- for (i = 0; i < n; i++)
- fprint(p[0], "<li><a href=\"%s/%s\">%s%s</a>\n", name, dir[i].name, dir[i].name,
- dir[i].mode&DMDIR?"/":"");
- free(dir);
- }
- fprint(p[0], "</ul>\n");
- fprint(p[0], "</body>\n");
- _exits(0);
- default:
- close(fd);
- close(p[0]);
- return p[1];
- }
-}
--- a/sys/src/cmd/mothra/filetype.c
+++ b/sys/src/cmd/mothra/filetype.c
@@ -86,7 +86,7 @@
"application/pdf", PDF,
"application/octet-stream", SUFFIX,
"application/zip", ZIP,
- 0, HTML
+ 0, SUFFIX
};
int content2type(char *s, char *name){
int type;
--- a/sys/src/cmd/mothra/forms.c
+++ b/sys/src/cmd/mothra/forms.c
@@ -12,7 +12,7 @@
typedef struct Option Option;
struct Form{
int method;
- Url *action;
+ char *action;
Field *fields, *efields;
Form *next;
};
@@ -98,12 +98,8 @@
break;
}
g->form=emallocz(sizeof(Form), 1);
- g->form->action=emalloc(sizeof(Url));
s=pl_getattr(g->attr, "action");
- if(s==0)
- *g->form->action=*g->dst->url;
- else
- crackurl(g->form->action, s, g->dst->base);
+ g->form->action=strdup((s && s[0]) ? s : g->dst->url->fullname);
s=pl_getattr(g->attr, "method");
if(s==0)
g->form->method=GET;
@@ -268,12 +264,8 @@
form=emalloc(sizeof(Form));
form->fields=0;
form->efields=0;
- form->action=emalloc(sizeof(Url));
s=pl_getattr(g->attr, "action");
- if(s==0)
- *form->action=*g->dst->url;
- else
- crackurl(form->action, s, g->dst->base);
+ form->action=strdup((s && s[0]) ? s : g->dst->url->fullname);
form->method=GET;
form->fields=0;
f=newfield(form);
@@ -537,7 +529,7 @@
Field *f;
Option *o;
form=((Field *)p->userp)->form;
- if(form->method==GET) size=ulen(form->action->fullname)+1;
+ if(form->method==GET) size=ulen(form->action)+1;
else size=1;
for(f=form->fields;f;f=f->next) switch(f->type){
case TYPEIN:
@@ -564,7 +556,7 @@
}
buf=emalloc(size);
if(form->method==GET){
- strcpy(buf, form->action->fullname);
+ strcpy(buf, form->action);
sep='?';
}
else{
@@ -623,8 +615,8 @@
geturl(buf, GET, 0, 0, 0);
}
else{
-fprint(2, "POST %s: %s\n", form->action->fullname, buf);
- geturl(form->action->fullname, POST, buf, 0, 0);
+fprint(2, "POST %s: %s\n", form->action, buf);
+ geturl(form->action, POST, buf, 0, 0);
}
free(buf);
}
--- a/sys/src/cmd/mothra/ftp.c
+++ /dev/null
@@ -1,428 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <panel.h>
-#include <bio.h>
-#include <ndb.h>
-#include <ctype.h>
-#include <ip.h>
-#include "mothra.h"
-
-enum
-{
- /* return codes */
- Extra= 1,
- Success= 2,
- Incomplete= 3,
- TempFail= 4,
- PermFail= 5,
-
- NAMELEN= 28,
- Nnetdir= 3*NAMELEN, /* max length of network directory paths */
- Ndialstr= 64, /* max length of dial strings */
-};
-
-typedef struct Ftp Ftp;
-struct Ftp
-{
- char net[Nnetdir];
- Biobuf *ftpctl;
- Url *u;
-};
-
-static int ftpdebug;
-
-
-/*
- * read from biobuf turning cr/nl into nl
- */
-char*
-getcrnl(Biobuf *b)
-{
- char *p, *ep;
-
- p = Brdline(b, '\n');
- if(p == nil)
- return nil;
- ep = p + Blinelen(b) - 1;
- if(*(ep-1) == '\r')
- ep--;
- *ep = 0;
- return p;
-}
-
-char*
-readfile(char *file, char *buf, int len)
-{
- int n, fd;
-
- fd = open(file, OREAD);
- if(fd < 0)
- return nil;
- n = read(fd, buf, len-1);
- close(fd);
- if(n <= 0)
- return nil;
- buf[n] = 0;
- return buf;
-}
-
-char*
-sysname(void)
-{
- static char sys[Ndbvlen];
- char *p;
-
- p = readfile("/dev/sysname", sys, sizeof(sys));
- if(p == nil)
- return "unknown";
- return p;
-}
-
-char*
-domainname(void)
-{
- static char domain[Ndbvlen];
- Ndbtuple *t;
-
- if(*domain)
- return domain;
-
- t = csgetval(0, "sys", sysname(), "dom", domain);
- if(t){
- ndbfree(t);
- return domain;
- } else
- return sysname();
-}
-
-static int
-sendrequest(Biobuf *b, char *fmt, ...)
-{
- char buf[2*1024], *s;
- va_list args;
-
- va_start(args, fmt);
- s = buf + vsnprint(buf, (sizeof(buf)-4) / sizeof(*buf), fmt, args);
- va_end(args);
- *s++ = '\r';
- *s++ = '\n';
- if(write(Bfildes(b), buf, s - buf) != s - buf)
- return -1;
- if(ftpdebug)
- write(2, buf, s - buf);
- return 0;
-}
-
-static int
-getreply(Biobuf *b, char *msg, int len)
-{
- char *line;
- int rv;
- int i, n;
-
- while(line = getcrnl(b)){
- /* add line to message buffer, strip off \r */
- n = Blinelen(b);
- if(ftpdebug)
- write(2, line, n);
- if(n > len - 1)
- i = len - 1;
- else
- i = n;
- if(i > 0){
- memmove(msg, line, i);
- msg += i;
- len -= i;
- *msg = 0;
- }
-
- /* stop if not a continuation */
- rv = atoi(line);
- if(rv >= 100 && rv < 600 && (n == 4 || (n > 4 && line[3] == ' ')))
- return rv/100;
- }
-
- return -1;
-}
-
-int
-terminateftp(Ftp *d)
-{
- if(d->ftpctl){
- close(Bfildes(d->ftpctl));
- Bterm(d->ftpctl);
- free(d->ftpctl);
- d->ftpctl = nil;
- }
- free(d);
- return -1;
-}
-
-Biobuf*
-hello(Ftp *d)
-{
- int fd;
- char *p;
- Biobuf *b;
- char msg[1024];
- char ndir[Nnetdir];
-
- snprint(msg, sizeof msg, "tcp!%s!%d", d->u->ipaddr, d->u->port);
- fd = dial(msg, 0, ndir, 0);
- if(fd < 0){
- d->ftpctl = nil;
- return nil;
- }
- b = emalloc(sizeof(Biobuf));
- Binit(b, fd, OREAD);
- d->ftpctl = b;
-
- /* remember network for the data connections */
- p = strrchr(ndir, '/');
- if(p == 0){
- fprint(2, "dial is out of date\n");
- return nil;
- }
- *p = 0;
- strcpy(d->net, ndir);
-
- /* wait for hello from other side */
- if(getreply(b, msg, sizeof(msg)) != Success){
- fprint(2, "instead of hello: %s\n", msg);
- return nil;
- }
- return b;
-}
-
-int
-logon(Ftp *d)
-{
- char msg[1024];
-
- /* login anonymous */
- sendrequest(d->ftpctl, "USER anonymous");
- switch(getreply(d->ftpctl, msg, sizeof(msg))){
- case Success:
- return 0;
- case Incomplete:
- break; /* need password */
- default:
- fprint(2, "login failed: %s\n", msg);
- werrstr(msg);
- return -1;
- }
-
- /* send user id as password */
- sprint(msg, "%s@", getuser());
- sendrequest(d->ftpctl, "PASS %s", msg);
- if(getreply(d->ftpctl, msg, sizeof(msg)) != Success){
- fprint(2, "login failed: %s\n", msg);
- werrstr(msg);
- return -1;
- }
-
- return 0;
-}
-
-int
-xfertype(Ftp *d, char *t)
-{
- char msg[1024];
-
- sendrequest(d->ftpctl, "TYPE %s", t);
- if(getreply(d->ftpctl, msg, sizeof(msg)) != Success){
- fprint(2, "can't set type %s: %s\n", t, msg);
- werrstr(msg);
- return -1;
- }
- return 0;
-}
-
-int
-passive(Ftp *d)
-{
- char msg[1024];
- char dialstr[Ndialstr];
- char *f[6];
- char *p;
- int fd;
-
- sendrequest(d->ftpctl, "PASV");
- if(getreply(d->ftpctl, msg, sizeof(msg)) != Success)
- return -1;
-
- /* get address and port number from reply, this is AI */
- p = strchr(msg, '(');
- if(p == nil){
- for(p = msg+3; *p; p++)
- if(isdigit(*p))
- break;
- } else
- p++;
- if(getfields(p, f, 6, 0, ",") < 6){
- fprint(2, "passive mode protocol botch: %s\n", msg);
- werrstr("ftp protocol botch");
- return -1;
- }
- snprint(dialstr, sizeof(dialstr), "%s!%s.%s.%s.%s!%d", d->net,
- f[0], f[1], f[2], f[3],
- ((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff));
-
-
- /* open data connection */
- fd = dial(dialstr, 0, 0, 0);
- if(fd < 0){
- fprint(2, "passive mode connect to %s failed: %r\n", dialstr);
- return -1;
- }
-
- /* tell remote to send a file */
- sendrequest(d->ftpctl, "RETR %s", d->u->reltext);
- if(getreply(d->ftpctl, msg, sizeof(msg)) != Extra){
- fprint(2, "passive mode retrieve failed: %s\n", msg);
- werrstr(msg);
- return -1;
- }
- return fd;
-}
-
-int
-active(Ftp *d)
-{
- char msg[1024];
- char buf[Ndialstr];
- char netdir[Nnetdir];
- char newdir[Nnetdir];
- uchar ipaddr[4];
- int dfd, cfd, listenfd;
- char *p;
- int port;
-
- /* get a channel to listen on, let kernel pick the port number */
- sprint(buf, "%s!*!0", d->net);
- listenfd = announce(buf, netdir);
- if(listenfd < 0){
- fprint(2, "can't listen for ftp callback: %r\n", buf);
- return -1;
- }
-
- /* get the local address and port number */
- sprint(newdir, "%s/local", netdir);
- readfile(newdir, buf, sizeof buf);
- p = strchr(buf, '!')+1;
- parseip(ipaddr, buf);
- port = atoi(p);
-
- /* tell remote side address and port*/
- sendrequest(d->ftpctl, "PORT %d,%d,%d,%d,%d,%d", ipaddr[0], ipaddr[1], ipaddr[2],
- ipaddr[3], port>>8, port&0xff);
- if(getreply(d->ftpctl, msg, sizeof(msg)) != Success){
- close(listenfd);
- werrstr("ftp protocol botch");
- fprint(2, "active mode connect failed %s\n", msg);
- return -1;
- }
-
- /* tell remote to send a file */
- sendrequest(d->ftpctl, "RETR %s", d->u->reltext);
- if(getreply(d->ftpctl, msg, sizeof(msg)) != Extra){
- close(listenfd);
- fprint(2, "active mode connect failed: %s\n", msg);
- werrstr(msg);
- return -1;
- }
-
- /* wait for a new call */
- cfd = listen(netdir, newdir);
- close(listenfd);
- if(cfd < 0){
- fprint(2, "active mode connect failed: %r\n");
- return -1;
- }
-
- /* open the data connection and close the control connection */
- dfd = accept(cfd, newdir);
- close(cfd);
- if(dfd < 0){
- fprint(2, "active mode connect failed: %r\n");
- werrstr("ftp protocol botch");
- return -1;
- }
-
- return dfd;
-}
-
-/*
- * Given a url, return a file descriptor on which caller can
- * read an ftp document.
- * The caller is responsible for processing redirection loops.
- */
-int
-ftp(Url *url)
-{
- int n;
- int data;
- Ftp *d;
- int pfd[2];
- char buf[2048];
-
- if(url->type == 0)
- url->type = PLAIN;
-
- d = (Ftp*)emalloc(sizeof(Ftp));
- d->u = url;
- d->ftpctl = nil;
-
- if(hello(d) == nil)
- return terminateftp(d);
- if(logon(d) < 0)
- return terminateftp(d);
-
- switch(url->type){
- case PLAIN:
- case HTML:
- if(xfertype(d, "A") < 0)
- return terminateftp(d);
- break;
- default:
- if(xfertype(d, "I") < 0)
- return terminateftp(d);
- break;
- }
-
- /* first try passive mode, then active */
- data = passive(d);
- if(data < 0){
- if(d->ftpctl == nil)
- return -1;
- data = active(d);
- if(data < 0)
- return -1;
- }
-
- if(pipe(pfd) < 0)
- return -1;
-
- switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
- case -1:
- werrstr("Can't fork");
- close(pfd[0]);
- close(pfd[1]);
- return terminateftp(d);
- case 0:
- close(pfd[0]);
- while((n=read(data, buf, sizeof(buf)))>0)
- write(pfd[1], buf, n);
- if(n<0)
- fprint(2, "ftp: %s: %r\n", url->fullname);
- _exits(0);
- default:
- close(pfd[1]);
- close(data);
- terminateftp(d);
- return pfd[0];
- }
- return -1;
-}
--- a/sys/src/cmd/mothra/getpix.c
+++ b/sys/src/cmd/mothra/getpix.c
@@ -39,7 +39,7 @@
Pix *p;
ap=t->user;
- crackurl(&url, ap->image, w->base);
+ seturl(&url, ap->image, w->url->fullname);
for(p=w->pix;p!=nil; p=p->next)
if(strcmp(ap->image, p->name)==0 && ap->width==p->width && ap->height==p->height){
storebitmap(t, p->b);
@@ -105,12 +105,55 @@
}
void getpix(Rtext *t, Www *w){
+ int i, pid, nworker, worker[NXPROC];
Action *ap;
+ nworker = 0;
+ for(i=0; i<nelem(worker); i++)
+ worker[i] = -1;
+
for(;t!=0;t=t->next){
ap=t->user;
- if(ap && ap->image)
- getimage(t, w);
+ if(ap && ap->image){
+ pid = rfork(RFFDG|RFPROC|RFMEM);
+ switch(pid){
+ case -1:
+ fprint(2, "fork: %r\n");
+ break;
+ case 0:
+ getimage(t, w);
+ exits(0);
+ default:
+ for(i=0; i<nelem(worker); i++)
+ if(worker[i] == -1){
+ worker[i] = pid;
+ nworker++;
+ break;
+ }
+
+ while(nworker == nelem(worker)){
+ if((pid = waitpid()) < 0)
+ break;
+ for(i=0; i<nelem(worker); i++)
+ if(worker[i] == pid){
+ worker[i] = -1;
+ nworker--;
+ break;
+ }
+ }
+ }
+
+ }
+ }
+ while(nworker > 0){
+ if((pid = waitpid()) < 0)
+ break;
+ for(i=0; i<nelem(worker); i++)
+ if(worker[i] == pid){
+ worker[i] = -1;
+ nworker--;
+ break;
+ }
}
}
--- a/sys/src/cmd/mothra/gopher.c
+++ /dev/null
@@ -1,38 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <panel.h>
-#include "mothra.h"
-void httpheader(Url *, char *);
-/*
- * Given a url, return a file descriptor on which caller can
- * read a gopher document.
- */
-int gopher(Url *url){
- int pfd[2];
- char port[30];
- if(pipe(pfd)==-1) return -1;
- switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
- case -1:
- close(pfd[0]);
- close(pfd[1]);
- return -1;
- case 0:
- dup(pfd[1], 1);
- close(pfd[0]);
- close(pfd[1]);
- sprint(port, "%d", url->port);
- execl("/bin/aux/gopher2html",
- "gopher2html", url->ipaddr, port, url->reltext+1, 0);
- fprint(2, "Can't exec aux/gopher2html!\n");
- print("<head><title>Mothra error</title></head>\n");
- print("<body><h1>Mothra error</h1>\n");
- print("Can't exec aux/gopher2html!</body>\n");
- exits("no exec");
- default:
- close(pfd[1]);
- url->type=HTML;
- return pfd[0];
- }
-}
--- a/sys/src/cmd/mothra/gopher2html.c
+++ /dev/null
@@ -1,230 +1,0 @@
-/*
- * Reads gopher output from a TCP port, outputs
- * html on standard output.
- * Usage: gopher2html gopher-string
- * where gopher-string is the string sent to
- * the gopher server to get the document.
- *
- * Gopher protocol is described in rfc1436
- */
-#include <u.h>
-#include <libc.h>
-char *cmd;
-int ifd;
-void errexit(char *s, ...){
- static char buf[1024];
- char *out;
- va_list args;
- va_start(args, s);
- out = doprint(buf, buf+sizeof(buf), s, args);
- va_end(args);
- *out='\0';
- print("<head><title>%s error</title></head>\n", cmd);
- print("<body><h1>%s error</h1>\n", cmd);
- print("%s</body>\n", buf);
- exits("gopher error");
-}
-void wtext(char *buf, char *ebuf){
- char *bp;
- for(bp=buf;bp!=ebuf;bp++){
- if(*bp=='<' || *bp=='>' || *bp=='&' || *bp=='"'){
- if(bp!=buf) write(1, buf, bp-buf);
- buf=bp+1;
- switch(*bp){
- case '<': print("<"); break;
- case '>': print(">"); break;
- case '&': print("&"); break;
- case '"': print("""); break;
- }
- }
- }
- if(bp!=buf) write(1, buf, bp-buf);
-}
-void savefile(char *name, char *type){
- int fd, n;
- char save[30], buf[1024];
- for(n=1;;n++){
- if(n==100) errexit("can't save binary file %s: %r", name);
- sprint(save, "gopher.save.%d", n);
- fd=create(save, OWRITE, 0444);
- if(fd!=-1) break;
- }
- print("<head><title>%s</title></head\n", name);
- print("<body><h1>%s</h1><p>\n", name);
- print("Saving %s file %s in <tt>%s</tt>...\n", type, name, save);
- while((n=read(ifd, buf, sizeof buf))>0) write(fd, buf, n);
- close(fd);
- print("done</body>\n");
-}
-void copyfile(char *title){
- char buf[1024];
- int n;
- print("<head><title>%s</title></head>\n", title);
- print("<body><h1>%s</h1><pre>\n", title);
- while((n=read(ifd, buf, sizeof buf))>0) wtext(buf, buf+n);
- print("</pre></body>\n");
-}
-/*
- * A directory entry contains
- * type name selector host port
- * all tab separated, except type and name (type is one character)
- */
-char ibuf[1024], *ibp, *eibuf;
-#define EOF (-1)
-int get(void){
- int n;
-Again:
- if(ibp==eibuf){
- n=read(ifd, ibuf, sizeof(ibuf));
- if(n<=0) return EOF;
- eibuf=ibuf+n;
- ibp=ibuf;
- }
- if(*ibp=='\r'){
- ibp++;
- goto Again;
- }
- return *ibp++&255;
-}
-char *escape(char *in){
- static char out[516];
- char *op, *eop;
- eop=out+512;
- op=out;
- for(;*in;in++){
- if(op<eop){
- if(strchr("/$-_@.&!*'(),", *in)
- || 'a'<=*in && *in<='z'
- || 'A'<=*in && *in<='Z'
- || '0'<=*in && *in<='9')
- *op++=*in;
- else{
- sprint(op, "%%%.2X", *in&255);
- op+=3;
- }
- }
- }
- *op='\0';
- return out;
-}
-void copydir(char *title){
- int type, c;
- char name[513], *ename;
- char selector[513];
- char host[513];
- char port[513];
- char *bp;
- print("<head><title>%s</title></head>\n", title);
- print("<body><h1>%s</h1><ul>\n", title);
- for(;;){
- type=get();
- if(type==EOF || type=='.') break;
- bp=name;
- while((c=get())!=EOF && c!='\t') if(bp!=&name[512]) *bp++=c;
- ename=bp;
- bp=selector;
- while((c=get())!=EOF && c!='\t') if(bp!=&selector[512]) *bp++=c;
- *bp='\0';
- bp=host;
- while((c=get())!=EOF && c!='\t') if(bp!=&host[512]) *bp++=c;
- *bp='\0';
- bp=port;
- while((c=get())!=EOF && c!='\t' && c!='\n') if(bp!=&port[512]) *bp++=c;
- while(c!=EOF && c!='\n') c=get();
- *bp='\0';
- switch(type){
- case '3':
- print("<li>");
- wtext(name, ename);
- break;
- case '7':
- print("<li><isindex action=\"gopher://%s:%s/%c%s\">",
- host, port, type, escape(selector));
- wtext(name, ename);
- break;
- default:
- print("<li><a href=\"gopher://%s:%s/%c%s\">",
- host, port, type, escape(selector));
- wtext(name, ename);
- print("</a>\n");
- break;
- }
- }
- print("</ul></body>\n");
-}
-int hexdigit(int c){
- if('0'<=c && c<='9') return c-'0';
- if('a'<=c && c<='f') return c-'a'+10;
- if('A'<=c && c<='F') return c-'A'+10;
- return -1;
-}
-void unescape(char *s){
- char *t;
- int hi, lo;
- t=s;
- while(*s){
- if(*s=='%'
- && (hi=hexdigit(s[1]))>=0
- && (lo=hexdigit(s[2]))>=0){
- *t++=hi*16+lo;
- s+=3;
- }
- else *t++=*s++;
- }
- *t='\0';
-}
-void main(int argc, char *argv[]){
- char dialstr[1024];
- char *name;
- cmd=argv[0];
- if(argc!=4) errexit("Usage: %s host port selector", argv[0]);
- sprint(dialstr, "tcp!%s!%s", argv[1], argv[2]);
- ifd=dial(dialstr, 0, 0, 0);
- if(ifd==-1) errexit("can't call %s:%s", argv[1], argv[2]);
- unescape(argv[3]);
- switch(argv[3][0]){
- case '/':
- fprint(ifd, "\r\n");
- copydir(argv[3]);
- break;
- case '\0':
- fprint(ifd, "\r\n");
- copydir(argv[1]);
- break;
- case '7': /* index query */
- name=strchr(argv[3], '?');
- if(name!=0){
- if(name==argv[3]+1){
- argv[3][1]=argv[3][0];
- argv[3]++;
- }
- else
- *name='\t';
- name++;
- }
- else
- name=argv[3];
- fprint(ifd, "%s\r\n", argv[3]+1);
- copydir(name);
- break;
- default:
- fprint(ifd, "%s\r\n", argv[3]+1);
- name=strrchr(argv[3], '/');
- if(name==0) name=argv[3];
- else name++;
- switch(argv[3][0]){
- default: errexit("sorry, can't handle %s (type %c)",
- argv[3]+1, argv[3][0]);
- case '0': copyfile(name); break;
- case '1': copydir(name); break;
- case '4': savefile(name, "Macintosh BINHEX"); break;
- case '5': savefile(name, "DOS binary"); break;
- case '6': savefile(name, "uuencoded"); break;
- case '9': savefile(name, "binary"); break;
- case 'g': savefile(name, "GIF"); break;
- case 'I': savefile(name, "some sort of image"); break;
- }
- break;
- }
- exits(0);
-}
--- a/sys/src/cmd/mothra/help.html
+++ /dev/null
@@ -1,78 +1,0 @@
-<html><head><title>Mothra help</title>
-</head>
-<body>
-<H1>Mothra Help</H1>
-<p>
-Mothra is a World-wide Web browser. Its display looks like this:
-<p><img src="file:display.pic" alt="[mothra display]">
-<p>The display's regions, from top to bottom, are:
-<ul>
-<li>Error messages and other information.
-<li>A text input window in which <a href="#commands">commands</a> can be typed.
-<li>A scrollable list of titles of previously visited documents, with the most recent first.
-Pointing at one of these lines with mouse button 1 revisits the document.
-<li>The title of the currently-displayed document.
-<li>The URL of the currently-displayed document.
-<li>The scrollable document display. Underlined text and
-images surrounded by boxes may be pointed at with button 1 to
-visit the files that they refer to. Files that are not
-HTML documents (for example images or mailto: urls) cause
-<i>9v</i> or <i>mail</i> to pop up in a new 8½ window.
-</ul>
-<h4>Mouse Action</H4>
-<p>Pointing with button
-2 instead of button 1 selects a url without following it;
-the url will be displayed in the selection: area and commands
-will refer to the url, but it will not be drawn in the document display.
-Button 3 pops up a command menu that contains
-<ul>
-<li><b>alt display</b><br>switches to (or from) the alternate display, which shows only
-the scrollable document display area. This might be useful when running mothra
-in a small window.
-<li><b>snarf url</b><br>copies the selected url into the snarf buffer.
-<li><b>paste</b><br>appends the snarf buffer to the command window.
-<li><b>inline pix</b><br>turn off/on loading of inline images. Image maps cannot be disabled.
-<li><b>fix cmap</b><br>reload the default plan 9 colormap
-<li><b>save hit</b><br>appends the selected url to file:$home/lib/hit.html
-<li><b>hit list</b><br>displays file:$home/lib/hit.html
-<li><b>exit</b>
-</ul>
-<a name="#commands"><h4>Commands</h4></a>
-<p>The commands you can type are:
-<ul>
-<li>g [url]<br>get the page with the given url (default, the selection.)
-<li>r [url]<br>refresh the display if the URL changes.
-Otherwise, you will probably see a cached version.
-<li>s file<br>save the current page in the given file.
-<li>w file<br>write a bitmap image of the document display area in the given file.
-<li>q<br>exit.
-<li>?<br>get help.
-<li>h<br>get help.
-</ul>
-<p>
-<h4>Configuration</h4>
-Mothra gets configuration information from the environment.
-<ul>
-<li>$url<br>The default <i>url</i> displayed when mothra starts.
-A <i>url</i> given on the command line overrides this.
-The default is <b>/sys/lib/mothra/start.html</b>
-<li>$httpproxy<br>The network address of an http proxy server,
-in the format expected by dial(2). If $httpproxy is not set
-or is null, no proxy server is used.
-</ul>
-<h4>Command line</h4>
-If the mothra command has an argument, it is the name of a <i>url</i> to visit
-instead of the startup page. Giving mothra the <b>-i</b> flag disables loading
-of inline images. The <b>inline pix</b> menu item will reset this option.
-<h4>Files</h4>
-Mothra creates several files in $home/lib/mothra.
-<ul>
-<li>mothra.log<br>a list of all the url's visited
-<li>mothra.err<br>a log of error messages, mostly uninteresting
-<li>hit.html<br>the hit list used by the <b>save hit</b>
-and <b>hit list</b> commands. Since <b>save hit</b> only
-adds new urls to the end of this file, it is safe to edit it
-to add annotation or sort the saved urls.
-</ul>
-</body>
-</html>
--- a/sys/src/cmd/mothra/http.c
+++ /dev/null
@@ -1,486 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <event.h>
-#include <panel.h>
-
-#include <libsec.h> /* tlsClient */
-
-#include "mothra.h"
-typedef struct Cache Cache;
-struct Cache{
- int fd; /* file descriptor on which to write cached data */
- ulong hash; /* hash of url, used to compute cache file name */
- int modtime; /* time at which cache entry was created */
- int type; /* url->type of cached entry */
-};
-void httpheader(Url *, char *);
-int httpresponse(char *);
-static char *proxyserver; /* name of proxy server */
-void exitnow(void*, char*){
- noted(NDFLT);
-}
-void hashname(char *name, int n, char *stem, Cache *c){
- snprint(name, n, "/sys/lib/mothra/cache/%s.%.8lux", stem, c->hash);
-}
-// #define CacheEnabled
-/*
- * Returns fd of cached file, if found (else -1)
- * Fills in Cache data structure for caller
- * If stale is set, caller has determined that the existing
- * cache entry for this url is stale, so we shouldn't bother re-examining it.
- */
-int cacheopen(Url *url, Cache *c, int stale){
-#ifdef CacheEnabled
- int fd, n;
- char name[NNAME+1], *s, *l;
- /*
- * If we're using a proxy server or the url contains a ? or =,
- * don't even bother.
- */
- if(proxyserver || strchr(url->reltext, '?')!=0 || strchr(url->reltext, '=')!=0){
- c->fd=-1;
- return -1;
- }
- c->hash=0;
- for(s=url->fullname,n=0;*s;s++,n++) c->hash=c->hash*n+(*s&255);
- if(stale)
- fd=-1;
- else{
- hashname(name, sizeof(name), "cache", c);
- fd=open(name, OREAD);
- }
- if(fd==-1){
- hashname(name, sizeof(name), "write", c);
- c->fd=create(name, OWRITE, 0444);
- if(c->fd!=-1)
- fprint(c->fd, "%s %10ld\n", url->fullname, time(0));
- return -1;
- }
- c->fd=-1;
- for(l=name;l!=&name[NNAME];l+=n){
- n=&name[NNAME]-l;
- n=read(fd, l, n);
- if(n<=0) break;
- }
- *l='\0';
- s=strchr(name, ' ');
- if(s==0){
- close(fd);
- return -1;
- }
- *s='\0';
- if(strcmp(url->fullname, name)!=0){
- close(fd);
- return -1;
- }
- c->modtime=atol(++s);
- s=strchr(s, '\n');
- if(s==0){
- close(fd);
- return -1;
- }
- s++;
- if(strncmp(s, "type ", 5)!=0){
- close(fd);
- return -1;
- }
- c->type=atoi(s+5);
- s=strchr(s+5, '\n');
- if(s==0){
- close(fd);
- return -1;
- }
-
- seek(fd, s-name+1, 0);
- return fd;
-#else
- c->fd=-1;
- return -1;
-#endif
-}
-/*
- * Close url->fd and either rename the cache file or
- * remove it, depending on success
- */
-void cacheclose(Cache *c, int success){
- char wname[NNAME+1], cname[NNAME+1], *celem;
- Dir *wdir;
- if(c->fd==-1) return;
- close(c->fd);
- hashname(wname, sizeof(wname), "write", c);
- if(!success){
- remove(wname);
- return;
- }
- if((wdir = dirstat(wname)) == 0)
- return;
- hashname(cname, sizeof(cname), "cache", c);
- if(access(cname, 0) == 0){
- if(remove(cname)==-1){
- remove(wname);
- free(wdir);
- return;
- }
- /*
- * This looks implausible, but it's what the mv command does
- */
- do; while(remove(cname)!=-1);
- }
- celem=strrchr(cname, '/');
- if(celem==0) celem=cname;
- else celem++;
- strcpy(wdir->name, celem);
- if(dirwstat(wname, wdir)==-1)
- remove(wname);
- free(wdir);
-}
-static char *wkday[]={
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-static char *month[]={
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
-/*
- * Sun, 06 Nov 1994 08:49:38 GMT
- * 123456789 123456789 123456789
- */
-char *rfc1123date(long time){
- static char buf[50];
- Tm *t;
- t=gmtime(time);
- snprint(buf, sizeof(buf), "%s, %2.2d %s %4.4d %2.2d:%2.2d:%2.2d GMT",
- wkday[t->wday], t->mday, month[t->mon], t->year+1900,
- t->hour, t->min, t->sec);
- return buf;
-}
-/*
- * Given a url, return a file descriptor on which caller can
- * read an http document. As a side effect, we parse the
- * http header and fill in some fields in the url.
- * The caller is responsible for processing redirection loops.
- * Method can be either GET or POST. If method==post, body
- * is the text to be posted.
- */
-int http(Url *url, int method, char *body){
- char *addr, *com;
- int fd, n, nnl, len;
- int ncom, m;
- int pfd[2];
- char buf[1024], *bp, *ebp;
- char line[1024+1], *lp, *elp;
- char authstr[NAUTH], *urlname;
- int gotresponse;
- int response;
- Cache cache;
- int cfd, cookiefd;
- static int firsttime=1;
- static int gotcookies;
-
- if(firsttime){
- proxyserver=getenv("httpproxy");
- gotcookies=(access("/mnt/webcookies/http", AREAD|AWRITE)==0);
- firsttime=0;
- }
- *authstr = 0;
-Authorize:
- cfd=-1;
- cookiefd=-1;
- if(proxyserver && proxyserver[0]!='\0'){
- addr=strdup(proxyserver);
- urlname=url->fullname;
- }
- else{
- addr=emalloc(strlen(url->ipaddr)+100);
- sprint(addr, "tcp!%s!%d", url->ipaddr, url->port);
- urlname=url->reltext;
- }
- fd=dial(addr, 0, 0, 0);
- free(addr);
- if(fd==-1) goto ErrReturn;
- if(url->ssl){
- int tfd;
- TLSconn conn;
-
- memset(&conn, 0, sizeof conn);
- tfd = tlsClient(fd, &conn);
- if(tfd < 0){
- close(fd);
- goto ErrReturn;
- }
- /* BUG: check cert here? */
- if(conn.cert)
- free(conn.cert);
- close(fd);
- fd = tfd;
- }
- ncom=strlen(urlname)+sizeof(buf);
- com=emalloc(ncom+2);
- cache.fd=-1;
- switch(method){
- case GET:
- cfd=cacheopen(url, &cache, 0);
- if(cfd==-1)
- n=sprint(com,
- "GET %s HTTP/1.0\r\n%s"
- "Accept: */*\r\n"
- "User-agent: mothra/%s\r\n"
- "Host: %s\r\n",
- urlname, authstr, version, url->ipaddr);
- else
- n=sprint(com,
- "GET %s HTTP/1.0\r\n%s"
- "If-Modified-since: %s\r\n"
- "Accept: */*\r\n"
- "User-agent: mothra/%s\r\n"
- "Host: %s\r\n",
- urlname, authstr, rfc1123date(cache.modtime), version, url->ipaddr);
- break;
- case POST:
- len=strlen(body);
- n=sprint(com,
- "POST %s HTTP/1.0\r\n%s"
- "Content-type: application/x-www-form-urlencoded\r\n"
- "Content-length: %d\r\n"
- "User-agent: mothra/%s\r\n",
- urlname, authstr, len, version);
- break;
- }
- if(gotcookies && (cookiefd=open("/mnt/webcookies/http", ORDWR)) >= 0){
- if(fprint(cookiefd, "%s", url->fullname) > 0){
- while((m=read(cookiefd, buf, sizeof buf)) > 0){
- if(m+n>ncom){
- if(write(fd, com, n)!= n){
- free(com);
- goto fdErrReturn;
- }
- n=0;
- com[0] = '\0';
- }
- strncat(com, buf, m);
- n += m;
- }
- }else{
- close(cookiefd);
- cookiefd=-1;
- }
- }
- strcat(com, "\r\n");
- n += 2;
- switch(method){
- case GET:
- if(write(fd, com, n)!=n){
- free(com);
- goto fdErrReturn;
- }
- break;
- case POST:
- if(write(fd, com, n)!=n
- || write(fd, body, len)!=len){
- free(com);
- goto fdErrReturn;
- }
- break;
- }
- free(com);
- if(pipe(pfd)==-1) goto fdErrReturn;
- n=read(fd, buf, 1024);
- if(n<=0){
- EarlyEof:
- if(n==0){
- fprint(2, "%s: EOF in header\n", url->fullname);
- werrstr("EOF in header");
- }
- pfdErrReturn:
- close(pfd[0]);
- close(pfd[1]);
- fdErrReturn:
- close(fd);
- ErrReturn:
- if(cookiefd>=0)
- close(cookiefd);
- cacheclose(&cache, 0);
- return -1;
- }
- bp=buf;
- ebp=buf+n;
- url->type=0;
- if(strncmp(buf, "HTTP/", 5)==0){ /* hack test for presence of header */
- SET(response);
- gotresponse=0;
- url->redirname[0]='\0';
- nnl=0;
- lp=line;
- elp=line+1024;
- while(nnl!=2){
- if(bp==ebp){
- n=read(fd, buf, 1024);
- if(n<=0) goto EarlyEof;
- ebp=buf+n;
- bp=buf;
- }
- if(*bp!='\r'){
- if(nnl==1 && (!gotresponse || (*bp!=' ' && *bp!='\t'))){
- *lp='\0';
- if(gotresponse){
- if(cookiefd>=0 && cistrncmp(line, "Set-Cookie:", 11) == 0)
- fprint(cookiefd, "%s\n", line);
- httpheader(url, line);
- }else{
- response=httpresponse(line);
- gotresponse=1;
- }
- lp=line;
- }
- if(*bp=='\n') nnl++;
- else{
- nnl=0;
- if(lp!=elp) *lp++=*bp;
- }
- }
- bp++;
- }
- if(gotresponse) switch(response){
- case 200: /* OK */
- case 201: /* Created */
- case 202: /* Accepted */
- break;
- case 204: /* No Content */
- werrstr("URL has no content");
- goto pfdErrReturn;
- case 301: /* Moved Permanently */
- case 302: /* Moved Temporarily */
- if(url->redirname[0]){
- url->type=FORWARD;
- werrstr("URL forwarded");
- goto pfdErrReturn;
- }
- break;
- case 304: /* Not Modified */
- if(cfd!=-1){
- url->type=cache.type;
- close(pfd[0]);
- close(pfd[1]);
- close(fd);
- if(cookiefd>=0)
- close(cookiefd);
- return cfd;
- }
- werrstr("Not modified!");
- goto pfdErrReturn;
- case 400: /* Bad Request */
- werrstr("Bad Request to server");
- goto pfdErrReturn;
- case 401: /* Unauthorized */
- case 402: /* ??? */
- if(*authstr == 0){
- close(pfd[0]);
- close(pfd[1]);
- close(fd);
- if(auth(url, authstr, sizeof(authstr)) == 0){
- if(cfd!=-1)
- close(cfd);
- goto Authorize;
- }
- goto ErrReturn;
- }
- break;
- case 403: /* Forbidden */
- werrstr("Forbidden by server");
- goto pfdErrReturn;
- case 404: /* Not Found */
- werrstr("Not found on server");
- goto pfdErrReturn;
- case 500: /* Internal server error */
- werrstr("Server choked");
- goto pfdErrReturn;
- case 501: /* Not implemented */
- werrstr("Server can't do it!");
- goto pfdErrReturn;
- case 502: /* Bad gateway */
- werrstr("Bad gateway");
- goto pfdErrReturn;
- case 503: /* Service unavailable */
- werrstr("Service unavailable");
- goto pfdErrReturn;
- }
- }
- if(cfd!=-1){
- close(cfd);
- cfd=cacheopen(url, &cache, 1);
- }
- if(cookiefd>=0){
- close(cookiefd);
- cookiefd=-1;
- }
- if(url->type==0)
- url->type=suffix2type(url->fullname);
- if(cache.fd!=-1) fprint(cache.fd, "type %d\n", url->type);
- switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
- case -1:
- werrstr("Can't fork");
- goto pfdErrReturn;
- case 0:
- notify(exitnow); /* otherwise write on closed pipe below may cause havoc */
- close(pfd[0]);
- if(bp!=ebp){
- write(pfd[1], bp, ebp-bp);
- if(cache.fd!=-1) write(cache.fd, bp, ebp-bp);
- }
- while((n=read(fd, buf, 1024))>0){
- write(pfd[1], buf, n);
- if(cache.fd!=-1) write(cache.fd, buf, n);
- }
- cacheclose(&cache, 1);
- _exits(0);
- default:
- if(cache.fd!=-1) close(cache.fd);
- close(pfd[1]);
- close(fd);
- return pfd[0];
- }
-}
-/*
- * Process a header line for this url
- */
-void httpheader(Url *url, char *line){
- char *name, *arg, *s, *arg2;
- name=line;
- while(*name==' ' || *name=='\t') name++;
- for(s=name;*s!=':';s++) if(*s=='\0') return;
- *s++='\0';
- while(*s==' ' || *s=='\t') s++;
- arg=s;
- while(*s!=' ' && *s!='\t' && *s!=';' && *s!='\0') s++;
- while(*s == ' ' || *s == '\t' || *s == ';')
- *s++ = '\0';
- arg2 = s;
- if(cistrcmp(name, "Content-Type")==0){
- url->type|=content2type(arg, url->reltext);
- if(cistrncmp(arg2, "charset=", 8) == 0){
- strncpy(url->charset, arg2+8, sizeof(url->charset));
- } else {
- url->charset[0] = '\0';
- }
- }
- else if(cistrcmp(name, "Content-Encoding")==0)
- url->type|=encoding2type(arg);
- else if(cistrcmp(name, "WWW-authenticate")==0){
- strncpy(url->authtype, arg, sizeof(url->authtype));
- strncpy(url->autharg, arg2, sizeof(url->autharg));
- }
- else if(cistrcmp(name, "URI")==0){
- if(*arg!='<') return;
- ++arg;
- for(s=arg;*s!='>';s++) if(*s=='\0') return;
- *s='\0';
- strncpy(url->redirname, arg, sizeof(url->redirname));
- }
- else if(cistrcmp(name, "Location")==0)
- strncpy(url->redirname, arg, sizeof(url->redirname));
-}
-int httpresponse(char *line){
- while(*line!=' ' && *line!='\t' && *line!='\0') line++;
- return atoi(line);
-}
--- a/sys/src/cmd/mothra/libpanel/mem.c
+++ b/sys/src/cmd/mothra/libpanel/mem.c
@@ -11,6 +11,7 @@
fprint(2, "Can't malloc!\n");
exits("no mem");
}
+ setmalloctag(v, getcallerpc(&n));
return v;
}
void pl_unexpected(Panel *g, char *rou){
--- a/sys/src/cmd/mothra/mkfile
+++ b/sys/src/cmd/mothra/mkfile
@@ -3,19 +3,12 @@
TARG=mothra
LIB=libpanel/libpanel.$O.a
CFILES= \
- cistr.c \
- crackurl.c \
- file.c \
filetype.c \
forms.c \
- ftp.c \
getpix.c \
- gopher.c \
html.syntax.c \
- http.c \
mothra.c \
rdhtml.c \
- auth.c \
OFILES=${CFILES:%.c=%.$O} version.$O
HFILES=mothra.h html.h tcs.h libpanel/panel.h libpanel/rtext.h
--- a/sys/src/cmd/mothra/mothra.c
+++ b/sys/src/cmd/mothra/mothra.c
@@ -23,29 +23,22 @@
Panel *msg; /* message display */
Panel *menu3; /* button 3 menu */
Mouse mouse; /* current mouse data */
-char helpfile[] = "file:/sys/lib/mothra/help.html";
char mothra[] = "mothra!";
Url defurl={
- "http://plan9.bell-labs.com/",
- 0,
- "plan9.bell-labs.com",
- "/",
+ "http://cat-v.org/",
"",
- "", "", "",
- 80,
- HTTP,
- HTML
+ "http://cat-v.org/",
+ "",
+ "",
+ HTML,
};
Url badurl={
+ "",
+ "",
"No file loaded",
- 0,
"",
- "/dev/null",
- "", "", "",
"",
- 0,
- FILE,
- HTML
+ HTML,
};
Cursor patientcurs={
0, 0,
@@ -83,6 +76,7 @@
0x0E, 0x60, 0x1C, 0x00, 0x38, 0x00, 0x71, 0xB6,
0x61, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
+char *mtpt="/mnt/web";
Www *current=0;
Url *selection=0;
int logfile;
@@ -210,6 +204,7 @@
sprint(home, "%s/lib/mothra", henv);
f=create(home, OREAD, DMDIR|0777);
if(f!=-1) close(f);
+ free(henv);
}
else
strcpy(home, "/tmp");
@@ -231,6 +226,9 @@
ARGBEGIN{
case 'd': debug++; break;
case 'v': verbose=1; break;
+ case 'm':
+ if(mtpt = ARGF())
+ break;
default: goto Usage;
}ARGEND
@@ -243,12 +241,12 @@
switch(argc){
default:
Usage:
- fprint(2, "Usage: %s [-d] [url]\n", argv[0]);
+ fprint(2, "Usage: %s [-d] [-m mtpt] [url]\n", argv[0]);
exits("usage");
case 0:
url=getenv("url");
if(url==0 || url[0]=='\0')
- url="file:/sys/lib/mothra/start.html";
+ url=defurl.fullname;
break;
case 1: url=argv[0]; break;
}
@@ -284,7 +282,6 @@
fillellipse(bullet, Pt(4,4), 3, 3, display->black, ZP);
new = www(-1);
new->url=&badurl;
- new->base=&badurl;
strcpy(new->title, "See error message above");
plrtstr(&new->text, 0, 0, font, "See error message above", 0, 0);
new->alldone=1;
@@ -527,10 +524,6 @@
default:
message("Unknown command %s, type h for help", s);
break;
- case '?':
- case 'h':
- geturl(helpfile, GET, 0, 1, 0);
- break;
case 'g':
s=arg(s);
if(*s=='\0'){
@@ -543,9 +536,8 @@
break;
case 'r':
s = arg(s);
- if(*s == '\0')
- s = selection ? selection->fullname : helpfile;
- geturl(s, GET, 0, 0, 0);
+ if(*s == '\0' && selection)
+ geturl(selection->fullname, GET, 0, 0, 0);
break;
case 'W':
s=arg(s);
@@ -697,57 +689,79 @@
_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 urlopen(Url *url, int method, char *body){
- int fd;
- Url prev;
- int nredir;
- Dir *dir;
- nredir=0;
-Again:
- if(++nredir==NREDIR){
- werrstr("redir loop");
+ int conn, ctlfd, fd, n;
+ char buf[1024+1];
+
+ 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;
}
- seek(logfile, 0, 2);
- fprint(logfile, "%s\n", url->fullname);
- switch(url->access){
- default:
- werrstr("unknown access type");
+ 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;
- case FTP:
- url->type = suffix2type(url->reltext);
- return ftp(url);
- case HTTP:
- fd=http(url, method, body);
- if(url->type==FORWARD){
- prev=*url;
- crackurl(url, prev.redirname, &prev);
+ }
- /*
- * I'm not convinced that the following two lines are right,
- * but once I got a redir loop because they were missing.
- */
- method=GET;
- body=0;
- goto Again;
+ 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){
+ close(fd);
+ goto ErrOut;
}
- return fd;
- case FILE:
- url->type=suffix2type(url->reltext);
- fd=open(url->reltext, OREAD);
- if(fd!=-1){
- dir=dirfstat(fd);
- if(dir->mode&DMDIR){
- url->type=HTML;
- free(dir);
- return dir2html(url->reltext, fd);
- }
- free(dir);
- }
- return fd;
- case GOPHER:
- return gopher(url);
+ 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->type = content2type(buf, url->fullname);
+
+ close(ctlfd);
+ return fd;
}
int pipeline(char *cmd, int fd)
@@ -781,27 +795,21 @@
/*
* select the file at the given url
*/
+void seturl(Url *url, char *urlname, char *base){
+ strncpy(url->reltext, urlname, sizeof(url->reltext));
+ strcpy(url->basename, base);
+ url->fullname[0] = 0;
+ url->charset[0] = 0;
+ url->tag[0] = 0;
+ url->type = 0;
+ url->map = 0;
+}
+
void selurl(char *urlname){
- Url *cur;
static Url url;
- if(current){
- cur=current->base;
- /*
- * I believe that the following test should never succeed
- */
- if(cur==0){
- cur=current->url;
- if(cur==0){
- fprint(2, "bad base & url, getting %s\n", urlname);
- cur=&defurl;
- }
- else
- fprint(2, "bad base, current %s, getting %s\n",
- current->url->fullname, urlname);
- }
- }
- else cur=&defurl;
- crackurl(&url, urlname, cur);
+ seturl(&url, urlname, current?
+ current->url->fullname :
+ defurl.fullname);
selection=&url;
message("selected: %s", selection->fullname);
}
@@ -828,61 +836,15 @@
selurl(urlname);
selection->map=map;
- message("getting %s", selection->fullname);
+ message("getting %s", selection->reltext);
esetcursor(&patientcurs);
- switch(selection->access){
- default:
- message("unknown access %d", selection->access);
- break;
- case TELNET:
- sprint(cmd, "telnet %s", selection->reltext);
- popwin(cmd);
- break;
- case MAILTO:
- if(body){
- /*
- * Undocumented Mozilla feature
- */
- pipe(pfd);
- switch(rfork(RFFDG|RFPROC|RFNOWAIT)){
- case -1:
- message("Can't fork!");
- break;
- case 0:
- close(0);
- dup(pfd[1], 0);
- close(pfd[1]);
- close(pfd[0]);
- execl("/bin/upas/send",
- "sendmail", selection->reltext, 0);
- message("Can't exec sendmail");
- _exits(0);
- default:
- close(pfd[1]);
- fprint(pfd[0],
- "Content-type: application/x-www-form-urlencoded\n"
- "Subject: Form posted from Mothra\n"
- "\n"
- "%s\n", body);
- close(pfd[0]);
- break;
- }
- }
- else{
- snprint(cmd, sizeof(cmd), "mail %s", selection->reltext);
- popwin(cmd);
- }
- break;
- case FTP:
- case HTTP:
- case FILE:
- case GOPHER:
- fd=urlopen(selection, method, body);
- if(fd==-1){
+ for(;;){
+ if((fd=urlopen(selection, method, body)) < 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)
@@ -908,19 +870,11 @@
freetext(w->text);
freeform(w->form);
freepix(w->pix);
- if(w->base != w->url)
- freeurl(w->base);
freeurl(w->url);
memset(w, 0, sizeof(*w));
}
- if(selection->map){
- if(current && current->base) /* always succeeds */
- w->url=copyurl(current->base);
- else{
- fprint(2, "no base for map!\n");
- w->url=copyurl(selection);
- }
- }
+ if(selection->map)
+ w->url=copyurl(current->url);
else
w->url=copyurl(selection);
w->finished = 0;
@@ -944,6 +898,7 @@
filter("fb/xbm2pic|fb/9v", fd);
break;
}
+ break;
}
donecurs();
}
--- a/sys/src/cmd/mothra/mothra.h
+++ b/sys/src/cmd/mothra/mothra.h
@@ -1,5 +1,6 @@
enum{
NWWW=64, /* # of pages we hold in the log */
+ NXPROC=5, /* # of parallel procs loading the pix */
NNAME=512,
NLINE=256,
NAUTH=128,
@@ -11,14 +12,7 @@
typedef struct Action Action;
typedef struct Url Url;
typedef struct Www Www;
-typedef struct Scheme Scheme;
typedef struct Field Field;
-struct Scheme{
- char *name;
- int type;
- int flags;
- int port;
-};
struct Action{
char *image;
Field *field;
@@ -30,23 +24,15 @@
};
struct Url{
char fullname[NNAME];
- Scheme *scheme;
- char ipaddr[NNAME];
+ char basename[NNAME];
char reltext[NNAME];
char tag[NNAME];
- char redirname[NNAME];
- char autharg[NAUTH];
- char authtype[NTITLE];
char charset[NNAME];
- int port;
- int access;
int type;
int map; /* is this an image map? */
- int ssl;
};
struct Www{
Url *url;
- Url *base;
void *pix;
void *form;
char title[NTITLE];
@@ -83,18 +69,6 @@
};
/*
- * url access types
- */
-enum{
- HTTP=1,
- FTP,
- FILE,
- TELNET,
- MAILTO,
- GOPHER,
-};
-
-/*
* authentication types
*/
enum{
@@ -119,7 +93,7 @@
void plrdhtml(char *, int, Www *);
void plrdplain(char *, int, Www *);
void htmlerror(char *, int, char *, ...); /* user-supplied routine */
-void crackurl(Url *, char *, Url *);
+void seturl(Url *, char *, char *);
void getpix(Rtext *, Www *);
int pipeline(char *, int);
int urlopen(Url *, int, char *);
@@ -128,16 +102,9 @@
void *emallocz(int, int);
void setbitmap(Rtext *);
void message(char *, ...);
-int ftp(Url *);
-int http(Url *, int, char *);
-int gopher(Url *);
-int cistrcmp(char *, char *);
-int cistrncmp(char *, char *, int);
int suffix2type(char *);
int content2type(char *, char *);
int encoding2type(char *);
void mkfieldpanel(Rtext *);
void geturl(char *, int, char *, int, int);
-int dir2html(char *, int);
-int auth(Url*, char*, int);
char version[];
--- a/sys/src/cmd/mothra/rdhtml.c
+++ b/sys/src/cmd/mothra/rdhtml.c
@@ -679,7 +679,6 @@
g.tp=g.text;
g.etext=g.text+NTITLE-1;
dst->title[0]='\0';
- dst->base=dst->url;
g.spacc=0;
g.form=0;
g.charset[0] = '\0';
@@ -795,12 +794,6 @@
case Tag_b:
case Tag_strong:
g.state->font=BOLD;
- break;
- case Tag_base:
- if(str=pl_getattr(g.attr, "href")){
- dst->base=emalloc(sizeof(Url));
- crackurl(dst->base, str, dst->url);
- }
break;
case Tag_blockquot:
g.spacc=0;
--- a/sys/src/cmd/mothra/urlcanon.c
+++ /dev/null
@@ -1,70 +1,0 @@
-#include <u.h>
-#include <libc.h>
-void *emalloc(int n){
- void *p;
- p=malloc(n);
- if(p==0){
- fprint(2, "can't malloc\n");
- exits("no mem");
- }
- return p;
-}
-void urlcanon(char *name){
- char *s, *t;
- char **comp, **p, **q;
- int rooted;
- rooted=name[0]=='/';
- /*
- * Break the name into a list of components
- */
- comp=emalloc(strlen(name)*sizeof(char *));
- p=comp;
- *p++=name;
- for(s=name;;s++){
- if(*s=='/'){
- *p++=s+1;
- *s='\0';
- }
- else if(*s=='\0')
- break;
- }
- *p=0;
- /*
- * go through the component list, deleting components that are empty (except
- * the last component) or ., and any .. and its non-.. predecessor.
- */
- p=q=comp;
- while(*p){
- if(strcmp(*p, "")==0 && p[1]!=0
- || strcmp(*p, ".")==0)
- p++;
- else if(strcmp(*p, "..")==0 && q!=comp && strcmp(q[-1], "..")!=0){
- --q;
- p++;
- }
- else
- *q++=*p++;
- }
- *q=0;
- /*
- * rebuild the path name
- */
- s=name;
- if(rooted) *s++='/';
- for(p=comp;*p;p++){
- t=*p;
- while(*t) *s++=*t++;
- if(p[1]!=0) *s++='/';
- }
- *s='\0';
- free(comp);
-}
-void main(int argc, char *argv[]){
- int i;
- for(i=1;i!=argc;i++){
- print("%s: ", argv[i]);
- urlcanon(argv[i]);
- print("%s\n", argv[i]);
- }
- exits(0);
-}
--- a/sys/src/cmd/mothra/version.c
+++ b/sys/src/cmd/mothra/version.c
@@ -1,1 +1,1 @@
-char version[]="Sep-4-19:07:30-CET-2011";
+char version[]="Sep-5-03:25:57-CET-2011";