/*
- * "$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);
/*
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...
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...
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...
*/
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...
* 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);
continue;
}
+ if (ch == '}')
+ fprintf(stderr, "DEBUG2: %*s\"{%s}\" at %ld...\n", indent, "", name,
+ ftell(in));
+
/*
* See if it has a value...
*/
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
{
/*
*/
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;
}
* {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
{
* Compare to a string...
*/
- op = ch;
-
for (s = compare; (ch = getc(in)) != EOF;)
if (ch == '?')
break;
innerptr = innername;
while ((ch = getc(in)) != EOF && ch != '}')
if (innerptr < (innername + sizeof(innername) - 1))
- *innerptr++ = ch;
+ *innerptr++ = (char)ch;
*innerptr = '\0';
if (innername[0] == '#')
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...
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;
}
}
+ 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
{
* 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 */
{
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...
*/
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("&", out);
- else
- putc(*s, out);
-
- s ++;
- }
-
- if (*s)
- s ++;
-
- fputs("\">", out);
- }
- else if (!strncasecmp(s, "</A>", 4))
- {
- fputs("</A>", out);
- s += 3;
- }
- else
- fputs("<", out);
- }
+ fputs("<", out);
else if (*s == '>')
fputs(">", out);
else if (*s == '\"')
fputs(""", out);
+ else if (*s == '\'')
+ fputs("'", out);
else if (*s == '&')
fputs("&", out);
else
/*
- * 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 ++;
+ }
+}