]> git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/template.c
Merge changes from CUPS trunk, r6739.
[thirdparty/cups.git] / cgi-bin / template.c
1 /*
2 * "$Id: template.c 6717 2007-07-24 23:47:12Z 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, "DEBUG2: 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, "DEBUG2: 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, "DEBUG2: 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, "DEBUG2: 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, "DEBUG2: %*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, "DEBUG2: %*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, "DEBUG2: %*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, "DEBUG2: %*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, "DEBUG2: %*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 if (!strcasecmp(name, "?cupsdconf_default"))
404 fputs(outptr, stdout);
405 else
406 cgi_puts(outptr, out);
407 }
408
409 continue;
410 }
411
412 /*
413 * OK, process one of the following checks:
414 *
415 * {name?exist:not-exist} Exists?
416 * {name=value?true:false} Equal
417 * {name<value?true:false} Less than
418 * {name>value?true:false} Greater than
419 * {name!value?true:false} Not equal
420 */
421
422 op = ch;
423
424 if (ch == '?')
425 {
426 /*
427 * Test for existance...
428 */
429
430 result = cgiGetArray(name, element) != NULL && outptr[0];
431 compare[0] = '\0';
432 }
433 else
434 {
435 /*
436 * Compare to a string...
437 */
438
439 for (s = compare; (ch = getc(in)) != EOF;)
440 if (ch == '?')
441 break;
442 else if (s >= (compare + sizeof(compare) - 1))
443 continue;
444 else if (ch == '#')
445 {
446 sprintf(s, "%d", element + 1);
447 s += strlen(s);
448 }
449 else if (ch == '{')
450 {
451 /*
452 * Grab the value of a variable...
453 */
454
455 innerptr = innername;
456 while ((ch = getc(in)) != EOF && ch != '}')
457 if (innerptr < (innername + sizeof(innername) - 1))
458 *innerptr++ = ch;
459 *innerptr = '\0';
460
461 if (innername[0] == '#')
462 sprintf(s, "%d", cgiGetSize(innername + 1));
463 else if ((innerptr = strrchr(innername, '-')) != NULL &&
464 isdigit(innerptr[1] & 255))
465 {
466 *innerptr++ = '\0';
467 if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL)
468 *s = '\0';
469 else
470 strlcpy(s, innerval, sizeof(compare) - (s - compare));
471 }
472 else if (innername[0] == '?')
473 {
474 if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
475 *s = '\0';
476 else
477 strlcpy(s, innerval, sizeof(compare) - (s - compare));
478 }
479 else if ((innerval = cgiGetArray(innername, element)) == NULL)
480 snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername);
481 else
482 strlcpy(s, innerval, sizeof(compare) - (s - compare));
483
484 s += strlen(s);
485 }
486 else if (ch == '\\')
487 *s++ = getc(in);
488 else
489 *s++ = ch;
490
491 *s = '\0';
492
493 if (ch != '?')
494 {
495 fprintf(stderr,
496 "DEBUG2: %*sBad terminator '%c' at file position %ld...\n",
497 indent, "", ch, ftell(in));
498 return;
499 }
500
501 /*
502 * Do the comparison...
503 */
504
505 switch (op)
506 {
507 case '<' :
508 result = strcasecmp(outptr, compare) < 0;
509 break;
510 case '>' :
511 result = strcasecmp(outptr, compare) > 0;
512 break;
513 case '=' :
514 result = strcasecmp(outptr, compare) == 0;
515 break;
516 case '!' :
517 result = strcasecmp(outptr, compare) != 0;
518 break;
519 default :
520 result = 1;
521 break;
522 }
523 }
524
525 fprintf(stderr,
526 "DEBUG2: %*sStarting \"{%s%c%s\" at %ld, result=%d...\n",
527 indent, "", name, op, compare, ftell(in), result);
528
529 if (result)
530 {
531 /*
532 * Comparison true; output first part and ignore second...
533 */
534
535 fprintf(stderr, "DEBUG2: %*sOutput first part...\n", indent, "");
536 cgi_copy(out, in, element, ':', indent + 2);
537
538 fprintf(stderr, "DEBUG2: %*sSkip second part...\n", indent, "");
539 cgi_copy(NULL, in, element, '}', indent + 2);
540 }
541 else
542 {
543 /*
544 * Comparison false; ignore first part and output second...
545 */
546
547 fprintf(stderr, "DEBUG2: %*sSkip first part...\n", indent, "");
548 cgi_copy(NULL, in, element, ':', indent + 2);
549
550 fprintf(stderr, "DEBUG2: %*sOutput second part...\n", indent, "");
551 cgi_copy(out, in, element, '}', indent + 2);
552 }
553
554 fprintf(stderr, "DEBUG2: %*sFinished \"{%s%c%s\", out=%p...\n", indent, "",
555 name, op, compare, out);
556 }
557 else if (ch == '\\') /* Quoted char */
558 {
559 if (out)
560 putc(getc(in), out);
561 else
562 getc(in);
563 }
564 else if (out)
565 putc(ch, out);
566
567 if (ch == EOF)
568 fprintf(stderr, "DEBUG2: %*sReturning at file position %ld on EOF...\n",
569 indent, "", ftell(in));
570 else
571 fprintf(stderr,
572 "DEBUG2: %*sReturning at file position %ld on character '%c'...\n",
573 indent, "", ftell(in), ch);
574
575 if (ch == EOF && term)
576 fprintf(stderr, "ERROR: %*sSaw EOF, expected '%c'!\n", indent, "", term);
577
578 /*
579 * Flush any pending output...
580 */
581
582 if (out)
583 fflush(out);
584 }
585
586
587 /*
588 * 'cgi_puts()' - Put a string to the output file, quoting as needed...
589 */
590
591 static void
592 cgi_puts(const char *s, /* I - String to output */
593 FILE *out) /* I - Output file */
594 {
595 while (*s)
596 {
597 if (*s == '<')
598 {
599 /*
600 * Pass <A HREF="url"> and </A>, otherwise quote it...
601 */
602
603 if (!strncasecmp(s, "<A HREF=\"", 9))
604 {
605 fputs("<A HREF=\"", out);
606 s += 9;
607
608 while (*s && *s != '\"')
609 {
610 if (*s == '&')
611 fputs("&amp;", out);
612 else
613 putc(*s, out);
614
615 s ++;
616 }
617
618 if (*s)
619 s ++;
620
621 fputs("\">", out);
622 }
623 else if (!strncasecmp(s, "</A>", 4))
624 {
625 fputs("</A>", out);
626 s += 3;
627 }
628 else
629 fputs("&lt;", out);
630 }
631 else if (*s == '>')
632 fputs("&gt;", out);
633 else if (*s == '\"')
634 fputs("&quot;", out);
635 else if (*s == '&')
636 fputs("&amp;", out);
637 else
638 putc(*s, out);
639
640 s ++;
641 }
642 }
643
644
645 /*
646 * 'cgi_puturi()' - Put a URI string to the output file, quoting as needed...
647 */
648
649 static void
650 cgi_puturi(const char *s, /* I - String to output */
651 FILE *out) /* I - Output file */
652 {
653 while (*s)
654 {
655 if (strchr("%&+ <>#=", *s) || *s & 128)
656 fprintf(out, "%%%02X", *s & 255);
657 else
658 putc(*s, out);
659
660 s ++;
661 }
662 }
663
664
665 /*
666 * End of "$Id: template.c 6717 2007-07-24 23:47:12Z mike $".
667 */