1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include <time.h>
7 #include <assert.h>
9 #include "utils_cgi.h"
10 #include "common.h"
12 #include <fcgiapp.h>
13 #include <fcgi_stdio.h>
15 struct parameter_s
16 {
17 char *key;
18 char *value;
19 };
20 typedef struct parameter_s parameter_t;
22 struct param_list_s
23 {
24 parameter_t *parameters;
25 size_t parameters_num;
26 };
28 static param_list_t *pl_global = NULL;
30 static char *uri_unescape_copy (char *dest, const char *src, size_t n) /* {{{ */
31 {
32 const char *src_ptr;
33 char *dest_ptr;
35 if ((dest == NULL) || (src == NULL) || (n < 1))
36 return (NULL);
38 src_ptr = src;
39 dest_ptr = dest;
41 *dest_ptr = 0;
43 while (*src_ptr != 0)
44 {
45 if (n < 2)
46 break;
48 if (*src_ptr == '+')
49 {
50 *dest_ptr = ' ';
51 }
52 else if ((src_ptr[0] == '%')
53 && isxdigit ((int) src_ptr[1]) && isxdigit ((int) src_ptr[2]))
54 {
55 char tmpstr[3];
56 char *endptr;
57 long value;
59 tmpstr[0] = src_ptr[1];
60 tmpstr[1] = src_ptr[2];
61 tmpstr[2] = 0;
63 errno = 0;
64 endptr = NULL;
65 value = strtol (tmpstr, &endptr, /* base = */ 16);
66 if ((endptr == tmpstr) || (errno != 0))
67 {
68 *dest_ptr = '?';
69 }
70 else
71 {
72 *dest_ptr = (char) value;
73 }
75 src_ptr += 2;
76 }
77 else
78 {
79 *dest_ptr = *src_ptr;
80 }
82 src_ptr++;
83 dest_ptr++;
84 *dest_ptr = 0;
85 } /* while (*src_ptr != 0) */
87 assert (*dest_ptr == 0);
88 return (dest);
89 } /* }}} char *uri_unescape */
91 static char *uri_unescape (const char *string) /* {{{ */
92 {
93 char buffer[4096];
95 if (string == NULL)
96 return (NULL);
98 uri_unescape_copy (buffer, string, sizeof (buffer));
100 return (strdup (buffer));
101 } /* }}} char *uri_unescape */
103 static int param_parse_keyval (param_list_t *pl, char *keyval) /* {{{ */
104 {
105 char *key_raw;
106 char *value_raw;
107 char *key;
108 char *value;
110 key_raw = keyval;
111 value_raw = strchr (key_raw, '=');
112 if (value_raw == NULL)
113 return (EINVAL);
114 *value_raw = 0;
115 value_raw++;
117 key = uri_unescape (key_raw);
118 if (key == NULL)
119 return (ENOMEM);
121 value = uri_unescape (value_raw);
122 if (value == NULL)
123 {
124 free (key);
125 return (ENOMEM);
126 }
128 param_set (pl, key, value);
130 free (key);
131 free (value);
133 return (0);
134 } /* }}} int param_parse_keyval */
136 static int parse_query_string (param_list_t *pl, /* {{{ */
137 char *query_string)
138 {
139 char *dummy;
140 char *keyval;
142 if ((pl == NULL) || (query_string == NULL))
143 return (EINVAL);
145 dummy = query_string;
146 while ((keyval = strtok (dummy, ";&")) != NULL)
147 {
148 dummy = NULL;
149 param_parse_keyval (pl, keyval);
150 }
152 return (0);
153 } /* }}} int parse_query_string */
155 int param_init (void) /* {{{ */
156 {
157 if (pl_global != NULL)
158 return (0);
160 pl_global = param_create (/* query string = */ NULL);
161 if (pl_global == NULL)
162 return (ENOMEM);
164 return (0);
165 } /* }}} int param_init */
167 void param_finish (void) /* {{{ */
168 {
169 param_destroy (pl_global);
170 pl_global = NULL;
171 } /* }}} void param_finish */
173 const char *param (const char *key) /* {{{ */
174 {
175 param_init ();
177 return (param_get (pl_global, key));
178 } /* }}} const char *param */
180 param_list_t *param_create (const char *query_string) /* {{{ */
181 {
182 char *tmp;
183 param_list_t *pl;
185 if (query_string == NULL)
186 query_string = getenv ("QUERY_STRING");
188 if (query_string == NULL)
189 return (NULL);
191 tmp = strdup (query_string);
192 if (tmp == NULL)
193 return (NULL);
195 pl = malloc (sizeof (*pl));
196 if (pl == NULL)
197 {
198 free (tmp);
199 return (NULL);
200 }
201 memset (pl, 0, sizeof (*pl));
203 parse_query_string (pl, tmp);
205 free (tmp);
206 return (pl);
207 } /* }}} param_list_t *param_create */
209 param_list_t *param_clone (__attribute__((unused)) param_list_t *pl) /* {{{ */
210 {
211 /* FIXME: To be implemented. */
212 assert (23 == 42);
213 return (NULL);
214 } /* }}} param_list_t *param_clone */
216 void param_destroy (param_list_t *pl) /* {{{ */
217 {
218 size_t i;
220 if (pl == NULL)
221 return;
223 for (i = 0; i < pl->parameters_num; i++)
224 {
225 free (pl->parameters[i].key);
226 free (pl->parameters[i].value);
227 }
228 free (pl->parameters);
229 free (pl);
230 } /* }}} void param_destroy */
232 const char *param_get (param_list_t *pl, const char *name) /* {{{ */
233 {
234 size_t i;
236 if ((pl == NULL) || (name == NULL))
237 return (NULL);
239 for (i = 0; i < pl->parameters_num; i++)
240 {
241 if ((name == NULL) && (pl->parameters[i].key == NULL))
242 return (pl->parameters[i].value);
243 else if ((name != NULL) && (pl->parameters[i].key != NULL)
244 && (strcmp (name, pl->parameters[i].key) == 0))
245 return (pl->parameters[i].value);
246 }
248 return (NULL);
249 } /* }}} char *param_get */
251 static int param_add (param_list_t *pl, /* {{{ */
252 const char *key, const char *value)
253 {
254 parameter_t *tmp;
256 tmp = realloc (pl->parameters,
257 sizeof (*pl->parameters) * (pl->parameters_num + 1));
258 if (tmp == NULL)
259 return (ENOMEM);
260 pl->parameters = tmp;
261 tmp = pl->parameters + pl->parameters_num;
263 memset (tmp, 0, sizeof (*tmp));
264 tmp->key = strdup (key);
265 if (tmp->key == NULL)
266 return (ENOMEM);
268 tmp->value = strdup (value);
269 if (tmp->value == NULL)
270 {
271 free (tmp->key);
272 return (ENOMEM);
273 }
275 pl->parameters_num++;
277 return (0);
278 } /* }}} int param_add */
280 static int param_delete (param_list_t *pl, /* {{{ */
281 const char *name)
282 {
283 size_t i;
285 if ((pl == NULL) || (name == NULL))
286 return (EINVAL);
288 for (i = 0; i < pl->parameters_num; i++)
289 if (strcasecmp (pl->parameters[i].key, name) == 0)
290 break;
292 if (i >= pl->parameters_num)
293 return (ENOENT);
295 if (i < (pl->parameters_num - 1))
296 {
297 parameter_t p;
299 p = pl->parameters[i];
300 pl->parameters[i] = pl->parameters[pl->parameters_num - 1];
301 pl->parameters[pl->parameters_num - 1] = p;
302 }
304 pl->parameters_num--;
305 free (pl->parameters[pl->parameters_num].key);
306 free (pl->parameters[pl->parameters_num].value);
308 return (0);
309 } /* }}} int param_delete */
311 int param_set (param_list_t *pl, const char *name, /* {{{ */
312 const char *value)
313 {
314 parameter_t *p;
315 char *value_copy;
316 size_t i;
318 if ((pl == NULL) || (name == NULL))
319 return (EINVAL);
321 if (value == NULL)
322 return (param_delete (pl, name));
324 p = NULL;
325 for (i = 0; i < pl->parameters_num; i++)
326 {
327 if (strcasecmp (pl->parameters[i].key, name) == 0)
328 {
329 p = pl->parameters + i;
330 break;
331 }
332 }
334 if (p == NULL)
335 return (param_add (pl, name, value));
337 value_copy = strdup (value);
338 if (value_copy == NULL)
339 return (ENOMEM);
341 free (p->value);
342 p->value = value_copy;
344 return (0);
345 } /* }}} int param_set */
347 char *param_as_string (param_list_t *pl) /* {{{ */
348 {
349 char buffer[4096];
350 char key[2048];
351 char value[2048];
352 size_t i;
354 if (pl == NULL)
355 return (NULL);
357 buffer[0] = 0;
358 for (i = 0; i < pl->parameters_num; i++)
359 {
360 uri_escape_copy (key, pl->parameters[i].key, sizeof (key));
361 uri_escape_copy (value, pl->parameters[i].value, sizeof (value));
363 if (i != 0)
364 strlcat (buffer, ";", sizeof (buffer));
365 strlcat (buffer, key, sizeof (buffer));
366 strlcat (buffer, "=", sizeof (buffer));
367 strlcat (buffer, value, sizeof (buffer));
368 }
370 return (strdup (buffer));
371 } /* }}} char *param_as_string */
373 int param_print_hidden (param_list_t *pl) /* {{{ */
374 {
375 char key[2048];
376 char value[2048];
377 size_t i;
379 if (pl == NULL)
380 return (EINVAL);
382 for (i = 0; i < pl->parameters_num; i++)
383 {
384 html_escape_copy (key, pl->parameters[i].key, sizeof (key));
385 html_escape_copy (value, pl->parameters[i].value, sizeof (value));
387 printf (" <input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
388 key, value);
389 }
391 return (0);
392 } /* }}} int param_print_hidden */
394 char *uri_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
395 {
396 size_t in;
397 size_t out;
399 in = 0;
400 out = 0;
401 while (42)
402 {
403 if (src[in] == 0)
404 {
405 dest[out] = 0;
406 return (dest);
407 }
408 else if ((((unsigned char) src[in]) < 32)
409 || (src[in] == '&')
410 || (src[in] == ';')
411 || (src[in] == '?')
412 || (src[in] == '/')
413 || (((unsigned char) src[in]) >= 128))
414 {
415 char esc[4];
417 if ((n - out) < 4)
418 break;
420 snprintf (esc, sizeof (esc), "%%%02x", (unsigned int) src[in]);
421 dest[out] = esc[0];
422 dest[out+1] = esc[1];
423 dest[out+2] = esc[2];
425 out += 3;
426 in++;
427 }
428 else
429 {
430 dest[out] = src[in];
431 out++;
432 in++;
433 }
434 } /* while (42) */
436 return (dest);
437 } /* }}} char *uri_escape_copy */
439 char *uri_escape (const char *string) /* {{{ */
440 {
441 char buffer[4096];
443 if (string == NULL)
444 return (NULL);
446 uri_escape_copy (buffer, string, sizeof (buffer));
448 return (strdup (buffer));
449 } /* }}} char *uri_escape */
451 const char *script_name (void) /* {{{ */
452 {
453 char *ret;
455 ret = getenv ("SCRIPT_NAME");
456 if (ret == NULL)
457 ret = "collection4.fcgi";
459 return (ret);
460 } /* }}} char *script_name */
462 int time_to_rfc1123 (time_t t, char *buffer, size_t buffer_size) /* {{{ */
463 {
464 struct tm tm_tmp;
465 size_t status;
467 /* RFC 1123 *requires* the time to be GMT and the "GMT" timezone string.
468 * Apache will ignore the timezone if "localtime_r" and "%z" is used,
469 * resulting in weird behavior. */
470 if (gmtime_r (&t, &tm_tmp) == NULL)
471 return (errno);
473 status = strftime (buffer, buffer_size, "%a, %d %b %Y %T GMT", &tm_tmp);
474 if (status == 0)
475 return (errno);
477 return (0);
478 } /* }}} int time_to_rfc1123 */
480 #define COPY_ENTITY(e) do { \
481 size_t len = strlen (e); \
482 if (dest_size < (len + 1)) \
483 break; \
484 strcpy (dest_ptr, (e)); \
485 dest_ptr += len; \
486 dest_size -= len; \
487 } while (0)
489 char *html_escape_copy (char *dest, const char *src, size_t n) /* {{{ */
490 {
491 char *dest_ptr;
492 size_t dest_size;
493 size_t pos;
495 dest[0] = 0;
496 dest_ptr = dest;
497 dest_size = n;
498 for (pos = 0; src[pos] != 0; pos++)
499 {
500 if (src[pos] == '"')
501 COPY_ENTITY (""");
502 else if (src[pos] == '<')
503 COPY_ENTITY ("<");
504 else if (src[pos] == '>')
505 COPY_ENTITY (">");
506 else if (src[pos] == '&')
507 COPY_ENTITY ("&");
508 else
509 {
510 *dest_ptr = src[pos];
511 dest_ptr++;
512 dest_size--;
513 *dest_ptr = 0;
514 }
516 if (dest_size <= 1)
517 break;
518 }
520 return (dest);
521 } /* }}} char *html_escape_copy */
523 #undef COPY_ENTITY
525 char *html_escape_buffer (char *buffer, size_t buffer_size) /* {{{ */
526 {
527 char tmp[buffer_size];
529 html_escape_copy (tmp, buffer, sizeof (tmp));
530 memcpy (buffer, tmp, buffer_size);
532 return (buffer);
533 } /* }}} char *html_escape_buffer */
535 char *html_escape (const char *string) /* {{{ */
536 {
537 char buffer[4096];
539 if (string == NULL)
540 return (NULL);
542 html_escape_copy (buffer, string, sizeof (buffer));
544 return (strdup (buffer));
545 } /* }}} char *html_escape */
547 int html_print_page (const char *title, /* {{{ */
548 const page_callbacks_t *cb, void *user_data)
549 {
550 char *title_html;
552 printf ("Content-Type: text/html\n\n");
554 if (title == NULL)
555 title = "c4: collection4 graph interface";
557 title_html = html_escape (title);
559 printf ("<html>\n"
560 " <head>\n"
561 " <title>%s</title>\n"
562 " <link rel=\"stylesheet\" type=\"text/css\" href=\"../share/style.css\" />\n"
563 " <script type=\"text/javascript\" src=\"../share/jquery-1.4.2.min.js\">\n"
564 " </script>\n"
565 " <script type=\"text/javascript\" src=\"../share/collection.js\">\n"
566 " </script>\n"
567 " </head>\n",
568 title_html);
570 printf (" <body>\n"
571 " <table id=\"layout-table\">\n"
572 " <tr id=\"layout-top\">\n"
573 " <td id=\"layout-top-left\">");
574 if (cb->top_left != NULL)
575 (*cb->top_left) (user_data);
576 printf ("</td>\n"
577 " <td id=\"layout-top-center\">");
578 if (cb->top_center != NULL)
579 (*cb->top_center) (user_data);
580 else
581 printf ("<h1>%s</h1>", title_html);
582 printf ("</td>\n"
583 " <td id=\"layout-top-right\">");
584 if (cb->top_right != NULL)
585 (*cb->top_right) (user_data);
586 printf ("</td>\n"
587 " </tr>\n"
588 " <tr id=\"layout-middle\">\n"
589 " <td id=\"layout-middle-left\">");
590 if (cb->middle_left != NULL)
591 (*cb->middle_left) (user_data);
592 printf ("</td>\n"
593 " <td id=\"layout-middle-center\">");
594 if (cb->middle_center != NULL)
595 (*cb->middle_center) (user_data);
596 printf ("</td>\n"
597 " <td id=\"layout-middle-right\">");
598 if (cb->middle_right != NULL)
599 (*cb->middle_right) (user_data);
600 printf ("</td>\n"
601 " </tr>\n"
602 " <tr id=\"layout-bottom\">\n"
603 " <td id=\"layout-bottom-left\">");
604 if (cb->bottom_left != NULL)
605 (*cb->bottom_left) (user_data);
606 printf ("</td>\n"
607 " <td id=\"layout-bottom-center\">");
608 if (cb->bottom_center != NULL)
609 (*cb->bottom_center) (user_data);
610 printf ("</td>\n"
611 " <td id=\"layout-bottom-right\">");
612 if (cb->bottom_right != NULL)
613 (*cb->bottom_right) (user_data);
614 printf ("</td>\n"
615 " </tr>\n"
616 " </table>\n"
617 " </body>\n"
618 "</html>\n");
620 free (title_html);
621 return (0);
622 } /* }}} int html_print_page */
624 int html_print_search_box (__attribute__((unused)) void *user_data) /* {{{ */
625 {
626 char *term_html;
628 term_html = html_escape (param ("q"));
630 printf ("<form action=\"%s\" method=\"get\" id=\"search-form\">\n"
631 " <input type=\"hidden\" name=\"action\" value=\"list_graphs\" />\n"
632 " <input type=\"text\" name=\"q\" value=\"%s\" id=\"search-input\" />\n"
633 " <input type=\"submit\" name=\"button\" value=\"Search\" />\n"
634 "</form>\n",
635 script_name (),
636 (term_html != NULL) ? term_html : "");
638 free (term_html);
640 return (0);
641 } /* }}} int html_print_search_box */
643 /* vim: set sw=2 sts=2 et fdm=marker : */