+ if (!path_info)
+ path_info = "";
+
+ /*
+ * Because we need relative links to go to the
+ * right place, it's important that our
+ * PATH_INFO should contain a slash right at the
+ * start, and no slashes anywhere else.
+ */
+ if (path_info[0] != '/') {
+ char *servername = getenv("SERVER_NAME");
+ char *scriptname = getenv("SCRIPT_NAME");
+ if (!servername || !scriptname) {
+ if (servername)
+ fprintf(stderr, "%s: SCRIPT_NAME unset\n", PNAME);
+ else if (scriptname)
+ fprintf(stderr, "%s: SCRIPT_NAME unset\n", PNAME);
+ else
+ fprintf(stderr, "%s: SERVER_NAME and "
+ "SCRIPT_NAME both unset\n", PNAME);
+ printf("Status: 500\nContent-type: text/html\n\n"
+ "<html><head>"
+ "<title>500 Internal Server Error</title>"
+ "</head><body>"
+ "<h1>500 Internal Server Error</h1>"
+ "<p><code>agedu</code> suffered an internal "
+ "error."
+ "</body></html>\n");
+ return 0;
+ }
+ printf("Status: 301\n"
+ "Location: http://%s/%s/\n"
+ "Content-type: text/html\n\n"
+ "<html><head>"
+ "<title>301 Moved</title>"
+ "</head><body>"
+ "<h1>301 Moved</h1>"
+ "<p>Moved."
+ "</body></html>\n",
+ servername, scriptname);
+ return 0;
+ } else if (strchr(path_info+1, '/')) {
+ printf("Status: 404\nContent-type: text/html\n\n"
+ "<html><head>"
+ "<title>404 Not Found</title>"
+ "</head><body>"
+ "<h1>400 Not Found</h1>"
+ "<p>Invalid <code>agedu</code> pathname."
+ "</body></html>\n");
+ return 0;
+ }
+ xi = atoi(path_info + 1);
+
+ if (xi >= trie_count(mappedfile)) {
+ printf("Status: 404\nContent-type: text/html\n\n"
+ "<html><head>"
+ "<title>404 Not Found</title>"
+ "</head><body>"
+ "<h1>404 Not Found</h1>"
+ "<p>This is not a valid pathname index."
+ "</body></html>\n");
+ return 0;
+ } else if (!index_has_root(mappedfile, xi)) {
+ printf("Status: 404\nContent-type: text/html\n\n"
+ "<html><head>"
+ "<title>404 Not Found</title>"
+ "</head><body>"
+ "<h1>404 Not Found</h1>"
+ "<p>Pathname index out of range."
+ "</body></html>\n");
+ return 0;
+ }
+ } else {
+ /*
+ * In ordinary --html mode, process a query
+ * directory passed in on the command line.
+ */
+
+ /*
+ * Trim trailing slash, just in case.
+ */
+ pathlen = strlen(querydir);
+ if (pathlen > 0 && querydir[pathlen-1] == pathsep)
+ querydir[--pathlen] = '\0';
+
+ xi = trie_before(mappedfile, querydir);
+ if (xi >= trie_count(mappedfile) ||
+ (trie_getpath(mappedfile, xi, pathbuf),
+ strcmp(pathbuf, querydir))) {
+ fprintf(stderr, "%s: pathname '%s' does not exist in index\n"
+ "%*s(check it is spelled exactly as it is in the "
+ "index, including\n%*sany leading './')\n",
+ PNAME, querydir,
+ (int)(1+sizeof(PNAME)), "",
+ (int)(1+sizeof(PNAME)), "");
+ return 1;
+ } else if (!index_has_root(mappedfile, xi)) {
+ fprintf(stderr, "%s: pathname '%s' is"
+ " a file, not a directory\n", PNAME, querydir);
+ return 1;
+ }
+ }
+
+ if (!querydir || !gotdepth) {
+ /*
+ * Single output file.
+ */
+ if (!querydir) {
+ cfg.format = "%.0lu"; /* use crosslinks in --cgi mode */
+ } else {
+ cfg.format = NULL;
+ }
+ cfg.rootpage = NULL;
+ cfg.autoage = htmlautoagerange;
+ cfg.oldest = htmloldest;
+ cfg.newest = htmlnewest;
+ cfg.showfiles = showfiles;
+ html = html_query(mappedfile, xi, &cfg, 1);
+ if (querydir && outfile != NULL) {
+ FILE *fp = fopen(outfile, "w");
+ if (!fp) {
+ fprintf(stderr, "%s: %s: open: %s\n", PNAME,
+ outfile, strerror(errno));
+ return 1;
+ } else if (fputs(html, fp) < 0) {
+ fprintf(stderr, "%s: %s: write: %s\n", PNAME,
+ outfile, strerror(errno));
+ fclose(fp);
+ return 1;
+ } else if (fclose(fp) < 0) {
+ fprintf(stderr, "%s: %s: fclose: %s\n", PNAME,
+ outfile, strerror(errno));
+ return 1;
+ }
+ } else {
+ if (!querydir) {
+ printf("Content-type: text/html\n\n");
+ }
+ fputs(html, stdout);
+ }
+ } else {
+ /*
+ * Multiple output files.
+ */
+ int dirlen = outfile ? 2+strlen(outfile) : 3;
+ char prefix[dirlen];
+ if (outfile) {
+ if (mkdir(outfile, 0777) < 0 && errno != EEXIST) {
+ fprintf(stderr, "%s: %s: mkdir: %s\n", PNAME,
+ outfile, strerror(errno));
+ return 1;
+ }
+ snprintf(prefix, dirlen, "%s/", outfile);
+ } else
+ snprintf(prefix, dirlen, "./");
+
+ unsigned long xi2;
+ /*
+ * pathbuf is only set up in the plain-HTML case and
+ * not in the CGI case; but that's OK, because the
+ * CGI case can't come to this branch of the if
+ * anyway.
+ */
+ make_successor(pathbuf);
+ xi2 = trie_before(mappedfile, pathbuf);
+
+ cfg.format = "%lu.html";
+ cfg.rootpage = "index.html";
+ cfg.autoage = htmlautoagerange;
+ cfg.oldest = htmloldest;
+ cfg.newest = htmlnewest;
+ cfg.showfiles = showfiles;
+ if (html_dump(mappedfile, xi, xi2, depth, &cfg, prefix))
+ return 1;
+ }
+
+ munmap(mappedfile, totalsize);
+ sfree(pathbuf);