[BACK]Return to cgi.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Diff for /mandoc/cgi.c between version 1.7 and 1.20

version 1.7, 2011/11/24 12:27:18 version 1.20, 2011/12/09 11:29:19
Line 36 
Line 36 
   
 #include "apropos_db.h"  #include "apropos_db.h"
 #include "mandoc.h"  #include "mandoc.h"
   #include "mdoc.h"
   #include "man.h"
   #include "main.h"
 #include "manpath.h"  #include "manpath.h"
   
 #ifdef __linux__  #ifdef __linux__
Line 51  enum page {
Line 54  enum page {
         PAGE__MAX          PAGE__MAX
 };  };
   
   /*
    * A query as passed to the search function.
    * See kval_query() on how this is parsed.
    */
   struct  query {
           const char      *arch; /* architecture */
           const char      *sec; /* manual section */
           const char      *expr; /* unparsed expression string */
           int              whatis; /* whether whatis mode */
           int              legacy; /* whether legacy mode */
   };
   
 struct  kval {  struct  kval {
         char            *key;          char            *key;
         char            *val;          char            *val;
Line 63  struct req {
Line 78  struct req {
 };  };
   
 static  int              atou(const char *, unsigned *);  static  int              atou(const char *, unsigned *);
 static  void             format_insecure(const char *);  static  void             catman(const char *);
 static  void             format_secure(const char *);  static  int              cmp(const void *, const void *);
   static  void             format(const char *);
 static  void             html_print(const char *);  static  void             html_print(const char *);
   static  void             html_putchar(char);
 static  int              kval_decode(char *);  static  int              kval_decode(char *);
 static  void             kval_parse(struct kval **, size_t *, char *);  
 static  void             kval_free(struct kval *, size_t);  static  void             kval_free(struct kval *, size_t);
   static  void             kval_parse(struct kval **, size_t *, char *);
   static  void             kval_query(struct query *,
                                   const struct kval *, size_t);
 static  void             pg_index(const struct manpaths *,  static  void             pg_index(const struct manpaths *,
                                 const struct req *, char *);                                  const struct req *, char *);
 static  void             pg_search(const struct manpaths *,  static  void             pg_search(const struct manpaths *,
Line 77  static void   pg_show(const struct manpaths *,
Line 96  static void   pg_show(const struct manpaths *,
                                 const struct req *, char *);                                  const struct req *, char *);
 static  void             resp_bad(void);  static  void             resp_bad(void);
 static  void             resp_baddb(void);  static  void             resp_baddb(void);
 static  void             resp_badexpr(const struct req *);  static  void             resp_error400(void);
 static  void             resp_badmanual(void);  static  void             resp_error404(const char *);
 static  void             resp_begin_html(int, const char *);  static  void             resp_begin_html(int, const char *);
 static  void             resp_begin_http(int, const char *);  static  void             resp_begin_http(int, const char *);
 static  void             resp_end_html(void);  static  void             resp_end_html(void);
Line 86  static void   resp_index(const struct req *);
Line 105  static void   resp_index(const struct req *);
 static  void             resp_search(struct res *, size_t, void *);  static  void             resp_search(struct res *, size_t, void *);
 static  void             resp_searchform(const struct req *);  static  void             resp_searchform(const struct req *);
   
 static  int               insecure = 1;  
 static  const char       *progname;  static  const char       *progname;
 static  const char       *cache;  static  const char       *cache;
 static  const char       *host;  static  const char       *host;
Line 98  static const char * const pages[PAGE__MAX] = {
Line 116  static const char * const pages[PAGE__MAX] = {
 };  };
   
 /*  /*
    * Initialise and parse a query structure from input.
    * This accomodates for mdocml's man.cgi and also for legacy man.cgi
    * input keys ("sektion" and "apropos").
    * Note that legacy mode has some quirks: if apropos legacy mode is
    * detected, we unset the section and architecture string.
    */
   static void
   kval_query(struct query *q, const struct kval *fields, size_t sz)
   {
           int              i, legacy;
   
           memset(q, 0, sizeof(struct query));
           legacy = -1;
   
           for (i = 0; i < (int)sz; i++)
                   if (0 == strcmp(fields[i].key, "expr"))
                           q->expr = fields[i].val;
                   else if (0 == strcmp(fields[i].key, "query"))
                           q->expr = fields[i].val;
                   else if (0 == strcmp(fields[i].key, "sec"))
                           q->sec = fields[i].val;
                   else if (0 == strcmp(fields[i].key, "sektion"))
                           q->sec = fields[i].val;
                   else if (0 == strcmp(fields[i].key, "arch"))
                           q->arch = fields[i].val;
                   else if (0 == strcmp(fields[i].key, "apropos"))
                           legacy = 0 == strcmp
                                   (fields[i].val, "0");
                   else if (0 == strcmp(fields[i].key, "op"))
                           q->whatis = 0 == strcasecmp
                                   (fields[i].val, "whatis");
   
           /* Test for old man.cgi compatibility mode. */
   
           if (legacy == 0) {
                   q->whatis = 0;
                   q->legacy = 1;
           } else if (legacy > 0) {
                   q->legacy = 1;
                   q->whatis = 1;
           }
   
           /* Section "0" means no section when in legacy mode. */
   
           if (q->legacy && NULL != q->sec && 0 == strcmp(q->sec, "0"))
                   q->sec = NULL;
   }
   
   /*
  * This is just OpenBSD's strtol(3) suggestion.   * This is just OpenBSD's strtol(3) suggestion.
  * I use it instead of strtonum(3) for portability's sake.   * I use it instead of strtonum(3) for portability's sake.
  */   */
Line 121  atou(const char *buf, unsigned *v)
Line 188  atou(const char *buf, unsigned *v)
 }  }
   
 /*  /*
  * Print a word, escaping HTML along the way.   * Print a character, escaping HTML along the way.
  * This will pass non-ASCII straight to output: be warned!   * This will pass non-ASCII straight to output: be warned!
  */   */
 static void  static void
   html_putchar(char c)
   {
   
           switch (c) {
           case ('"'):
                   printf("&quote;");
                   break;
           case ('&'):
                   printf("&amp;");
                   break;
           case ('>'):
                   printf("&gt;");
                   break;
           case ('<'):
                   printf("&lt;");
                   break;
           default:
                   putchar((unsigned char)c);
                   break;
           }
   }
   
   /*
    * Call through to html_putchar().
    * Accepts NULL strings.
    */
   static void
 html_print(const char *p)  html_print(const char *p)
 {  {
         char             c;  
   
         if (NULL == p)          if (NULL == p)
                 return;                  return;
   
         while ('\0' != *p)          while ('\0' != *p)
                 switch ((c = *p++)) {                  html_putchar(*p++);
                 case ('"'):  
                         printf("&quote;");  
                         break;  
                 case ('&'):  
                         printf("&amp;");  
                         break;  
                 case ('>'):  
                         printf("&gt;");  
                         break;  
                 case ('<'):  
                         printf("&lt;");  
                         break;  
                 default:  
                         putchar((unsigned char)c);  
                         break;  
                 }  
 }  }
   
 static void  static void
Line 268  resp_begin_http(int code, const char *msg)
Line 344  resp_begin_http(int code, const char *msg)
         if (200 != code)          if (200 != code)
                 printf("Status: %d %s\n", code, msg);                  printf("Status: %d %s\n", code, msg);
   
         puts("Content-Type: text/html; charset=utf-8"           "\n"          puts("Content-Type: text/html; charset=utf-8\n"
              "Cache-Control: no-cache"                          "\n"               "Cache-Control: no-cache\n"
              "Pragma: no-cache"                                 "\n"               "Pragma: no-cache\n"
              "");               "");
   
         fflush(stdout);          fflush(stdout);
Line 282  resp_begin_html(int code, const char *msg)
Line 358  resp_begin_html(int code, const char *msg)
   
         resp_begin_http(code, msg);          resp_begin_http(code, msg);
   
         puts("<!DOCTYPE HTML PUBLIC "                           "\n"          puts("<!DOCTYPE HTML PUBLIC "
              " \"-//W3C//DTD HTML 4.01//EN\""                   "\n"               " \"-//W3C//DTD HTML 4.01//EN\""
              " \"http://www.w3.org/TR/html4/strict.dtd\">"      "\n"               " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
              "<HTML>"                                           "\n"               "<HTML>\n"
              " <HEAD>"                                          "\n"               "<HEAD>\n"
              "  <TITLE>System Manpage Reference</TITLE>"        "\n"               "<META HTTP-EQUIV=\"Content-Type\""
              " </HEAD>"                                         "\n"               " CONTENT=\"text/html; charset=utf-8\">\n"
              " <BODY>"                                          "\n"               "<LINK REL=\"stylesheet\" HREF=\"/man.cgi.css\""
                " TYPE=\"text/css\" media=\"all\">\n"
                "<TITLE>System Manpage Reference</TITLE>\n"
                "</HEAD>\n"
                "<BODY>\n"
              "<!-- Begin page content. //-->");               "<!-- Begin page content. //-->");
 }  }
   
