Switch from Highcharts to Rickshaw, which is MIT / BSD licensed.
[collection4.git] / src / utils_cgi.c
index 92bda3e..f7ff84d 100644 (file)
@@ -1,3 +1,28 @@
+/**
+ * collection4 - utils_cgi.c
+ * Copyright (C) 2010  Florian octo Forster
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ *
+ * Authors:
+ *   Florian octo Forster <ff at octo.it>
+ **/
+
+#include "config.h"
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -79,6 +104,7 @@ static char *uri_unescape_copy (char *dest, const char *src, size_t n) /* {{{ */
       *dest_ptr = *src_ptr;
     }
 
+    n--;
     src_ptr++;
     dest_ptr++;
     *dest_ptr = 0;
@@ -86,7 +112,7 @@ static char *uri_unescape_copy (char *dest, const char *src, size_t n) /* {{{ */
 
   assert (*dest_ptr == 0);
   return (dest);
-} /* }}} char *uri_unescape */
+} /* }}} char *uri_unescape_copy */
 
 static char *uri_unescape (const char *string) /* {{{ */
 {
@@ -406,10 +432,17 @@ char *uri_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
       return (dest);
     }
     else if ((((unsigned char) src[in]) < 32)
-        || (src[in] == '&')
-        || (src[in] == ';')
-        || (src[in] == '?')
-        || (src[in] == '/')
+        || (src[in] == ' ')
+        /* RFC 3986, gen-delims */
+        || (src[in] == ':') || (src[in] == '/') || (src[in] == '?')
+        || (src[in] == '#') || (src[in] == '[') || (src[in] == ']')
+        || (src[in] == '@')
+        /* RFC 3986, sub-delims */
+        || (src[in] == '!') || (src[in] == '$') || (src[in] == '&')
+        || (src[in] == '(') || (src[in] == ')') || (src[in] == '*')
+        || (src[in] == '+') || (src[in] == ',') || (src[in] == ';')
+        || (src[in] == '=') || (src[in] == '\'')
+        /* 8-bit data */
         || (((unsigned char) src[in]) >= 128))
     {
       char esc[4];
@@ -436,6 +469,16 @@ char *uri_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
   return (dest);
 } /* }}} char *uri_escape_copy */
 
+char *uri_escape_buffer (char *buffer, size_t buffer_size) /* {{{ */
+{
+  char temp[buffer_size];
+
+  uri_escape_copy (temp, buffer, buffer_size);
+  memcpy (buffer, temp, buffer_size);
+
+  return (&buffer[0]);
+} /* }}} char *uri_escape_buffer */
+
 char *uri_escape (const char *string) /* {{{ */
 {
   char buffer[4096];
@@ -448,6 +491,89 @@ char *uri_escape (const char *string) /* {{{ */
   return (strdup (buffer));
 } /* }}} char *uri_escape */
 
+#define COPY_ENTITY(e) do {    \
+  size_t len = strlen (e);     \
+  if (dest_size < (len + 1))   \
+    break;                     \
+  strcpy (dest_ptr, (e));      \
+  dest_ptr += len;             \
+  dest_size -= len;            \
+} while (0)
+
+char *json_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
+{
+  char *dest_ptr;
+  size_t dest_size;
+  size_t pos;
+
+  dest[0] = 0;
+  dest_ptr = dest;
+  dest_size = n;
+  for (pos = 0; src[pos] != 0; pos++)
+  {
+    if (src[pos] == '"')
+      COPY_ENTITY ("\\\"");
+    else if (src[pos] == '\\')
+      COPY_ENTITY ("\\\\");
+    else if (((uint8_t) src[pos]) < 32)
+    {
+      if (src[pos] == '\n')
+        COPY_ENTITY ("\\n");
+      else if (src[pos] == '\r')
+        COPY_ENTITY ("\\r");
+      else if (src[pos] == '\t')
+        COPY_ENTITY ("\\t");
+      else if (src[pos] == '\b')
+        COPY_ENTITY ("\\b");
+      else if (src[pos] == '\f')
+        COPY_ENTITY ("\\f");
+      else
+      {
+        char buffer[8];
+        sprintf (buffer, "\\u%04"PRIx8, (uint8_t) src[pos]);
+        buffer[sizeof (buffer) - 1] = 0;
+        COPY_ENTITY (buffer);
+      }
+    }
+    else
+    {
+      *dest_ptr = src[pos];
+      dest_ptr++;
+      dest_size--;
+      *dest_ptr = 0;
+    }
+
+    if (dest_size <= 1)
+      break;
+  }
+
+  return (dest);
+} /* }}} char *json_escape_copy */
+
+#undef COPY_ENTITY
+
+char *json_escape_buffer (char *buffer, size_t buffer_size)
+{
+  char temp[buffer_size];
+
+  json_escape_copy (temp, buffer, buffer_size);
+  memcpy (buffer, temp, buffer_size);
+
+  return (buffer);
+} /* }}} char *json_escape_buffer */
+
+char *json_escape (const char *string) /* {{{ */
+{
+  char buffer[4096];
+
+  if (string == NULL)
+    return (NULL);
+
+  json_escape_copy (buffer, string, sizeof (buffer));
+
+  return (strdup (buffer));
+} /* }}} char *json_escape */
+
 const char *script_name (void) /* {{{ */
 {
   char *ret;
@@ -479,11 +605,11 @@ int time_to_rfc1123 (time_t t, char *buffer, size_t buffer_size) /* {{{ */
 
 #define COPY_ENTITY(e) do {    \
   size_t len = strlen (e);     \
-  if (dest_size < (len + 1)) \
+  if (dest_size < (len + 1))   \
     break;                     \
-  strcpy (dest_ptr, (e));    \
-  dest_ptr += len;           \
-  dest_size -= len;          \
+  strcpy (dest_ptr, (e));      \
+  dest_ptr += len;             \
+  dest_size -= len;            \
 } while (0)
 
 char *html_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
