Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>
#include "httpd.h"
#include "httpsrv.h"

static  Hio             *hout;
static  Hio             houtb;
static  HConnect        *connect;

void    doconvert(char*, int);

void
error(char *title, char *fmt, ...)
{
        va_list arg;
        char buf[1024], *out;

        va_start(arg, fmt);
        out = vseprint(buf, buf+sizeof(buf), fmt, arg);
        va_end(arg);
        *out = 0;

        hprint(hout, "%s 404 %s\n", hversion, title);
        hprint(hout, "Date: %D\n", time(nil));
        hprint(hout, "Server: Plan9\n");
        hprint(hout, "Content-type: text/html\n");
        hprint(hout, "\n");
        hprint(hout, "<head><title>%s</title></head>\n", title);
        hprint(hout, "<body><h1>%s</h1></body>\n", title);
        hprint(hout, "%s\n", buf);
        hflush(hout);
        writelog(connect, "Reply: 404\nReason: %s\n", title);
        exits(nil);
}

typedef struct Hit      Hit;
struct Hit 
{
        Hit *next;
        char *file;
};

void
lookup(char *object, int section, Hit **list)
{
        int fd;
        char *p, *f;
        Biobuf b;
        char file[256];
        Hit *h;

        while(*list != nil)
                list = &(*list)->next;

        snprint(file, sizeof(file), "/sys/man/%d/INDEX", section);
        fd = open(file, OREAD);
        if(fd > 0){
                Binit(&b, fd, OREAD);
                for(;;){
                        p = Brdline(&b, '\n');
                        if(p == nil)
                                break;
                        p[Blinelen(&b)-1] = 0;
                        f = strchr(p, ' ');
                        if(f == nil)
                                continue;
                        *f++ = 0;
                        if(strcmp(p, object) == 0){
                                h = ezalloc(sizeof *h);
                                *list = h;
                                h->next = nil;
                                snprint(file, sizeof(file), "/%d/%s", section, f);
                                h->file = estrdup(file);
                                close(fd);
                                return;
                        }
                }
                close(fd);
        }
        snprint(file, sizeof(file), "/sys/man/%d/%s", section, object);
        if(access(file, 0) == 0){
                h = ezalloc(sizeof *h);
                *list = h;
                h->next = nil;
                h->file = estrdup(file+8);
        }
}

void
manindex(int sect, int vermaj)
{
        int i;

        if(vermaj){
                hokheaders(connect);
                hprint(hout, "Content-type: text/html\r\n");
                hprint(hout, "\r\n");
        }

        hprint(hout, "<head><title>plan 9 section index");
        if(sect)
                hprint(hout, "(%d)\n", sect);
        hprint(hout, "</title></head><body>\n");
        hprint(hout, "<H6>Section Index");
        if(sect)
                hprint(hout, "(%d)\n", sect);
        hprint(hout, "</H6>\n");

        if(sect)
                hprint(hout, "<p><a href=\"/plan9/man%d.html\">/plan9/man%d.html</a>\n",
                        sect, sect);
        else for(i = 1; i < 10; i++)
                hprint(hout, "<p><a href=\"/plan9/man%d.html\">/plan9/man%d.html</a>\n",
                        i, i);
        hprint(hout, "</body>\n");
}

void
man(char *o, int sect, int vermaj)
{
        int i;
        Hit *list;

        list = nil;

        if(*o == 0){
                manindex(sect, vermaj);
                return;
        }

        if(sect > 0 && sect < 10)
                lookup(o, sect, &list);
        else
                for(i = 1; i < 9; i++)
                        lookup(o, i, &list);

        if(list != nil && list->next == nil){
                doconvert(list->file, vermaj);
                return;
        }

        if(vermaj){
                hokheaders(connect);
                hprint(hout, "Content-type: text/html\r\n");
                hprint(hout, "\r\n");
        }

        hprint(hout, "<head><title>plan 9 man %H", o);
        if(sect)
                hprint(hout, "(%d)\n", sect);
        hprint(hout, "</title></head><body>\n");
        hprint(hout, "<H6>Search for %H", o);
        if(sect)
                hprint(hout, "(%d)\n", sect);
        hprint(hout, "</H6>\n");

        for(; list; list = list->next)
                hprint(hout, "<p><a href=\"/magic/man2html%U\">/magic/man2html%H</a>\n",
                        list->file, list->file);
        hprint(hout, "</body>\n");
}

