1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include <time.h>
8 #include "utils_cgi.h"
10 #include <fcgiapp.h>
11 #include <fcgi_stdio.h>
13 struct parameter_s
14 {
15 char *key;
16 char *value;
17 };
18 typedef struct parameter_s parameter_t;
20 static parameter_t *parameters = NULL;
21 static size_t parameters_num = 0;
22 static _Bool parameters_init = 0;
24 static int parameter_add (const char *key, const char *value) /* {{{ */
25 {
26 parameter_t *ptr;
28 if (value == NULL)
29 return (EINVAL);
31 ptr = realloc (parameters, sizeof (*parameters) * (parameters_num + 1));
32 if (ptr == NULL)
33 return (ENOMEM);
34 parameters = ptr;
36 ptr = parameters + parameters_num;
37 if (key == NULL)
38 {
39 ptr->key = NULL;
40 }
41 else
42 {
43 ptr->key = strdup (key);
44 if (ptr->key == NULL)
45 return (ENOMEM);
46 }
48 ptr->value = strdup (value);
49 if (ptr->value == NULL)
50 {
51 free (ptr->key);
52 return (ENOMEM);
53 }
55 parameters_num++;
56 return (0);
57 } /* }}} int parameter_add */
59 static char *parameter_lookup (const char *key) /* {{{ */
60 {
61 size_t i;
63 for (i = 0; i < parameters_num; i++)
64 {
65 if ((key == NULL) && (parameters[i].key == NULL))
66 return (parameters[i].value);
67 else if ((key != NULL) && (parameters[i].key != NULL)
68 && (strcmp (key, parameters[i].key) == 0))
69 return (parameters[i].value);
70 }
72 return (NULL);
73 } /* }}} char *parameter_lookup */
75 static char *uri_unescape (char *string) /* {{{ */
76 {
77 char *in;
78 char *out;
80 if (string == NULL)
81 return (NULL);
83 in = string;
84 out = string;
86 while (*in != 0)
87 {
88 if (*in == '+')
89 {
90 *out = ' ';
91 }
92 else if ((in[0] == '%')
93 && isxdigit ((int) in[1]) && isxdigit ((int) in[2]))
94 {
95 char tmpstr[3];
96 char *endptr;
97 long value;
99 tmpstr[0] = in[1];
100 tmpstr[1] = in[2];
101 tmpstr[2] = 0;
103 errno = 0;
104 endptr = NULL;
105 value = strtol (tmpstr, &endptr, /* base = */ 16);
106 if ((endptr == tmpstr) || (errno != 0))
107 {
108 *out = '?';
109 }
110 else
111 {
112 *out = (char) value;
113 }
115 in += 2;
116 }
117 else
118 {
119 *out = *in;
120 }
122 in++;
123 out++;
124 } /* while (*in != 0) */
126 *out = 0;
127 return (string);
128 } /* }}} char *uri_unescape */
130 static int parse_keyval (char *keyval) /* {{{ */
131 {
132 char *key;
133 char *val;
135 val = strchr (keyval, '=');
136 if (val == NULL)
137 {
138 key = NULL;
139 val = keyval;
140 }
141 else
142 {
143 key = keyval;
144 *val = 0;
145 val++;
146 }
148 parameter_add (uri_unescape (key), uri_unescape (val));
150 return (0);
151 } /* }}} int parse_keyval */
153 static int parse_query_string (char *query_string) /* {{{ */
154 {
155 char *dummy;
156 char *keyval;
158 if (query_string == NULL)
159 return (EINVAL);
161 dummy = query_string;
162 while ((keyval = strtok (dummy, ";&")) != NULL)
163 {
164 dummy = NULL;
165 parse_keyval (keyval);
166 }
168 return (0);
169 } /* }}} int parse_query_string */
171 int param_init (void) /* {{{ */
172 {
173 const char *query_string;
174 char *copy;
175 int status;
177 if (parameters_init)
178 return (0);
180 query_string = getenv ("QUERY_STRING");
181 if (query_string == NULL)
182 return (ENOENT);
184 copy = strdup (query_string);
185 if (copy == NULL)
186 return (ENOMEM);
188 status = parse_query_string (copy);
189 free (copy);
191 parameters_init = 1;
193 return (status);
194 } /* }}} int param_init */
196 void param_finish (void) /* {{{ */
197 {
198 size_t i;
200 if (!parameters_init)
201 return;
203 for (i = 0; i < parameters_num; i++)
204 {
205 free (parameters[i].key);
206 free (parameters[i].value);
207 }
208 free (parameters);
210 parameters = NULL;
211 parameters_num = 0;
212 parameters_init = 0;
213 } /* }}} void param_finish */
215 const char *param (const char *key) /* {{{ */
216 {
217 param_init ();
219 return (parameter_lookup (key));
220 } /* }}} const char *param */
222 int uri_escape (char *dst, const char *src, size_t size) /* {{{ */
223 {
224 size_t in;
225 size_t out;
227 in = 0;
228 out = 0;
229 while (42)
230 {
231 if (src[in] == 0)
232 {
233 dst[out] = 0;
234 return (0);
235 }
236 else if ((src[in] < 32)
237 || (src[in] == '&')
238 || (src[in] == ';')
239 || (((unsigned char) src[in]) >= 128))
240 {
241 char esc[4];
243 if ((size - out) < 4)
244 break;
246 snprintf (esc, sizeof (esc), "%%%02x", (unsigned int) src[in]);
247 dst[out] = esc[0];
248 dst[out+1] = esc[1];
249 dst[out+2] = esc[2];
251 out += 3;
252 in++;
253 }
254 else
255 {
256 dst[out] = src[in];
257 out++;
258 in++;
259 }
260 } /* while (42) */
262 return (0);
263 } /* }}} int uri_escape */
265 const char *script_name (void) /* {{{ */
266 {
267 char *ret;
269 ret = getenv ("SCRIPT_NAME");
270 if (ret == NULL)
271 ret = "collection4.fcgi";
273 return (ret);
274 } /* }}} char *script_name */
276 int time_to_rfc1123 (time_t t, char *buffer, size_t buffer_size) /* {{{ */
277 {
278 struct tm tm_tmp;
279 size_t status;
281 /* RFC 1123 *requires* the time to be GMT and the "GMT" timezone string.
282 * Apache will ignore the timezone if "localtime_r" and "%z" is used,
283 * resulting in weird behavior. */
284 if (gmtime_r (&t, &tm_tmp) == NULL)
285 return (errno);
287 status = strftime (buffer, buffer_size, "%a, %d %b %Y %T GMT", &tm_tmp);
288 if (status == 0)
289 return (errno);
291 return (0);
292 } /* }}} int time_to_rfc1123 */
294 #define COPY_ENTITY(e) do { \
295 size_t len = strlen (e); \
296 if (dest_size < (len + 1)) \
297 break; \
298 strcpy (dest_ptr, (e)); \
299 dest_ptr += len; \
300 dest_size -= len; \
301 } while (0)
303 char *html_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
304 {
305 char *dest_ptr;
306 size_t dest_size;
307 size_t pos;
309 dest[0] = 0;
310 dest_ptr = dest;
311 dest_size = n;
312 for (pos = 0; src[pos] != 0; pos++)
313 {
314 if (src[pos] == '"')
315 COPY_ENTITY (""");
316 else if (src[pos] == '<')
317 COPY_ENTITY ("<");
318 else if (src[pos] == '>')
319 COPY_ENTITY (">");
320 else if (src[pos] == '&')
321 COPY_ENTITY ("&");
322 else
323 {
324 *dest_ptr = src[pos];
325 dest_ptr++;
326 dest_size--;
327 *dest_ptr = 0;
328 }
330 if (dest_size <= 1)
331 break;
332 }
334 return (dest);
335 } /* }}} char *html_escape_copy */
337 #undef COPY_ENTITY
339 char *html_escape_buffer (char *buffer, size_t buffer_size) /* {{{ */
340 {
341 char tmp[buffer_size];
343 html_escape_copy (tmp, buffer, sizeof (tmp));
344 memcpy (buffer, tmp, buffer_size);
346 return (buffer);
347 } /* }}} char *html_escape_buffer */
349 char *html_escape (const char *string) /* {{{ */
350 {
351 char buffer[4096];
353 if (string == NULL)
354 return (NULL);
356 html_escape_copy (buffer, string, sizeof (buffer));
358 return (strdup (buffer));
359 } /* }}} char *html_escape */
361 int html_print_page (const char *title, /* {{{ */
362 const page_callbacks_t *cb, void *user_data)
363 {
364 char *title_html;
366 printf ("Content-Type: text/html\n\n");
368 if (title == NULL)
369 title = "c4: collection4 graph interface";
371 title_html = html_escape (title);
373 printf ("<html>\n"
374 " <head>\n"
375 " <title>%s</title>\n"
376 " <link rel=\"stylesheet\" type=\"text/css\" href=\"../share/style.css\" />\n"
377 " <script type=\"text/javascript\" src=\"../share/jquery-1.4.2.min.js\">\n"
378 " </script>\n"
379 " <script type=\"text/javascript\" src=\"../share/collection.js\">\n"
380 " </script>\n"
381 " </head>\n",
382 title_html);
384 printf (" <body>\n"
385 " <table id=\"layout-table\">\n"
386 " <tr id=\"layout-top\">\n"
387 " <td id=\"layout-top-left\">");
388 if (cb->top_left != NULL)
389 (*cb->top_left) (user_data);
390 printf ("</td>\n"
391 " <td id=\"layout-top-center\">");
392 if (cb->top_center != NULL)
393 (*cb->top_center) (user_data);
394 else
395 printf ("<h1>%s</h1>", title_html);
396 printf ("</td>\n"
397 " <td id=\"layout-top-right\">");
398 if (cb->top_right != NULL)
399 (*cb->top_right) (user_data);
400 printf ("</td>\n"
401 " </tr>\n"
402 " <tr id=\"layout-middle\">\n"
403 " <td id=\"layout-middle-left\">");
404 if (cb->middle_left != NULL)
405 (*cb->middle_left) (user_data);
406 printf ("</td>\n"
407 " <td id=\"layout-middle-center\">");
408 if (cb->middle_center != NULL)
409 (*cb->middle_center) (user_data);
410 printf ("</td>\n"
411 " <td id=\"layout-middle-right\">");
412 if (cb->middle_right != NULL)
413 (*cb->middle_right) (user_data);
414 printf ("</td>\n"
415 " </tr>\n"
416 " <tr id=\"layout-bottom\">\n"
417 " <td id=\"layout-bottom-left\">");
418 if (cb->bottom_left != NULL)
419 (*cb->bottom_left) (user_data);
420 printf ("</td>\n"
421 " <td id=\"layout-bottom-center\">");
422 if (cb->bottom_center != NULL)
423 (*cb->bottom_center) (user_data);
424 printf ("</td>\n"
425 " <td id=\"layout-bottom-right\">");
426 if (cb->bottom_right != NULL)
427 (*cb->bottom_right) (user_data);
428 printf ("</td>\n"
429 " </tr>\n"
430 " </table>\n"
431 " </body>\n"
432 "</html>\n");
434 free (title_html);
435 return (0);
436 } /* }}} int html_print_page */
438 int html_print_search_box (__attribute__((unused)) void *user_data) /* {{{ */
439 {
440 char *term_html;
442 term_html = html_escape (param ("q"));
444 printf ("<form action=\"%s\" method=\"get\" id=\"search-form\">\n"
445 " <input type=\"hidden\" name=\"action\" value=\"list_graphs\" />\n"
446 " <input type=\"text\" name=\"q\" value=\"%s\" id=\"search-input\" />\n"
447 " <input type=\"submit\" name=\"button\" value=\"Search\" />\n"
448 "</form>\n",
449 script_name (),
450 (term_html != NULL) ? term_html : "");
452 free (term_html);
454 return (0);
455 } /* }}} int html_print_search_box */
457 /* vim: set sw=2 sts=2 et fdm=marker : */