1/*
2 * CUPS API test program for CUPS.
3 *
4 * Copyright 2007-2017 by Apple Inc.
5 * Copyright 2007 by Easy Software Products.
6 *
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
11 * missing or damaged, see the license at "http://www.cups.org/".
12 *
13 * This file is subject to the Apple OS-Developed Software exception.
14 */
15
16/*
17 * Include necessary headers...
18 */
19
20#undef _CUPS_NO_DEPRECATED
21#include "string-private.h"
22#include "cups.h"
23#include "ppd.h"
24#include <stdlib.h>
25
26
27/*
28 * Local functions...
29 */
30
31static int	dests_equal(cups_dest_t *a, cups_dest_t *b);
32static int	enum_cb(void *user_data, unsigned flags, cups_dest_t *dest);
33static void	show_diffs(cups_dest_t *a, cups_dest_t *b);
34
35
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 */
45		i,			/* Looping var */
46		num_dests;		/* Number of destinations */
47  cups_dest_t	*dests,			/* Destinations */
48		*dest,			/* Current destination */
49		*named_dest;		/* Current named destination */
50  const char	*dest_name,             /* Destination name */
51                *dval,                  /* Destination value */
52                *ppdfile;		/* PPD file */
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
57
58  if (argc > 1)
59  {
60    if (!strcmp(argv[1], "enum"))
61    {
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);
158    }
159    else if (!strcmp(argv[1], "password"))
160    {
161      const char *pass = cupsGetPassword("Password:");
162					  /* Password string */
163
164      if (pass)
165	printf("Password entered: %s\n", pass);
166      else
167	puts("No password entered.");
168    }
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    }
186    else if (!strcmp(argv[1], "print") && argc == 5)
187    {
188     /*
189      * ./testcups print printer file interval
190      */
191
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 */
197
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      }
203
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]);
213
214      if (cupsStartDocument(CUPS_HTTP_DEFAULT, argv[1], job_id, argv[2],
215			    CUPS_FORMAT_AUTO, 1) != HTTP_STATUS_CONTINUE)
216      {
217	puts("Unable to start document!");
218	return (1);
219      }
220
221      while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
222      {
223	printf("Writing %d bytes...\n", (int)bytes);
224
225	if (cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, (size_t)bytes) != HTTP_STATUS_CONTINUE)
226	{
227	  puts("Unable to write bytes!");
228	  return (1);
229	}
230
231        if (interval > 0)
232	  sleep((unsigned)interval);
233      }
234
235      cupsFileClose(fp);
236
237      if (cupsFinishDocument(CUPS_HTTP_DEFAULT,
238                             argv[1]) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
239      {
240	puts("Unable to finish document!");
241	return (1);
242      }
243    }
244    else
245    {
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("");
260      puts("Get the PPD file:");
261      puts("");
262      puts("    ./testcups ppd printer");
263      puts("");
264      puts("Print a file (interval controls delay between buffers in seconds):");
265      puts("");
266      puts("    ./testcups print printer file interval");
267      return (1);
268    }
269
270    return (0);
271  }
272
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
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);
360
361 /*
362  * cupsGetDest(printer)
363  */
364
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)");
375  fflush(stdout);
376
377  if ((dest = cupsGetDest(dest_name, NULL, num_dests, dests)) == NULL)
378  {
379    puts("FAIL");
380    return (1);
381  }
382  else
383    puts("PASS");
384
385 /*
386  * cupsGetNamedDest(NULL, printer, instance)
387  */
388
389  printf("cupsGetNamedDest(NULL, \"%s\", \"%s\"): ", dest->name,
390         dest->instance ? dest->instance : "(null)");
391  fflush(stdout);
392
393  if ((named_dest = cupsGetNamedDest(NULL, dest->name, dest->instance)) == NULL ||
394      !dests_equal(dest, named_dest))
395  {
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
405    status = 1;
406  }
407  else
408    puts("PASS");
409
410  if (named_dest)
411    cupsFreeDests(1, named_dest);
412
413 /*
414  * cupsPrintFile()
415  */
416
417  fputs("cupsPrintFile: ", stdout);
418  fflush(stdout);
419
420  if (cupsPrintFile(dest->name, "../test/testfile.pdf", "Test Page",
421                    dest->num_options, dest->options) <= 0)
422  {
423    printf("FAIL (%s)\n", cupsLastErrorString());
424    return (1);
425  }
426  else
427    puts("PASS");
428
429 /*
430  * cupsGetPPD(printer)
431  */
432
433  fputs("cupsGetPPD: ", stdout);
434  fflush(stdout);
435
436  if ((ppdfile = cupsGetPPD(dest->name)) == NULL)
437  {
438    puts("FAIL");
439  }
440  else
441  {
442    puts("PASS");
443
444   /*
445    * ppdOpenFile()
446    */
447
448    fputs("ppdOpenFile: ", stdout);
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
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
503  if (!a || !b)
504    return (0);
505
506  if (_cups_strcasecmp(a->name, b->name) ||
507      (a->instance && !b->instance) ||
508      (!a->instance && b->instance) ||
509      (a->instance && _cups_strcasecmp(a->instance, b->instance)) ||
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
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{
532  int		i;			/* Looping var */
533  cups_option_t	*option;		/* Current option */
534
535
536  (void)user_data;
537
538  if (flags & CUPS_DEST_FLAGS_REMOVED)
539    printf("Removed '%s':\n", dest->name);
540  else
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');
547
548  return (1);
549}
550
551
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 */
562  cups_option_t	*boption;		/* Current option */
563  const char	*bval;			/* Option value */
564
565
566  if (!a || !b)
567    return;
568
569  puts("    Item                  cupsGetDest               cupsGetNamedDest");
570  puts("    --------------------  ------------------------  ------------------------");
571
572  if (_cups_strcasecmp(a->name, b->name))
573    printf("    name                  %-24.24s  %-24.24s\n", a->name, b->name);
574
575  if ((a->instance && !b->instance) ||
576      (!a->instance && b->instance) ||
577      (a->instance && _cups_strcasecmp(a->instance, b->instance)))
578    printf("    instance              %-24.24s  %-24.24s\n",
579           a->instance ? a->instance : "(null)",
580	   b->instance ? b->instance : "(null)");
581
582  if (a->num_options != b->num_options)
583    printf("    num_options           %-24d  %-24d\n", a->num_options,
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))
590      printf("    %-20.20s  %-24.24s  %-24.24s\n", aoption->name,
591             aoption->value, bval ? bval : "(null)");
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)");
597}
598