void
strlwr(char *p)
{
        for(; *p; p++)
                if('A' <= *p && *p <= 'Z')
                        *p += 'a'-'A';
}

void
redirectto(char *uri)
{
        if(connect){
                hmoved(connect, uri);
                exits(0);
        }else
                hprint(hout, "Your selection moved to <a href=\"%U\"> here</a>.<p></body>\r\n", uri);
}

void
searchfor(char *search)
{
        int i, j, n, fd;
        char *p, *sp;
        Biobufhdr *b;
        char *arg[32];

        hprint(hout, "<head><title>plan 9 search for %H</title></head>\n", search);
        hprint(hout, "<body>\n");

        hprint(hout, "<p>This is a keyword search through Plan 9 man pages.\n");
        hprint(hout, "The search is case insensitive; blanks denote \"boolean and\".\n");
        hprint(hout, "<FORM METHOD=\"GET\" ACTION=\"/magic/man2html\">\n");
        hprint(hout, "<INPUT NAME=\"pat\" TYPE=\"text\" SIZE=\"60\">\n");
        hprint(hout, "<INPUT TYPE=\"submit\" VALUE=\"Submit\">\n");
        hprint(hout, "</FORM>\n");

        hprint(hout, "<hr><H6>Search for %H</H6>\n", search);
        n = getfields(search, arg, 32, 1, "+");
        for(i = 0; i < n; i++){
                for(j = i+1; j < n; j++){
                        if(strcmp(arg[i], arg[j]) > 0){
                                sp = arg[j];
                                arg[j] = arg[i];
                                arg[i] = sp;
                        }
                }
                sp = malloc(strlen(arg[i]) + 2);
                if(sp != nil){
                        strcpy(sp+1, arg[i]);
                        sp[0] = ' ';
                        arg[i] = sp;
                }
        }

        /*
         *  search index till line starts alphabetically < first token
         */
        fd = open("/sys/man/searchindex", OREAD);
        if(fd < 0){
                hprint(hout, "<body>error: No Plan 9 search index\n");
                hprint(hout, "</body>");
                return;
        }
        p = malloc(32*1024);
        if(p == nil){
                close(fd);
                return;
        }
        b = ezalloc(sizeof *b);
        Binits(b, fd, OREAD, (uchar*)p, 32*1024);
        for(;;){
                p = Brdline(b, '\n');
                if(p == nil)
                        break;
                p[Blinelen(b)-1] = 0;
                for(i = 0; i < n; i++){
                        sp = strstr(p, arg[i]);
                        if(sp == nil)
                                break;
                        p = sp;
                }
                if(i < n)
                        continue;
                sp = strrchr(p, '\t');
                if(sp == nil)
                        continue;
                sp++;
                hprint(hout, "<p><a href=\"/magic/man2html/%U\">/magic/man2html/%H</a>\n",
                        sp, sp);
        }
        hprint(hout, "</body>");

        Bterm(b);
        free(b);
        free(p);
        close(fd);
}

/*
 *  find man pages mentioning the search string
 */
void
dosearch(int vermaj, char *search)
{
        int sect;
        char *p;

        if(strncmp(search, "man=", 4) == 0){
                sect = 0;
                search = hurlunesc(connect, search+4);
                p = strchr(search, '&');
                if(p != nil){
                        *p++ = 0;
                        if(strncmp(p, "sect=", 5) == 0)
                                sect = atoi(p+5);
                }
                man(search, sect, vermaj);
                return;
        }

        if(vermaj){
                hokheaders(connect);
                hprint(hout, "Content-type: text/html\r\n");
                hprint(hout, "\r\n");
        }

        if(strncmp(search, "pat=", 4) == 0){
                search = hurlunesc(connect, search+4);
                search = hlower(search);
                searchfor(search);
                return;
        }

        hprint(hout, "<head><title>illegal search</title></head>\n");
        hprint(hout, "<body><p>Illegally formatted Plan 9 man page search</p>\n");
        search = hurlunesc(connect, search);
        hprint(hout, "<body><p>%H</p>\n", search);
        hprint(hout, "</body>");
}

