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