+/**
+ * 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>
#include <ctype.h>
#include <errno.h>
#include <time.h>
+#include <assert.h>
#include "utils_cgi.h"
+#include "common.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
struct parameter_s
{
};
typedef struct parameter_s parameter_t;
-static parameter_t *parameters = NULL;
-static size_t parameters_num = 0;
-static _Bool parameters_init = 0;
-
-static int parameter_add (const char *key, const char *value) /* {{{ */
+struct param_list_s
{
- parameter_t *ptr;
-
- if (value == NULL)
- return (EINVAL);
-
- ptr = realloc (parameters, sizeof (*parameters) * (parameters_num + 1));
- if (ptr == NULL)
- return (ENOMEM);
- parameters = ptr;
-
- ptr = parameters + parameters_num;
- if (key == NULL)
- {
- ptr->key = NULL;
- }
- else
- {
- ptr->key = strdup (key);
- if (ptr->key == NULL)
- return (ENOMEM);
- }
-
- ptr->value = strdup (value);
- if (ptr->value == NULL)
- {
- free (ptr->key);
- return (ENOMEM);
- }
-
- parameters_num++;
- return (0);
-} /* }}} int parameter_add */
-
-static char *parameter_lookup (const char *key) /* {{{ */
-{
- size_t i;
+ parameter_t *parameters;
+ size_t parameters_num;
+};
- for (i = 0; i < parameters_num; i++)
- {
- if ((key == NULL) && (parameters[i].key == NULL))
- return (parameters[i].value);
- else if ((key != NULL) && (parameters[i].key != NULL)
- && (strcmp (key, parameters[i].key) == 0))
- return (parameters[i].value);
- }
+static param_list_t *pl_global = NULL;
- return (NULL);
-} /* }}} char *parameter_lookup */
-
-static char *uri_unescape (char *string) /* {{{ */
+static char *uri_unescape_copy (char *dest, const char *src, size_t n) /* {{{ */
{
- char *in;
- char *out;
+ const char *src_ptr;
+ char *dest_ptr;
- if (string == NULL)
+ if ((dest == NULL) || (src == NULL) || (n < 1))
return (NULL);
- in = string;
- out = string;
+ src_ptr = src;
+ dest_ptr = dest;
+
+ *dest_ptr = 0;
- while (*in != 0)
+ while (*src_ptr != 0)
{
- if (*in == '+')
+ if (n < 2)
+ break;
+
+ if (*src_ptr == '+')
{
- *out = ' ';
+ *dest_ptr = ' ';
}
- else if ((in[0] == '%')
- && isxdigit ((int) in[1]) && isxdigit ((int) in[2]))
+ else if ((src_ptr[0] == '%')
+ && isxdigit ((int) src_ptr[1]) && isxdigit ((int) src_ptr[2]))
{
char tmpstr[3];
char *endptr;
long value;
- tmpstr[0] = in[1];
- tmpstr[1] = in[2];
+ tmpstr[0] = src_ptr[1];
+ tmpstr[1] = src_ptr[2];
tmpstr[2] = 0;
errno = 0;
value = strtol (tmpstr, &endptr, /* base = */ 16);
if ((endptr == tmpstr) || (errno != 0))
{
- *out = '?';
+ *dest_ptr = '?';
}
else
{
- *out = (char) value;
+ *dest_ptr = (char) value;
}
- in += 2;
+ src_ptr += 2;
}
else
{
- *out = *in;
+ *dest_ptr = *src_ptr;
}
- in++;
- out++;
- } /* while (*in != 0) */
+ src_ptr++;
+ dest_ptr++;
+ *dest_ptr = 0;
+ } /* while (*src_ptr != 0) */
+
+ assert (*dest_ptr == 0);
+ return (dest);
+} /* }}} char *uri_unescape */
+
+static char *uri_unescape (const char *string) /* {{{ */
+{
+ char buffer[4096];
+
+ if (string == NULL)
+ return (NULL);
- *out = 0;
- return (string);
+ uri_unescape_copy (buffer, string, sizeof (buffer));
+
+ return (strdup (buffer));
} /* }}} char *uri_unescape */
-static int parse_keyval (char *keyval) /* {{{ */
+static int param_parse_keyval (param_list_t *pl, char *keyval) /* {{{ */
{
+ char *key_raw;
+ char *value_raw;
char *key;
- char *val;
+ char *value;
- val = strchr (keyval, '=');
- if (val == NULL)
- {
- key = NULL;
- val = keyval;
- }
- else
+ key_raw = keyval;
+ value_raw = strchr (key_raw, '=');
+ if (value_raw == NULL)
+ return (EINVAL);
+ *value_raw = 0;
+ value_raw++;
+
+ key = uri_unescape (key_raw);
+ if (key == NULL)
+ return (ENOMEM);
+
+ value = uri_unescape (value_raw);
+ if (value == NULL)
{
- key = keyval;
- *val = 0;
- val++;
+ free (key);
+ return (ENOMEM);
}
+
+ param_set (pl, key, value);
- parameter_add (uri_unescape (key), uri_unescape (val));
+ free (key);
+ free (value);
return (0);
-} /* }}} int parse_keyval */
+} /* }}} int param_parse_keyval */
-static int parse_query_string (char *query_string) /* {{{ */
+static int parse_query_string (param_list_t *pl, /* {{{ */
+ char *query_string)
{
char *dummy;
char *keyval;
- if (query_string == NULL)
+ if ((pl == NULL) || (query_string == NULL))
return (EINVAL);
dummy = query_string;
while ((keyval = strtok (dummy, ";&")) != NULL)
{
dummy = NULL;
- parse_keyval (keyval);
+ param_parse_keyval (pl, keyval);
}
return (0);
int param_init (void) /* {{{ */
{
- const char *query_string;
- char *copy;
- int status;
-
- if (parameters_init)
+ if (pl_global != NULL)
return (0);
- query_string = getenv ("QUERY_STRING");
+ pl_global = param_create (/* query string = */ NULL);
+ if (pl_global == NULL)
+ return (ENOMEM);
+
+ return (0);
+} /* }}} int param_init */
+
+void param_finish (void) /* {{{ */
+{
+ param_destroy (pl_global);
+ pl_global = NULL;
+} /* }}} void param_finish */
+
+const char *param (const char *key) /* {{{ */
+{
+ param_init ();
+
+ return (param_get (pl_global, key));
+} /* }}} const char *param */
+
+param_list_t *param_create (const char *query_string) /* {{{ */
+{
+ char *tmp;
+ param_list_t *pl;
+
if (query_string == NULL)
- return (ENOENT);
+ query_string = getenv ("QUERY_STRING");
- copy = strdup (query_string);
- if (copy == NULL)
- return (ENOMEM);
+ if (query_string == NULL)
+ return (NULL);
- status = parse_query_string (copy);
- free (copy);
+ tmp = strdup (query_string);
+ if (tmp == NULL)
+ return (NULL);
+
+ pl = malloc (sizeof (*pl));
+ if (pl == NULL)
+ {
+ free (tmp);
+ return (NULL);
+ }
+ memset (pl, 0, sizeof (*pl));
- parameters_init = 1;
+ parse_query_string (pl, tmp);
- return (status);
-} /* }}} int param_init */
+ free (tmp);
+ return (pl);
+} /* }}} param_list_t *param_create */
-void param_finish (void) /* {{{ */
+ param_list_t *param_clone (__attribute__((unused)) param_list_t *pl) /* {{{ */
+{
+ /* FIXME: To be implemented. */
+ assert (23 == 42);
+ return (NULL);
+} /* }}} param_list_t *param_clone */
+
+void param_destroy (param_list_t *pl) /* {{{ */
{
size_t i;
- if (!parameters_init)
+ if (pl == NULL)
return;
- for (i = 0; i < parameters_num; i++)
+ for (i = 0; i < pl->parameters_num; i++)
{
- free (parameters[i].key);
- free (parameters[i].value);
+ free (pl->parameters[i].key);
+ free (pl->parameters[i].value);
}
- free (parameters);
+ free (pl->parameters);
+ free (pl);
+} /* }}} void param_destroy */
- parameters = NULL;
- parameters_num = 0;
- parameters_init = 0;
-} /* }}} void param_finish */
+const char *param_get (param_list_t *pl, const char *name) /* {{{ */
+{
+ size_t i;
-const char *param (const char *key) /* {{{ */
+ if ((pl == NULL) || (name == NULL))
+ return (NULL);
+
+ for (i = 0; i < pl->parameters_num; i++)
+ {
+ if ((name == NULL) && (pl->parameters[i].key == NULL))
+ return (pl->parameters[i].value);
+ else if ((name != NULL) && (pl->parameters[i].key != NULL)
+ && (strcmp (name, pl->parameters[i].key) == 0))
+ return (pl->parameters[i].value);
+ }
+
+ return (NULL);
+} /* }}} char *param_get */
+
+static int param_add (param_list_t *pl, /* {{{ */
+ const char *key, const char *value)
{
- param_init ();
+ parameter_t *tmp;
- return (parameter_lookup (key));
-} /* }}} const char *param */
+ tmp = realloc (pl->parameters,
+ sizeof (*pl->parameters) * (pl->parameters_num + 1));
+ if (tmp == NULL)
+ return (ENOMEM);
+ pl->parameters = tmp;
+ tmp = pl->parameters + pl->parameters_num;
+
+ memset (tmp, 0, sizeof (*tmp));
+ tmp->key = strdup (key);
+ if (tmp->key == NULL)
+ return (ENOMEM);
+
+ tmp->value = strdup (value);
+ if (tmp->value == NULL)
+ {
+ free (tmp->key);
+ return (ENOMEM);
+ }
+
+ pl->parameters_num++;
+
+ return (0);
+} /* }}} int param_add */
+
+static int param_delete (param_list_t *pl, /* {{{ */
+ const char *name)
+{
+ size_t i;
+
+ if ((pl == NULL) || (name == NULL))
+ return (EINVAL);
+
+ for (i = 0; i < pl->parameters_num; i++)
+ if (strcasecmp (pl->parameters[i].key, name) == 0)
+ break;
+
+ if (i >= pl->parameters_num)
+ return (ENOENT);
+
+ if (i < (pl->parameters_num - 1))
+ {
+ parameter_t p;
+
+ p = pl->parameters[i];
+ pl->parameters[i] = pl->parameters[pl->parameters_num - 1];
+ pl->parameters[pl->parameters_num - 1] = p;
+ }
+
+ pl->parameters_num--;
+ free (pl->parameters[pl->parameters_num].key);
+ free (pl->parameters[pl->parameters_num].value);
+
+ return (0);
+} /* }}} int param_delete */
-int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
+int param_set (param_list_t *pl, const char *name, /* {{{ */
+ const char *value)
+{
+ parameter_t *p;
+ char *value_copy;
+ size_t i;
+
+ if ((pl == NULL) || (name == NULL))
+ return (EINVAL);
+
+ if (value == NULL)
+ return (param_delete (pl, name));
+
+ p = NULL;
+ for (i = 0; i < pl->parameters_num; i++)
+ {
+ if (strcasecmp (pl->parameters[i].key, name) == 0)
+ {
+ p = pl->parameters + i;
+ break;
+ }
+ }
+
+ if (p == NULL)
+ return (param_add (pl, name, value));
+
+ value_copy = strdup (value);
+ if (value_copy == NULL)
+ return (ENOMEM);
+
+ free (p->value);
+ p->value = value_copy;
+
+ return (0);
+} /* }}} int param_set */
+
+char *param_as_string (param_list_t *pl) /* {{{ */
+{
+ char buffer[4096];
+ char key[2048];
+ char value[2048];
+ size_t i;
+
+ if (pl == NULL)
+ return (NULL);
+
+ buffer[0] = 0;
+ for (i = 0; i < pl->parameters_num; i++)
+ {
+ uri_escape_copy (key, pl->parameters[i].key, sizeof (key));
+ uri_escape_copy (value, pl->parameters[i].value, sizeof (value));
+
+ if (i != 0)
+ strlcat (buffer, ";", sizeof (buffer));
+ strlcat (buffer, key, sizeof (buffer));
+ strlcat (buffer, "=", sizeof (buffer));
+ strlcat (buffer, value, sizeof (buffer));
+ }
+
+ return (strdup (buffer));
+} /* }}} char *param_as_string */
+
+int param_print_hidden (param_list_t *pl) /* {{{ */
+{
+ char key[2048];
+ char value[2048];
+ size_t i;
+
+ if (pl == NULL)
+ return (EINVAL);
+
+ for (i = 0; i < pl->parameters_num; i++)
+ {
+ html_escape_copy (key, pl->parameters[i].key, sizeof (key));
+ html_escape_copy (value, pl->parameters[i].value, sizeof (value));
+
+ printf (" <input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
+ key, value);
+ }
+
+ return (0);
+} /* }}} int param_print_hidden */
+
+char *uri_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
{
size_t in;
size_t out;
{
if (src[in] == 0)
{
- dst[out] = 0;
- return (0);
+ dest[out] = 0;
+ return (dest);
}
- else if ((src[in] < 32)
+ else if ((((unsigned char) src[in]) < 32)
|| (src[in] == '&')
|| (src[in] == ';')
+ || (src[in] == '?')
+ || (src[in] == '/')
|| (((unsigned char) src[in]) >= 128))
{
char esc[4];
- if ((size - out) < 4)
+ if ((n - out) < 4)
break;
snprintf (esc, sizeof (esc), "%%%02x", (unsigned int) src[in]);
- dst[out] = esc[0];
- dst[out+1] = esc[1];
- dst[out+2] = esc[2];
+ dest[out] = esc[0];
+ dest[out+1] = esc[1];
+ dest[out+2] = esc[2];
out += 3;
in++;
}
else
{
- dst[out] = src[in];
+ dest[out] = src[in];
out++;
in++;
}
} /* while (42) */
- return (0);
-} /* }}} int uri_escape */
+ return (dest);
+} /* }}} char *uri_escape_copy */
+
+char *uri_escape (const char *string) /* {{{ */
+{
+ char buffer[4096];
+
+ if (string == NULL)
+ return (NULL);
+
+ uri_escape_copy (buffer, string, sizeof (buffer));
+
+ 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) /* {{{ */
{
#define COPY_ENTITY(e) do { \
size_t len = strlen (e); \
- if (buffer_size < (len + 1)) \
+ if (dest_size < (len + 1)) \
break; \
- strcpy (buffer_ptr, (e)); \
- buffer_ptr += len; \
- buffer_size -= len; \
+ strcpy (dest_ptr, (e)); \
+ dest_ptr += len; \
+ dest_size -= len; \
} while (0)
-char *html_escape (const char *string) /* {{{ */
+char *html_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
{
- char buffer[4096];
- char *buffer_ptr;
- size_t buffer_size;
+ char *dest_ptr;
+ size_t dest_size;
size_t pos;
- buffer[0] = 0;
- buffer_ptr = &buffer[0];
- buffer_size = sizeof (buffer);
- for (pos = 0; string[pos] != 0; pos++)
+ dest[0] = 0;
+ dest_ptr = dest;
+ dest_size = n;
+ for (pos = 0; src[pos] != 0; pos++)
{
- if (string[pos] == '"')
+ if (src[pos] == '"')
COPY_ENTITY (""");
- else if (string[pos] == '<')
+ else if (src[pos] == '<')
COPY_ENTITY ("<");
- else if (string[pos] == '>')
+ else if (src[pos] == '>')
COPY_ENTITY (">");
- else if (string[pos] == '&')
+ else if (src[pos] == '&')
COPY_ENTITY ("&");
else
{
- *buffer_ptr = string[pos];
- buffer_ptr++;
- buffer_size--;
- *buffer_ptr = 0;
+ *dest_ptr = src[pos];
+ dest_ptr++;
+ dest_size--;
+ *dest_ptr = 0;
}
- if (buffer_size <= 1)
+ if (dest_size <= 1)
break;
}
+ return (dest);
+} /* }}} char *html_escape_copy */
+
+#undef COPY_ENTITY
+
+char *html_escape_buffer (char *buffer, size_t buffer_size) /* {{{ */
+{
+ char tmp[buffer_size];
+
+ html_escape_copy (tmp, buffer, sizeof (tmp));
+ memcpy (buffer, tmp, buffer_size);
+
+ return (buffer);
+} /* }}} char *html_escape_buffer */
+
+char *html_escape (const char *string) /* {{{ */
+{
+ char buffer[4096];
+
+ if (string == NULL)
+ return (NULL);
+
+ html_escape_copy (buffer, string, sizeof (buffer));
+
return (strdup (buffer));
} /* }}} char *html_escape */
-#undef COPY_ENTITY
+int html_print_page (const char *title, /* {{{ */
+ const page_callbacks_t *cb, void *user_data)
+{
+ char *title_html;
+
+ printf ("Content-Type: text/html\n"
+ "X-Generator: "PACKAGE_STRING"\n"
+ "\n\n");
+
+ if (title == NULL)
+ title = "C₄: 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"
+ " </script>\n"
+ " <script type=\"text/javascript\" src=\"../share/collection.js\">\n"
+ " </script>\n"
+ " </head>\n",
+ title_html);
+
+ printf (" <body>\n"
+ " <table id=\"layout-table\">\n"
+ " <tr id=\"layout-top\">\n"
+ " <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)
+ (*cb->top_center) (user_data);
+ else
+ printf ("<h1>%s</h1>", title_html);
+ printf ("</td>\n"
+ " <td id=\"layout-top-right\">");
+ if (cb->top_right != NULL)
+ (*cb->top_right) (user_data);
+ printf ("</td>\n"
+ " </tr>\n"
+ " <tr id=\"layout-middle\">\n"
+ " <td id=\"layout-middle-left\">");
+ if (cb->middle_left != NULL)
+ (*cb->middle_left) (user_data);
+ printf ("</td>\n"
+ " <td id=\"layout-middle-center\">");
+ if (cb->middle_center != NULL)
+ (*cb->middle_center) (user_data);
+ printf ("</td>\n"
+ " <td id=\"layout-middle-right\">");
+ if (cb->middle_right != NULL)
+ (*cb->middle_right) (user_data);
+ printf ("</td>\n"
+ " </tr>\n"
+ " <tr id=\"layout-bottom\">\n"
+ " <td id=\"layout-bottom-left\">");
+ if (cb->bottom_left != NULL)
+ (*cb->bottom_left) (user_data);
+ printf ("</td>\n"
+ " <td id=\"layout-bottom-center\">");
+ if (cb->bottom_center != NULL)
+ (*cb->bottom_center) (user_data);
+ printf ("</td>\n"
+ " <td id=\"layout-bottom-right\">");
+ if (cb->bottom_right != NULL)
+ (*cb->bottom_right) (user_data);
+ printf ("</td>\n"
+ " </tr>\n"
+ " </table>\n"
+ " <div class=\"footer\">"PACKAGE_STRING"</div>\n"
+ " </body>\n"
+ "</html>\n");
+
+ free (title_html);
+ 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 4</div>\n"
+ "</a>\n");
+
+ return (0);
+} /* }}} int html_print_search_box */
+
+int html_print_search_box (__attribute__((unused)) void *user_data) /* {{{ */
+{
+ char *term_html;
+
+ term_html = html_escape (param ("q"));
+
+ printf ("<form action=\"%s\" method=\"get\" id=\"search-form\">\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",
+ script_name (),
+ (term_html != NULL) ? term_html : "");
+
+ free (term_html);
+
+ return (0);
+} /* }}} int html_print_search_box */
/* vim: set sw=2 sts=2 et fdm=marker : */