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