]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cgi-bin/template.c
Update more IPP strings.
[thirdparty/cups.git] / cgi-bin / template.c
index dfcd1b85e8e72792ef2cdf082ee69ee62a03110b..1972b4ae2ca2252b03135ae5a6a523fdfe02bfb7 100644 (file)
@@ -1,47 +1,25 @@
 /*
- * "$Id: template.c 4921 2006-01-12 21:26:26Z mike $"
+ * CGI template function.
  *
- *   CGI template function.
+ * Copyright 2007-2015 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
  *
- *   Copyright 1997-2006 by Easy Software Products.
- *
- *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
- *
- * Contents:
- *
- *   cgiCopyTemplateFile() - Copy a template file and replace all the
- *                           '{variable}' strings with the variable value.
- *   cgiCopyTemplateLang() - Copy a template file using a language...
- *   cgiGetTemplateDir()   - Get the templates directory...
- *   cgiSetServerVersion() - Set the server name and CUPS version...
- *   cgi_copy()            - Copy the template file, substituting as needed...
- *   cgi_puts()            - Put a string to the output file, quoting as
- *                           needed...
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
 #include "cgi-private.h"
+#include <errno.h>
+#include <regex.h>
 
 
 /*
  * Local functions...
  */
 
-static void    cgi_copy(FILE *out, FILE *in, int element, char term);
+static void    cgi_copy(FILE *out, FILE *in, int element, char term,
+                        int indent);
 static void    cgi_puts(const char *s, FILE *out);
+static void    cgi_puturi(const char *s, FILE *out);
 
 
 /*
@@ -56,18 +34,32 @@ cgiCopyTemplateFile(FILE       *out,        /* I - Output file */
   FILE *in;                            /* Input file */
 
 
+  fprintf(stderr, "DEBUG2: cgiCopyTemplateFile(out=%p, tmpl=\"%s\")\n", out,
+          tmpl ? tmpl : "(null)");
+
+ /*
+  * Range check input...
+  */
+
+  if (!tmpl || !out)
+    return;
+
  /*
   * Open the template file...
   */
 
   if ((in = fopen(tmpl, "r")) == NULL)
+  {
+    fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
+            tmpl ? tmpl : "(null)", strerror(errno));
     return;
+  }
 
  /*
   * Parse the file to the end...
   */
 
-  cgi_copy(out, in, 0, 0);
+  cgi_copy(out, in, 0, 0, 0);
 
  /*
   * Close the template file and return...
@@ -84,30 +76,34 @@ cgiCopyTemplateFile(FILE       *out,        /* I - Output file */
 void
 cgiCopyTemplateLang(const char *tmpl)  /* I - Base filename */
 {
-  int          i;                      /* Looping var */
   char         filename[1024],         /* Filename */
-               locale[16];             /* Locale name */
+               locale[16],             /* Locale name */
+               *locptr;                /* Pointer into locale name */
   const char   *directory,             /* Directory for templates */
                *lang;                  /* Language */
   FILE         *in;                    /* Input file */
 
 
+  fprintf(stderr, "DEBUG2: cgiCopyTemplateLang(tmpl=\"%s\")\n",
+          tmpl ? tmpl : "(null)");
+
  /*
   * Convert the language to a locale name...
   */
 
+  locale[0] = '\0';
+
   if ((lang = getenv("LANG")) != NULL)
   {
-    for (i = 0; lang[i] && i < 15; i ++)
-      if (isalnum(lang[i] & 255))
-        locale[i] = tolower(lang[i]);
-      else
-        locale[i] = '_';
+    locale[0] = '/';
+    strlcpy(locale + 1, lang, sizeof(locale) - 1);
 
-    locale[i] = '\0';
+    if ((locptr = strchr(locale, '.')) != NULL)
+      *locptr = '\0';                  /* Strip charset */
   }
-  else
-    locale[0] = '\0';
+
+  fprintf(stderr, "DEBUG2: lang=\"%s\", locale=\"%s\"...\n",
+          lang ? lang : "(null)", locale);
 
  /*
   * See if we have a template file for this language...
@@ -115,28 +111,37 @@ cgiCopyTemplateLang(const char *tmpl)     /* I - Base filename */
 
   directory = cgiGetTemplateDir();
 
-  snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
-  if (access(filename, 0))
+  snprintf(filename, sizeof(filename), "%s%s/%s", directory, locale, tmpl);
+  if ((in = fopen(filename, "r")) == NULL)
   {
-    locale[2] = '\0';
+    locale[3] = '\0';
 
-    snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
-    if (access(filename, 0))
+    snprintf(filename, sizeof(filename), "%s%s/%s", directory, locale, tmpl);
+    if ((in = fopen(filename, "r")) == NULL)
+    {
       snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
+      in = fopen(filename, "r");
+    }
   }
 
+  fprintf(stderr, "DEBUG2: Template file is \"%s\"...\n", filename);
+
  /*
   * Open the template file...
   */
 
-  if ((in = fopen(filename, "r")) == NULL)
+  if (!in)
+  {
+    fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
+            filename, strerror(errno));
     return;
+  }
 
  /*
   * Parse the file to the end...
   */
 
