/* * CUPS API test program for CUPS. * * Copyright 2007-2017 by Apple Inc. * Copyright 2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. 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, see the license at "http://www.cups.org/". * * This file is subject to the Apple OS-Developed Software exception. */ /* * Include necessary headers... */ #undef _CUPS_NO_DEPRECATED #include "string-private.h" #include "cups.h" #include "ppd.h" #include <stdlib.h> /* * Local functions... */ static int dests_equal(cups_dest_t *a, cups_dest_t *b); static int enum_cb(void *user_data, unsigned flags, cups_dest_t *dest); static void show_diffs(cups_dest_t *a, cups_dest_t *b); /* * 'main()' - Main entry. */ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int status = 0, /* Exit status */ i, /* Looping var */ num_dests; /* Number of destinations */ cups_dest_t *dests, /* Destinations */ *dest, /* Current destination */ *named_dest; /* Current named destination */ const char *dest_name, /* Destination name */ *dval, /* Destination value */ *ppdfile; /* PPD file */ ppd_file_t *ppd; /* PPD file data */ int num_jobs; /* Number of jobs for queue */ cups_job_t *jobs; /* Jobs for queue */ if (argc > 1) { if (!strcmp(argv[1], "enum")) { cups_ptype_t mask = CUPS_PRINTER_LOCAL, /* Printer type mask */ type = CUPS_PRINTER_LOCAL; /* Printer type */ int msec = 0; /* Timeout in milliseconds */ for (i = 2; i < argc; i ++) if (isdigit(argv[i][0] & 255) || argv[i][0] == '.') msec = (int)(atof(argv[i]) * 1000); else if (!_cups_strcasecmp(argv[i], "bw")) { mask |= CUPS_PRINTER_BW; type |= CUPS_PRINTER_BW; } else if (!_cups_strcasecmp(argv[i], "color")) { mask |= CUPS_PRINTER_COLOR; type |= CUPS_PRINTER_COLOR; } else if (!_cups_strcasecmp(argv[i], "mono")) { mask |= CUPS_PRINTER_COLOR; } else if (!_cups_strcasecmp(argv[i], "duplex")) { mask |= CUPS_PRINTER_DUPLEX; type |= CUPS_PRINTER_DUPLEX; } else if (!_cups_strcasecmp(argv[i], "simplex")) { mask |= CUPS_PRINTER_DUPLEX; } else if (!_cups_strcasecmp(argv[i], "staple")) { mask |= CUPS_PRINTER_STAPLE; type |= CUPS_PRINTER_STAPLE; } else if (!_cups_strcasecmp(argv[i], "copies")) { mask |= CUPS_PRINTER_COPIES; type |= CUPS_PRINTER_COPIES; } else if (!_cups_strcasecmp(argv[i], "collate")) { mask |= CUPS_PRINTER_COLLATE; type |= CUPS_PRINTER_COLLATE; } else if (!_cups_strcasecmp(argv[i], "punch")) { mask |= CUPS_PRINTER_PUNCH; type |= CUPS_PRINTER_PUNCH; } else if (!_cups_strcasecmp(argv[i], "cover")) { mask |= CUPS_PRINTER_COVER; type |= CUPS_PRINTER_COVER; } else if (!_cups_strcasecmp(argv[i], "bind")) { mask |= CUPS_PRINTER_BIND; type |= CUPS_PRINTER_BIND; } else if (!_cups_strcasecmp(argv[i], "sort")) { mask |= CUPS_PRINTER_SORT; type |= CUPS_PRINTER_SORT; } else if (!_cups_strcasecmp(argv[i], "mfp")) { mask |= CUPS_PRINTER_MFP; type |= CUPS_PRINTER_MFP; } else if (!_cups_strcasecmp(argv[i], "printer")) { mask |= CUPS_PRINTER_MFP; } else if (!_cups_strcasecmp(argv[i], "large")) { mask |= CUPS_PRINTER_LARGE; type |= CUPS_PRINTER_LARGE; } else if (!_cups_strcasecmp(argv[i], "medium")) { mask |= CUPS_PRINTER_MEDIUM; type |= CUPS_PRINTER_MEDIUM; } else if (!_cups_strcasecmp(argv[i], "small")) { mask |= CUPS_PRINTER_SMALL; type |= CUPS_PRINTER_SMALL; } else fprintf(stderr, "Unknown argument \"%s\" ignored...\n", argv[i]); cupsEnumDests(CUPS_DEST_FLAGS_NONE, msec, NULL, type, mask, enum_cb, NULL); } else if (!strcmp(argv[1], "password")) { const char *pass = cupsGetPassword("Password:"); /* Password string */ if (pass) printf("Password entered: %s\n", pass); else puts("No password entered."); } else if (!strcmp(argv[1], "ppd") && argc == 3) { /* * ./testcups ppd printer */ http_status_t http_status; /* Status */ char buffer[1024]; /* PPD filename */ time_t modtime = 0; /* Last modified */ if ((http_status = cupsGetPPD3(CUPS_HTTP_DEFAULT, argv[2], &modtime, buffer, sizeof(buffer))) != HTTP_STATUS_OK) printf("Unable to get PPD: %d (%s)\n", (int)http_status, cupsLastErrorString()); else puts(buffer); } else if (!strcmp(argv[1], "print") && argc == 5) { /* * ./testcups print printer file interval */ int interval, /* Interval between writes */ job_id; /* Job ID */ cups_file_t *fp; /* Print file */ char buffer[16384]; /* Read/write buffer */ ssize_t bytes; /* Bytes read/written */ if ((fp = cupsFileOpen(argv[3], "r")) == NULL) { printf("Unable to open \"%s\": %s\n", argv[2], strerror(errno)); return (1); } if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, argv[2], "testcups", 0, NULL)) <= 0) { printf("Unable to create print job on %s: %s\n", argv[1], cupsLastErrorString()); return (1); } interval = atoi(argv[4]); if (cupsStartDocument(CUPS_HTTP_DEFAULT, argv[1], job_id, argv[2], CUPS_FORMAT_AUTO, 1) != HTTP_STATUS_CONTINUE) { puts("Unable to start document!"); return (1); } while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0) { printf("Writing %d bytes...\n", (int)bytes); if (cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, (size_t)bytes) != HTTP_STATUS_CONTINUE) { puts("Unable to write bytes!"); return (1); } if (interval > 0) sleep((unsigned)interval); } cupsFileClose(fp); if (cupsFinishDocument(CUPS_HTTP_DEFAULT, argv[1]) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) { puts("Unable to finish document!"); return (1); } } else { puts("Usage:"); puts(""); puts("Run basic unit tests:"); puts(""); puts(" ./testcups"); puts(""); puts("Enumerate printers (for N seconds, -1 for indefinitely):"); puts(""); puts(" ./testcups enum [seconds]"); puts(""); puts("Ask for a password:"); puts(""); puts(" ./testcups password"); puts(""); puts("Get the PPD file:"); puts(""); puts(" ./testcups ppd printer"); puts(""); puts("Print a file (interval controls delay between buffers in seconds):"); puts(""); puts(" ./testcups print printer file interval"); return (1); } return (0); } /* * cupsGetDests() */ fputs("cupsGetDests: ", stdout); fflush(stdout); num_dests = cupsGetDests(&dests); if (num_dests == 0) { puts("FAIL"); return (1); } else { printf("PASS (%d dests)\n", num_dests); for (i = num_dests, dest = dests; i > 0; i --, dest ++) { printf(" %s", dest->name); if (dest->instance) printf(" /%s", dest->instance); if (dest->is_default) puts(" ***DEFAULT***"); else putchar('\n'); } } /* * cupsGetDest(NULL) */ fputs("cupsGetDest(NULL): ", stdout); fflush(stdout); if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL) { for (i = num_dests, dest = dests; i > 0; i --, dest ++) if (dest->is_default) break; if (i) { status = 1; puts("FAIL"); } else puts("PASS (no default)"); dest = NULL; } else printf("PASS (%s)\n", dest->name); /* * cupsGetNamedDest(NULL, NULL, NULL) */ fputs("cupsGetNamedDest(NULL, NULL, NULL): ", stdout); fflush(stdout); if ((named_dest = cupsGetNamedDest(NULL, NULL, NULL)) == NULL || !dests_equal(dest, named_dest)) { if (!dest) puts("PASS (no default)"); else if (named_dest) { puts("FAIL (different values)"); show_diffs(dest, named_dest); status = 1; } else { puts("FAIL (no default)"); status = 1; } } else printf("PASS (%s)\n", named_dest->name); if (named_dest) cupsFreeDests(1, named_dest); /* * cupsGetDest(printer) */ for (i = 0, dest_name = NULL; i < num_dests; i ++) { if ((dval = cupsGetOption("printer-is-temporary", dests[i].num_options, dest[i].options)) != NULL && !strcmp(dval, "false")) { dest_name = dests[i].name; break; } } printf("cupsGetDest(\"%s\"): ", dest_name ? dest_name : "(null)"); fflush(stdout); if ((dest = cupsGetDest(dest_name, NULL, num_dests, dests)) == NULL) { puts("FAIL"); return (1); } else puts("PASS"); /* * cupsGetNamedDest(NULL, printer, instance) */ printf("cupsGetNamedDest(NULL, \"%s\", \"%s\"): ", dest->name, dest->instance ? dest->instance : "(null)"); fflush(stdout); if ((named_dest = cupsGetNamedDest(NULL, dest->name, dest->instance)) == NULL || !dests_equal(dest, named_dest)) { if (named_dest) { puts("FAIL (different values)"); show_diffs(dest, named_dest); } else puts("FAIL (no destination)"); status = 1; } else puts("PASS"); if (named_dest) cupsFreeDests(1, named_dest); /* * cupsPrintFile() */ fputs("cupsPrintFile: ", stdout); fflush(stdout); if (cupsPrintFile(dest->name, "../test/testfile.pdf", "Test Page", dest->num_options, dest->options) <= 0) { printf("FAIL (%s)\n", cupsLastErrorString()); return (1); } else puts("PASS"); /* * cupsGetPPD(printer) */ fputs("cupsGetPPD: ", stdout); fflush(stdout); if ((ppdfile = cupsGetPPD(dest->name)) == NULL) { puts("FAIL"); } else { puts("PASS"); /* * ppdOpenFile() */ fputs("ppdOpenFile: ", stdout); fflush(stdout); if ((ppd = ppdOpenFile(ppdfile)) == NULL) { puts("FAIL"); return (1); } else puts("PASS"); ppdClose(ppd); unlink(ppdfile); } /* * cupsGetJobs() */ fputs("cupsGetJobs: ", stdout); fflush(stdout); num_jobs = cupsGetJobs(&jobs, NULL, 0, -1); if (num_jobs == 0) { puts("FAIL"); return (1); } else puts("PASS"); cupsFreeJobs(num_jobs, jobs); cupsFreeDests(num_dests, dests); return (status); } /* * 'dests_equal()' - Determine whether two destinations are equal. */ static int /* O - 1 if equal, 0 if not equal */ dests_equal(cups_dest_t *a, /* I - First destination */ cups_dest_t *b) /* I - Second destination */ { int i; /* Looping var */ cups_option_t *aoption; /* Current option */ const char *bval; /* Option value */ if (a == b) return (1); if (!a || !b) return (0); if (_cups_strcasecmp(a->name, b->name) || (a->instance && !b->instance) || (!a->instance && b->instance) || (a->instance && _cups_strcasecmp(a->instance, b->instance)) || a->num_options != b->num_options) return (0); for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++) if ((bval = cupsGetOption(aoption->name, b->num_options, b->options)) == NULL || strcmp(aoption->value, bval)) return (0); return (1); } /* * 'enum_cb()' - Report additions and removals. */ static int /* O - 1 to continue, 0 to stop */ enum_cb(void *user_data, /* I - User data (unused) */ unsigned flags, /* I - Destination flags */ cups_dest_t *dest) /* I - Destination */ { int i; /* Looping var */ cups_option_t *option; /* Current option */ (void)user_data; if (flags & CUPS_DEST_FLAGS_REMOVED) printf("Removed '%s':\n", dest->name); else printf("Added '%s':\n", dest->name); for (i = dest->num_options, option = dest->options; i > 0; i --, option ++) printf(" %s=\"%s\"\n", option->name, option->value); putchar('\n'); return (1); } /* * 'show_diffs()' - Show differences between two destinations. */ static void show_diffs(cups_dest_t *a, /* I - First destination */ cups_dest_t *b) /* I - Second destination */ { int i; /* Looping var */ cups_option_t *aoption; /* Current option */ cups_option_t *boption; /* Current option */ const char *bval; /* Option value */ if (!a || !b) return; puts(" Item cupsGetDest cupsGetNamedDest"); puts(" -------------------- ------------------------ ------------------------"); if (_cups_strcasecmp(a->name, b->name)) printf(" name %-24.24s %-24.24s\n", a->name, b->name); if ((a->instance && !b->instance) || (!a->instance && b->instance) || (a->instance && _cups_strcasecmp(a->instance, b->instance))) printf(" instance %-24.24s %-24.24s\n", a->instance ? a->instance : "(null)", b->instance ? b->instance : "(null)"); if (a->num_options != b->num_options) printf(" num_options %-24d %-24d\n", a->num_options, b->num_options); for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++) if ((bval = cupsGetOption(aoption->name, b->num_options, b->options)) == NULL || strcmp(aoption->value, bval)) printf(" %-20.20s %-24.24s %-24.24s\n", aoption->name, aoption->value, bval ? bval : "(null)"); for (i = b->num_options, boption = b->options; i > 0; i --, boption ++) if (!cupsGetOption(boption->name, a->num_options, a->options)) printf(" %-20.20s %-24.24s %-24.24s\n", boption->name, boption->value, "(null)"); }