=================================================================== RCS file: /cvs/mandoc/cgi.c,v retrieving revision 1.24 retrieving revision 1.31 diff -u -p -r1.24 -r1.31 --- mandoc/cgi.c 2011/12/10 21:51:07 1.24 +++ mandoc/cgi.c 2011/12/14 13:36:59 1.31 @@ -1,4 +1,4 @@ -/* $Id: cgi.c,v 1.24 2011/12/10 21:51:07 kristaps Exp $ */ +/* $Id: cgi.c,v 1.31 2011/12/14 13:36:59 kristaps Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons * @@ -67,6 +67,7 @@ struct query { const char *arch; /* architecture */ const char *sec; /* manual section */ const char *expr; /* unparsed expression string */ + int manroot; /* manroot index (or -1)*/ int whatis; /* whether whatis mode */ int legacy; /* whether legacy mode */ }; @@ -85,7 +86,7 @@ static void format(const char *); static void html_print(const char *); static void html_putchar(char); static int http_decode(char *); -static void http_parse(struct query *, char *); +static void http_parse(struct req *, char *); static int pathstop(DIR *); static void pathgen(DIR *, char *, struct req *); static void pg_index(const struct req *, char *); @@ -102,9 +103,10 @@ static void resp_index(const struct req *); static void resp_search(struct res *, size_t, void *); static void resp_searchform(const struct req *); -static const char *progname; -static const char *cache; -static const char *host; +static const char *progname; /* cgi script name */ +static const char *cache; /* cache directory */ +static const char *css; /* css directory */ +static const char *host; /* hostname */ static const char * const pages[PAGE__MAX] = { "index", /* PAGE_INDEX */ @@ -182,16 +184,17 @@ html_print(const char *p) * uses only GET for simplicity. */ static void -http_parse(struct query *q, char *p) +http_parse(struct req *req, char *p) { - char *key, *val; + char *key, *val, *manroot; size_t sz; - int legacy; + int i, legacy; - memset(q, 0, sizeof(struct query)); + memset(&req->q, 0, sizeof(struct query)); - q->whatis = 1; + req->q.whatis = 1; legacy = -1; + manroot = NULL; while (p && '\0' != *p) { while (' ' == *p) @@ -232,29 +235,31 @@ http_parse(struct query *q, char *p) break; if (0 == strcmp(key, "expr")) - q->expr = val; + req->q.expr = val; else if (0 == strcmp(key, "query")) - q->expr = val; + req->q.expr = val; else if (0 == strcmp(key, "sec")) - q->sec = val; + req->q.sec = val; else if (0 == strcmp(key, "sektion")) - q->sec = val; + req->q.sec = val; else if (0 == strcmp(key, "arch")) - q->arch = val; + req->q.arch = val; + else if (0 == strcmp(key, "manpath")) + manroot = val; else if (0 == strcmp(key, "apropos")) legacy = 0 == strcmp(val, "0"); else if (0 == strcmp(key, "op")) - q->whatis = 0 == strcasecmp(val, "whatis"); + req->q.whatis = 0 == strcasecmp(val, "whatis"); } /* Test for old man.cgi compatibility mode. */ if (legacy == 0) { - q->whatis = 0; - q->legacy = 1; + req->q.whatis = 0; + req->q.legacy = 1; } else if (legacy > 0) { - q->legacy = 1; - q->whatis = 1; + req->q.legacy = 1; + req->q.whatis = 1; } /* @@ -262,12 +267,21 @@ http_parse(struct query *q, char *p) * For some man.cgi scripts, "default" arch is none. */ - if (q->legacy && NULL != q->sec) - if (0 == strcmp(q->sec, "0")) - q->sec = NULL; - if (q->legacy && NULL != q->arch) - if (0 == strcmp(q->arch, "default")) - q->arch = NULL; + if (req->q.legacy && NULL != req->q.sec) + if (0 == strcmp(req->q.sec, "0")) + req->q.sec = NULL; + if (req->q.legacy && NULL != req->q.arch) + if (0 == strcmp(req->q.arch, "default")) + req->q.arch = NULL; + + /* Default to first manroot. */ + + if (NULL != manroot) { + for (i = 0; i < (int)req->psz; i++) + if (0 == strcmp(req->p[i].name, manroot)) + break; + req->q.manroot = i < (int)req->psz ? i : -1; + } } /* @@ -325,19 +339,19 @@ resp_begin_html(int code, const char *msg) resp_begin_http(code, msg); - puts("\n" - "\n" - "\n" - "\n" - "\n" - "System Manpage Reference\n" - "\n" - "\n" - ""); + printf("\n" + "\n" + "\n" + "\n" + "\n" + "System Manpage Reference\n" + "\n" + "\n" + "\n", css); } static void @@ -351,18 +365,18 @@ resp_end_html(void) static void resp_searchform(const struct req *req) { + int i; puts(""); - printf("
\n"); - printf("
\n" + printf("\n" + "
\n" "Search Parameters\n" " or \n" " for manuals satisfying \n" - "q.expr ? req->q.expr : ""); printf("\">, section " "q.arch ? req->q.arch : ""); - puts("\">.\n" + printf("\">"); + if (req->psz > 1) { + puts(", "); + } + puts(".\n" "\n" "
\n" ""); @@ -443,14 +472,17 @@ resp_search(struct res *r, size_t sz, void *arg) int i; const struct req *req; + req = (const struct req *)arg; + assert(req->q.manroot >= 0); + if (1 == sz) { /* * If we have just one result, then jump there now * without any delay. */ puts("Status: 303 See Other"); - printf("Location: http://%s%s/show/%u/%u.html\n", - host, progname, + printf("Location: http://%s%s/show/%d/%u/%u.html\n", + host, progname, req->q.manroot, r[0].volume, r[0].rec); puts("Content-Type: text/html; charset=utf-8\n"); return; @@ -459,8 +491,6 @@ resp_search(struct res *r, size_t sz, void *arg) qsort(r, sz, sizeof(struct res), cmp); resp_begin_html(200, NULL); - - req = (const struct req *)arg; resp_searchform(req); if (0 == sz) { @@ -468,9 +498,8 @@ resp_search(struct res *r, size_t sz, void *arg) "No %s results found.\n", req->q.whatis ? "whatis" : "apropos"); if (req->q.whatis) { - printf("(Try q.expr ? req->q.expr : ""); printf("&sec="); html_print(req->q.sec ? req->q.sec : ""); @@ -489,9 +518,9 @@ resp_search(struct res *r, size_t sz, void *arg) for (i = 0; i < (int)sz; i++) { printf("\n" "\n" - "", r[i].volume, r[i].rec); + "", + progname, req->q.manroot, + r[i].volume, r[i].rec); html_print(r[i].title); putchar('('); html_print(r[i].cat); @@ -534,20 +563,20 @@ catman(const char *file) } resp_begin_http(200, NULL); - puts("\n" - "\n" - "\n" - "\n" - "\n" - "System Manpage Reference\n" - "\n" - "\n" - "\n" - "
");
+	printf("\n"
+	       "\n"
+	       "\n"
+	       "\n"
+	       "\n"
+	       "System Manpage Reference\n"
+	       "\n"
+	       "\n"
+	       "\n"
+	       "
\n", css);
 
 	while (NULL != (p = fgetln(f, &len))) {
 		bold = italic = 0;
@@ -690,10 +719,10 @@ format(const char *file)
 		return;
 	}
 
-	snprintf(opts, sizeof(opts), "style=/man.css,"
+	snprintf(opts, sizeof(opts), "style=%s/man.css,"
 			"man=%s/search.html?sec=%%S&expr=%%N,"
 			/*"includes=/cgi-bin/man.cgi/usr/include/%%I"*/,
-			progname);
+			css, progname);
 
 	mparse_result(mp, &mdoc, &man);
 	vp = html_alloc(opts);
@@ -719,42 +748,55 @@ pg_show(const struct req *req, char *path)
 	char		 file[MAXPATHLEN];
 	const char	*fn, *cp;
 	int		 rc;
-	unsigned int	 vol, rec;
+	unsigned int	 vol, rec, mr;
 	DB		*idx;
 	DBT		 key, val;
 
 	idx = NULL;
 
-	if (0 == req->psz || NULL == path) {
+	/* Parse out mroot, volume, and record from the path. */
+
+	if (NULL == path || NULL == (sub = strchr(path, '/'))) {
 		resp_error400();
 		return;
-	} else if (NULL == (sub = strrchr(path, '/'))) {
+	} 
+	*sub++ = '\0';
+	if ( ! atou(path, &mr)) {
 		resp_error400();
 		return;
-	} else
-		*sub++ = '\0';
+	}
+	path = sub;
+	if (NULL == (sub = strchr(path, '/'))) {
+		resp_error400();
+		return;
+	}
+	*sub++ = '\0';
+	if ( ! atou(path, &vol) || ! atou(sub, &rec)) {
+		resp_error400();
+		return;
+	} else if (mr >= (unsigned int)req->psz) {
+		resp_error400();
+		return;
+	}
 
 	/*
-	 * Begin by chdir()ing into the root of the manpath.
+	 * Begin by chdir()ing into the manroot.
 	 * This way we can pick up the database files, which are
 	 * relative to the manpath root.
 	 */
 
-	if (-1 == chdir(req->p[0].path)) {
-		perror(req->p[0].path);
-		resp_error400();
+	if (-1 == chdir(req->p[(int)mr].path)) {
+		perror(req->p[(int)mr].path);
+		resp_baddb();
 		return;
 	}
 
 	memset(&ps, 0, sizeof(struct manpaths));
-	manpath_manconf("etc/catman.conf", &ps);
+	manpath_manconf(&ps, "etc/catman.conf");
 
-	if ( ! (atou(path, &vol) && atou(sub, &rec))) {
+	if (vol >= (unsigned int)ps.sz) {
 		resp_error400();
 		goto out;
-	} else if (vol >= (unsigned int)ps.sz) {
-		resp_error400();
-		goto out;
 	}
 
 	strlcpy(file, ps.paths[vol], MAXPATHLEN);
@@ -808,7 +850,7 @@ pg_search(const struct req *req, char *path)
 	struct opts	  opt;
 	struct expr	 *expr;
 
-	if (0 == req->psz) {
+	if (req->q.manroot < 0 || 0 == req->psz) {
 		resp_search(NULL, 0, (void *)req);
 		return;
 	}
@@ -828,14 +870,15 @@ pg_search(const struct req *req, char *path)
 	 * relative to the manpath root.
 	 */
 
-	if (-1 == (chdir(req->p[0].path))) {
-		perror(req->p[0].path);
+	assert(req->q.manroot < (int)req->psz);
+	if (-1 == (chdir(req->p[req->q.manroot].path))) {
+		perror(req->p[req->q.manroot].path);
 		resp_search(NULL, 0, (void *)req);
 		return;
 	}
 
 	memset(&ps, 0, sizeof(struct manpaths));
-	manpath_manconf("etc/catman.conf", &ps);
+	manpath_manconf(&ps, "etc/catman.conf");
 
 	/*
 	 * Poor man's tokenisation: just break apart by spaces.
@@ -896,16 +939,16 @@ main(void)
 
 	/* Scan our run-time environment. */
 
-	progname = getenv("SCRIPT_NAME");
-	if (NULL == progname)
+	if (NULL == (cache = getenv("CACHE_DIR")))
+		cache = "/cache/man.cgi";
+
+	if (NULL == (progname = getenv("SCRIPT_NAME")))
 		progname = "";
 
-	cache = getenv("CACHE_DIR");
-	if (NULL == cache)
-		cache = "/cache/man.cgi";
+	if (NULL == (css = getenv("CSS_DIR")))
+		css = "";
 
-	host = getenv("HTTP_HOST");
-	if (NULL == host)
+	if (NULL == (host = getenv("HTTP_HOST")))
 		host = "localhost";
 
 	/*
@@ -933,7 +976,7 @@ main(void)
 	/* Next parse out the query string. */
 
 	if (NULL != (p = getenv("QUERY_STRING")))
-		http_parse(&req.q, p);
+		http_parse(&req, p);
 
 	/*
 	 * Now juggle paths to extract information.
@@ -1070,14 +1113,17 @@ pathgen(DIR *dir, char *path, struct req *req)
 
 	if (rc > 0) {
 		/* This also strips the trailing slash. */
-		path[(int)sz - 1] = '\0';
+		path[(int)--sz] = '\0';
 		req->p = mandoc_realloc
 			(req->p, 
 			 (req->psz + 1) * sizeof(struct paths));
+		/*
+		 * Strip out the leading "./" unless we're just a ".",
+		 * in which case use an empty string as our name.
+		 */
 		req->p[(int)req->psz].path = mandoc_strdup(path);
-		/* And this strips out the leading "./". */
 		req->p[(int)req->psz].name = 
-			cp = mandoc_strdup(path + 2);
+			cp = mandoc_strdup(path + (1 == sz ? 1 : 2));
 		req->psz++;
 		/* 
 		 * The name is just the path with all the slashes taken