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