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