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