Line 297  static void
Line 377  static void
 resp_end_html(void)  resp_end_html(void)
 {  {
   
         puts(" </BODY>\n</HTML>");          puts("</BODY>\n"
                "</HTML>");
 }  }
   
 static void  static void
 resp_searchform(const struct req *req)  resp_searchform(const struct req *req)
 {  {
         int              i;          struct query     q;
         const char      *expr, *sec, *arch;  
   
         expr = sec = arch = "";          kval_query(&q, req->fields, req->fieldsz);
   
         for (i = 0; i < (int)req->fieldsz; i++)  
                 if (0 == strcmp(req->fields[i].key, "expr"))  
                         expr = req->fields[i].val;  
                 else if (0 == strcmp(req->fields[i].key, "sec"))  
                         sec = req->fields[i].val;  
                 else if (0 == strcmp(req->fields[i].key, "arch"))  
                         arch = req->fields[i].val;  
   
         puts("<!-- Begin search form. //-->");          puts("<!-- Begin search form. //-->");
         printf("<FORM ACTION=\"");          printf("<FORM ACTION=\"");
         html_print(progname);          html_print(progname);
         printf("/search\" METHOD=\"get\">\n");          printf("/search.html\" METHOD=\"get\">\n");
         puts(" <FIELDSET>"                                      "\n"          printf("<FIELDSET>\n"
              "  <INPUT TYPE=\"submit\" VALUE=\"Search:\">");                 "<LEGEND>Search Parameters</LEGEND>\n"
         printf("  Terms: <INPUT TYPE=\"text\" "                 "<INPUT TYPE=\"submit\" NAME=\"op\""
                         "SIZE=\"60\" NAME=\"expr\" VALUE=\"");                 " VALUE=\"Whatis\"> or \n"
         html_print(expr);                 "<INPUT TYPE=\"submit\" NAME=\"op\""
         puts("\">");                 " VALUE=\"apropos\"> for manuals satisfying \n"
         printf("  Section: <INPUT TYPE=\"text\" "                 "<INPUT TYPE=\"text\" NAME=\"expr\" VALUE=\"");
                         "SIZE=\"4\" NAME=\"sec\" VALUE=\"");          html_print(q.expr ? q.expr : "");
         html_print(sec);          printf("\">, section "
         puts("\">");                 "<INPUT TYPE=\"text\""
         printf("  Arch: <INPUT TYPE=\"text\" "                 " SIZE=\"4\" NAME=\"sec\" VALUE=\"");
                         "SIZE=\"8\" NAME=\"arch\" VALUE=\"");          html_print(q.sec ? q.sec : "");
         html_print(arch);          printf("\">, arch "
         puts("\">");                 "<INPUT TYPE=\"text\""
         puts(" </FIELDSET>\n</FORM>\n<!-- End search form. //-->");                 " SIZE=\"8\" NAME=\"arch\" VALUE=\"");
           html_print(q.arch ? q.arch : "");
           puts("\">.\n"
                "<INPUT TYPE=\"reset\" VALUE=\"Reset\">\n"
                "</FIELDSET>\n"
                "</FORM>");
           puts("<!-- End search form. //-->");
 }  }
   
 static void  static void