/*
 *  convert a man page to html and output
 */
void
doconvert(char *uri, int vermaj)
{
        char *p;
        char file[256];
        char title[256];
        char err[ERRMAX];
        int pfd[2];
        Dir *d;
        Waitmsg *w;
        int x;

        if(strstr(uri, ".."))
                error("bad URI", "man page URI cannot contain ..");
        p = strstr(uri, "/intro");

        if(p == nil){
                while(*uri == '/')
                        uri++;
                /* redirect section requests */
                snprint(file, sizeof(file), "/sys/man/%s", uri);
                d = dirstat(file);
                if(d == nil){
                        strlwr(file);
                        if(dirstat(file) != nil){
                                snprint(file, sizeof(file), "/magic/man2html/%s", uri);
                                strlwr(file);
                                redirectto(file);
                        }
                        error(uri, "man page not found");
                }
                x = d->qid.type;
                free(d);
                if(x & QTDIR){
                        if(*uri == 0 || strcmp(uri, "/") == 0)
                                redirectto("/sys/man/index.html");
                        else {
                                snprint(file, sizeof(file), "/sys/man/%s/INDEX.html",
                                        uri+1);
                                redirectto(file);
                        }
                        return;
                }
        } else {
                /* rewrite the name intro */
                *p = 0;
                snprint(file, sizeof(file), "/sys/man/%s/0intro", uri);
                d = dirstat(file);
                free(d);
                if(d == nil)
                        error(uri, "man page not found");
        }

        if(vermaj){
                hokheaders(connect);
                hprint(hout, "Content-type: text/html\r\n");
                hprint(hout, "\r\n");
        }
        hflush(hout);

        if(pipe(pfd) < 0)
                error("out of resources", "pipe failed");

        /* troff -manhtml <file> | troff2html -t '' */
        switch(fork()){
        case -1:
                error("out of resources", "fork failed");
        case 0:
                snprint(title, sizeof(title), "Plan 9 %s", file);
                close(0);
                dup(pfd[0], 0);
                close(pfd[0]);
                close(pfd[1]);
                execl("/bin/troff2html", "troff2html", "-t", title, nil);
                errstr(err, sizeof err);
                exits(err);
        }
        switch(fork()){
        case -1:
                error("out of resources", "fork failed");
        case 0:
                snprint(title, sizeof(title), "Plan 9 %s", file);
                close(0);
                close(1);
                dup(pfd[1], 1);
                close(pfd[0]);
                close(pfd[1]);
                execl("/bin/troff", "troff", "-manhtml", file, nil);
                errstr(err, sizeof err);
                exits(err);
        }
        close(pfd[0]);
        close(pfd[1]);

        /* wait for completion */
        for(;;){
                w = wait();
                if(w == nil)
                        break;
                if(w->msg[0] != 0)
                        print("whoops %s\n", w->msg);
                free(w);
        }
}

void
main(int argc, char **argv)
{
        fmtinstall('H', httpfmt);
        fmtinstall('U', hurlfmt);

        if(argc == 2){
                hinit(&houtb, 1, Hwrite);
                hout = &houtb;
                doconvert(argv[1], 0);
                exits(nil);
        }
        close(2);

        connect = init(argc, argv);
        hout = &connect->hout;
        if(hparseheaders(connect, HSTIMEOUT) < 0)
                exits("failed");

        if(strcmp(connect->req.meth, "GET") != 0 && strcmp(connect->req.meth, "HEAD") != 0){
                hunallowed(connect, "GET, HEAD");
                exits("not allowed");
        }
        if(connect->head.expectother || connect->head.expectcont){
                hfail(connect, HExpectFail, nil);
                exits("failed");
        }

        bind("/usr/web/sys/man", "/sys/man", MREPL);

        if(connect->req.search != nil)
                dosearch(connect->req.vermaj, connect->req.search);
        else
                doconvert(connect->req.uri, connect->req.vermaj);
        hflush(hout);
        writelog(connect, "200 man2html %ld %ld\n", hout->seek, hout->seek);
        exits(nil);
}