#include <config.h>
#include <cups/cups.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_MXML_H
# include <mxml.h>
typedef struct _cups_reg_s
{
char *name,
*member,
*sub_member,
*syntax;
} _cups_reg_t;
static int compare_reg(_cups_reg_t *a, _cups_reg_t *b);
static mxml_node_t *load_xml(const char *reg_file);
static int match_xref(mxml_node_t *xref, const char *standard);
static _cups_reg_t *new_reg(mxml_node_t *name, mxml_node_t *member,
mxml_node_t *sub_member, mxml_node_t *syntax);
static int usage(void);
static void write_expect(_cups_reg_t *reg, ipp_tag_t group);
int
main(int argc,
char *argv[])
{
int i;
const char *reg_file = NULL,
*reg_standard = NULL;
mxml_node_t *reg_xml,
*reg_2,
*reg_record,
*reg_collection,
*reg_name,
*reg_member,
*reg_sub_member,
*reg_syntax,
*reg_xref;
cups_array_t *attrs;
_cups_reg_t *current;
ipp_tag_t group = IPP_TAG_ZERO,
reg_group;
for (i = 1; i < argc; i ++)
{
if (!strcmp(argv[i], "--job") && group == IPP_TAG_ZERO)
group = IPP_TAG_JOB;
else if (!strcmp(argv[i], "--ref"))
{
i ++;
if (i >= argc)
return (usage());
reg_standard = argv[i];
}
else if (!strcmp(argv[i], "--printer") && group == IPP_TAG_ZERO)
group = IPP_TAG_PRINTER;
else if (argv[i][0] == '-' || reg_file)
return (usage());
else
reg_file = argv[i];
}
if (group == IPP_TAG_ZERO)
return (usage());
if (!reg_file)
reg_file = "http://www.iana.org/assignments/ipp-registrations/"
"ipp-registrations.xml";
if ((reg_xml = load_xml(reg_file)) == NULL)
return (1);
if ((reg_2 = mxmlFindElement(reg_xml, reg_xml, "registry", "id",
"ipp-registrations-2",
MXML_DESCEND)) == NULL)
{
fprintf(stderr, "xmltotest: No IPP attribute registrations in \"%s\".\n",
reg_file);
return (1);
}
attrs = cupsArrayNew((cups_array_func_t)compare_reg, NULL);
for (reg_record = mxmlFindElement(reg_2, reg_2, "record", NULL, NULL,
MXML_DESCEND);
reg_record;
reg_record = mxmlFindElement(reg_record, reg_2, "record", NULL, NULL,
MXML_NO_DESCEND))
{
reg_collection = mxmlFindElement(reg_record, reg_record, "collection",
NULL, NULL, MXML_DESCEND);
reg_name = mxmlFindElement(reg_record, reg_record, "name", NULL, NULL,
MXML_DESCEND);
reg_member = mxmlFindElement(reg_record, reg_record, "member_attribute",
NULL, NULL, MXML_DESCEND);
reg_sub_member = mxmlFindElement(reg_record, reg_record,
"sub-member_attribute", NULL, NULL,
MXML_DESCEND);
reg_syntax = mxmlFindElement(reg_record, reg_record, "syntax", NULL,
NULL, MXML_DESCEND);
reg_xref = mxmlFindElement(reg_record, reg_record, "xref", NULL, NULL,
MXML_DESCEND);
if (!reg_collection || !reg_name || !reg_syntax || !reg_xref)
continue;
if (!strcmp(reg_collection->child->value.opaque, "Printer Description"))
reg_group = IPP_TAG_PRINTER;
else if (!strcmp(reg_collection->child->value.opaque, "Job Description"))
reg_group = IPP_TAG_JOB;
else if (!strcmp(reg_collection->child->value.opaque, "Job Template"))
{
if (strstr(reg_name->child->value.opaque, "-default") ||
strstr(reg_name->child->value.opaque, "-supported"))
reg_group = IPP_TAG_PRINTER;
else
reg_group = IPP_TAG_JOB;
}
else
reg_group = IPP_TAG_ZERO;
if (reg_group != group)
continue;
if (reg_standard && !match_xref(reg_xref, reg_standard))
continue;
if ((current = new_reg(reg_name, reg_member, reg_sub_member,
reg_syntax)) != NULL)
cupsArrayAdd(attrs, current);
}
puts("{");
if (group == IPP_TAG_PRINTER)
{
puts("\tOPERATION Get-Printer-Attributes");
puts("\tGROUP operation-attributes-tag");
puts("\tATTR charset attributes-charset utf-8");
puts("\tATTR naturalLanguage attributes-natural-language en");
puts("\tATTR uri printer-uri $uri");
puts("\tATTR name requesting-user-name $user");
puts("\tATTR keyword requested-attributes all,media-col-database");
puts("");
puts("\tSTATUS successful-ok");
puts("\tSTATUS successful-ok-ignored-or-substituted-attributes");
puts("");
}
else
{
puts("\tOPERATION Get-Job-Attributes");
puts("\tGROUP operation-attributes-tag");
puts("\tATTR charset attributes-charset utf-8");
puts("\tATTR naturalLanguage attributes-natural-language en");
puts("\tATTR uri printer-uri $uri");
puts("\tATTR integer job-id $job-id");
puts("\tATTR name requesting-user-name $user");
puts("");
puts("\tSTATUS successful-ok");
puts("");
}
for (current = cupsArrayFirst(attrs);
current;
current = cupsArrayNext(attrs))
write_expect(current, group);
puts("}");
return (0);
}
static int
compare_reg(_cups_reg_t *a,
_cups_reg_t *b)
{
int retval;
if ((retval = strcmp(a->name, b->name)) != 0)
return (retval);
if (a->member && b->member)
retval = strcmp(a->member, b->member);
else if (a->member)
retval = 1;
else if (b->member)
retval = -1;
if (retval)
return (retval);
if (a->sub_member && b->sub_member)
retval = strcmp(a->sub_member, b->sub_member);
else if (a->sub_member)
retval = 1;
else if (b->sub_member)
retval = -1;
return (retval);
}
static mxml_node_t *
load_xml(const char *reg_file)
{
mxml_node_t *xml;
char scheme[256],
userpass[256],
hostname[256],
resource[1024],
filename[1024];
int port,
fd;
if (httpSeparateURI(HTTP_URI_CODING_ALL, reg_file, scheme, sizeof(scheme),
userpass, sizeof(userpass), hostname, sizeof(hostname),
&port, resource, sizeof(resource)) < HTTP_URI_OK)
{
fprintf(stderr, "xmltotest: Bad URI or filename \"%s\".\n", reg_file);
return (NULL);
}
if (!strcmp(scheme, "file"))
{
if ((fd = open(resource, O_RDONLY)) < 0)
{
fprintf(stderr, "xmltotest: Unable to open \"%s\": %s\n", resource,
strerror(errno));
return (NULL);
}
filename[0] = '\0';
}
else if (strcmp(scheme, "http") && strcmp(scheme, "https"))
{
fprintf(stderr, "xmltotest: Unsupported URI scheme \"%s\".\n", scheme);
return (NULL);
}
else
{
http_t *http;
http_encryption_t encryption;
http_status_t status;
if (!strcmp(scheme, "https") || port == 443)
encryption = HTTP_ENCRYPT_ALWAYS;
else
encryption = HTTP_ENCRYPT_IF_REQUESTED;
if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL)
{
fprintf(stderr, "xmltotest: Unable to connect to \"%s\": %s\n", hostname,
cupsLastErrorString());
return (NULL);
}
if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
{
fprintf(stderr, "xmltotest: Unable to create temporary file: %s\n",
strerror(errno));
httpClose(http);
return (NULL);
}
status = cupsGetFd(http, resource, fd);
httpClose(http);
if (status != HTTP_OK)
{
fprintf(stderr, "mxmltotest: Unable to get \"%s\": %d\n", reg_file,
status);
close(fd);
unlink(filename);
return (NULL);
}
lseek(fd, 0, SEEK_SET);
}
xml = mxmlLoadFd(NULL, fd, MXML_OPAQUE_CALLBACK);
close(fd);
if (filename[0])
unlink(filename);
return (xml);
}
static int
match_xref(mxml_node_t *xref,
const char *standard)
{
const char *data;
char s[256];
if ((data = mxmlElementGetAttr(xref, "data")) == NULL)
return (1);
if (!strcmp(data, standard))
return (1);
if (!strncmp(standard, "pwg", 3))
{
snprintf(s, sizeof(s), "-%s.pdf", standard + 3);
return (strstr(data, s) != NULL);
}
else
return (0);
}
static _cups_reg_t *
new_reg(mxml_node_t *name,
mxml_node_t *member,
mxml_node_t *sub_member,
mxml_node_t *syntax)
{
_cups_reg_t *reg;
if ((reg = calloc(1, sizeof(_cups_reg_t))) != NULL)
{
reg->name = name->child->value.opaque;
reg->syntax = syntax->child->value.opaque;
if (member)
reg->member = member->child->value.opaque;
if (sub_member)
reg->sub_member = sub_member->child->value.opaque;
}
return (reg);
}
static int
usage(void)
{
puts("Usage ./xmltotest [--ref standard] {--job|--printer} [XML file/URL] "
">file.test");
return (1);
}
static void
write_expect(_cups_reg_t *reg,
ipp_tag_t group)
{
const char *syntax;
int single = 1,
skip = 0;
printf("\tEXPECT ?%s OF-TYPE ", reg->name);
syntax = reg->syntax;
while (*syntax)
{
if (!strncmp(syntax, "1setOf", 6))
{
single = 0;
syntax += 6;
while (isspace(*syntax & 255))
syntax ++;
if (*syntax == '(')
syntax ++;
}
else if (!strncmp(syntax, "type1", 5) || !strncmp(syntax, "type2", 5) ||
!strncmp(syntax, "type3", 5))
syntax += 5;
else if (*syntax == '(')
{
skip = 1;
syntax ++;
}
else if (*syntax == ')')
{
skip = 0;
syntax ++;
}
else if (!skip && (*syntax == '|' || isalpha(*syntax & 255)))
putchar(*syntax++);
else
syntax ++;
}
if (single)
printf(" IN-GROUP %s COUNT 1\n", ippTagString(group));
else
printf(" IN-GROUP %s\n", ippTagString(group));
}
#else
int
main(void)
{
return (1);
}
#endif