Line 347  resp_index(const struct req *req)
Line 425  resp_index(const struct req *req)
 }  }
   
 static void  static void
 resp_badmanual(void)  resp_error400(void)
 {  {
   
         resp_begin_html(404, "Not Found");          resp_begin_html(400, "Query Malformed");
         puts("<P>Requested manual not found.</P>");          printf("<H1>Malformed Query</H1>\n"
                  "<P>\n"
                  "The query your entered was malformed.\n"
                  "Try again from the\n"
                  "<A HREF=\"%s/index.html\">main page</A>\n"
                  "</P>", progname);
         resp_end_html();          resp_end_html();
 }  }
   
 static void  static void
 resp_badexpr(const struct req *req)  resp_error404(const char *page)
 {  {
   
         resp_begin_html(200, NULL);          resp_begin_html(404, "Not Found");
         resp_searchform(req);          puts("<H1>Page Not Found</H1>\n"
         puts("<P>Your search didn't work.</P>");               "<P>\n"
                "The page you're looking for, ");
           printf("<B>");
           html_print(page);
           printf("</B>,\n"
                  "could not be found.\n"
                  "Try searching from the\n"
                  "<A HREF=\"%s/index.html\">main page</A>\n"
                  "</P>", progname);
         resp_end_html();          resp_end_html();
 }  }
   
