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