]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/template.c
Mass change of copyright to CUPS' new owner, Apple Inc.
[thirdparty/cups.git] / cgi-bin / template.c
CommitLineData
9153c417 1/*
c9d3f842 2 * "$Id$"
9153c417 3 *
4 * CGI template function.
5 *
4e8d321f 6 * Copyright 2007 by Apple Inc.
8d72b7e6 7 * Copyright 1997-2006 by Easy Software Products.
4a409eae 8 *
921a23f4 9 * These coded instructions, statements, and computer programs are the
4e8d321f 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/".
a548a235 14 *
15 * Contents:
16 *
17 * cgiCopyTemplateFile() - Copy a template file and replace all the
18 * '{variable}' strings with the variable value.
a3e17a89 19 * cgiCopyTemplateLang() - Copy a template file using a language...
921a23f4 20 * cgiGetTemplateDir() - Get the templates directory...
21 * cgiSetServerVersion() - Set the server name and CUPS version...
90beaed3 22 * cgi_copy() - Copy the template file, substituting as needed...
1d5c0d20 23 * cgi_puts() - Put a string to the output file, quoting as
24 * needed...
9153c417 25 */
26
921a23f4 27#include "cgi-private.h"
a0932c5c 28#include <errno.h>
9153c417 29
30
90beaed3 31/*
32 * Local functions...
33 */
34
a0932c5c 35static void cgi_copy(FILE *out, FILE *in, int element, char term,
36 int indent);
1d5c0d20 37static void cgi_puts(const char *s, FILE *out);
a2885801 38static void cgi_puturi(const char *s, FILE *out);
90beaed3 39
40
9153c417 41/*
a548a235 42 * 'cgiCopyTemplateFile()' - Copy a template file and replace all the
43 * '{variable}' strings with the variable value.
9153c417 44 */
45
46void
a3e17a89 47cgiCopyTemplateFile(FILE *out, /* I - Output file */
48 const char *tmpl) /* I - Template file to read */
9153c417 49{
a3e17a89 50 FILE *in; /* Input file */
51
52
a0932c5c 53 fprintf(stderr, "DEBUG: cgiCopyTemplateFile(out=%p, tmpl=\"%s\")\n", out,
48d2c418 54 tmpl ? tmpl : "(null)");
a0932c5c 55
a3e17a89 56 /*
57 * Open the template file...
58 */
59
60 if ((in = fopen(tmpl, "r")) == NULL)
a0932c5c 61 {
62 fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
48d2c418 63 tmpl ? tmpl : "(null)", strerror(errno));
a3e17a89 64 return;
a0932c5c 65 }
a3e17a89 66
67 /*
68 * Parse the file to the end...
69 */
70
a0932c5c 71 cgi_copy(out, in, 0, 0, 0);
a3e17a89 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
85void
8d72b7e6 86cgiCopyTemplateLang(const char *tmpl) /* I - Base filename */
a3e17a89 87{
8d72b7e6 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 */
9153c417 94
95
48d2c418 96 fprintf(stderr, "DEBUG: cgiCopyTemplateLang(tmpl=\"%s\")\n",
97 tmpl ? tmpl : "(null)");
a0932c5c 98
a3e17a89 99 /*
100 * Convert the language to a locale name...
101 */
102
8d72b7e6 103 if ((lang = getenv("LANG")) != NULL)
a3e17a89 104 {
105 for (i = 0; lang[i] && i < 15; i ++)
6d3d0c4d 106 if (isalnum(lang[i] & 255) || lang[i] == '_')
a3e17a89 107 locale[i] = tolower(lang[i]);
7225c653 108 else if (lang[i] == '-')
a3e17a89 109 locale[i] = '_';
7225c653 110 else
111 break;
a3e17a89 112
113 locale[i] = '\0';
114 }
115 else
116 locale[0] = '\0';
117
a0932c5c 118 fprintf(stderr, "DEBUG: locale=\"%s\"...\n", locale);
7225c653 119
a3e17a89 120 /*
121 * See if we have a template file for this language...
122 */
123
8d72b7e6 124 directory = cgiGetTemplateDir();
125
a6988fb1 126 snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
a3e17a89 127 if (access(filename, 0))
128 {
129 locale[2] = '\0';
130
a6988fb1 131 snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
a3e17a89 132 if (access(filename, 0))
a6988fb1 133 snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
a3e17a89 134 }
135
a0932c5c 136 fprintf(stderr, "DEBUG: Template file is \"%s\"...\n", filename);
137
9153c417 138 /*
139 * Open the template file...
140 */
141
a3e17a89 142 if ((in = fopen(filename, "r")) == NULL)
a0932c5c 143 {
144 fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
145 filename, strerror(errno));
9153c417 146 return;
a0932c5c 147 }
9153c417 148
90beaed3 149 /*
150 * Parse the file to the end...
151 */
152
a0932c5c 153 cgi_copy(stdout, in, 0, 0, 0);
90beaed3 154
155 /*
156 * Close the template file and return...
157 */
158
159 fclose(in);
160}
161
162
921a23f4 163/*
164 * 'cgiGetTemplateDir()' - Get the templates directory...
165 */
166
167char * /* O - Template directory */
168cgiGetTemplateDir(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
194void
195cgiSetServerVersion(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
90beaed3 207/*
208 * 'cgi_copy()' - Copy the template file, substituting as needed...
209 */
210
211static void
a0932c5c 212cgi_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 */
90beaed3 217{
a0932c5c 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 */
a2885801 231 int uriencode; /* Encode as URI */
a0932c5c 232
233
234 fprintf(stderr, "DEBUG: %*sStarting at file position %ld...\n", indent, "",
235 ftell(in));
90beaed3 236
9153c417 237 /*
238 * Parse the file to the end...
239 */
240
241 while ((ch = getc(in)) != EOF)
3f78f826 242 if (ch == term)
90beaed3 243 break;
244 else if (ch == '{')
9153c417 245 {
246 /*
247 * Get a variable name...
248 */
249
a2885801 250 uriencode = 0;
251
3f78f826 252 for (s = name; (ch = getc(in)) != EOF;)
e0663562 253 if (strchr("}]<>=! \t\n", ch))
9153c417 254 break;
a2885801 255 else if (s == name && ch == '%')
256 uriencode = 1;
778c51c8 257 else if (s > name && ch == '?')
258 break;
3225d87b 259 else if (s < (name + sizeof(name) - 1))
3f78f826 260 *s++ = ch;
261
9153c417 262 *s = '\0';
263
da275f55 264 if (s == name && isspace(ch & 255))
462bddea 265 {
a0932c5c 266 fprintf(stderr, "DEBUG: %*sLone { at %ld...\n", indent, "", ftell(in));
267
4874fe20 268 if (out)
269 {
270 putc('{', out);
271 putc(ch, out);
272 }
273
462bddea 274 continue;
275 }
276
a0932c5c 277 if (ch == '}')
278 fprintf(stderr, "DEBUG: %*s\"{%s}\" at %ld...\n", indent, "", name,
279 ftell(in));
280
9153c417 281 /*
282 * See if it has a value...
283 */
284
3d860279 285 if (name[0] == '?')
90beaed3 286 {
287 /*
288 * Insert value only if it exists...
289 */
290
da275f55 291 if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
e9b903a7 292 {
293 *nameptr++ = '\0';
294
295 if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL)
4874fe20 296 outptr = value;
e9b903a7 297 else
4874fe20 298 {
e9b903a7 299 outval[0] = '\0';
4874fe20 300 outptr = outval;
301 }
e9b903a7 302 }
1f4b7b03 303 else if ((value = cgiGetArray(name + 1, element)) != NULL)
4874fe20 304 outptr = value;
3f78f826 305 else
4874fe20 306 {
3f78f826 307 outval[0] = '\0';
4874fe20 308 outptr = outval;
309 }
90beaed3 310 }
311 else if (name[0] == '#')
312 {
313 /*
314 * Insert count...
315 */
316
4a409eae 317 if (name[1])
318 sprintf(outval, "%d", cgiGetSize(name + 1));
319 else
320 sprintf(outval, "%d", element + 1);
4874fe20 321
322 outptr = outval;
90beaed3 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
da275f55 335 if (isdigit(name[1] & 255))
3f78f826 336 count = atoi(name + 1);
337 else
338 count = cgiGetSize(name + 1);
339
340 pos = ftell(in);
90beaed3 341
a0932c5c 342 fprintf(stderr, "DEBUG: %*sLooping on \"%s\" at %ld, count=%d...\n",
343 indent, "", name + 1, pos, count);
344
3f78f826 345 if (count > 0)
90beaed3 346 {
3f78f826 347 for (i = 0; i < count; i ++)
348 {
a0932c5c 349 if (i)
350 fseek(in, pos, SEEK_SET);
351
352 cgi_copy(out, in, i, '}', indent + 2);
3f78f826 353 }
354 }
355 else
a0932c5c 356 cgi_copy(NULL, in, 0, '}', indent + 2);
357
358 fprintf(stderr, "DEBUG: %*sFinished looping on \"%s\"...\n", indent,
359 "", name + 1);
892b98d3 360
361 continue;
90beaed3 362 }
9153c417 363 else
3d860279 364 {
90beaed3 365 /*
366 * Insert variable or variable name (if element is NULL)...
367 */
3d860279 368
da275f55 369 if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
e9b903a7 370 {
371 *nameptr++ = '\0';
372 if ((value = cgiGetArray(name, atoi(nameptr) - 1)) == NULL)
4874fe20 373 {
a6988fb1 374 snprintf(outval, sizeof(outval), "{%s}", name);
4874fe20 375 outptr = outval;
376 }
e9b903a7 377 else
4874fe20 378 outptr = value;
e9b903a7 379 }
380 else if ((value = cgiGetArray(name, element)) == NULL)
4874fe20 381 {
a6988fb1 382 snprintf(outval, sizeof(outval), "{%s}", name);
4874fe20 383 outptr = outval;
384 }
90beaed3 385 else
4874fe20 386 outptr = value;
3f78f826 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)
a2885801 400 {
401 if (uriencode)
402 cgi_puturi(outptr, out);
403 else
404 cgi_puts(outptr, out);
405 }
3f78f826 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
a0932c5c 420 op = ch;
421
3f78f826 422 if (ch == '?')
423 {
424 /*
425 * Test for existance...
426 */
427
a0932c5c 428 result = cgiGetArray(name, element) != NULL && outptr[0];
429 compare[0] = '\0';
3f78f826 430 }
431 else
432 {
433 /*
434 * Compare to a string...
435 */
436
3f78f826 437 for (s = compare; (ch = getc(in)) != EOF;)
438 if (ch == '?')
439 break;
4874fe20 440 else if (s >= (compare + sizeof(compare) - 1))
441 continue;
4a409eae 442 else if (ch == '#')
443 {
444 sprintf(s, "%d", element + 1);
445 s += strlen(s);
446 }
d4c438d4 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 != '}')
3225d87b 455 if (innerptr < (innername + sizeof(innername) - 1))
456 *innerptr++ = ch;
d4c438d4 457 *innerptr = '\0';
458
459 if (innername[0] == '#')
460 sprintf(s, "%d", cgiGetSize(innername + 1));
461 else if ((innerptr = strrchr(innername, '-')) != NULL &&
da275f55 462 isdigit(innerptr[1] & 255))
d4c438d4 463 {
464 *innerptr++ = '\0';
e9b903a7 465 if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL)
d4c438d4 466 *s = '\0';
467 else
def978d5 468 strlcpy(s, innerval, sizeof(compare) - (s - compare));
d4c438d4 469 }
470 else if (innername[0] == '?')
471 {
472 if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
473 *s = '\0';
474 else
def978d5 475 strlcpy(s, innerval, sizeof(compare) - (s - compare));
d4c438d4 476 }
477 else if ((innerval = cgiGetArray(innername, element)) == NULL)
c79d1143 478 snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername);
d4c438d4 479 else
def978d5 480 strlcpy(s, innerval, sizeof(compare) - (s - compare));
d4c438d4 481
482 s += strlen(s);
483 }
3f78f826 484 else if (ch == '\\')
485 *s++ = getc(in);
486 else
487 *s++ = ch;
488
489 *s = '\0';
490
491 if (ch != '?')
a0932c5c 492 {
493 fprintf(stderr,
494 "DEBUG: %*sBad terminator '%c' at file position %ld...\n",
495 indent, "", ch, ftell(in));
3f78f826 496 return;
a0932c5c 497 }
3f78f826 498
499 /*
500 * Do the comparison...
501 */
502
503 switch (op)
504 {
505 case '<' :
4874fe20 506 result = strcasecmp(outptr, compare) < 0;
3f78f826 507 break;
508 case '>' :
4874fe20 509 result = strcasecmp(outptr, compare) > 0;
3f78f826 510 break;
511 case '=' :
4874fe20 512 result = strcasecmp(outptr, compare) == 0;
3f78f826 513 break;
514 case '!' :
4874fe20 515 result = strcasecmp(outptr, compare) != 0;
3f78f826 516 break;
d21a7597 517 default :
518 result = 1;
519 break;
3f78f826 520 }
521 }
522
a0932c5c 523 fprintf(stderr,
524 "DEBUG: %*sStarting \"{%s%c%s\" at %ld, result=%d...\n",
525 indent, "", name, op, compare, ftell(in), result);
526
3f78f826 527 if (result)
528 {
529 /*
530 * Comparison true; output first part and ignore second...
531 */
532
a0932c5c 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);
3f78f826 538 }
539 else
540 {
541 /*
542 * Comparison false; ignore first part and output second...
543 */
544
a0932c5c 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);
90beaed3 550 }
a0932c5c 551
552 fprintf(stderr, "DEBUG: %*sFinished \"{%s%c%s\", out=%p...\n", indent, "",
553 name, op, compare, out);
9153c417 554 }
555 else if (ch == '\\') /* Quoted char */
3f78f826 556 {
557 if (out)
558 putc(getc(in), out);
559 else
560 getc(in);
561 }
562 else if (out)
9153c417 563 putc(ch, out);
4874fe20 564
a0932c5c 565 if (ch == EOF)
566 fprintf(stderr, "DEBUG: %*sReturning at file position %ld on EOF...\n",
46fd19e2 567 indent, "", ftell(in));
a0932c5c 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
4874fe20 576 /*
577 * Flush any pending output...
578 */
579
580 if (out)
581 fflush(out);
9153c417 582}
583
584
585/*
1d5c0d20 586 * 'cgi_puts()' - Put a string to the output file, quoting as needed...
587 */
588
589static void
372d627e 590cgi_puts(const char *s, /* I - String to output */
591 FILE *out) /* I - Output file */
1d5c0d20 592{
593 while (*s)
594 {
372d627e 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 == '>')
753453e4 630 fputs("&gt;", out);
822daded 631 else if (*s == '\"')
632 fputs("&quot;", out);
372d627e 633 else if (*s == '&')
822daded 634 fputs("&amp;", out);
1d5c0d20 635 else
636 putc(*s, out);
637
638 s ++;
639 }
640}
641
642
a2885801 643/*
644 * 'cgi_puturi()' - Put a URI string to the output file, quoting as needed...
645 */
646
647static void
648cgi_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
1d5c0d20 663/*
c9d3f842 664 * End of "$Id$".
9153c417 665 */