1/* 2 * "$Id: testcups.c 11214 2013-08-01 22:24:05Z msweet $" 3 * 4 * CUPS API test program for CUPS. 5 * 6 * Copyright 2007-2013 by Apple Inc. 7 * Copyright 2007 by Easy Software Products. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * This file is subject to the Apple OS-Developed Software exception. 16 * 17 * Contents: 18 * 19 * main() - Main entry. 20 * dests_equal() - Determine whether two destinations are equal. 21 */ 22 23/* 24 * Include necessary headers... 25 */ 26 27#undef _CUPS_NO_DEPRECATED 28#include "string-private.h" 29#include "cups.h" 30#include "ppd.h" 31#include <stdlib.h> 32 33 34/* 35 * Local functions... 36 */ 37 38static int dests_equal(cups_dest_t *a, cups_dest_t *b); 39static int enum_cb(void *user_data, unsigned flags, cups_dest_t *dest); 40static void show_diffs(cups_dest_t *a, cups_dest_t *b); 41 42 43/* 44 * 'main()' - Main entry. 45 */ 46 47int /* O - Exit status */ 48main(int argc, /* I - Number of command-line arguments */ 49 char *argv[]) /* I - Command-line arguments */ 50{ 51 int status = 0, /* Exit status */ 52 i, /* Looping var */ 53 num_dests; /* Number of destinations */ 54 cups_dest_t *dests, /* Destinations */ 55 *dest, /* Current destination */ 56 *named_dest; /* Current named destination */ 57 const char *ppdfile; /* PPD file */ 58 ppd_file_t *ppd; /* PPD file data */ 59 int num_jobs; /* Number of jobs for queue */ 60 cups_job_t *jobs; /* Jobs for queue */ 61 62 63 if (argc > 1) 64 { 65 if (!strcmp(argv[1], "enum")) 66 { 67 cups_ptype_t mask = CUPS_PRINTER_LOCAL, 68 /* Printer type mask */ 69 type = CUPS_PRINTER_LOCAL; 70 /* Printer type */ 71 int msec = 0; /* Timeout in milliseconds */ 72 73 74 for (i = 2; i < argc; i ++) 75 if (isdigit(argv[i][0] & 255) || argv[i][0] == '.') 76 msec = (int)(atof(argv[i]) * 1000); 77 else if (!_cups_strcasecmp(argv[i], "bw")) 78 { 79 mask |= CUPS_PRINTER_BW; 80 type |= CUPS_PRINTER_BW; 81 } 82 else if (!_cups_strcasecmp(argv[i], "color")) 83 { 84 mask |= CUPS_PRINTER_COLOR; 85 type |= CUPS_PRINTER_COLOR; 86 } 87 else if (!_cups_strcasecmp(argv[i], "mono")) 88 { 89 mask |= CUPS_PRINTER_COLOR; 90 } 91 else if (!_cups_strcasecmp(argv[i], "duplex")) 92 { 93 mask |= CUPS_PRINTER_DUPLEX; 94 type |= CUPS_PRINTER_DUPLEX; 95 } 96 else if (!_cups_strcasecmp(argv[i], "simplex")) 97 { 98 mask |= CUPS_PRINTER_DUPLEX; 99 } 100 else if (!_cups_strcasecmp(argv[i], "staple")) 101 { 102 mask |= CUPS_PRINTER_STAPLE; 103 type |= CUPS_PRINTER_STAPLE; 104 } 105 else if (!_cups_strcasecmp(argv[i], "copies")) 106 { 107 mask |= CUPS_PRINTER_COPIES; 108 type |= CUPS_PRINTER_COPIES; 109 } 110 else if (!_cups_strcasecmp(argv[i], "collate")) 111 { 112 mask |= CUPS_PRINTER_COLLATE; 113 type |= CUPS_PRINTER_COLLATE; 114 } 115 else if (!_cups_strcasecmp(argv[i], "punch")) 116 { 117 mask |= CUPS_PRINTER_PUNCH; 118 type |= CUPS_PRINTER_PUNCH; 119 } 120 else if (!_cups_strcasecmp(argv[i], "cover")) 121 { 122 mask |= CUPS_PRINTER_COVER; 123 type |= CUPS_PRINTER_COVER; 124 } 125 else if (!_cups_strcasecmp(argv[i], "bind")) 126 { 127 mask |= CUPS_PRINTER_BIND; 128 type |= CUPS_PRINTER_BIND; 129 } 130 else if (!_cups_strcasecmp(argv[i], "sort")) 131 { 132 mask |= CUPS_PRINTER_SORT; 133 type |= CUPS_PRINTER_SORT; 134 } 135 else if (!_cups_strcasecmp(argv[i], "mfp")) 136 { 137 mask |= CUPS_PRINTER_MFP; 138 type |= CUPS_PRINTER_MFP; 139 } 140 else if (!_cups_strcasecmp(argv[i], "printer")) 141 { 142 mask |= CUPS_PRINTER_MFP; 143 } 144 else if (!_cups_strcasecmp(argv[i], "large")) 145 { 146 mask |= CUPS_PRINTER_LARGE; 147 type |= CUPS_PRINTER_LARGE; 148 } 149 else if (!_cups_strcasecmp(argv[i], "medium")) 150 { 151 mask |= CUPS_PRINTER_MEDIUM; 152 type |= CUPS_PRINTER_MEDIUM; 153 } 154 else if (!_cups_strcasecmp(argv[i], "small")) 155 { 156 mask |= CUPS_PRINTER_SMALL; 157 type |= CUPS_PRINTER_SMALL; 158 } 159 else 160 fprintf(stderr, "Unknown argument \"%s\" ignored...\n", argv[i]); 161 162 cupsEnumDests(CUPS_DEST_FLAGS_NONE, msec, NULL, type, mask, enum_cb, NULL); 163 } 164 else if (!strcmp(argv[1], "password")) 165 { 166 const char *pass = cupsGetPassword("Password:"); 167 /* Password string */ 168 169 if (pass) 170 printf("Password entered: %s\n", pass); 171 else 172 puts("No password entered."); 173 } 174 else if (!strcmp(argv[1], "ppd") && argc == 3) 175 { 176 /* 177 * ./testcups ppd printer 178 */ 179 180 http_status_t http_status; /* Status */ 181 char buffer[1024]; /* PPD filename */ 182 time_t modtime = 0; /* Last modified */ 183 184 if ((http_status = cupsGetPPD3(CUPS_HTTP_DEFAULT, argv[2], &modtime, 185 buffer, sizeof(buffer))) != HTTP_STATUS_OK) 186 printf("Unable to get PPD: %d (%s)\n", (int)http_status, 187 cupsLastErrorString()); 188 else 189 puts(buffer); 190 } 191 else if (!strcmp(argv[1], "print") && argc == 5) 192 { 193 /* 194 * ./testcups print printer file interval 195 */ 196 197 int interval, /* Interval between writes */ 198 job_id; /* Job ID */ 199 cups_file_t *fp; /* Print file */ 200 char buffer[16384]; /* Read/write buffer */ 201 ssize_t bytes; /* Bytes read/written */ 202 203 if ((fp = cupsFileOpen(argv[3], "r")) == NULL) 204 { 205 printf("Unable to open \"%s\": %s\n", argv[2], strerror(errno)); 206 return (1); 207 } 208 209 if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, argv[2], "testcups", 0, 210 NULL)) <= 0) 211 { 212 printf("Unable to create print job on %s: %s\n", argv[1], 213 cupsLastErrorString()); 214 return (1); 215 } 216 217 interval = atoi(argv[4]); 218 219 if (cupsStartDocument(CUPS_HTTP_DEFAULT, argv[1], job_id, argv[2], 220 CUPS_FORMAT_AUTO, 1) != HTTP_STATUS_CONTINUE) 221 { 222 puts("Unable to start document!"); 223 return (1); 224 } 225 226 while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0) 227 { 228 printf("Writing %d bytes...\n", (int)bytes); 229 230 if (cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, 231 bytes) != HTTP_STATUS_CONTINUE) 232 { 233 puts("Unable to write bytes!"); 234 return (1); 235 } 236 237 if (interval > 0) 238 sleep(interval); 239 } 240 241 cupsFileClose(fp); 242 243 if (cupsFinishDocument(CUPS_HTTP_DEFAULT, 244 argv[1]) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) 245 { 246 puts("Unable to finish document!"); 247 return (1); 248 } 249 } 250 else 251 { 252 puts("Usage:"); 253 puts(""); 254 puts("Run basic unit tests:"); 255 puts(""); 256 puts(" ./testcups"); 257 puts(""); 258 puts("Enumerate printers (for N seconds, -1 for indefinitely):"); 259 puts(""); 260 puts(" ./testcups enum [seconds]"); 261 puts(""); 262 puts("Ask for a password:"); 263 puts(""); 264 puts(" ./testcups password"); 265 puts(""); 266 puts("Get the PPD file:"); 267 puts(""); 268 puts(" ./testcups ppd printer"); 269 puts(""); 270 puts("Print a file (interval controls delay between buffers in seconds):"); 271 puts(""); 272 puts(" ./testcups print printer file interval"); 273 return (1); 274 } 275 276 return (0); 277 } 278 279 /* 280 * cupsGetDests() 281 */ 282 283 fputs("cupsGetDests: ", stdout); 284 fflush(stdout); 285 286 num_dests = cupsGetDests(&dests); 287 288 if (num_dests == 0) 289 { 290 puts("FAIL"); 291 return (1); 292 } 293 else 294 { 295 printf("PASS (%d dests)\n", num_dests); 296 297 for (i = num_dests, dest = dests; i > 0; i --, dest ++) 298 { 299 printf(" %s", dest->name); 300 301 if (dest->instance) 302 printf(" /%s", dest->instance); 303 304 if (dest->is_default) 305 puts(" ***DEFAULT***"); 306 else 307 putchar('\n'); 308 } 309 } 310 311 /* 312 * cupsGetDest(NULL) 313 */ 314 315 fputs("cupsGetDest(NULL): ", stdout); 316 fflush(stdout); 317 318 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL) 319 { 320 for (i = num_dests, dest = dests; i > 0; i --, dest ++) 321 if (dest->is_default) 322 break; 323 324 if (i) 325 { 326 status = 1; 327 puts("FAIL"); 328 } 329 else 330 puts("PASS (no default)"); 331 332 dest = NULL; 333 } 334 else 335 printf("PASS (%s)\n", dest->name); 336 337 /* 338 * cupsGetNamedDest(NULL, NULL, NULL) 339 */ 340 341 fputs("cupsGetNamedDest(NULL, NULL, NULL): ", stdout); 342 fflush(stdout); 343 344 if ((named_dest = cupsGetNamedDest(NULL, NULL, NULL)) == NULL || 345 !dests_equal(dest, named_dest)) 346 { 347 if (!dest) 348 puts("PASS (no default)"); 349 else if (named_dest) 350 { 351 puts("FAIL (different values)"); 352 show_diffs(dest, named_dest); 353 status = 1; 354 } 355 else 356 { 357 puts("FAIL (no default)"); 358 status = 1; 359 } 360 } 361 else 362 printf("PASS (%s)\n", named_dest->name); 363 364 if (named_dest) 365 cupsFreeDests(1, named_dest); 366 367 /* 368 * cupsGetDest(printer) 369 */ 370 371 printf("cupsGetDest(\"%s\"): ", dests[num_dests / 2].name); 372 fflush(stdout); 373 374 if ((dest = cupsGetDest(dests[num_dests / 2].name, NULL, num_dests, 375 dests)) == NULL) 376 { 377 puts("FAIL"); 378 return (1); 379 } 380 else 381 puts("PASS"); 382 383 /* 384 * cupsGetNamedDest(NULL, printer, instance) 385 */ 386 387 printf("cupsGetNamedDest(NULL, \"%s\", \"%s\"): ", dest->name, 388 dest->instance ? dest->instance : "(null)"); 389 fflush(stdout); 390 391 if ((named_dest = cupsGetNamedDest(NULL, dest->name, 392 dest->instance)) == NULL || 393 !dests_equal(dest, named_dest)) 394 { 395 if (named_dest) 396 { 397 puts("FAIL (different values)"); 398 show_diffs(dest, named_dest); 399 } 400 else 401 puts("FAIL (no destination)"); 402 403 404 status = 1; 405 } 406 else 407 puts("PASS"); 408 409 if (named_dest) 410 cupsFreeDests(1, named_dest); 411 412 /* 413 * cupsPrintFile() 414 */ 415 416 fputs("cupsPrintFile: ", stdout); 417 fflush(stdout); 418 419 if (cupsPrintFile(dest->name, "../data/testprint", "Test Page", 420 dest->num_options, dest->options) <= 0) 421 { 422 printf("FAIL (%s)\n", cupsLastErrorString()); 423 return (1); 424 } 425 else 426 puts("PASS"); 427 428 /* 429 * cupsGetPPD(printer) 430 */ 431 432 fputs("cupsGetPPD(): ", stdout); 433 fflush(stdout); 434 435 if ((ppdfile = cupsGetPPD(dest->name)) == NULL) 436 { 437 puts("FAIL"); 438 } 439 else 440 { 441 puts("PASS"); 442 443 /* 444 * ppdOpenFile() 445 */ 446 447 fputs("ppdOpenFile(): ", stdout); 448 fflush(stdout); 449 450 if ((ppd = ppdOpenFile(ppdfile)) == NULL) 451 { 452 puts("FAIL"); 453 return (1); 454 } 455 else 456 puts("PASS"); 457 458 ppdClose(ppd); 459 unlink(ppdfile); 460 } 461 462 /* 463 * cupsGetJobs() 464 */ 465 466 fputs("cupsGetJobs: ", stdout); 467 fflush(stdout); 468 469 num_jobs = cupsGetJobs(&jobs, NULL, 0, -1); 470 471 if (num_jobs == 0) 472 { 473 puts("FAIL"); 474 return (1); 475 } 476 else 477 puts("PASS"); 478 479 cupsFreeJobs(num_jobs, jobs); 480 cupsFreeDests(num_dests, dests); 481 482 return (status); 483} 484 485 486/* 487 * 'dests_equal()' - Determine whether two destinations are equal. 488 */ 489 490static int /* O - 1 if equal, 0 if not equal */ 491dests_equal(cups_dest_t *a, /* I - First destination */ 492 cups_dest_t *b) /* I - Second destination */ 493{ 494 int i; /* Looping var */ 495 cups_option_t *aoption; /* Current option */ 496 const char *bval; /* Option value */ 497 498 499 if (a == b) 500 return (1); 501 502 if (!a || !b) 503 return (0); 504 505 if (_cups_strcasecmp(a->name, b->name) || 506 (a->instance && !b->instance) || 507 (!a->instance && b->instance) || 508 (a->instance && _cups_strcasecmp(a->instance, b->instance)) || 509 a->num_options != b->num_options) 510 return (0); 511 512 for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++) 513 if ((bval = cupsGetOption(aoption->name, b->num_options, 514 b->options)) == NULL || 515 strcmp(aoption->value, bval)) 516 return (0); 517 518 return (1); 519} 520 521 522/* 523 * 'enum_cb()' - Report additions and removals. 524 */ 525 526static int /* O - 1 to continue, 0 to stop */ 527enum_cb(void *user_data, /* I - User data (unused) */ 528 unsigned flags, /* I - Destination flags */ 529 cups_dest_t *dest) /* I - Destination */ 530{ 531 int i; /* Looping var */ 532 cups_option_t *option; /* Current option */ 533 534 535 if (flags & CUPS_DEST_FLAGS_REMOVED) 536 printf("Removed '%s':\n", dest->name); 537 else 538 printf("Added '%s':\n", dest->name); 539 540 for (i = dest->num_options, option = dest->options; i > 0; i --, option ++) 541 printf(" %s=\"%s\"\n", option->name, option->value); 542 543 putchar('\n'); 544 545 return (1); 546} 547 548 549/* 550 * 'show_diffs()' - Show differences between two destinations. 551 */ 552 553static void 554show_diffs(cups_dest_t *a, /* I - First destination */ 555 cups_dest_t *b) /* I - Second destination */ 556{ 557 int i; /* Looping var */ 558 cups_option_t *aoption; /* Current option */ 559 const char *bval; /* Option value */ 560 561 562 if (!a || !b) 563 return; 564 565 puts(" Item cupsGetDest cupsGetNamedDest"); 566 puts(" -------------------- -------------------- --------------------"); 567 568 if (_cups_strcasecmp(a->name, b->name)) 569 printf(" name %-20.20s %-20.20s\n", a->name, b->name); 570 571 if ((a->instance && !b->instance) || 572 (!a->instance && b->instance) || 573 (a->instance && _cups_strcasecmp(a->instance, b->instance))) 574 printf(" instance %-20.20s %-20.20s\n", 575 a->instance ? a->instance : "(null)", 576 b->instance ? b->instance : "(null)"); 577 578 if (a->num_options != b->num_options) 579 printf(" num_options %-20d %-20d\n", a->num_options, 580 b->num_options); 581 582 for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++) 583 if ((bval = cupsGetOption(aoption->name, b->num_options, 584 b->options)) == NULL || 585 strcmp(aoption->value, bval)) 586 printf(" %-20.20s %-20.20s %-20.20s\n", aoption->name, 587 aoption->value, bval ? bval : "(null)"); 588} 589 590 591/* 592 * End of "$Id: testcups.c 11214 2013-08-01 22:24:05Z msweet $". 593 */ 594