X-Git-Url: https://git.octo.it/?p=collection4.git;a=blobdiff_plain;f=src%2Futils_cgi.c;h=40768dd605bd0097c0a2a87fc86fe976b67ef0d3;hp=184578869cacda2f8f062084d19835e677d0187a;hb=ae3e7993c119bcfedc76239c1f8a5d8cf1a8c8d9;hpb=e9d94ae68f4081b25c4d278cea49b51354062e7d diff --git a/src/utils_cgi.c b/src/utils_cgi.c index 1845788..40768dd 100644 --- a/src/utils_cgi.c +++ b/src/utils_cgi.c @@ -1,11 +1,41 @@ +/** + * 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 + **/ + +#include "config.h" + #include #include #include #include #include #include +#include #include "utils_cgi.h" +#include "common.h" + +#include +#include struct parameter_s { @@ -14,87 +44,45 @@ 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) /* {{{ */ -{ - 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) /* {{{ */ +struct param_list_s { - 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); - 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; - tmpstr[0] = in[1]; - tmpstr[1] = in[2]; + tmpstr[0] = src_ptr[1]; + tmpstr[1] = src_ptr[2]; tmpstr[2] = 0; errno = 0; @@ -102,64 +90,89 @@ static char *uri_unescape (char *string) /* {{{ */ 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) */ + 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]; + + 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); @@ -167,56 +180,244 @@ static int parse_query_string (char *query_string) /* {{{ */ 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); -int uri_escape (char *dst, const char *src, size_t size) /* {{{ */ + 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 (" \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; @@ -227,37 +428,151 @@ int uri_escape (char *dst, const char *src, size_t size) /* {{{ */ { 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]; - 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_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) /* {{{ */ { @@ -288,4 +603,188 @@ int time_to_rfc1123 (time_t t, char *buffer, size_t buffer_size) /* {{{ */ return (0); } /* }}} int time_to_rfc1123 */ +#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 *html_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 (src[pos] == '>') + COPY_ENTITY (">"); + else if (src[pos] == '&') + COPY_ENTITY ("&"); + else + { + *dest_ptr = src[pos]; + dest_ptr++; + dest_size--; + *dest_ptr = 0; + } + + 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 */ + +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 ("\n" + " \n" + " %s\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n", + title_html); + + printf (" \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
"); + if (cb->top_left != NULL) + (*cb->top_left) (user_data); + else + html_print_logo (NULL); + printf (""); + if (cb->top_center != NULL) + (*cb->top_center) (user_data); + else + printf ("

%s

", title_html); + printf ("
"); + if (cb->top_right != NULL) + (*cb->top_right) (user_data); + printf ("
"); + if (cb->middle_left != NULL) + (*cb->middle_left) (user_data); + printf (""); + if (cb->middle_center != NULL) + (*cb->middle_center) (user_data); + printf (""); + if (cb->middle_right != NULL) + (*cb->middle_right) (user_data); + printf ("
"); + if (cb->bottom_left != NULL) + (*cb->bottom_left) (user_data); + printf (""); + if (cb->bottom_center != NULL) + (*cb->bottom_center) (user_data); + printf (""); + if (cb->bottom_right != NULL) + (*cb->bottom_right) (user_data); + printf ("
\n" + " \n" + " \n" + "\n"); + + free (title_html); + return (0); +} /* }}} int html_print_page */ + +int html_print_logo (__attribute__((unused)) void *user_data) /* {{{ */ +{ + printf ("\n" + "

C4

\n" + "
collection 4
\n" + "
\n", script_name ()); + + 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 ("
\n" + " \n" + " \n" + " \n" + "
\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 : */