#include "cgi-private.h"
#include <errno.h>
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);
void
cgiCopyTemplateFile(FILE *out,
const char *tmpl)
{
FILE *in;
fprintf(stderr, "DEBUG2: cgiCopyTemplateFile(out=%p, tmpl=\"%s\")\n", out,
tmpl ? tmpl : "(null)");
if (!tmpl || !out)
return;
if ((in = fopen(tmpl, "r")) == NULL)
{
fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
tmpl ? tmpl : "(null)", strerror(errno));
return;
}
cgi_copy(out, in, 0, 0, 0);
fclose(in);
}
void
cgiCopyTemplateLang(const char *tmpl)
{
char filename[1024],
locale[16],
*locptr;
const char *directory,
*lang;
FILE *in;
fprintf(stderr, "DEBUG2: cgiCopyTemplateLang(tmpl=\"%s\")\n",
tmpl ? tmpl : "(null)");
locale[0] = '\0';
if ((lang = getenv("LANG")) != NULL)
{
locale[0] = '/';
strlcpy(locale + 1, lang, sizeof(locale) - 1);
if ((locptr = strchr(locale, '.')) != NULL)
*locptr = '\0';
}
fprintf(stderr, "DEBUG: lang=\"%s\", locale=\"%s\"...\n",
lang ? lang : "(null)", locale);
directory = cgiGetTemplateDir();
snprintf(filename, sizeof(filename), "%s%s/%s", directory, locale, tmpl);
if ((in = fopen(filename, "r")) == NULL)
{
locale[3] = '\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);
if (!in)
{
fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n",
filename, strerror(errno));
return;
}
cgi_copy(stdout, in, 0, 0, 0);
fclose(in);
}
char *
cgiGetTemplateDir(void)
{
const char *datadir;
static char templates[1024] = "";
if (!templates[0])
{
if ((datadir = getenv("CUPS_DATADIR")) == NULL)
datadir = CUPS_DATADIR;
snprintf(templates, sizeof(templates), "%s/templates", datadir);
}
return (templates);
}
void
cgiSetServerVersion(void)
{
cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME"));
cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER"));
cgiSetVariable("CUPS_VERSION", CUPS_SVERSION);
#ifdef LC_TIME
setlocale(LC_TIME, "");
#endif
}
static void
cgi_copy(FILE *out,
FILE *in,
int element,
char term,
int indent)
{
int ch;
char op;
char name[255],
*nameptr,
innername[255],
*innerptr,
*s;
const char *value;
const char *innerval;
const char *outptr;
char outval[1024],
compare[1024];
int result;
int uriencode;
fprintf(stderr, "DEBUG2: %*sStarting at file position %ld...\n", indent, "",
ftell(in));
while ((ch = getc(in)) != EOF)
if (ch == term)
break;
else if (ch == '{')
{
uriencode = 0;
for (s = name; (ch = getc(in)) != EOF;)
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 = '\0';
if (s == name && isspace(ch & 255))
{
fprintf(stderr, "DEBUG2: %*sLone { at %ld...\n", indent, "", ftell(in));
if (out)
{
putc('{', out);
putc(ch, out);
}
continue;
}
if (ch == '}')
fprintf(stderr, "DEBUG2: %*s\"{%s}\" at %ld...\n", indent, "", name,
ftell(in));
if (name[0] == '?')
{
if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
{
*nameptr++ = '\0';
if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL)
outptr = value;
else
{
outval[0] = '\0';
outptr = outval;
}
}
else if ((value = cgiGetArray(name + 1, element)) != NULL)
outptr = value;
else
{
outval[0] = '\0';
outptr = outval;
}
}
else if (name[0] == '#')
{
if (name[1])
sprintf(outval, "%d", cgiGetSize(name + 1));
else
sprintf(outval, "%d", element + 1);
outptr = outval;
}
else if (name[0] == '[')
{
int i;
long pos;
int count;
if (isdigit(name[1] & 255))
count = atoi(name + 1);
else
count = cgiGetSize(name + 1);
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 ++)
{
if (i)
fseek(in, pos, SEEK_SET);
cgi_copy(out, in, i, '}', indent + 2);
}
}
else
cgi_copy(NULL, in, 0, '}', indent + 2);
fprintf(stderr, "DEBUG2: %*sFinished looping on \"%s\"...\n", indent,
"", name + 1);
continue;
}
else
{
if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
{
*nameptr++ = '\0';
if ((value = cgiGetArray(name, atoi(nameptr) - 1)) == NULL)
{
snprintf(outval, sizeof(outval), "{%s}", name);
outptr = outval;
}
else
outptr = value;
}
else if ((value = cgiGetArray(name, element)) == NULL)
{
snprintf(outval, sizeof(outval), "{%s}", name);
outptr = outval;
}
else
outptr = value;
}
if (ch == '}')
{
if (out)
{
if (uriencode)
cgi_puturi(outptr, out);
else if (!strcasecmp(name, "?cupsdconf_default"))
fputs(outptr, stdout);
else
cgi_puts(outptr, out);
}
continue;
}
op = ch;
if (ch == '?')
{
result = cgiGetArray(name, element) != NULL && outptr[0];
compare[0] = '\0';
}
else
{
for (s = compare; (ch = getc(in)) != EOF;)
if (ch == '?')
break;
else if (s >= (compare + sizeof(compare) - 1))
continue;
else if (ch == '#')
{
sprintf(s, "%d", element + 1);
s += strlen(s);
}
else if (ch == '{')
{
innerptr = innername;
while ((ch = getc(in)) != EOF && ch != '}')
if (innerptr < (innername + sizeof(innername) - 1))
*innerptr++ = ch;
*innerptr = '\0';
if (innername[0] == '#')
sprintf(s, "%d", cgiGetSize(innername + 1));
else if ((innerptr = strrchr(innername, '-')) != NULL &&
isdigit(innerptr[1] & 255))
{
*innerptr++ = '\0';
if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL)
*s = '\0';
else
strlcpy(s, innerval, sizeof(compare) - (s - compare));
}
else if (innername[0] == '?')
{
if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
*s = '\0';
else
strlcpy(s, innerval, sizeof(compare) - (s - compare));
}
else if ((innerval = cgiGetArray(innername, element)) == NULL)
snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername);
else
strlcpy(s, innerval, sizeof(compare) - (s - compare));
s += strlen(s);
}
else if (ch == '\\')
*s++ = getc(in);
else
*s++ = ch;
*s = '\0';
if (ch != '?')
{
fprintf(stderr,
"DEBUG2: %*sBad terminator '%c' at file position %ld...\n",
indent, "", ch, ftell(in));
return;
}
switch (op)
{
case '<' :
result = strcasecmp(outptr, compare) < 0;
break;
case '>' :
result = strcasecmp(outptr, compare) > 0;
break;
case '=' :
result = strcasecmp(outptr, compare) == 0;
break;
case '!' :
result = strcasecmp(outptr, compare) != 0;
break;
default :
result = 1;
break;
}
}
fprintf(stderr,
"DEBUG2: %*sStarting \"{%s%c%s\" at %ld, result=%d...\n",
indent, "", name, op, compare, ftell(in), result);
if (result)
{
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
{
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 == '\\')
{
if (out)
putc(getc(in), out);
else
getc(in);
}
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);
if (out)
fflush(out);
}
static void
cgi_puts(const char *s,
FILE *out)
{
while (*s)
{
if (*s == '<')
{
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);
}
else if (*s == '>')
fputs(">", out);
else if (*s == '\"')
fputs(""", out);
else if (*s == '&')
fputs("&", out);
else
putc(*s, out);
s ++;
}
}
static void
cgi_puturi(const char *s,
FILE *out)
{
while (*s)
{
if (strchr("%&+ <>#=", *s) || *s & 128)
fprintf(out, "%%%02X", *s & 255);
else
putc(*s, out);
s ++;
}
}