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