1/*
2 * "$Id: testcups.c 11560 2014-02-06 20:10:19Z msweet $"
3 *
4 * CUPS API test program for CUPS.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 2007 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file.  If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
18/*
19 * Include necessary headers...
20 */
21
22#undef _CUPS_NO_DEPRECATED
23#include "string-private.h"
24#include "cups.h"
25#include "ppd.h"
26#include <stdlib.h>
27
28
29/*
30 * Local functions...
31 */
32
33static int	dests_equal(cups_dest_t *a, cups_dest_t *b);
34static int	enum_cb(void *user_data, unsigned flags, cups_dest_t *dest);
35static void	show_diffs(cups_dest_t *a, cups_dest_t *b);
36
37
38/*
39 * 'main()' - Main entry.
40 */
41
42int					/* O - Exit status */
43main(int  argc,				/* I - Number of command-line arguments */
44     char *argv[])			/* I - Command-line arguments */
45{
46  int		status = 0,		/* Exit status */
47		i,			/* Looping var */
48		num_dests;		/* Number of destinations */
49  cups_dest_t	*dests,			/* Destinations */
50		*dest,			/* Current destination */
51		*named_dest;		/* Current named destination */
52  const char	*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  printf("cupsGetDest(\"%s\"): ", dests[num_dests / 2].name);
366  fflush(stdout);
367
368  if ((dest = cupsGetDest(dests[num_dests / 2].name, NULL, num_dests,
369                          dests)) == NULL)
370  {
371    puts("FAIL");
372    return (1);
373  }
374  else
375    puts("PASS");
376
377 /*
378  * cupsGetNamedDest(NULL, printer, instance)
379  */
380
381  printf("cupsGetNamedDest(NULL, \"%s\", \"%s\"): ", dest->name,
382         dest->instance ? dest->instance : "(null)");
383  fflush(stdout);
384
385  if ((named_dest = cupsGetNamedDest(NULL, dest->name,
386                                     dest->instance)) == NULL ||
387      !dests_equal(dest, named_dest))
388  {
389    if (named_dest)
390    {
391      puts("FAIL (different values)");
392      show_diffs(dest, named_dest);
393    }
394    else
395      puts("FAIL (no destination)");
396
397
398    status = 1;
399  }
400  else
401    puts("PASS");
402
403  if (named_dest)
404    cupsFreeDests(1, named_dest);
405
406 /*
407  * cupsPrintFile()
408  */
409
410  fputs("cupsPrintFile: ", stdout);
411  fflush(stdout);
412
413  if (cupsPrintFile(dest->name, "../data/testprint", "Test Page",
414                    dest->num_options, dest->options) <= 0)
415  {
416    printf("FAIL (%s)\n", cupsLastErrorString());
417    return (1);
418  }
419  else
420    puts("PASS");
421
422 /*
423  * cupsGetPPD(printer)
424  */
425
426  fputs("cupsGetPPD(): ", stdout);
427  fflush(stdout);
428
429  if ((ppdfile = cupsGetPPD(dest->name)) == NULL)
430  {
431    puts("FAIL");
432  }
433  else
434  {
435    puts("PASS");
436
437   /*
438    * ppdOpenFile()
439    */
440
441    fputs("ppdOpenFile(): ", stdout);
442    fflush(stdout);
443
444    if ((ppd = ppdOpenFile(ppdfile)) == NULL)
445    {
446      puts("FAIL");
447      return (1);
448    }
449    else
450      puts("PASS");
451
452    ppdClose(ppd);
453    unlink(ppdfile);
454  }
455
456 /*
457  * cupsGetJobs()
458  */
459
460  fputs("cupsGetJobs: ", stdout);
461  fflush(stdout);
462
463  num_jobs = cupsGetJobs(&jobs, NULL, 0, -1);
464
465  if (num_jobs == 0)
466  {
467    puts("FAIL");
468    return (1);
469  }
470  else
471    puts("PASS");
472
473  cupsFreeJobs(num_jobs, jobs);
474  cupsFreeDests(num_dests, dests);
475
476  return (status);
477}
478
479
480/*
481 * 'dests_equal()' - Determine whether two destinations are equal.
482 */
483
484static int				/* O - 1 if equal, 0 if not equal */
485dests_equal(cups_dest_t *a,		/* I - First destination */
486            cups_dest_t *b)		/* I - Second destination */
487{
488  int		i;			/* Looping var */
489  cups_option_t	*aoption;		/* Current option */
490  const char	*bval;			/* Option value */
491
492
493  if (a == b)
494    return (1);
495
496  if (!a || !b)
497    return (0);
498
499  if (_cups_strcasecmp(a->name, b->name) ||
500      (a->instance && !b->instance) ||
501      (!a->instance && b->instance) ||
502      (a->instance && _cups_strcasecmp(a->instance, b->instance)) ||
503      a->num_options != b->num_options)
504    return (0);
505
506  for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++)
507    if ((bval = cupsGetOption(aoption->name, b->num_options,
508                              b->options)) == NULL ||
509        strcmp(aoption->value, bval))
510      return (0);
511
512  return (1);
513}
514
515
516/*
517 * 'enum_cb()' - Report additions and removals.
518 */
519
520static int				/* O - 1 to continue, 0 to stop */
521enum_cb(void        *user_data,		/* I - User data (unused) */
522        unsigned    flags,		/* I - Destination flags */
523        cups_dest_t *dest)		/* I - Destination */
524{
525  int		i;			/* Looping var */
526  cups_option_t	*option;		/* Current option */
527
528
529  (void)user_data;
530
531  if (flags & CUPS_DEST_FLAGS_REMOVED)
532    printf("Removed '%s':\n", dest->name);
533  else
534    printf("Added '%s':\n", dest->name);
535
536  for (i = dest->num_options, option = dest->options; i > 0; i --, option ++)
537    printf("    %s=\"%s\"\n", option->name, option->value);
538
539  putchar('\n');
540
541  return (1);
542}
543
544
545/*
546 * 'show_diffs()' - Show differences between two destinations.
547 */
548
549static void
550show_diffs(cups_dest_t *a,		/* I - First destination */
551           cups_dest_t *b)		/* I - Second destination */
552{
553  int		i;			/* Looping var */
554  cups_option_t	*aoption;		/* Current option */
555  const char	*bval;			/* Option value */
556
557
558  if (!a || !b)
559    return;
560
561  puts("    Item                  cupsGetDest           cupsGetNamedDest");
562  puts("    --------------------  --------------------  --------------------");
563
564  if (_cups_strcasecmp(a->name, b->name))
565    printf("    name                  %-20.20s  %-20.20s\n", a->name, b->name);
566
567  if ((a->instance && !b->instance) ||
568      (!a->instance && b->instance) ||
569      (a->instance && _cups_strcasecmp(a->instance, b->instance)))
570    printf("    instance              %-20.20s  %-20.20s\n",
571           a->instance ? a->instance : "(null)",
572	   b->instance ? b->instance : "(null)");
573
574  if (a->num_options != b->num_options)
575    printf("    num_options           %-20d  %-20d\n", a->num_options,
576           b->num_options);
577
578  for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++)
579    if ((bval = cupsGetOption(aoption->name, b->num_options,
580                              b->options)) == NULL ||
581        strcmp(aoption->value, bval))
582      printf("    %-20.20s  %-20.20s  %-20.20s\n", aoption->name,
583             aoption->value, bval ? bval : "(null)");
584}
585
586
587/*
588 * End of "$Id: testcups.c 11560 2014-02-06 20:10:19Z msweet $".
589 */
590