diff --git a/src/utils_cgi.c b/src/utils_cgi.c
index 9030eb8b31a5354f8d0ff8ba45db2e4eef44de95..7995e3f1b8cd323992bdbb7c0150b0c461624e2d 100644 (file)
--- a/src/utils_cgi.c
+++ b/src/utils_cgi.c
+/**
+ * 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 <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 "utils_cgi.h"
+#include "common.h"
#include <fcgiapp.h>
#include <fcgi_stdio.h>
#include <fcgiapp.h>
#include <fcgi_stdio.h>
};
typedef struct parameter_s parameter_t;
};
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;
-
- 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);
- }
+ parameter_t *parameters;
+ size_t parameters_num;
+};
- return (NULL);
-} /* }}} char *parameter_lookup */
+static param_list_t *pl_global = NULL;
-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);
return (NULL);
- in = string;
- out = string;
+ src_ptr = src;
+ dest_ptr = dest;
- while (*in != 0)
+ *dest_ptr = 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;
{
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;
tmpstr[2] = 0;
errno = 0;
value = strtol (tmpstr, &endptr, /* base = */ 16);
if ((endptr == tmpstr) || (errno != 0))
{
value = strtol (tmpstr, &endptr, /* base = */ 16);
if ((endptr == tmpstr) || (errno != 0))
{
- *out = '?';
+ *dest_ptr = '?';
}
else
{
}
else
{
- *out = (char) value;
+ *dest_ptr = (char) value;
}
}
- in += 2;
+ src_ptr += 2;
}
else
{
}
else
{
- *out = *in;
+ *dest_ptr = *src_ptr;
}
}
- in++;
- out++;
- } /* while (*in != 0) */
+ n--;
+ src_ptr++;
+ dest_ptr++;
+ *dest_ptr = 0;
+ } /* while (*src_ptr != 0) */
+
+ assert (*dest_ptr == 0);
+ return (dest);
+} /* }}} char *uri_unescape_copy */
+
+static char *uri_unescape (const char *string) /* {{{ */
+{
+ char buffer[4096];
- *out = 0;
- return (string);
+ if (string == NULL)
+ return (NULL);
+
+ uri_unescape_copy (buffer, string, sizeof (buffer));
+
+ return (strdup (buffer));
} /* }}} char *uri_unescape */
} /* }}} 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 *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);
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;
{
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;
return (EINVAL);
dummy = query_string;
while ((keyval = strtok (dummy, ";&")) != NULL)
{
dummy = NULL;
- parse_keyval (keyval);
+ param_parse_keyval (pl, keyval);
}
return (0);
}
return (0);
int param_init (void) /* {{{ */
{
int param_init (void) /* {{{ */
{
- const char *query_string;
- char *copy;
- int status;
-
- if (parameters_init)
+ if (pl_global != NULL)
return (0);
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)
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;
{
size_t i;
- if (!parameters_init)
+ if (pl == NULL)
return;
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);
+ }
-int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
+ 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 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;
{
size_t in;
size_t out;
{
if (src[in] == 0)
{
{
if (src[in] == 0)
{
- dst[out] = 0;
- return (0);
+ dest[out] = 0;
+ return (dest);
}
}
- else if ((src[in] < 32)
- || (src[in] == '&')
- || (src[in] == ';')
+ else if ((((unsigned char) src[in]) < 32)
+ || (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];
|| (((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]);
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
{
out += 3;
in++;
}
else
{
- dst[out] = src[in];
+ dest[out] = src[in];
out++;
in++;
}
} /* while (42) */
out++;
in++;
}
} /* while (42) */
- return (0);
-} /* }}} int uri_escape */
+ 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];
+
+ 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) /* {{{ */
{
const char *script_name (void) /* {{{ */
{
#define COPY_ENTITY(e) do { \
size_t len = strlen (e); \
#define COPY_ENTITY(e) do { \
size_t len = strlen (e); \
- if (dest_size < (len + 1)) \
+ if (dest_size < (len + 1)) \
break; \
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) /* {{{ */
} while (0)
char *html_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
{
char *title_html;
{
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)
if (title == NULL)
- title = "c4: collection4 graph interface";
+ title = "C₄: collection4 graph interface";
title_html = html_escape (title);
title_html = html_escape (title);
" <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"
" <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/raphael-min.js\">\n"
+ " </script>\n"
+ " <script type=\"text/javascript\" src=\"../share/g.raphael-min.js\">\n"
+ " </script>\n"
+ " <script type=\"text/javascript\" src=\"../share/g.line-min.js\">\n"
+ " </script>\n"
" <script type=\"text/javascript\" src=\"../share/collection.js\">\n"
" </script>\n"
" </head>\n",
" <script type=\"text/javascript\" src=\"../share/collection.js\">\n"
" </script>\n"
" </head>\n",
" <td id=\"layout-top-left\">");
if (cb->top_left != NULL)
(*cb->top_left) (user_data);
" <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)
printf ("</td>\n"
" <td id=\"layout-top-center\">");
if (cb->top_center != NULL)
printf ("</td>\n"
" </tr>\n"
" </table>\n"
printf ("</td>\n"
" </tr>\n"
" </table>\n"
+ " <div class=\"footer\">"PACKAGE_STRING"</div>\n"
" </body>\n"
"</html>\n");
" </body>\n"
"</html>\n");
return (0);
} /* }}} int html_print_page */
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", script_name ());
+
+ return (0);
+} /* }}} int html_print_search_box */
+
int html_print_search_box (__attribute__((unused)) void *user_data) /* {{{ */
{
char *term_html;
int html_print_search_box (__attribute__((unused)) void *user_data) /* {{{ */
{
char *term_html;
- term_html = html_escape (param ("search"));
+ term_html = html_escape (param ("q"));
- printf ("<form action=\"%s\" method=\"get\">\n"
- " <input type=\"hidden\" name=\"action\" value=\"list_graphs\" />\n"
- " <input type=\"text\" name=\"search\" value=\"%s\" id=\"search-input\" />\n"
+ 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 (),
" <input type=\"submit\" name=\"button\" value=\"Search\" />\n"
"</form>\n",
script_name (),