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