-  cgi_copy(stdout, in, 0, 0);
+  cgi_copy(stdout, in, 0, 0, 0);
 
  /*
   * Close the template file and return...
@@ -195,25 +200,31 @@ cgiSetServerVersion(void)
  */
 
 static void
-cgi_copy(FILE *out,            /* I - Output file */
-         FILE *in,             /* I - Input file */
-        int  element,          /* I - Element number (0 to N) */
-        char term)             /* I - Terminating character */
+cgi_copy(FILE *out,                    /* I - Output file */
+         FILE *in,                     /* I - Input file */
+        int  element,                  /* I - Element number (0 to N) */
+        char term,                     /* I - Terminating character */
+        int  indent)                   /* I - Debug info indentation */
 {
-  int          ch;             /* Character from file */
-  char         op;             /* Operation */
-  char         name[255],      /* Name of variable */
-               *nameptr,       /* Pointer into name */
-               innername[255], /* Inner comparison name */
-               *innerptr,      /* Pointer into inner name */
-               *s;             /* String pointer */
-  const char   *value;         /* Value of variable */
-  const char   *innerval;      /* Inner value */
-  const char   *outptr;        /* Output string pointer */
-  char         outval[1024],   /* Formatted output string */
-               compare[1024];  /* Comparison string */
-  int          result;         /* Result of comparison */
-
+  int          ch;                     /* Character from file */
+  char         op;                     /* Operation */
+  char         name[255],              /* Name of variable */
+               *nameptr,               /* Pointer into name */
+               innername[255],         /* Inner comparison name */
+               *innerptr,              /* Pointer into inner name */
+               *s;                     /* String pointer */
+  const char   *value;                 /* Value of variable */
+  const char   *innerval;              /* Inner value */
+  const char   *outptr;                /* Output string pointer */
+  char         outval[1024],           /* Formatted output string */
+               compare[1024];          /* Comparison string */
+  int          result;                 /* Result of comparison */
+  int          uriencode;              /* Encode as URI */
+  regex_t      re;                     /* Regular expression to match */
+
+
+  fprintf(stderr, "DEBUG2: %*sStarting at file position %ld...\n", indent, "",
+          ftell(in));
 
  /*
   * Parse the file to the end...
@@ -228,18 +239,24 @@ cgi_copy(FILE *out,               /* I - Output file */
       * Get a variable name...
       */
 
+      uriencode = 0;
+
       for (s = name; (ch = getc(in)) != EOF;)
-        if (strchr("}]<>=! \t\n", ch))
+        if (strchr("}]<>=!~ \t\n", ch))
           break;
+       else if (s == name && ch == '%')
+         uriencode = 1;
         else if (s > name && ch == '?')
          break;
        else if (s < (name + sizeof(name) - 1))
-          *s++ = ch;
+          *s++ = (char)ch;
 
       *s = '\0';
 
       if (s == name && isspace(ch & 255))
       {
+        fprintf(stderr, "DEBUG2: %*sLone { at %ld...\n", indent, "", ftell(in));
+
         if (out)
        {
           putc('{', out);
@@ -249,6 +266,10 @@ cgi_copy(FILE *out,                /* I - Output file */
        continue;
       }
 
+      if (ch == '}')
+       fprintf(stderr, "DEBUG2: %*s\"{%s}\" at %ld...\n", indent, "", name,
+               ftell(in));
+
      /*
       * See if it has a value...
       */
@@ -310,19 +331,41 @@ cgi_copy(FILE *out,               /* I - Output file */
 
        pos = ftell(in);
 
+        fprintf(stderr, "DEBUG2: %*sLooping on \"%s\" at %ld, count=%d...\n",
+               indent, "", name + 1, pos, count);
+
         if (count > 0)
        {
           for (i = 0; i < count; i ++)
          {
-           fseek(in, pos, SEEK_SET);
-           cgi_copy(out, in, i, '}');
+           if (i)
+             fseek(in, pos, SEEK_SET);
+
+           cgi_copy(out, in, i, '}', indent + 2);
          }
         }
        else
-         cgi_copy(NULL, in, 0, '}');
+         cgi_copy(NULL, in, 0, '}', indent + 2);
+
+        fprintf(stderr, "DEBUG2: %*sFinished looping on \"%s\"...\n", indent,
+               "", name + 1);
 
         continue;
       }
+      else if (name[0] == '$')
+      {
+       /*
+        * Insert cookie value or nothing if not defined.
+       */
+
+        if ((value = cgiGetCookie(name + 1)) != NULL)
+         outptr = value;
+       else
+       {
+         outval[0] = '\0';
+         outptr    = outval;
+       }
+      }
       else
       {
        /*
@@ -360,7 +403,14 @@ cgi_copy(FILE *out,                /* I - Output file */
         */
 
        if (out)
-         cgi_puts(outptr, out);
+       {
+         if (uriencode)
+           cgi_puturi(outptr, out);
+         else if (!_cups_strcasecmp(name, "?cupsdconf_default"))
+           fputs(outptr, stdout);
+         else
+           cgi_puts(outptr, out);
+        }
 
         continue;
       }
@@ -373,15 +423,26 @@ cgi_copy(FILE *out,               /* I - Output file */
       *   {name<value?true:false}    Less than
       *   {name>value?true:false}    Greater than
       *   {name!value?true:false}    Not equal
+      *   {name~refex?true:false}    Regex match
       */
 
+      op = (char)ch;
+
       if (ch == '?')
       {
        /*
         * Test for existance...
        */
 
-        result = cgiGetArray(name, element) != NULL && outptr[0];
+        if (name[0] == '?')
+         result = cgiGetArray(name + 1, element) != NULL;
+       else if (name[0] == '#')
+         result = cgiGetVariable(name + 1) != NULL;
+        else
+          result = cgiGetArray(name, element) != NULL;
+
+       result     = result && outptr[0];
+       compare[0] = '\0';
       }
       else
       {
@@ -389,8 +450,6 @@ cgi_copy(FILE *out,         /* I - Output file */
         * Compare to a string...
        */
 
-        op = ch;
-
        for (s = compare; (ch = getc(in)) != EOF;)
           if (ch == '?')
             break;
@@ -410,7 +469,7 @@ cgi_copy(FILE *out,         /* I - Output file */
            innerptr = innername;
            while ((ch = getc(in)) != EOF && ch != '}')
              if (innerptr < (innername + sizeof(innername) - 1))
-               *innerptr++ = ch;
+               *innerptr++ = (char)ch;
            *innerptr = '\0';
 
             if (innername[0] == '#')
@@ -422,31 +481,36 @@ cgi_copy(FILE *out,               /* I - Output file */
              if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL)
                *s = '\0';
              else
-               strlcpy(s, innerval, sizeof(compare) - (s - compare));
+               strlcpy(s, innerval, sizeof(compare) - (size_t)(s - compare));
            }
            else if (innername[0] == '?')
            {
              if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
                *s = '\0';
              else
-               strlcpy(s, innerval, sizeof(compare) - (s - compare));
+               strlcpy(s, innerval, sizeof(compare) - (size_t)(s - compare));
             }
            else if ((innerval = cgiGetArray(innername, element)) == NULL)
-             snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername);
+             snprintf(s, sizeof(compare) - (size_t)(s - compare), "{%s}", innername);
            else
-             strlcpy(s, innerval, sizeof(compare) - (s - compare));
+             strlcpy(s, innerval, sizeof(compare) - (size_t)(s - compare));
 
             s += strlen(s);
          }
           else if (ch == '\\')
-           *s++ = getc(in);
+           *s++ = (char)getc(in);
          else
-            *s++ = ch;
+            *s++ = (char)ch;
 
         *s = '\0';
 
         if (ch != '?')
+       {
+         fprintf(stderr,
+                 "DEBUG2: %*sBad terminator '%c' at file position %ld...\n",
+                 indent, "", ch, ftell(in));
          return;
+       }
 
        /*
         * Do the comparison...
@@ -455,16 +519,49 @@ cgi_copy(FILE *out,               /* I - Output file */
         switch (op)
        {
          case '<' :
-             result = strcasecmp(outptr, compare) < 0;
+             result = _cups_strcasecmp(outptr, compare) < 0;
              break;
          case '>' :
-             result = strcasecmp(outptr, compare) > 0;
+             result = _cups_strcasecmp(outptr, compare) > 0;
              break;
          case '=' :
-             result = strcasecmp(outptr, compare) == 0;
+             result = _cups_strcasecmp(outptr, compare) == 0;
              break;
          case '!' :
-             result = strcasecmp(outptr, compare) != 0;
+             result = _cups_strcasecmp(outptr, compare) != 0;
+             break;
+         case '~' :
+             fprintf(stderr, "DEBUG: Regular expression \"%s\"\n", compare);
+
+             if (regcomp(&re, compare, REG_EXTENDED | REG_ICASE))
+             {
+               fprintf(stderr,
+                       "ERROR: Unable to compile regular expression \"%s\"!\n",
+                       compare);
+               result = 0;
+             }
+             else
+             {
+               regmatch_t matches[10];
+
+               result = 0;
+
+               if (!regexec(&re, outptr, 10, matches, 0))
+               {
+                 int i;
+                 for (i = 0; i < 10; i ++)
+                 {
+                   fprintf(stderr, "DEBUG: matches[%d].rm_so=%d\n", i,
+                           (int)matches[i].rm_so);
+                   if (matches[i].rm_so < 0)
+                     break;
+
+                   result ++;
+                 }
+               }
+
+               regfree(&re);
+             }
              break;
          default :
              result = 1;
@@ -472,14 +569,21 @@ cgi_copy(FILE *out,               /* I - Output file */
        }
       }
 
+      fprintf(stderr,
+              "DEBUG2: %*sStarting \"{%s%c%s\" at %ld, result=%d...\n",
+             indent, "", name, op, compare, ftell(in), result);
+
       if (result)
       {
        /*
        * Comparison true; output first part and ignore second...
        */
 
-       cgi_copy(out, in, element, ':');
-       cgi_copy(NULL, in, element, '}');
+        fprintf(stderr, "DEBUG2: %*sOutput first part...\n", indent, "");
+       cgi_copy(out, in, element, ':', indent + 2);
+
+        fprintf(stderr, "DEBUG2: %*sSkip second part...\n", indent, "");
+       cgi_copy(NULL, in, element, '}', indent + 2);
       }
       else
       {
@@ -487,9 +591,15 @@ cgi_copy(FILE *out,                /* I - Output file */
        * Comparison false; ignore first part and output second...
        */
 
-       cgi_copy(NULL, in, element, ':');
-       cgi_copy(out, in, element, '}');
+        fprintf(stderr, "DEBUG2: %*sSkip first part...\n", indent, "");
+       cgi_copy(NULL, in, element, ':', indent + 2);
+
+        fprintf(stderr, "DEBUG2: %*sOutput second part...\n", indent, "");
+       cgi_copy(out, in, element, '}', indent + 2);
       }
+
+      fprintf(stderr, "DEBUG2: %*sFinished \"{%s%c%s\", out=%p...\n", indent, "",
+              name, op, compare, out);
     }
     else if (ch == '\\')       /* Quoted char */
     {
@@ -501,6 +611,17 @@ cgi_copy(FILE *out,                /* I - Output file */
     else if (out)
       putc(ch, out);
 
+  if (ch == EOF)
+    fprintf(stderr, "DEBUG2: %*sReturning at file position %ld on EOF...\n",
+           indent, "", ftell(in));
+  else
+    fprintf(stderr,
+            "DEBUG2: %*sReturning at file position %ld on character '%c'...\n",
+           indent, "", ftell(in), ch);
+
+  if (ch == EOF && term)
+    fprintf(stderr, "ERROR: %*sSaw EOF, expected '%c'!\n", indent, "", term);
+
  /*
   * Flush any pending output...
   */
@@ -521,43 +642,13 @@ cgi_puts(const char *s,                   /* I - String to output */
   while (*s)
   {
     if (*s == '<')
-    {
-     /*
-      * Pass <A HREF="url"> and </A>, otherwise quote it...
-      */
-
-      if (!strncasecmp(s, "<A HREF=\"", 9))
-      {
-        fputs("<A HREF=\"", out);
-       s += 9;
-
-       while (*s && *s != '\"')
-       {
-          if (*s == '&')
-            fputs("&amp;", out);
-         else
-           putc(*s, out);
-
-         s ++;
-       }
-
-        if (*s)
-         s ++;
-
-       fputs("\">", out);
-      }
-      else if (!strncasecmp(s, "</A>", 4))
-      {
-        fputs("</A>", out);
-       s += 3;
-      }
-      else
-        fputs("&lt;", out);
-    }
+      fputs("&lt;", out);
     else if (*s == '>')
       fputs("&gt;", out);
     else if (*s == '\"')
       fputs("&quot;", out);
+    else if (*s == '\'')
+      fputs("&#39;", out);
     else if (*s == '&')
       fputs("&amp;", out);
     else
@@ -569,5 +660,20 @@ cgi_puts(const char *s,                    /* I - String to output */
 
 
 /*
- * End of "$Id: template.c 4921 2006-01-12 21:26:26Z mike $".
+ * 'cgi_puturi()' - Put a URI string to the output file, quoting as needed...
  */
+
+static void
+cgi_puturi(const char *s,              /* I - String to output */
+           FILE       *out)            /* I - Output file */
+{
+  while (*s)
+  {
+    if (strchr("%@&+ <>#=", *s) || *s < ' ' || *s & 128)
+      fprintf(out, "%%%02X", *s & 255);
+    else
+      putc(*s, out);
+
+    s ++;
+  }
+}