@@ -549,20 +675,27 @@ int html_print_page (const char *title, /* {{{ */
 {
   char *title_html;
 
-  printf ("Content-Type: text/html\n\n");
+  printf ("Content-Type: text/html\n"
+      "X-Generator: "PACKAGE_STRING"\n"
+      "\n\n");
 
   if (title == NULL)
-    title = "c4: collection4 graph interface";
+    title = "C&#x2084;: collection4 graph interface";
 
   title_html = html_escape (title);
 
   printf ("<html>\n"
       "  <head>\n"
       "    <title>%s</title>\n"
-      "    <link rel=\"stylesheet\" type=\"text/css\" href=\"../share/style.css\" />\n"
-      "    <script type=\"text/javascript\" src=\"../share/jquery-1.4.2.min.js\">\n"
+      "    <link rel=\"stylesheet\" type=\"text/css\" href=\"../../share/"PACKAGE"/style.css\" />\n"
+      "    <link rel=\"stylesheet\" type=\"text/css\" href=\"../../share/"PACKAGE"/rickshaw.min.css\" />\n"
+      "    <script type=\"text/javascript\" src=\"../../share/"PACKAGE"/jquery-1.4.4.min.js\">\n"
       "    </script>\n"
-      "    <script type=\"text/javascript\" src=\"../share/collection.js\">\n"
+      "    <script type=\"text/javascript\" src=\"../../share/"PACKAGE"/d3.min.js\">\n"
+      "    </script>\n"
+      "    <script type=\"text/javascript\" src=\"../../share/"PACKAGE"/rickshaw.min.js\">\n"
+      "    </script>\n"
+      "    <script type=\"text/javascript\" src=\"../../share/"PACKAGE"/collection.js\">\n"
       "    </script>\n"
       "  </head>\n",
       title_html);
@@ -573,6 +706,8 @@ int html_print_page (const char *title, /* {{{ */
       "        <td id=\"layout-top-left\">");
   if (cb->top_left != NULL)
     (*cb->top_left) (user_data);
+  else
+    html_print_logo (NULL);
   printf ("</td>\n"
       "        <td id=\"layout-top-center\">");
   if (cb->top_center != NULL)
@@ -614,6 +749,7 @@ int html_print_page (const char *title, /* {{{ */
   printf ("</td>\n"
       "      </tr>\n"
       "    </table>\n"
+      "    <div class=\"footer\"><a href=\"http://octo.it/c4/\">"PACKAGE_STRING"</a></div>\n"
       "  </body>\n"
       "</html>\n");
 
@@ -621,6 +757,16 @@ int html_print_page (const char *title, /* {{{ */
   return (0);
 } /* }}} int html_print_page */
 
+int html_print_logo (__attribute__((unused)) void *user_data) /* {{{ */
+{
+  printf ("<a href=\"%s?action=list_graphs\" id=\"logo-canvas\">\n"
+      "  <h1>C<sub>4</sub></h1>\n"
+      "  <div id=\"logo-subscript\">collection&nbsp;4</div>\n"
+      "</a>\n", script_name ());
+
+  return (0);
+} /* }}} int html_print_search_box */
+
 int html_print_search_box (__attribute__((unused)) void *user_data) /* {{{ */
 {
   char *term_html;
@@ -628,7 +774,7 @@ int html_print_search_box (__attribute__((unused)) void *user_data) /* {{{ */
   term_html = html_escape (param ("q"));
 
   printf ("<form action=\"%s\" method=\"get\" id=\"search-form\">\n"
-      "  <input type=\"hidden\" name=\"action\" value=\"list_graphs\" />\n"
+      "  <input type=\"hidden\" name=\"action\" value=\"search\" />\n"
       "  <input type=\"text\" name=\"q\" value=\"%s\" id=\"search-input\" />\n"
       "  <input type=\"submit\" name=\"button\" value=\"Search\" />\n"
       "</form>\n",