]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/template.c
Load cups into easysw/current.
[thirdparty/cups.git] / cgi-bin / template.c
1 /*
2 * "$Id: template.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * CGI template function.
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Contents:
16 *
17 * cgiCopyTemplateFile() - Copy a template file and replace all the
18 * '{variable}' strings with the variable value.
19 * cgiCopyTemplateLang() - Copy a template file using a language...
20 * cgiGetTemplateDir() - Get the templates directory...
21 * cgiSetServerVersion() - Set the server name and CUPS version...
22 * cgi_copy() - Copy the template file, substituting as needed...
23 * cgi_puts() - Put a string to the output file, quoting as
24 * needed...
25 */
26
27 #include "cgi-private.h"
28 #include <errno.h>
29
30
31 /*
32 * Local functions...
33 */
34
35 static void cgi_copy(FILE *out, FILE *in, int element, char term,
36 int indent);
37 static void cgi_puts(const char *s, FILE *out);
38 static void cgi_puturi(const char *s, FILE *out);
39
40
41 /*
42 * 'cgiCopyTemplateFile()' - Copy a template file and replace all the
43 * '{variable}' strings with the variable value.
44 */
45
46 void
47 cgiCopyTemplateFile(FILE *out, /* I - Output file */
48 const char *tmpl) /* I - Template file to read */
49 {
50 FILE *in; /* Input file */
51
52
53 fprintf(stderr, "DEBUG: cgiCopyTemplateFile(out=%p, tmpl=\"%s\")\n", out,
54 tmpl ? tmpl : "(null)");
55
56 /*
57 * Open the template file...
58 */
59
60 if ((in = fopen(tmpl, "r")) == NULL)
61 {
62 fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
63 tmpl ? tmpl : "(null)", strerror(errno));
64 return;
65 }
66
67 /*
68 * Parse the file to the end...
69 */
70
71 cgi_copy(out, in, 0, 0, 0);
72
73 /*
74 * Close the template file and return...
75 */
76
77 fclose(in);
78 }
79
80
81 /*
82 * 'cgiCopyTemplateLang()' - Copy a template file using a language...
83 */
84
85 void
86 cgiCopyTemplateLang(const char *tmpl) /* I - Base filename */
87 {
88 int i; /* Looping var */
89 char filename[1024], /* Filename */
90 locale[16]; /* Locale name */
91 const char *directory, /* Directory for templates */
92 *lang; /* Language */
93 FILE *in; /* Input file */
94
95
96 fprintf(stderr, "DEBUG: cgiCopyTemplateLang(tmpl=\"%s\")\n",
97 tmpl ? tmpl : "(null)");
98
99 /*
100 * Convert the language to a locale name...
101 */
102
103 if ((lang = getenv("LANG")) != NULL)
104 {
105 for (i = 0; lang[i] && i < 15; i ++)
106 if (isalnum(lang[i] & 255) || lang[i] == '_')
107 locale[i] = tolower(lang[i]);
108 else if (lang[i] == '-')
109 locale[i] = '_';
110 else
111 break;
112
113 locale[i] = '\0';
114 }
115 else
116 locale[0] = '\0';
117
118 fprintf(stderr, "DEBUG: locale=\"%s\"...\n", locale);
119
120 /*
121 * See if we have a template file for this language...
122 */
123
124 directory = cgiGetTemplateDir();
125
126 snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
127 if (access(filename, 0))
128 {
129 locale[2] = '\0';
130
131 snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
132 if (access(filename, 0))
133 snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
134 }
135
136 fprintf(stderr, "DEBUG: Template file is \"%s\"...\n", filename);
137
138 /*
139 * Open the template file...
140 */
141
142 if ((in = fopen(filename, "r")) == NULL)
143 {
144 fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
145 filename, strerror(errno));
146 return;
147 }
148
149 /*
150 * Parse the file to the end...
151 */
152
153 cgi_copy(stdout, in, 0, 0, 0);
154
155 /*
156 * Close the template file and return...
157 */
158
159 fclose(in);
160 }
161
162
163 /*
164 * 'cgiGetTemplateDir()' - Get the templates directory...
165 */
166
167 char * /* O - Template directory */
168 cgiGetTemplateDir(void)
169 {
170 const char *datadir; /* CUPS_DATADIR env var */
171 static char templates[1024] = ""; /* Template directory */
172
173
174 if (!templates[0])
175 {
176 /*
177 * Build the template directory pathname...
178 */
179
180 if ((datadir = getenv("CUPS_DATADIR")) == NULL)
181 datadir = CUPS_DATADIR;
182
183 snprintf(templates, sizeof(templates), "%s/templates", datadir);
184 }
185
186 return (templates);
187 }
188
189
190 /*
191 * 'cgiSetServerVersion()' - Set the server name and CUPS version...
192 */
193
194 void
195 cgiSetServerVersion(void)
196 {
197 cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME"));
198 cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER"));
199 cgiSetVariable("CUPS_VERSION", CUPS_SVERSION);
200
201 #ifdef LC_TIME
202 setlocale(LC_TIME, "");
203 #endif /* LC_TIME */
204 }
205
206
207 /*
208 * 'cgi_copy()' - Copy the template file, substituting as needed...
209 */
210
211 static void
212 cgi_copy(FILE *out, /* I - Output file */
213 FILE *in, /* I - Input file */
214 int element, /* I - Element number (0 to N) */
215 char term, /* I - Terminating character */
216 int indent) /* I - Debug info indentation */
217 {
218 int ch; /* Character from file */
219 char op; /* Operation */
220 char name[255], /* Name of variable */
221 *nameptr, /* Pointer into name */
222 innername[255], /* Inner comparison name */
223 *innerptr, /* Pointer into inner name */
224 *s; /* String pointer */
225 const char *value; /* Value of variable */
226 const char *innerval; /* Inner value */
227 const char *outptr; /* Output string pointer */
228 char outval[1024], /* Formatted output string */
229 compare[1024]; /* Comparison string */
230 int result; /* Result of comparison */
231 int uriencode; /* Encode as URI */
232
233
234 fprintf(stderr, "DEBUG: %*sStarting at file position %ld...\n", indent, "",
235 ftell(in));
236
237 /*
238 * Parse the file to the end...
239 */
240
241 while ((ch = getc(in)) != EOF)
242 if (ch == term)
243 break;
244 else if (ch == '{')
245 {
246 /*
247 * Get a variable name...
248 */
249
250 uriencode = 0;
251
252 for (s = name; (ch = getc(in)) != EOF;)
253 if (strchr("}]<>=! \t\n", ch))
254 break;
255 else if (s == name && ch == '%')
256 uriencode = 1;
257 else if (s > name && ch == '?')
258 break;
259 else if (s < (name + sizeof(name) - 1))
260 *s++ = ch;
261
262 *s = '\0';
263
264 if (s == name && isspace(ch & 255))
265 {
266 fprintf(stderr, "DEBUG: %*sLone { at %ld...\n", indent, "", ftell(in));
267
268 if (out)
269 {
270 putc('{', out);
271 putc(ch, out);
272 }
273
274 continue;
275 }
276
277 if (ch == '}')
278 fprintf(stderr, "DEBUG: %*s\"{%s}\" at %ld...\n", indent, "", name,
279 ftell(in));
280
281 /*
282 * See if it has a value...
283 */
284
285 if (name[0] == '?')
286 {
287 /*
288 * Insert value only if it exists...
289 */
290
291 if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
292 {
293 *nameptr++ = '\0';
294
295 if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL)
296 outptr = value;
297 else
298 {
299 outval[0] = '\0';
300 outptr = outval;
301 }
302 }
303 else if ((value = cgiGetArray(name + 1, element)) != NULL)
304 outptr = value;
305 else
306 {
307 outval[0] = '\0';
308 outptr = outval;
309 }
310 }
311 else if (name[0] == '#')
312 {
313 /*
314 * Insert count...
315 */
316
317 if (name[1])
318 sprintf(outval, "%d", cgiGetSize(name + 1));
319 else
320 sprintf(outval, "%d", element + 1);
321
322 outptr = outval;
323 }
324 else if (name[0] == '[')
325 {
326 /*
327 * Loop for # of elements...
328 */
329
330 int i; /* Looping var */
331 long pos; /* File position */
332 int count; /* Number of elements */
333
334
335 if (isdigit(name[1] & 255))
336 count = atoi(name + 1);
337 else
338 count = cgiGetSize(name + 1);
339
340 pos = ftell(in);
341
342 fprintf(stderr, "DEBUG: %*sLooping on \"%s\" at %ld, count=%d...\n",
343 indent, "", name + 1, pos, count);
344
345 if (count > 0)
346 {
347 for (i = 0; i < count; i ++)
348 {
349 if (i)
350 fseek(in, pos, SEEK_SET);
351
352 cgi_copy(out, in, i, '}', indent + 2);
353 }
354 }
355 else
356 cgi_copy(NULL, in, 0, '}', indent + 2);
357
358 fprintf(stderr, "DEBUG: %*sFinished looping on \"%s\"...\n", indent,
359 "", name + 1);
360
361 continue;
362 }
363 else
364 {
365 /*
366 * Insert variable or variable name (if element is NULL)...
367 */
368
369 if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
370 {
371 *nameptr++ = '\0';
372 if ((value = cgiGetArray(name, atoi(nameptr) - 1)) == NULL)
373 {
374 snprintf(outval, sizeof(outval), "{%s}", name);
375 outptr = outval;
376 }
377 else
378 outptr = value;
379 }
380 else if ((value = cgiGetArray(name, element)) == NULL)
381 {
382 snprintf(outval, sizeof(outval), "{%s}", name);
383 outptr = outval;
384 }
385 else
386 outptr = value;
387 }
388
389 /*
390 * See if the terminating character requires another test...
391 */
392
393 if (ch == '}')
394 {
395 /*
396 * End of substitution...
397 */
398
399 if (out)
400 {
401 if (uriencode)
402 cgi_puturi(outptr, out);
403 else
404 cgi_puts(outptr, out);
405 }
406
407 continue;
408 }
409
410 /*
411 * OK, process one of the following checks:
412 *
413 * {name?exist:not-exist} Exists?
414 * {name=value?true:false} Equal
415 * {name<value?true:false} Less than
416 * {name>value?true:false} Greater than
417 * {name!value?true:false} Not equal
418 */
419
420 op = ch;
421
422 if (ch == '?')
423 {
424 /*
425 * Test for existance...
426 */
427
428 result = cgiGetArray(name, element) != NULL && outptr[0];
429 compare[0] = '\0';
430 }
431 else
432 {
433 /*
434 * Compare to a string...
435 */
436
437 for (s = compare; (ch = getc(in)) != EOF;)
438 if (ch == '?')
439 break;
440 else if (s >= (compare + sizeof(compare) - 1))
441 continue;
442 else if (ch == '#')
443 {
444 sprintf(s, "%d", element + 1);
445 s += strlen(s);
446 }
447 else if (ch == '{')
448 {
449 /*
450 * Grab the value of a variable...
451 */
452
453 innerptr = innername;
454 while ((ch = getc(in)) != EOF && ch != '}')
455 if (innerptr < (innername + sizeof(innername) - 1))
456 *innerptr++ = ch;
457 *innerptr = '\0';
458
459 if (innername[0] == '#')
460 sprintf(s, "%d", cgiGetSize(innername + 1));
461 else if ((innerptr = strrchr(innername, '-')) != NULL &&
462 isdigit(innerptr[1] & 255))
463 {
464 *innerptr++ = '\0';
465 if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL)
466 *s = '\0';
467 else
468 strlcpy(s, innerval, sizeof(compare) - (s - compare));
469 }
470 else if (innername[0] == '?')
471 {
472 if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
473 *s = '\0';
474 else
475 strlcpy(s, innerval, sizeof(compare) - (s - compare));
476 }
477 else if ((innerval = cgiGetArray(innername, element)) == NULL)
478 snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername);
479 else
480 strlcpy(s, innerval, sizeof(compare) - (s - compare));
481
482 s += strlen(s);
483 }
484 else if (ch == '\\')
485 *s++ = getc(in);
486 else
487 *s++ = ch;
488
489 *s = '\0';
490
491 if (ch != '?')
492 {
493 fprintf(stderr,
494 "DEBUG: %*sBad terminator '%c' at file position %ld...\n",
495 indent, "", ch, ftell(in));
496 return;
497 }
498
499 /*
500 * Do the comparison...
501 */
502
503 switch (op)
504 {
505 case '<' :
506 result = strcasecmp(outptr, compare) < 0;
507 break;
508 case '>' :
509 result = strcasecmp(outptr, compare) > 0;
510 break;
511 case '=' :
512 result = strcasecmp(outptr, compare) == 0;
513 break;
514 case '!' :
515 result = strcasecmp(outptr, compare) != 0;
516 break;
517 default :
518 result = 1;
519 break;
520 }
521 }
522
523 fprintf(stderr,
524 "DEBUG: %*sStarting \"{%s%c%s\" at %ld, result=%d...\n",
525 indent, "", name, op, compare, ftell(in), result);
526
527 if (result)
528 {
529 /*
530 * Comparison true; output first part and ignore second...
531 */
532
533 fprintf(stderr, "DEBUG: %*sOutput first part...\n", indent, "");
534 cgi_copy(out, in, element, ':', indent + 2);
535
536 fprintf(stderr, "DEBUG: %*sSkip second part...\n", indent, "");
537 cgi_copy(NULL, in, element, '}', indent + 2);
538 }
539 else
540 {
541 /*
542 * Comparison false; ignore first part and output second...
543 */
544
545 fprintf(stderr, "DEBUG: %*sSkip first part...\n", indent, "");
546 cgi_copy(NULL, in, element, ':', indent + 2);
547
548 fprintf(stderr, "DEBUG: %*sOutput second part...\n", indent, "");
549 cgi_copy(out, in, element, '}', indent + 2);
550 }
551
552 fprintf(stderr, "DEBUG: %*sFinished \"{%s%c%s\", out=%p...\n", indent, "",
553 name, op, compare, out);
554 }
555 else if (ch == '\\') /* Quoted char */
556 {
557 if (out)
558 putc(getc(in), out);
559 else
560 getc(in);
561 }
562 else if (out)
563 putc(ch, out);
564
565 if (ch == EOF)
566 fprintf(stderr, "DEBUG: %*sReturning at file position %ld on EOF...\n",
567 indent, "", ftell(in));
568 else
569 fprintf(stderr,
570 "DEBUG: %*sReturning at file position %ld on character '%c'...\n",
571 indent, "", ftell(in), ch);
572
573 if (ch == EOF && term)
574 fprintf(stderr, "ERROR: %*sSaw EOF, expected '%c'!\n", indent, "", term);
575
576 /*
577 * Flush any pending output...
578 */
579
580 if (out)
581 fflush(out);
582 }
583
584
585 /*
586 * 'cgi_puts()' - Put a string to the output file, quoting as needed...
587 */
588
589 static void
590 cgi_puts(const char *s, /* I - String to output */
591 FILE *out) /* I - Output file */
592 {
593 while (*s)
594 {
595 if (*s == '<')
596 {
597 /*
598 * Pass <A HREF="url"> and </A>, otherwise quote it...
599 */
600
601 if (!strncasecmp(s, "<A HREF=\"", 9))
602 {
603 fputs("<A HREF=\"", out);
604 s += 9;
605
606 while (*s && *s != '\"')
607 {
608 if (*s == '&')
609 fputs("&amp;", out);
610 else
611 putc(*s, out);
612
613 s ++;
614 }
615
616 if (*s)
617 s ++;
618
619 fputs("\">", out);
620 }
621 else if (!strncasecmp(s, "</A>", 4))
622 {
623 fputs("</A>", out);
624 s += 3;
625 }
626 else
627 fputs("&lt;", out);
628 }
629 else if (*s == '>')
630 fputs("&gt;", out);
631 else if (*s == '\"')
632 fputs("&quot;", out);
633 else if (*s == '&')
634 fputs("&amp;", out);
635 else
636 putc(*s, out);
637
638 s ++;
639 }
640 }
641
642
643 /*
644 * 'cgi_puturi()' - Put a URI string to the output file, quoting as needed...
645 */
646
647 static void
648 cgi_puturi(const char *s, /* I - String to output */
649 FILE *out) /* I - Output file */
650 {
651 while (*s)
652 {
653 if (strchr("%&+ <>#=", *s) || *s & 128)
654 fprintf(out, "%%%02X", *s & 255);
655 else
656 putc(*s, out);
657
658 s ++;
659 }
660 }
661
662
663 /*
664 * End of "$Id: template.c 6649 2007-07-11 21:46:42Z mike $".
665 */