Line 385  resp_baddb(void)
Line 476  resp_baddb(void)
 static void  static void
 resp_search(struct res *r, size_t sz, void *arg)  resp_search(struct res *r, size_t sz, void *arg)
 {  {
         int              i;          int               i;
           struct query      q;
           const struct req *req;
   
         if (1 == sz) {          if (1 == sz) {
                 /*                  /*
Line 400  resp_search(struct res *r, size_t sz, void *arg)
Line 493  resp_search(struct res *r, size_t sz, void *arg)
                 return;                  return;
         }          }
   
           qsort(r, sz, sizeof(struct res), cmp);
   
         resp_begin_html(200, NULL);          resp_begin_html(200, NULL);
         resp_searchform((const struct req *)arg);  
   
         if (0 == sz)          req = (const struct req *)arg;
                 puts("<P>No results found.</P>");          resp_searchform(req);
           kval_query(&q, req->fields, req->fieldsz);
   
           if (0 == sz) {
                   puts("<P>\n"
                        "No results found.");
                   if (q.whatis) {
                           printf("(Try <A HREF=\"");
                           html_print(progname);
                           printf("/search.html?op=apropos&amp;expr=");
                           html_print(q.expr ? q.expr : "");
                           printf("&amp;sec=");
                           html_print(q.sec ? q.sec : "");
                           printf("&amp;arch=");
                           html_print(q.arch ? q.arch : "");
                           puts("\">apropos</A>?)");
                   }
                   puts("</P>");
                   resp_end_html();
                   return;
           }
   
           puts("<P></P>\n"
                "<TABLE>");
   
         for (i = 0; i < (int)sz; i++) {          for (i = 0; i < (int)sz; i++) {
                 printf("<P><A HREF=\"");                  printf("<TR>\n"
                          "<TD CLASS=\"title\">\n"
                          "<A HREF=\"");
                 html_print(progname);                  html_print(progname);
                 printf("/show/%u/%u.html\">", r[i].volume, r[i].rec);                  printf("/show/%u/%u.html\">", r[i].volume, r[i].rec);
                 html_print(r[i].title);                  html_print(r[i].title);
Line 417  resp_search(struct res *r, size_t sz, void *arg)
Line 536  resp_search(struct res *r, size_t sz, void *arg)
                         putchar('/');                          putchar('/');
                         html_print(r[i].arch);                          html_print(r[i].arch);
                 }                  }
                 printf(")</A> ");                  printf(")</A>\n"
                          "</TD>\n"
                          "<TD CLASS=\"desc\">");
                 html_print(r[i].desc);                  html_print(r[i].desc);
                 puts("</P>");                  puts("</TD>\n"
                        "</TR>");
         }          }
   
           puts("</TABLE>");
         resp_end_html();          resp_end_html();
 }  }
   
Line 434  pg_index(const struct manpaths *ps, const struct req *
Line 557  pg_index(const struct manpaths *ps, const struct req *
 }  }
   
 static void  static void
 format_insecure(const char *file)  catman(const char *file)
 {  {
         pid_t            pid;          FILE            *f;
         char             cmd[MAXPATHLEN];          size_t           len;
           int              i;
           char            *p;
           int              italic, bold;
   
         strlcpy(cmd, "man=", MAXPATHLEN);          if (NULL == (f = fopen(file, "r"))) {
         strlcat(cmd, progname, MAXPATHLEN);                  resp_baddb();
         strlcat(cmd, "/search?expr=%N&sec=%S", MAXPATHLEN);                  return;
           }
   
         /* Get ready to call the child mandoc(1) process. */          resp_begin_http(200, NULL);
           puts("<!DOCTYPE HTML PUBLIC "
                " \"-//W3C//DTD HTML 4.01//EN\""
                " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
                "<HTML>\n"
                "<HEAD>\n"
                "<META HTTP-EQUIV=\"Content-Type\""
                " CONTENT=\"text/html; charset=utf-8\">\n"
                "<LINK REL=\"stylesheet\" HREF=\"/catman.css\""
                " TYPE=\"text/css\" media=\"all\">\n"
                "<TITLE>System Manpage Reference</TITLE>\n"
                "</HEAD>\n"
                "<BODY>\n"
                "<!-- Begin page content. //-->\n"
                "<PRE>");
   
         if (-1 == (pid = fork()))          while (NULL != (p = fgetln(f, &len))) {
                 exit(EXIT_FAILURE);                  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) {                          if ('\b' == p[i] || '\n' == p[i])
                 waitpid(pid, NULL, 0);                                  continue;
                 return;  
         }  
   
         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("</I>");
                                   if (bold)
                                           printf("</B>");
                                   italic = bold = 0;
                                   html_putchar(p[i]);
                                   continue;
                           } else if (i + 2 >= (int)len)
                                   continue;
   
         fflush(stdout);                          /* Italic mode. */
   
         execlp("mandoc", "mandoc", "-T",                          if ('_' == p[i]) {
                 "html", "-O", cmd, file, (char *)NULL);                                  if (bold)
                                           printf("</B>");
                                   if ( ! italic)
                                           printf("<I>");
                                   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("</I>");
                                   if (bold)
                                           printf("</B>");
                                   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("</I>");
                                   if (bold)
                                           printf("</B>");
                                   italic = bold = 0;
                                   putchar('+');
                                   i += 2;
                                   continue;
                           }
   
                           /* Bold mode. */
   
                           if (italic)
                                   printf("</I>");
                           if ( ! bold)
                                   printf("<B>");
                           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("</I>");
                   if (bold)
                           printf("</B>");
   
                   if (i == (int)len - 1 && '\n' != p[i])
                           html_putchar(p[i]);
   
                   putchar('\n');
           }
   
           puts("</PRE>\n"
                "</BODY>\n"
                "</HTML>");
   
           fclose(f);
 }  }
   
 static void  static void
 format_secure(const char *file)  format(const char *file)
 {  {
         char             buf[BUFSIZ];          struct mparse   *mp;
         int              fd;          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))) {          if (-1 == (fd = open(file, O_RDONLY, 0))) {
                 resp_baddb();                  resp_baddb();
                 return;                  return;
         }          }
   
         resp_begin_http(200, NULL);          mp = mparse_alloc(MPARSE_AUTO, MANDOCLEVEL_FATAL, NULL, NULL);
           rc = mparse_readfd(mp, fd, file);
           close(fd);
   
         do {          if (rc >= MANDOCLEVEL_FATAL) {
                 ssz = read(fd, buf, BUFSIZ);                  resp_baddb();
                 if (ssz > 0)                  return;
                         write(STDOUT_FILENO, buf, ssz);          }
         } while (ssz > 0);  
   
         close(fd);          snprintf(opts, sizeof(opts), "style=/man.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  static void
Line 491  pg_show(const struct manpaths *ps, const struct req *r
Line 753  pg_show(const struct manpaths *ps, const struct req *r
 {  {
         char            *sub;          char            *sub;
         char             file[MAXPATHLEN];          char             file[MAXPATHLEN];
           const char      *fn, *cp;
         int              rc;          int              rc;
         unsigned int     vol, rec;          unsigned int     vol, rec;
         DB              *db;          DB              *idx;
         DBT              key, val;          DBT              key, val;
   
         if (NULL == path) {          if (NULL == path) {
                 resp_badmanual();                  resp_error400();
                 return;                  return;
         } else if (NULL == (sub = strrchr(path, '/'))) {          } else if (NULL == (sub = strrchr(path, '/'))) {
                 resp_badmanual();                  resp_error400();
                 return;                  return;
         } else          } else
                 *sub++ = '\0';                  *sub++ = '\0';
   
         if ( ! (atou(path, &vol) && atou(sub, &rec))) {          if ( ! (atou(path, &vol) && atou(sub, &rec))) {
                 resp_badmanual();                  resp_error400();
                 return;                  return;
         } else if (vol >= (unsigned int)ps->sz) {          } else if (vol >= (unsigned int)ps->sz) {
                 resp_badmanual();                  resp_error400();
                 return;                  return;
         }          }
   
Line 518  pg_show(const struct manpaths *ps, const struct req *r
Line 781  pg_show(const struct manpaths *ps, const struct req *r
   
         /* Open the index recno(3) database. */          /* Open the index recno(3) database. */
   
         db = dbopen(file, O_RDONLY, 0, DB_RECNO, NULL);          idx = dbopen(file, O_RDONLY, 0, DB_RECNO, NULL);
         if (NULL == db) {          if (NULL == idx) {
                 resp_baddb();                  resp_baddb();
                 return;                  return;
         }          }
Line 527  pg_show(const struct manpaths *ps, const struct req *r
Line 790  pg_show(const struct manpaths *ps, const struct req *r
         key.data = &rec;          key.data = &rec;
         key.size = 4;          key.size = 4;
   
         if (0 != (rc = (*db->get)(db, &key, &val, 0))) {          if (0 != (rc = (*idx->get)(idx, &key, &val, 0))) {
                 rc < 0 ? resp_baddb() : resp_badmanual();                  rc < 0 ? resp_baddb() : resp_error400();
                 (*db->close)(db);                  goto out;
                 return;  
         }          }
   
         /* Extra filename: the first nil-terminated entry. */          cp = (char *)val.data;
   
         (*db->close)(db);          if (NULL == (fn = memchr(cp, '\0', val.size)))
                   resp_baddb();
         strlcpy(file, ps->paths[vol], MAXPATHLEN);          else if (++fn - cp >= (int)val.size)
         strlcat(file, "/", MAXPATHLEN);                  resp_baddb();
         strlcat(file, (char *)val.data, MAXPATHLEN);          else if (NULL == memchr(fn, '\0', val.size - (fn - cp)))
                   resp_baddb();
         if ( ! insecure) {          else {
                 strlcat(file, ".html", MAXPATHLEN);                  strlcpy(file, cache, MAXPATHLEN);
                 format_secure(file);                  strlcat(file, "/", MAXPATHLEN);
         } else                  strlcat(file, fn, MAXPATHLEN);
                 format_insecure(file);                  if (0 == strcmp(cp, "cat"))
                           catman(file);
                   else
                           format(file);
           }
   out:
           (*idx->close)(idx);
 }  }
   
 static void  static void
Line 557  pg_search(const struct manpaths *ps, const struct req 
Line 825  pg_search(const struct manpaths *ps, const struct req 
         char            **cp;          char            **cp;
         struct opts       opt;          struct opts       opt;
         struct expr      *expr;          struct expr      *expr;
           struct query      q;
   
         expr = NULL;          kval_query(&q, req->fields, req->fieldsz);
         cp = NULL;  
         ep = NULL;  
         sz = 0;  
   
         memset(&opt, 0, sizeof(struct opts));          memset(&opt, 0, sizeof(struct opts));
   
         for (sz = i = 0; i < (int)req->fieldsz; i++)          ep       = q.expr;
                 if (0 == strcmp(req->fields[i].key, "expr"))          opt.arch = q.arch;
                         ep = req->fields[i].val;          opt.cat  = q.sec;
                 else if (0 == strcmp(req->fields[i].key, "sec"))          rc       = -1;
                         opt.cat = req->fields[i].val;          sz       = 0;
                 else if (0 == strcmp(req->fields[i].key, "arch"))          cp       = NULL;
                         opt.arch = req->fields[i].val;  
   
         /*          /*
          * Poor man's tokenisation.           * Poor man's tokenisation.
Line 594  pg_search(const struct manpaths *ps, const struct req 
Line 858  pg_search(const struct manpaths *ps, const struct req 
                         ep++;                          ep++;
         }          }
   
         rc = -1;  
   
         /*          /*
          * Pump down into apropos backend.           * Pump down into apropos backend.
          * The resp_search() function is called with the results.           * The resp_search() function is called with the results.
          */           */
   
         if (NULL != (expr = exprcomp(sz, cp, &tt)))          expr = q.whatis ? termcomp(sz, cp, &tt) :
                             exprcomp(sz, cp, &tt);
   
           if (NULL != expr)
                 rc = apropos_search                  rc = apropos_search
                         (ps->sz, ps->paths, &opt,                          (ps->sz, ps->paths, &opt,
                          expr, tt, (void *)req, resp_search);                           expr, tt, (void *)req, resp_search);
Line 611  pg_search(const struct manpaths *ps, const struct req 
Line 876  pg_search(const struct manpaths *ps, const struct req 
         if (0 == rc)          if (0 == rc)
                 resp_baddb();                  resp_baddb();
         else if (-1 == rc)          else if (-1 == rc)
                 resp_badexpr(req);                  resp_search(NULL, 0, (void *)req);
   
         for (i = 0; i < sz; i++)          for (i = 0; i < sz; i++)
                 free(cp[i]);                  free(cp[i]);
Line 638  main(void)
Line 903  main(void)
         if (NULL == cache)          if (NULL == cache)
                 cache = "/cache/man.cgi";                  cache = "/cache/man.cgi";
   
         if (NULL == getenv("INSECURE")) {          if (-1 == chdir(cache)) {
                 insecure = 0;                  resp_bad();
                 if (-1 == chdir(cache)) {                  return(EXIT_FAILURE);
                         resp_bad();  
                         return(EXIT_FAILURE);  
                 }  
         }          }
   
         host = getenv("HTTP_HOST");          host = getenv("HTTP_HOST");
Line 689  main(void)
Line 951  main(void)
         /* Initialise MANPATH. */          /* Initialise MANPATH. */
   
         memset(&paths, 0, sizeof(struct manpaths));          memset(&paths, 0, sizeof(struct manpaths));
         if ( ! insecure)          manpath_manconf("etc/catman.conf", &paths);
                 manpath_manconf("etc/man.conf", &paths);  
         else  
                 manpath_parse(&paths, NULL, NULL);  
   
         /* Route pages. */          /* Route pages. */
   
Line 707  main(void)
Line 966  main(void)
                 pg_show(&paths, &req, subpath);                  pg_show(&paths, &req, subpath);
                 break;                  break;
         default:          default:
                   resp_error404(path);
                 break;                  break;
         }          }
   
Line 715  main(void)
Line 975  main(void)
   
         return(EXIT_SUCCESS);          return(EXIT_SUCCESS);
 }  }
   
   static int
   cmp(const void *p1, const void *p2)
   {
   
           return(strcasecmp(((const struct res *)p1)->title,
                                   ((const struct res *)p2)->title));
   }
   

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.20

CVSweb