Home | History | Annotate | Download | only in cups
      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 
     31 static int	dests_equal(cups_dest_t *a, cups_dest_t *b);
     32 static int	enum_cb(void *user_data, unsigned flags, cups_dest_t *dest);
     33 static void	show_diffs(cups_dest_t *a, cups_dest_t *b);
     34 
     35 
     36 /*
     37  * 'main()' - Main entry.
     38  */
     39 
     40 int					/* O - Exit status */
     41 main(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 
    491 static int				/* O - 1 if equal, 0 if not equal */
    492 dests_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 
    527 static int				/* O - 1 to continue, 0 to stop */
    528 enum_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 
    556 static void
    557 show_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