/* * Threaded test program for CUPS. * * Copyright © 2012-2019 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Include necessary headers... */ #include #include #include #include /* * Local functions... */ static int enum_dests_cb(void *_name, unsigned flags, cups_dest_t *dest); static void *run_query(cups_dest_t *dest); static void show_supported(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value); /* * 'main()' - Main entry. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { /* * Go through all the available destinations to find the requested one... */ (void)argc; cupsEnumDests(CUPS_DEST_FLAGS_NONE, -1, NULL, 0, 0, enum_dests_cb, argv[1]); return (0); } /* * 'enum_dests_cb()' - Destination enumeration function... */ static int /* O - 1 to continue, 0 to stop */ enum_dests_cb(void *_name, /* I - Printer name, if any */ unsigned flags, /* I - Enumeration flags */ cups_dest_t *dest) /* I - Found destination */ { const char *name = (const char *)_name; /* Printer name */ cups_dest_t *cdest; /* Copied destination */ (void)flags; /* * If a name was specified, compare it... */ if (name && strcasecmp(name, dest->name)) return (1); /* Continue */ /* * Copy the destination and run the query on a separate thread... */ cupsCopyDest(dest, 0, &cdest); _cupsThreadWait(_cupsThreadCreate((_cups_thread_func_t)run_query, cdest)); cupsFreeDests(1, cdest); /* * Continue if no name was specified or the name matches... */ return (!name || !strcasecmp(name, dest->name)); } /* * 'run_query()' - Query printer capabilities on a separate thread. */ static void * /* O - Return value (not used) */ run_query(cups_dest_t *dest) /* I - Destination to query */ { http_t *http; /* Connection to destination */ cups_dinfo_t *dinfo; /* Destination info */ unsigned dflags = CUPS_DEST_FLAGS_NONE; /* Destination flags */ if ((http = cupsConnectDest(dest, dflags, 300, NULL, NULL, 0, NULL, NULL)) == NULL) { printf("testthreads: Unable to connect to destination \"%s\": %s\n", dest->name, cupsLastErrorString()); return (NULL); } if ((dinfo = cupsCopyDestInfo(http, dest)) == NULL) { printf("testdest: Unable to get information for destination \"%s\": %s\n", dest->name, cupsLastErrorString()); return (NULL); } printf("\n%s:\n", dest->name); show_supported(http, dest, dinfo, NULL, NULL); return (NULL); } /* * 'show_supported()' - Show supported options, values, etc. */ static void show_supported(http_t *http, /* I - Connection to destination */ cups_dest_t *dest, /* I - Destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option, /* I - Option, if any */ const char *value) /* I - Value, if any */ { ipp_attribute_t *attr; /* Attribute */ int i, /* Looping var */ count; /* Number of values */ if (!option) { attr = cupsFindDestSupported(http, dest, dinfo, "job-creation-attributes"); if (attr) { count = ippGetCount(attr); for (i = 0; i < count; i ++) show_supported(http, dest, dinfo, ippGetString(attr, i, NULL), NULL); } else { static const char * const options[] = { /* List of standard options */ CUPS_COPIES, CUPS_FINISHINGS, CUPS_MEDIA, CUPS_NUMBER_UP, CUPS_ORIENTATION, CUPS_PRINT_COLOR_MODE, CUPS_PRINT_QUALITY, CUPS_SIDES }; puts(" No job-creation-attributes-supported attribute, probing instead."); for (i = 0; i < (int)(sizeof(options) / sizeof(options[0])); i ++) if (cupsCheckDestSupported(http, dest, dinfo, options[i], NULL)) show_supported(http, dest, dinfo, options[i], NULL); } } else if (!value) { printf(" %s (%s - %s)\n", option, cupsLocalizeDestOption(http, dest, dinfo, option), cupsCheckDestSupported(http, dest, dinfo, option, NULL) ? "supported" : "not-supported"); if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL) { count = ippGetCount(attr); switch (ippGetValueTag(attr)) { case IPP_TAG_INTEGER : for (i = 0; i < count; i ++) printf(" %d\n", ippGetInteger(attr, i)); break; case IPP_TAG_ENUM : for (i = 0; i < count; i ++) { int val = ippGetInteger(attr, i); char valstr[256]; snprintf(valstr, sizeof(valstr), "%d", val); printf(" %s (%s)\n", ippEnumString(option, ippGetInteger(attr, i)), cupsLocalizeDestValue(http, dest, dinfo, option, valstr)); } break; case IPP_TAG_RANGE : for (i = 0; i < count; i ++) { int upper, lower = ippGetRange(attr, i, &upper); printf(" %d-%d\n", lower, upper); } break; case IPP_TAG_RESOLUTION : for (i = 0; i < count; i ++) { int xres, yres; ipp_res_t units; xres = ippGetResolution(attr, i, &yres, &units); if (xres == yres) printf(" %d%s\n", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); else printf(" %dx%d%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); } break; case IPP_TAG_KEYWORD : for (i = 0; i < count; i ++) printf(" %s (%s)\n", ippGetString(attr, i, NULL), cupsLocalizeDestValue(http, dest, dinfo, option, ippGetString(attr, i, NULL))); break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : for (i = 0; i < count; i ++) printf(" %s\n", ippGetString(attr, i, NULL)); break; case IPP_TAG_STRING : for (i = 0; i < count; i ++) { int j, len; unsigned char *data = ippGetOctetString(attr, i, &len); fputs(" ", stdout); for (j = 0; j < len; j ++) { if (data[j] < ' ' || data[j] >= 0x7f) printf("<%02X>", data[j]); else putchar(data[j]); } putchar('\n'); } break; case IPP_TAG_BOOLEAN : break; default : printf(" %s\n", ippTagString(ippGetValueTag(attr))); break; } } } else if (cupsCheckDestSupported(http, dest, dinfo, option, value)) puts("YES"); else puts("NO"); }