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