===================================================================
RCS file: /cvs/mandoc/cgi.c,v
retrieving revision 1.7
retrieving revision 1.10
diff -u -p -r1.7 -r1.10
--- mandoc/cgi.c 2011/11/24 12:27:18 1.7
+++ mandoc/cgi.c 2011/12/07 00:23:04 1.10
@@ -1,4 +1,4 @@
-/* $Id: cgi.c,v 1.7 2011/11/24 12:27:18 kristaps Exp $ */
+/* $Id: cgi.c,v 1.10 2011/12/07 00:23:04 kristaps Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons
\n" + " The query your entered was malformed.\n" + " Try again from the\n" + " main page\n" + "
"); resp_end_html(); } static void -resp_badexpr(const struct req *req) +resp_error404(const char *page) { - resp_begin_html(200, NULL); - resp_searchform(req); - puts("Your search didn't work.
"); + resp_begin_html(404, "Not Found"); + puts("\n" + " The page you're looking for, "); + printf(" "); + html_print(page); + puts(",\n" + " could not be found.\n" + " Try searching from the\n" + " main page\n" + "
"); resp_end_html(); } @@ -434,56 +457,182 @@ pg_index(const struct manpaths *ps, const struct req * } static void -format_insecure(const char *file) +catman(const char *file) { - pid_t pid; - char cmd[MAXPATHLEN]; + FILE *f; + size_t len; + int i; + char *p; + int italic, bold; - strlcpy(cmd, "man=", MAXPATHLEN); - strlcat(cmd, progname, MAXPATHLEN); - strlcat(cmd, "/search?expr=%N&sec=%S", MAXPATHLEN); + if (NULL == (f = fopen(file, "r"))) { + resp_baddb(); + return; + } - /* Get ready to call the child mandoc(1) process. */ + resp_begin_html(200, NULL); - if (-1 == (pid = fork())) - exit(EXIT_FAILURE); + puts(""); + while (NULL != (p = fgetln(f, &len))) { + bold = italic = 0; + for (i = 0; i < (int)len - 1; i++) { + /* + * This means that the catpage is out of state. + * Ignore it and keep going (although the + * catpage is bogus). + */ - if (pid > 0) { - waitpid(pid, NULL, 0); - return; - } + if ('\b' == p[i] || '\n' == p[i]) + continue; - dup2(STDOUT_FILENO, STDERR_FILENO); + /* + * Print a regular character. + * Close out any bold/italic scopes. + * If we're in back-space mode, make sure we'll + * have something to enter when we backspace. + */ - puts("Content-Type: text/html; charset=utf-8\n"); + if ('\b' != p[i + 1]) { + if (italic) + printf(""); + if (bold) + printf(""); + italic = bold = 0; + html_putchar(p[i]); + continue; + } else if (i + 2 >= (int)len) + continue; - fflush(stdout); + /* Italic mode. */ - execlp("mandoc", "mandoc", "-T", - "html", "-O", cmd, file, (char *)NULL); + if ('_' == p[i]) { + if (bold) + printf(""); + if ( ! italic) + printf(""); + bold = 0; + italic = 1; + i += 2; + html_putchar(p[i]); + continue; + } + + /* + * Handle funny behaviour troff-isms. + * These grok'd from the original man2html.c. + */ + + if (('+' == p[i] && 'o' == p[i + 2]) || + ('o' == p[i] && '+' == p[i + 2]) || + ('|' == p[i] && '=' == p[i + 2]) || + ('=' == p[i] && '|' == p[i + 2]) || + ('*' == p[i] && '=' == p[i + 2]) || + ('=' == p[i] && '*' == p[i + 2]) || + ('*' == p[i] && '|' == p[i + 2]) || + ('|' == p[i] && '*' == p[i + 2])) { + if (italic) + printf(""); + if (bold) + printf(""); + italic = bold = 0; + putchar('*'); + i += 2; + continue; + } else if (('|' == p[i] && '-' == p[i + 2]) || + ('-' == p[i] && '|' == p[i + 1]) || + ('+' == p[i] && '-' == p[i + 1]) || + ('-' == p[i] && '+' == p[i + 1]) || + ('+' == p[i] && '|' == p[i + 1]) || + ('|' == p[i] && '+' == p[i + 1])) { + if (italic) + printf(""); + if (bold) + printf(""); + italic = bold = 0; + putchar('+'); + i += 2; + continue; + } + + /* Bold mode. */ + + if (italic) + printf(""); + if ( ! bold) + printf(""); + bold = 1; + italic = 0; + i += 2; + html_putchar(p[i]); + } + + /* + * Clean up the last character. + * We can get to a newline; don't print that. + */ + + if (italic) + printf(""); + if (bold) + printf(""); + + if (i == (int)len - 1 && '\n' != p[i]) + html_putchar(p[i]); + + putchar('\n'); + } + + puts("\n" + "\n" + ""); + + fclose(f); } static void -format_secure(const char *file) +format(const char *file) { - char buf[BUFSIZ]; + struct mparse *mp; int fd; - ssize_t ssz; + struct mdoc *mdoc; + struct man *man; + void *vp; + enum mandoclevel rc; + char opts[MAXPATHLEN + 128]; if (-1 == (fd = open(file, O_RDONLY, 0))) { resp_baddb(); return; } - resp_begin_http(200, NULL); + mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL); + rc = mparse_readfd(mp, fd, file); + close(fd); - do { - ssz = read(fd, buf, BUFSIZ); - if (ssz > 0) - write(STDOUT_FILENO, buf, ssz); - } while (ssz > 0); + if (rc >= MANDOCLEVEL_FATAL) { + resp_baddb(); + return; + } - close(fd); + snprintf(opts, sizeof(opts), "style=/style.css," + "man=%s/search.html?sec=%%S&expr=%%N," + "includes=/cgi-bin/man.cgi/usr/include/%%I", + progname); + + mparse_result(mp, &mdoc, &man); + vp = html_alloc(opts); + + if (NULL != mdoc) { + resp_begin_http(200, NULL); + html_mdoc(vp, mdoc); + } else if (NULL != man) { + resp_begin_http(200, NULL); + html_man(vp, man); + } else + resp_baddb(); + + html_free(vp); + mparse_free(mp); } static void @@ -491,25 +640,26 @@ pg_show(const struct manpaths *ps, const struct req *r { char *sub; char file[MAXPATHLEN]; + const char *fn, *cp; int rc; unsigned int vol, rec; - DB *db; + DB *idx; DBT key, val; if (NULL == path) { - resp_badmanual(); + resp_error400(); return; } else if (NULL == (sub = strrchr(path, '/'))) { - resp_badmanual(); + resp_error400(); return; } else *sub++ = '\0'; if ( ! (atou(path, &vol) && atou(sub, &rec))) { - resp_badmanual(); + resp_error400(); return; } else if (vol >= (unsigned int)ps->sz) { - resp_badmanual(); + resp_error400(); return; } @@ -518,8 +668,8 @@ pg_show(const struct manpaths *ps, const struct req *r /* Open the index recno(3) database. */ - db = dbopen(file, O_RDONLY, 0, DB_RECNO, NULL); - if (NULL == db) { + idx = dbopen(file, O_RDONLY, 0, DB_RECNO, NULL); + if (NULL == idx) { resp_baddb(); return; } @@ -527,25 +677,30 @@ pg_show(const struct manpaths *ps, const struct req *r key.data = &rec; key.size = 4; - if (0 != (rc = (*db->get)(db, &key, &val, 0))) { - rc < 0 ? resp_baddb() : resp_badmanual(); - (*db->close)(db); - return; + if (0 != (rc = (*idx->get)(idx, &key, &val, 0))) { + rc < 0 ? resp_baddb() : resp_error400(); + goto out; } - /* Extra filename: the first nil-terminated entry. */ + cp = (char *)val.data; - (*db->close)(db); - - strlcpy(file, ps->paths[vol], MAXPATHLEN); - strlcat(file, "/", MAXPATHLEN); - strlcat(file, (char *)val.data, MAXPATHLEN); - - if ( ! insecure) { - strlcat(file, ".html", MAXPATHLEN); - format_secure(file); - } else - format_insecure(file); + if (NULL == (fn = memchr(cp, '\0', val.size))) + resp_baddb(); + else if (++fn - cp >= (int)val.size) + resp_baddb(); + else if (NULL == memchr(fn, '\0', val.size - (fn - cp))) + resp_baddb(); + else { + strlcpy(file, ps->paths[vol], MAXPATHLEN); + strlcat(file, "/", MAXPATHLEN); + strlcat(file, fn, MAXPATHLEN); + if (0 == strcmp(cp, "cat")) + catman(file); + else + format(file); + } +out: + (*idx->close)(idx); } static void @@ -611,7 +766,7 @@ pg_search(const struct manpaths *ps, const struct req if (0 == rc) resp_baddb(); else if (-1 == rc) - resp_badexpr(req); + resp_search(NULL, 0, (void *)req); for (i = 0; i < sz; i++) free(cp[i]); @@ -638,12 +793,9 @@ main(void) if (NULL == cache) cache = "/cache/man.cgi"; - if (NULL == getenv("INSECURE")) { - insecure = 0; - if (-1 == chdir(cache)) { - resp_bad(); - return(EXIT_FAILURE); - } + if (-1 == chdir(cache)) { + resp_bad(); + return(EXIT_FAILURE); } host = getenv("HTTP_HOST"); @@ -689,10 +841,7 @@ main(void) /* Initialise MANPATH. */ memset(&paths, 0, sizeof(struct manpaths)); - if ( ! insecure) - manpath_manconf("etc/man.conf", &paths); - else - manpath_parse(&paths, NULL, NULL); + manpath_manconf("etc/catman.conf", &paths); /* Route pages. */ @@ -707,6 +856,7 @@ main(void) pg_show(&paths, &req, subpath); break; default: + resp_error404(path); break; }