]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/var.c
Finish up cups-driverd and fix some bugs.
[thirdparty/cups.git] / cgi-bin / var.c
CommitLineData
9153c417 1/*
c9d3f842 2 * "$Id$"
9153c417 3 *
90beaed3 4 * CGI form variable and array functions.
9153c417 5 *
c9d3f842 6 * Copyright 1997-2005 by Easy Software Products.
4a409eae 7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
a548a235 21 *
22 * Contents:
23 *
24 * cgiInitialize() - Initialize the CGI variable "database"...
d694b7ed 25 * cgiIsPOST() - Determine whether this page was POSTed.
ef15b5ef 26 * cgiCheckVariables() - Check for the presence of "required" variables.
90beaed3 27 * cgiGetArray() - Get an element from a form array...
28 * cgiGetSize() - Get the size of a form array value.
a548a235 29 * cgiGetVariable() - Get a CGI variable from the database...
90beaed3 30 * cgiSetArray() - Set array element N to the specified string.
a548a235 31 * cgiSetVariable() - Set a CGI variable in the database...
a548a235 32 * cgi_add_variable() - Add a form variable.
90beaed3 33 * cgi_compare_variables() - Compare two variables.
34 * cgi_find_variable() - Find a variable...
a548a235 35 * cgi_initialize_get() - Initialize form variables using the GET method.
36 * cgi_initialize_post() - Initialize variables using the POST method.
90beaed3 37 * cgi_initialize_string() - Initialize form variables from a string.
38 * cgi_sort_variables() - Sort all form variables for faster lookup.
9153c417 39 */
40
7b69bd6f 41/*#define DEBUG*/
9153c417 42#include "cgi.h"
f2bc527f 43#include <cups/cups.h>
7c935cd3 44#include <errno.h>
45#include <syslog.h>
9153c417 46
47
48/*
90beaed3 49 * Data structure to hold all the CGI form variables and arrays...
9153c417 50 */
51
52typedef struct
53{
90beaed3 54 const char *name; /* Name of variable */
55 int nvalues, /* Number of values */
56 avalues; /* Number of values allocated */
57 const char **values; /* Value(s) of variable */
9153c417 58} var_t;
59
60
61/*
62 * Local globals...
63 */
64
90beaed3 65static int form_count = 0, /* Form variable count */
66 form_alloc = 0; /* Number of variables allocated */
9153c417 67static var_t *form_vars = NULL; /* Form variables */
68
69
70/*
71 * Local functions...
72 */
73
ea373144 74static void cgi_add_variable(const char *name, int element,
75 const char *value);
76static int cgi_compare_variables(const var_t *v1, const var_t *v2);
77static var_t *cgi_find_variable(const char *name);
78static int cgi_initialize_get(void);
79static int cgi_initialize_post(void);
80static int cgi_initialize_string(const char *data);
81static const char *cgi_passwd(const char *prompt);
82static void cgi_sort_variables(void);
9153c417 83
84
85/*
a548a235 86 * 'cgiInitialize()' - Initialize the CGI variable "database"...
9153c417 87 */
88
ea373144 89int /* O - Non-zero if there was form data */
36694ee4 90cgiInitialize(void)
9153c417 91{
ea373144 92 const char *method; /* Form posting method */
9153c417 93
94
ea373144 95 /*
96 * Setup a password callback for authentication...
97 */
98
99 cupsSetPasswordCB(cgi_passwd);
100
7b69bd6f 101#ifdef DEBUG
ea373144 102 /*
103 * Disable output buffering to find bugs...
104 */
105
7b69bd6f 106 setbuf(stdout, NULL);
107 puts("Content-type: text/plain\n");
108#endif /* DEBUG */
109
ea373144 110 /*
111 * Get the request method (GET or POST)...
112 */
113
9153c417 114 method = getenv("REQUEST_METHOD");
115
ea373144 116 if (!method)
781d64bb 117 return (0);
9153c417 118
ea373144 119 /*
120 * Grab form data from the corresponding location...
121 */
122
123 if (!strcasecmp(method, "GET"))
36694ee4 124 return (cgi_initialize_get());
ea373144 125 else if (!strcasecmp(method, "POST"))
36694ee4 126 return (cgi_initialize_post());
9153c417 127 else
781d64bb 128 return (0);
9153c417 129}
130
131
ef15b5ef 132/*
133 * 'cgiCheckVariables()' - Check for the presence of "required" variables.
134 *
90beaed3 135 * Names may be separated by spaces and/or commas.
ef15b5ef 136 */
137
90beaed3 138int /* O - 1 if all variables present, 0 otherwise */
139cgiCheckVariables(const char *names) /* I - Variables to look for */
ef15b5ef 140{
90beaed3 141 char name[255], /* Current variable name */
142 *s; /* Pointer in string */
143 const char *val; /* Value of variable */
144 int element; /* Array element number */
ef15b5ef 145
146
147 if (names == NULL)
148 return (1);
149
150 while (*names != '\0')
151 {
152 while (*names == ' ' || *names == ',')
153 names ++;
154
155 for (s = name; *names != '\0' && *names != ' ' && *names != ','; s ++, names ++)
156 *s = *names;
157
158 *s = 0;
159 if (name[0] == '\0')
160 break;
161
90beaed3 162 if ((s = strrchr(name, '-')) != NULL)
163 {
164 *s = '\0';
165 element = atoi(s + 1) - 1;
166 val = cgiGetArray(name, element);
167 }
168 else
169 val = cgiGetVariable(name);
170
171 if (val == NULL)
ef15b5ef 172 return (0);
3915f775 173
174 if (*val == '\0')
175 return (0); /* Can't be blank, either! */
90beaed3 176 }
ef15b5ef 177
178 return (1);
179}
180
181
d694b7ed 182/*
183 * 'cgiIsPOST()' - Determine whether this page was POSTed.
184 */
185
186int /* O - 1 if POST, 0 if GET */
187cgiIsPOST(void)
188{
189 const char *method; /* REQUEST_METHOD environment variable */
190
191
192 if ((method = getenv("REQUEST_METHOD")) == NULL)
193 return (0);
194 else
195 return (!strcmp(method, "POST"));
196}
197
198
a548a235 199/*
90beaed3 200 * 'cgiGetArray()' - Get an element from a form array...
a548a235 201 */
202
90beaed3 203const char * /* O - Element value or NULL */
204cgiGetArray(const char *name, /* I - Name of array variable */
205 int element) /* I - Element number (0 to N) */
a548a235 206{
90beaed3 207 var_t *var; /* Pointer to variable */
a548a235 208
209
90beaed3 210 if ((var = cgi_find_variable(name)) == NULL)
a548a235 211 return (NULL);
212
4a409eae 213 if (var->nvalues == 1)
214 return (var->values[0]);
215
90beaed3 216 if (element < 0 || element >= var->nvalues)
217 return (NULL);
218
219 return (var->values[element]);
220}
221
222
223/*
224 * 'cgiGetSize()' - Get the size of a form array value.
225 */
226
227int /* O - Number of elements */
228cgiGetSize(const char *name) /* I - Name of variable */
229{
230 var_t *var; /* Pointer to variable */
231
232
233 if ((var = cgi_find_variable(name)) == NULL)
234 return (0);
235
236 return (var->nvalues);
237}
238
239
240/*
241 * 'cgiGetVariable()' - Get a CGI variable from the database...
242 *
243 * Returns NULL if the variable doesn't exist... If the variable is an
244 * array of values, returns the last element...
245 */
246
247const char * /* O - Value of variable */
248cgiGetVariable(const char *name)/* I - Name of variable */
249{
250 const var_t *var; /* Returned variable */
251
a548a235 252
90beaed3 253 var = cgi_find_variable(name);
a548a235 254
7b69bd6f 255#ifdef DEBUG
256 if (var == NULL)
257 printf("cgiGetVariable(\"%s\") is returning NULL...\n", name);
258 else
90beaed3 259 printf("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name,
260 var->values[var->nvalues - 1]);
7b69bd6f 261#endif /* DEBUG */
262
90beaed3 263 return ((var == NULL) ? NULL : var->values[var->nvalues - 1]);
a548a235 264}
265
266
267/*
90beaed3 268 * 'cgiSetArray()' - Set array element N to the specified string.
269 *
270 * If the variable array is smaller than (element + 1), the intervening
271 * elements are set to NULL.
a548a235 272 */
273
274void
90beaed3 275cgiSetArray(const char *name, /* I - Name of variable */
276 int element, /* I - Element number (0 to N) */
277 const char *value) /* I - Value of variable */
a548a235 278{
90beaed3 279 int i; /* Looping var */
280 var_t *var; /* Returned variable */
a548a235 281
282
901b295d 283 if (name == NULL || value == NULL || element < 0 || element > 100000)
f8965d70 284 return;
285
90beaed3 286 if ((var = cgi_find_variable(name)) == NULL)
a548a235 287 {
90beaed3 288 cgi_add_variable(name, element, value);
289 cgi_sort_variables();
a548a235 290 }
291 else
90beaed3 292 {
293 if (element >= var->avalues)
294 {
295 var->avalues = element + 16;
b26a9a6f 296 var->values = (const char **)realloc((void *)(var->values),
297 sizeof(char *) * var->avalues);
90beaed3 298 }
a548a235 299
90beaed3 300 if (element >= var->nvalues)
301 {
302 for (i = var->nvalues; i < element; i ++)
303 var->values[i] = NULL;
304
305 var->nvalues = element + 1;
306 }
307 else if (var->values[element])
308 free((char *)var->values[element]);
309
310 var->values[element] = strdup(value);
311 }
312}
313
314
e846bf33 315/*
316 * 'cgiSetSize()' - Set the array size.
317 */
318
319void
320cgiSetSize(const char *name, /* I - Name of variable */
321 int size) /* I - Number of elements (0 to N) */
322{
323 int i; /* Looping var */
324 var_t *var; /* Returned variable */
325
326
901b295d 327 if (name == NULL || size < 0 || size > 100000)
e846bf33 328 return;
329
330 if ((var = cgi_find_variable(name)) == NULL)
331 return;
332
333 if (size >= var->avalues)
334 {
335 var->avalues = size + 16;
b26a9a6f 336 var->values = (const char **)realloc((void *)(var->values),
337 sizeof(char *) * var->avalues);
e846bf33 338 }
339
340 if (size > var->nvalues)
341 {
342 for (i = var->nvalues; i < size; i ++)
343 var->values[i] = NULL;
344 }
345 else if (size < var->nvalues)
346 {
347 for (i = size; i < var->nvalues; i ++)
348 if (var->values[i])
b26a9a6f 349 free((void *)(var->values[i]));
e846bf33 350 }
351
352 var->nvalues = size;
353}
354
355
90beaed3 356/*
357 * 'cgiSetVariable()' - Set a CGI variable in the database...
358 *
359 * If the variable is an array, this truncates the array to a single element.
360 */
361
362void
363cgiSetVariable(const char *name, /* I - Name of variable */
364 const char *value) /* I - Value of variable */
365{
366 int i; /* Looping var */
367 var_t *var; /* Returned variable */
368
369
370 if (name == NULL || value == NULL)
371 return;
372
373 if ((var = cgi_find_variable(name)) == NULL)
a548a235 374 {
90beaed3 375 cgi_add_variable(name, 0, value);
a548a235 376 cgi_sort_variables();
377 }
378 else
379 {
90beaed3 380 for (i = 0; i < var->nvalues; i ++)
381 if (var->values[i])
382 free((char *)var->values[i]);
383
384 var->values[0] = strdup(value);
385 var->nvalues = 1;
386 }
a548a235 387}
388
389
390/*
90beaed3 391 * 'cgi_add_variable()' - Add a form variable.
a548a235 392 */
393
9153c417 394static void
90beaed3 395cgi_add_variable(const char *name, /* I - Variable name */
396 int element, /* I - Array element number */
397 const char *value) /* I - Variable value */
9153c417 398{
90beaed3 399 var_t *var; /* New variable */
7b69bd6f 400
7b69bd6f 401
901b295d 402 if (name == NULL || value == NULL || element < 0 || element > 100000)
9153c417 403 return;
404
7b69bd6f 405#ifdef DEBUG
90beaed3 406 printf("Adding variable \'%s\' with value \'%s\'...\n", name, value);
7b69bd6f 407#endif /* DEBUG */
90beaed3 408
409 if (form_count >= form_alloc)
410 {
411 if (form_alloc == 0)
412 form_vars = malloc(sizeof(var_t) * 16);
413 else
414 form_vars = realloc(form_vars, (form_alloc + 16) * sizeof(var_t));
415
416 form_alloc += 16;
417 }
418
419 var = form_vars + form_count;
420 var->name = strdup(name);
421 var->nvalues = element + 1;
422 var->avalues = element + 1;
423 var->values = calloc(element + 1, sizeof(char *));
424 var->values[element] = strdup(value);
425
426 form_count ++;
9153c417 427}
428
429
a548a235 430/*
431 * 'cgi_compare_variables()' - Compare two variables.
432 */
433
90beaed3 434static int /* O - Result of comparison */
435cgi_compare_variables(const var_t *v1, /* I - First variable */
436 const var_t *v2) /* I - Second variable */
9153c417 437{
438 return (strcasecmp(v1->name, v2->name));
439}
440
441
a548a235 442/*
90beaed3 443 * 'cgi_find_variable()' - Find a variable...
a548a235 444 */
445
90beaed3 446static var_t * /* O - Variable pointer or NULL */
447cgi_find_variable(const char *name) /* I - Name of variable */
9153c417 448{
90beaed3 449 var_t key; /* Search key */
9153c417 450
451
90beaed3 452 if (form_count < 1 || name == NULL)
453 return (NULL);
454
455 key.name = name;
456
457 return ((var_t *)bsearch(&key, form_vars, form_count, sizeof(var_t),
458 (int (*)(const void *, const void *))cgi_compare_variables));
459}
460
461
462/*
463 * 'cgi_initialize_get()' - Initialize form variables using the GET method.
464 */
465
36694ee4 466static int /* O - 1 if form data read */
467cgi_initialize_get(void)
90beaed3 468{
36694ee4 469 char *data; /* Pointer to form data string */
90beaed3 470
f8965d70 471
7b69bd6f 472#ifdef DEBUG
90beaed3 473 puts("Initializing variables using GET method...");
7b69bd6f 474#endif /* DEBUG */
475
90beaed3 476 /*
477 * Check to see if there is anything for us to read...
478 */
9153c417 479
90beaed3 480 data = getenv("QUERY_STRING");
481 if (data == NULL || strlen(data) == 0)
482 return (0);
483
484 /*
485 * Parse it out and return...
486 */
487
488 return (cgi_initialize_string(data));
489}
490
491
492/*
493 * 'cgi_initialize_post()' - Initialize variables using the POST method.
494 */
495
36694ee4 496static int /* O - 1 if form data was read */
497cgi_initialize_post(void)
90beaed3 498{
499 char *content_length, /* Length of input data (string) */
500 *data; /* Pointer to form data string */
501 int length, /* Length of input data */
502 nbytes, /* Number of bytes read this read() */
503 tbytes, /* Total number of bytes read */
504 status; /* Return status */
505
506
507#ifdef DEBUG
508 puts("Initializing variables using POST method...");
509#endif /* DEBUG */
510
511 /*
512 * Check to see if there is anything for us to read...
513 */
514
515 content_length = getenv("CONTENT_LENGTH");
0819478b 516 if (content_length == NULL || atoi(content_length) <= 0)
90beaed3 517 return (0);
518
519 /*
520 * Get the length of the input stream and allocate a buffer for it...
521 */
522
523 length = atoi(content_length);
524 data = malloc(length + 1);
525
0819478b 526 if (data == NULL)
527 return (0);
528
90beaed3 529 /*
530 * Read the data into the buffer...
531 */
532
533 for (tbytes = 0; tbytes < length; tbytes += nbytes)
534 if ((nbytes = read(0, data + tbytes, length - tbytes)) < 0)
7c935cd3 535 if (errno != EAGAIN)
536 {
537 free(data);
538 return (0);
539 }
90beaed3 540
541 data[length] = '\0';
542
543 /*
544 * Parse it out...
545 */
546
547 status = cgi_initialize_string(data);
548
549 /*
550 * Free the data and return...
551 */
552
553 free(data);
554
555 return (status);
9153c417 556}
557
558
559/*
560 * 'cgi_initialize_string()' - Initialize form variables from a string.
561 */
562
f8965d70 563static int
90beaed3 564cgi_initialize_string(const char *data) /* I - Form data string */
9153c417 565{
566 int done; /* True if we're done reading a form variable */
567 char *s, /* Pointer to current form string */
568 ch, /* Temporary character */
569 name[255], /* Name of form variable */
570 value[65536]; /* Variable value... */
571
572
573 /*
574 * Check input...
575 */
576
577 if (data == NULL)
f8965d70 578 return (0);
9153c417 579
580 /*
581 * Loop until we've read all the form data...
582 */
583
584 while (*data != '\0')
585 {
586 /*
587 * Get the variable name...
588 */
589
7c935cd3 590 for (s = name; *data != '\0'; data ++)
9153c417 591 if (*data == '=')
592 break;
0819478b 593 else if (*data >= ' ' && s < (name + sizeof(name) - 1))
7c935cd3 594 *s++ = *data;
9153c417 595
596 *s = '\0';
597 if (*data == '=')
598 data ++;
f8965d70 599 else
600 return (0);
9153c417 601
602 /*
603 * Read the variable value...
604 */
605
0819478b 606 for (s = value, done = 0; !done && *data != '\0'; data ++)
9153c417 607 switch (*data)
608 {
609 case '&' : /* End of data... */
610 done = 1;
9153c417 611 break;
612
613 case '+' : /* Escaped space character */
0819478b 614 if (s < (value + sizeof(value) - 1))
615 *s++ = ' ';
9153c417 616 break;
617
618 case '%' : /* Escaped control character */
619 /*
0819478b 620 * Read the hex code...
9153c417 621 */
622
0819478b 623 if (s < (value + sizeof(value) - 1))
624 {
625 data ++;
626 ch = *data - '0';
627 if (ch > 9)
628 ch -= 7;
629 *s = ch << 4;
630
631 data ++;
632 ch = *data - '0';
633 if (ch > 9)
634 ch -= 7;
635 *s++ |= ch;
636 }
637 else
638 data += 2;
9153c417 639 break;
640
641 default : /* Other characters come straight through */
0819478b 642 if (*data >= ' ' && s < (value + sizeof(value) - 1))
643 *s++ = *data;
9153c417 644 break;
90beaed3 645 }
9153c417 646
647 *s = '\0'; /* nul terminate the string */
648
6ee2c4c1 649 /*
650 * Remove trailing whitespace...
651 */
652
7c935cd3 653 if (s > value)
654 s --;
655
6ee2c4c1 656 while (s >= value && *s == ' ')
657 *s-- = '\0';
658
9153c417 659 /*
660 * Add the string to the variable "database"...
661 */
662
da275f55 663 if ((s = strrchr(name, '-')) != NULL && isdigit(s[1] & 255))
90beaed3 664 {
f63a2256 665 *s++ = '\0';
d1ad21c3 666 if (value[0])
667 cgiSetArray(name, atoi(s) - 1, value);
90beaed3 668 }
3d9e2586 669 else if (cgiGetVariable(name) != NULL)
670 cgiSetArray(name, cgiGetSize(name), value);
90beaed3 671 else
672 cgiSetVariable(name, value);
673 }
f8965d70 674
675 return (1);
9153c417 676}
677
678
ea373144 679/*
680 * 'cgi_passwd()' - Catch authentication requests and notify the server.
681 *
682 * This function sends a Status header and exits, forcing authentication
683 * for this request.
684 */
685
686static const char * /* O - NULL (no return) */
687cgi_passwd(const char *prompt) /* I - Prompt (not used) */
688{
689 (void)prompt;
690
691 /*
692 * Send a 401 (unauthorized) status to the server, so it can notify
693 * the client that authentication is required.
694 */
695
696 puts("Status: 401\n");
697 exit(0);
698
699 /*
700 * This code is never executed, but is present to satisfy the compiler.
701 */
702
703 return (NULL);
704}
705
706
9153c417 707/*
90beaed3 708 * 'cgi_sort_variables()' - Sort all form variables for faster lookup.
9153c417 709 */
710
90beaed3 711static void
712cgi_sort_variables(void)
9153c417 713{
7b69bd6f 714#ifdef DEBUG
90beaed3 715 int i;
9153c417 716
717
90beaed3 718 puts("Sorting variables...");
719#endif /* DEBUG */
a548a235 720
90beaed3 721 if (form_count < 2)
722 return;
9153c417 723
90beaed3 724 qsort(form_vars, form_count, sizeof(var_t),
725 (int (*)(const void *, const void *))cgi_compare_variables);
9153c417 726
7b69bd6f 727#ifdef DEBUG
7c935cd3 728 puts("Sorted variable list is:");
90beaed3 729 for (i = 0; i < form_count; i ++)
7c935cd3 730 printf("%d: %s (%d) = \"%s\" ...\n", i, form_vars[i].name,
731 form_vars[i].nvalues, form_vars[i].values[0]);
7b69bd6f 732#endif /* DEBUG */
9153c417 733}
734
735
736/*
c9d3f842 737 * End of "$Id$".
9153c417 738 */