Revert manifest to default one
[external/cups.git] / systemv / lpstat.c
1 /*
2  * "$Id: lpstat.c 10064 2011-10-07 21:41:07Z mike $"
3  *
4  *   "lpstat" command for CUPS.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1997-2006 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  * Contents:
16  *
17  *   main()           - Parse options and show status information.
18  *   check_dest()     - Verify that the named destination(s) exists.
19  *   match_list()     - Match a name from a list of comma or space-separated
20  *                      names.
21  *   show_accepting() - Show acceptance status.
22  *   show_classes()   - Show printer classes.
23  *   show_default()   - Show default destination.
24  *   show_devices()   - Show printer devices.
25  *   show_jobs()      - Show active print jobs.
26  *   show_printers()  - Show printers.
27  *   show_scheduler() - Show scheduler status.
28  */
29
30 /*
31  * Include necessary headers...
32  */
33
34 #include <cups/cups-private.h>
35
36
37 /*
38  * Local functions...
39  */
40
41 static void     check_dest(const char *command, const char *name,
42                            int *num_dests, cups_dest_t **dests);
43 static int      match_list(const char *list, const char *name);
44 static int      show_accepting(const char *printers, int num_dests,
45                                cups_dest_t *dests);
46 static int      show_classes(const char *dests);
47 static void     show_default(cups_dest_t *dest);
48 static int      show_devices(const char *printers, int num_dests,
49                              cups_dest_t *dests);
50 static int      show_jobs(const char *dests, const char *users, int long_status,
51                           int ranking, const char *which);
52 static int      show_printers(const char *printers, int num_dests,
53                               cups_dest_t *dests, int long_status);
54 static void     show_scheduler(void);
55
56
57 /*
58  * 'main()' - Parse options and show status information.
59  */
60
61 int
62 main(int  argc,                         /* I - Number of command-line arguments */
63      char *argv[])                      /* I - Command-line arguments */
64 {
65   int           i,                      /* Looping var */
66                 status;                 /* Exit status */
67   int           num_dests;              /* Number of user destinations */
68   cups_dest_t   *dests;                 /* User destinations */
69   int           long_status;            /* Long status report? */
70   int           ranking;                /* Show job ranking? */
71   const char    *which;                 /* Which jobs to show? */
72   char          op;                     /* Last operation on command-line */
73
74
75   _cupsSetLocale(argv);
76
77  /*
78   * Parse command-line options...
79   */
80
81   num_dests   = 0;
82   dests       = NULL;
83   long_status = 0;
84   ranking     = 0;
85   status      = 0;
86   which       = "not-completed";
87   op          = 0;
88
89   for (i = 1; i < argc; i ++)
90     if (argv[i][0] == '-')
91       switch (argv[i][1])
92       {
93         case 'D' : /* Show description */
94             long_status = 1;
95             break;
96
97         case 'E' : /* Encrypt */
98 #ifdef HAVE_SSL
99             cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
100 #else
101             _cupsLangPrintf(stderr,
102                             _("%s: Sorry, no encryption support."),
103                             argv[0]);
104 #endif /* HAVE_SSL */
105             break;
106
107         case 'H' : /* Show server and port */
108             if (cupsServer()[0] == '/')
109               _cupsLangPuts(stdout, cupsServer());
110             else
111               _cupsLangPrintf(stdout, "%s:%d", cupsServer(), ippPort());
112             break;
113
114         case 'P' : /* Show paper types */
115             op = 'P';
116             break;
117
118         case 'R' : /* Show ranking */
119             ranking = 1;
120             break;
121
122         case 'S' : /* Show charsets */
123             op = 'S';
124             if (!argv[i][2])
125               i ++;
126             break;
127
128         case 'U' : /* Username */
129             if (argv[i][2])
130               cupsSetUser(argv[i] + 2);
131             else
132             {
133               i ++;
134               if (i >= argc)
135               {
136                 _cupsLangPrintf(stderr,
137                                 _("%s: Error - expected username after "
138                                   "\"-U\" option."),
139                                 argv[0]);
140                 return (1);
141               }
142
143               cupsSetUser(argv[i]);
144             }
145             break;
146
147         case 'W' : /* Show which jobs? */
148             if (argv[i][2])
149               which = argv[i] + 2;
150             else
151             {
152               i ++;
153
154               if (i >= argc)
155               {
156                 _cupsLangPrintf(stderr,
157                                 _("%s: Error - need \"completed\", "
158                                   "\"not-completed\", or \"all\" after "
159                                   "\"-W\" option."),
160                                 argv[0]);
161                 return (1);
162               }
163
164               which = argv[i];
165             }
166
167             if (strcmp(which, "completed") && strcmp(which, "not-completed") &&
168                 strcmp(which, "all"))
169             {
170               _cupsLangPrintf(stderr,
171                               _("%s: Error - need \"completed\", "
172                                 "\"not-completed\", or \"all\" after "
173                                 "\"-W\" option."),
174                               argv[0]);
175               return (1);
176             }
177             break;
178
179         case 'a' : /* Show acceptance status */
180             op = 'a';
181
182             if (argv[i][2])
183             {
184               check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
185
186               status |= show_accepting(argv[i] + 2, num_dests, dests);
187             }
188             else if ((i + 1) < argc && argv[i + 1][0] != '-')
189             {
190               i ++;
191
192               check_dest(argv[0], argv[i], &num_dests, &dests);
193
194               status |= show_accepting(argv[i], num_dests, dests);
195             }
196             else
197             {
198               if (num_dests <= 1)
199               {
200                 cupsFreeDests(num_dests, dests);
201                 num_dests = cupsGetDests(&dests);
202               }
203
204               status |= show_accepting(NULL, num_dests, dests);
205             }
206             break;
207
208 #ifdef __sgi
209         case 'b' : /* Show both the local and remote status */
210             op = 'b';
211
212             if (argv[i][2])
213             {
214              /*
215               * The local and remote status are separated by a blank line;
216               * since all CUPS jobs are networked, we only output the
217               * second list for now...  In the future, we might further
218               * emulate this by listing the remote server's queue, but
219               * for now this is enough to make the SGI printstatus program
220               * happy...
221               */
222
223               check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
224
225               puts("");
226               status |= show_jobs(argv[i] + 2, NULL, 3, ranking, which);
227             }
228             else
229             {
230               _cupsLangPrintf(stderr,
231                               _("%s: Error - expected destination after "
232                                 "\"-b\" option."),
233                               argv[0]);
234
235               return (1);
236             }
237             break;
238 #endif /* __sgi */
239
240         case 'c' : /* Show classes and members */
241             op = 'c';
242
243             if (argv[i][2])
244             {
245               check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
246
247               status |= show_classes(argv[i] + 2);
248             }
249             else if ((i + 1) < argc && argv[i + 1][0] != '-')
250             {
251               i ++;
252
253               check_dest(argv[0], argv[i], &num_dests, &dests);
254
255               status |= show_classes(argv[i]);
256             }
257             else
258               status |= show_classes(NULL);
259             break;
260
261         case 'd' : /* Show default destination */
262             op = 'd';
263
264             if (num_dests != 1 || !dests[0].is_default)
265             {
266               cupsFreeDests(num_dests, dests);
267
268               dests     = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
269               num_dests = dests ? 1 : 0;
270             }
271
272             show_default(dests);
273             break;
274
275         case 'f' : /* Show forms */
276             op   = 'f';
277             if (!argv[i][2])
278               i ++;
279             break;
280
281         case 'h' : /* Connect to host */
282             if (argv[i][2])
283               cupsSetServer(argv[i] + 2);
284             else
285             {
286               i ++;
287
288               if (i >= argc)
289               {
290                 _cupsLangPrintf(stderr,
291                                 _("%s: Error - expected hostname after "
292                                   "\"-h\" option."),
293                                 argv[0]);
294                 return (1);
295               }
296
297               cupsSetServer(argv[i]);
298             }
299             break;
300
301         case 'l' : /* Long status or long job status */
302 #ifdef __sgi
303             op = 'l';
304
305             if (argv[i][2])
306             {
307               check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
308
309               status |= show_jobs(argv[i] + 2, NULL, 3, ranking, which);
310             }
311             else
312 #endif /* __sgi */
313               long_status = 2;
314             break;
315
316         case 'o' : /* Show jobs by destination */
317             op = 'o';
318
319             if (argv[i][2])
320             {
321               check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
322
323               status |= show_jobs(argv[i] + 2, NULL, long_status, ranking,
324                                   which);
325             }
326             else if ((i + 1) < argc && argv[i + 1][0] != '-')
327             {
328               i ++;
329
330               check_dest(argv[0], argv[i], &num_dests, &dests);
331
332               status |= show_jobs(argv[i], NULL, long_status, ranking, which);
333             }
334             else
335               status |= show_jobs(NULL, NULL, long_status, ranking, which);
336             break;
337
338         case 'p' : /* Show printers */
339             op = 'p';
340
341             if (argv[i][2])
342             {
343               check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
344
345               status |= show_printers(argv[i] + 2, num_dests, dests,
346                                       long_status);
347             }
348             else if ((i + 1) < argc && argv[i + 1][0] != '-')
349             {
350               i ++;
351
352               check_dest(argv[0], argv[i], &num_dests, &dests);
353
354               status |= show_printers(argv[i], num_dests, dests, long_status);
355             }
356             else
357             {
358               if (num_dests <= 1)
359               {
360                 cupsFreeDests(num_dests, dests);
361                 num_dests = cupsGetDests(&dests);
362               }
363
364               status |= show_printers(NULL, num_dests, dests, long_status);
365             }
366             break;
367
368         case 'r' : /* Show scheduler status */
369             op = 'r';
370
371             show_scheduler();
372             break;
373
374         case 's' : /* Show summary */
375             op = 's';
376
377             if (num_dests <= 1)
378             {
379               cupsFreeDests(num_dests, dests);
380               num_dests = cupsGetDests(&dests);
381             }
382
383             show_default(cupsGetDest(NULL, NULL, num_dests, dests));
384             status |= show_classes(NULL);
385             status |= show_devices(NULL, num_dests, dests);
386             break;
387
388         case 't' : /* Show all info */
389             op = 't';
390
391             if (num_dests <= 1)
392             {
393               cupsFreeDests(num_dests, dests);
394               num_dests = cupsGetDests(&dests);
395             }
396
397             show_scheduler();
398             show_default(cupsGetDest(NULL, NULL, num_dests, dests));
399             status |= show_classes(NULL);
400             status |= show_devices(NULL, num_dests, dests);
401             status |= show_accepting(NULL, num_dests, dests);
402             status |= show_printers(NULL, num_dests, dests, long_status);
403             status |= show_jobs(NULL, NULL, long_status, ranking, which);
404             break;
405
406         case 'u' : /* Show jobs by user */
407             op = 'u';
408
409             if (argv[i][2])
410               status |= show_jobs(NULL, argv[i] + 2, long_status, ranking,
411                                   which);
412             else if ((i + 1) < argc && argv[i + 1][0] != '-')
413             {
414               i ++;
415               status |= show_jobs(NULL, argv[i], long_status, ranking, which);
416             }
417             else
418               status |= show_jobs(NULL, NULL, long_status, ranking, which);
419             break;
420
421         case 'v' : /* Show printer devices */
422             op = 'v';
423
424             if (argv[i][2])
425             {
426               check_dest(argv[0], argv[i] + 2, &num_dests, &dests);
427
428               status |= show_devices(argv[i] + 2, num_dests, dests);
429             }
430             else if ((i + 1) < argc && argv[i + 1][0] != '-')
431             {
432               i ++;
433
434               check_dest(argv[0], argv[i], &num_dests, &dests);
435
436               status |= show_devices(argv[i], num_dests, dests);
437             }
438             else
439             {
440               if (num_dests <= 1)
441               {
442                 cupsFreeDests(num_dests, dests);
443                 num_dests = cupsGetDests(&dests);
444               }
445
446               status |= show_devices(NULL, num_dests, dests);
447             }
448             break;
449
450         default :
451             _cupsLangPrintf(stderr,
452                             _("%s: Error - unknown option \"%c\"."),
453                             argv[0], argv[i][1]);
454             return (1);
455       }
456     else
457     {
458       status |= show_jobs(argv[i], NULL, long_status, ranking, which);
459       op = 'o';
460     }
461
462   if (!op)
463     status |= show_jobs(NULL, cupsUser(), long_status, ranking, which);
464
465   return (status);
466 }
467
468
469 /*
470  * 'check_dest()' - Verify that the named destination(s) exists.
471  */
472
473 static void
474 check_dest(const char  *command,        /* I  - Command name */
475            const char  *name,           /* I  - List of printer/class names */
476            int         *num_dests,      /* IO - Number of destinations */
477            cups_dest_t **dests)         /* IO - Destinations */
478 {
479   const char    *dptr;                  /* Pointer into name */
480   char          *pptr,                  /* Pointer into printer */
481                 printer[1024];          /* Current printer/class name */
482
483
484  /*
485   * Load the destination list as necessary...
486   */
487
488   if (*num_dests <= 1)
489   {
490     if (*num_dests)
491       cupsFreeDests(*num_dests, *dests);
492
493     if (strchr(name, ','))
494       *num_dests = cupsGetDests(dests);
495     else
496     {
497       strlcpy(printer, name, sizeof(printer));
498       if ((pptr = strchr(printer, '/')) != NULL)
499         *pptr++ = '\0';
500
501       if ((*dests = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer, pptr)) == NULL)
502       {
503         _cupsLangPrintf(stderr,
504                         _("%s: Invalid destination name in list \"%s\"."),
505                         command, name);
506         exit(1);
507       }
508       else
509       {
510         *num_dests = 1;
511         return;
512       }
513     }
514   }
515
516  /*
517   * Scan the name string for printer/class name(s)...
518   */
519
520   for (dptr = name; *dptr;)
521   {
522    /*
523     * Skip leading whitespace and commas...
524     */
525
526     while (isspace(*dptr & 255) || *dptr == ',')
527       dptr ++;
528
529     if (!*dptr)
530       break;
531
532    /*
533     * Extract a single destination name from the name string...
534     */
535
536     for (pptr = printer; !isspace(*dptr & 255) && *dptr != ',' && *dptr;)
537     {
538       if ((pptr - printer) < (sizeof(printer) - 1))
539         *pptr++ = *dptr++;
540       else
541       {
542         _cupsLangPrintf(stderr,
543                         _("%s: Invalid destination name in list \"%s\"."),
544                         command, name);
545         exit(1);
546       }
547     }
548
549     *pptr = '\0';
550
551    /*
552     * Check the destination...
553     */
554
555     if (!cupsGetDest(printer, NULL, *num_dests, *dests))
556     {
557       _cupsLangPrintf(stderr,
558                       _("%s: Unknown destination \"%s\"."), command, printer);
559       exit(1);
560     }
561   }
562 }
563
564
565 /*
566  * 'match_list()' - Match a name from a list of comma or space-separated names.
567  */
568
569 static int                              /* O - 1 on match, 0 on no match */
570 match_list(const char *list,            /* I - List of names */
571            const char *name)            /* I - Name to find */
572 {
573   const char    *nameptr;               /* Pointer into name */
574
575
576  /*
577   * An empty list always matches...
578   */
579
580   if (!list || !*list)
581     return (1);
582
583   if (!name)
584     return (0);
585
586   while (*list)
587   {
588    /*
589     * Skip leading whitespace and commas...
590     */
591
592     while (isspace(*list & 255) || *list == ',')
593       list ++;
594
595     if (!*list)
596       break;
597
598    /*
599     * Compare names...
600     */
601
602     for (nameptr = name;
603          *nameptr && *list && tolower(*nameptr & 255) == tolower(*list & 255);
604          nameptr ++, list ++);
605
606     if (!*nameptr && (!*list || *list == ',' || isspace(*list & 255)))
607       return (1);
608
609     while (*list && !isspace(*list & 255) && *list != ',')
610       list ++;
611   }
612
613   return (0);
614 }
615
616
617 /*
618  * 'show_accepting()' - Show acceptance status.
619  */
620
621 static int                              /* O - 0 on success, 1 on fail */
622 show_accepting(const char  *printers,   /* I - Destinations */
623                int         num_dests,   /* I - Number of user-defined dests */
624                cups_dest_t *dests)      /* I - User-defined destinations */
625 {
626   int           i;                      /* Looping var */
627   ipp_t         *request,               /* IPP Request */
628                 *response;              /* IPP Response */
629   ipp_attribute_t *attr;                /* Current attribute */
630   const char    *printer,               /* Printer name */
631                 *message;               /* Printer device URI */
632   int           accepting;              /* Accepting requests? */
633   time_t        ptime;                  /* Printer state time */
634   struct tm     *pdate;                 /* Printer state date & time */
635   char          printer_state_time[255];/* Printer state time */
636   static const char *pattrs[] =         /* Attributes we need for printers... */
637                 {
638                   "printer-name",
639                   "printer-state-change-time",
640                   "printer-state-message",
641                   "printer-is-accepting-jobs"
642                 };
643
644
645   DEBUG_printf(("show_accepting(printers=\"%s\")\n", printers));
646
647   if (printers != NULL && !strcmp(printers, "all"))
648     printers = NULL;
649
650  /*
651   * Build a CUPS_GET_PRINTERS request, which requires the following
652   * attributes:
653   *
654   *    attributes-charset
655   *    attributes-natural-language
656   *    requested-attributes
657   *    requesting-user-name
658   */
659
660   request = ippNewRequest(CUPS_GET_PRINTERS);
661
662   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
663                 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
664                 NULL, pattrs);
665
666   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
667                NULL, cupsUser());
668
669  /*
670   * Do the request and get back a response...
671   */
672
673   if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
674   {
675     DEBUG_puts("show_accepting: request succeeded...");
676
677     if (response->request.status.status_code > IPP_OK_CONFLICT)
678     {
679       _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
680       ippDelete(response);
681       return (1);
682     }
683
684    /*
685     * Loop through the printers returned in the list and display
686     * their devices...
687     */
688
689     for (attr = response->attrs; attr != NULL; attr = attr->next)
690     {
691      /*
692       * Skip leading attributes until we hit a printer...
693       */
694
695       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
696         attr = attr->next;
697
698       if (attr == NULL)
699         break;
700
701      /*
702       * Pull the needed attributes from this printer...
703       */
704
705       printer   = NULL;
706       message   = NULL;
707       accepting = 1;
708       ptime     = 0;
709
710       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
711       {
712         if (!strcmp(attr->name, "printer-name") &&
713             attr->value_tag == IPP_TAG_NAME)
714           printer = attr->values[0].string.text;
715         else if (!strcmp(attr->name, "printer-state-change-time") &&
716                  attr->value_tag == IPP_TAG_INTEGER)
717           ptime = (time_t)attr->values[0].integer;
718         else if (!strcmp(attr->name, "printer-state-message") &&
719                  attr->value_tag == IPP_TAG_TEXT)
720           message = attr->values[0].string.text;
721         else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
722                  attr->value_tag == IPP_TAG_BOOLEAN)
723           accepting = attr->values[0].boolean;
724
725         attr = attr->next;
726       }
727
728      /*
729       * See if we have everything needed...
730       */
731
732       if (printer == NULL)
733       {
734         if (attr == NULL)
735           break;
736         else
737           continue;
738       }
739
740      /*
741       * Display the printer entry if needed...
742       */
743
744       if (match_list(printers, printer))
745       {
746         pdate = localtime(&ptime);
747         strftime(printer_state_time, sizeof(printer_state_time), "%c", pdate);
748
749         if (accepting)
750           _cupsLangPrintf(stdout, _("%s accepting requests since %s"),
751                           printer, printer_state_time);
752         else
753         {
754           _cupsLangPrintf(stdout, _("%s not accepting requests since %s -"),
755                           printer, printer_state_time);
756           _cupsLangPrintf(stdout, _("\t%s"),
757                           (message == NULL || !*message) ?
758                               "reason unknown" : message);
759         }
760
761         for (i = 0; i < num_dests; i ++)
762           if (!_cups_strcasecmp(dests[i].name, printer) && dests[i].instance)
763           {
764             if (accepting)
765               _cupsLangPrintf(stdout, _("%s/%s accepting requests since %s"),
766                               printer, dests[i].instance, printer_state_time);
767             else
768             {
769               _cupsLangPrintf(stdout,
770                               _("%s/%s not accepting requests since %s -"),
771                               printer, dests[i].instance, printer_state_time);
772               _cupsLangPrintf(stdout, _("\t%s"),
773                               (message == NULL || !*message) ?
774                                   "reason unknown" : message);
775             }
776           }
777       }
778
779       if (attr == NULL)
780         break;
781     }
782
783     ippDelete(response);
784   }
785   else
786   {
787     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
788     return (1);
789   }
790
791   return (0);
792 }
793
794
795 /*
796  * 'show_classes()' - Show printer classes.
797  */
798
799 static int                              /* O - 0 on success, 1 on fail */
800 show_classes(const char *dests)         /* I - Destinations */
801 {
802   int           i;                      /* Looping var */
803   ipp_t         *request,               /* IPP Request */
804                 *response,              /* IPP Response */
805                 *response2;             /* IPP response from remote server */
806   http_t        *http2;                 /* Remote server */
807   ipp_attribute_t *attr;                /* Current attribute */
808   const char    *printer,               /* Printer class name */
809                 *printer_uri;           /* Printer class URI */
810   ipp_attribute_t *members;             /* Printer members */
811   char          method[HTTP_MAX_URI],   /* Request method */
812                 username[HTTP_MAX_URI], /* Username:password */
813                 server[HTTP_MAX_URI],   /* Server name */
814                 resource[HTTP_MAX_URI]; /* Resource name */
815   int           port;                   /* Port number */
816   static const char *cattrs[] =         /* Attributes we need for classes... */
817                 {
818                   "printer-name",
819                   "printer-uri-supported",
820                   "member-names"
821                 };
822
823
824   DEBUG_printf(("show_classes(dests=\"%s\")\n", dests));
825
826   if (dests != NULL && !strcmp(dests, "all"))
827     dests = NULL;
828
829  /*
830   * Build a CUPS_GET_CLASSES request, which requires the following
831   * attributes:
832   *
833   *    attributes-charset
834   *    attributes-natural-language
835   *    requested-attributes
836   *    requesting-user-name
837   */
838
839   request = ippNewRequest(CUPS_GET_CLASSES);
840
841   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
842                 "requested-attributes", sizeof(cattrs) / sizeof(cattrs[0]),
843                 NULL, cattrs);
844
845   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
846                NULL, cupsUser());
847
848  /*
849   * Do the request and get back a response...
850   */
851
852   if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
853   {
854     DEBUG_puts("show_classes: request succeeded...");
855
856     if (response->request.status.status_code > IPP_OK_CONFLICT)
857     {
858       _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
859       ippDelete(response);
860       return (1);
861     }
862
863    /*
864     * Loop through the printers returned in the list and display
865     * their devices...
866     */
867
868     for (attr = response->attrs; attr != NULL; attr = attr->next)
869     {
870      /*
871       * Skip leading attributes until we hit a job...
872       */
873
874       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
875         attr = attr->next;
876
877       if (attr == NULL)
878         break;
879
880      /*
881       * Pull the needed attributes from this job...
882       */
883
884       printer     = NULL;
885       printer_uri = NULL;
886       members     = NULL;
887
888       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
889       {
890         if (!strcmp(attr->name, "printer-name") &&
891             attr->value_tag == IPP_TAG_NAME)
892           printer = attr->values[0].string.text;
893
894         if (!strcmp(attr->name, "printer-uri-supported") &&
895             attr->value_tag == IPP_TAG_URI)
896           printer_uri = attr->values[0].string.text;
897
898         if (!strcmp(attr->name, "member-names") &&
899             attr->value_tag == IPP_TAG_NAME)
900           members = attr;
901
902         attr = attr->next;
903       }
904
905      /*
906       * If this is a remote class, grab the class info from the
907       * remote server...
908       */
909
910       response2 = NULL;
911       if (members == NULL && printer_uri != NULL)
912       {
913         httpSeparateURI(HTTP_URI_CODING_ALL, printer_uri, method, sizeof(method),
914                         username, sizeof(username), server, sizeof(server),
915                         &port, resource, sizeof(resource));
916
917         if (!_cups_strcasecmp(server, cupsServer()))
918           http2 = CUPS_HTTP_DEFAULT;
919         else
920           http2 = httpConnectEncrypt(server, port, cupsEncryption());
921
922        /*
923         * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
924         * following attributes:
925         *
926         *    attributes-charset
927         *    attributes-natural-language
928         *    printer-uri
929         *    requested-attributes
930         */
931
932         request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
933
934         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
935                      "printer-uri", NULL, printer_uri);
936
937         ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
938                       "requested-attributes",
939                       sizeof(cattrs) / sizeof(cattrs[0]),
940                       NULL, cattrs);
941
942         if ((response2 = cupsDoRequest(http2, request, "/")) != NULL)
943           members = ippFindAttribute(response2, "member-names", IPP_TAG_NAME);
944
945         if (http2)
946           httpClose(http2);
947       }
948
949      /*
950       * See if we have everything needed...
951       */
952
953       if (printer == NULL)
954       {
955         if (response2)
956           ippDelete(response2);
957
958         if (attr == NULL)
959           break;
960         else
961           continue;
962       }
963
964      /*
965       * Display the printer entry if needed...
966       */
967
968       if (match_list(dests, printer))
969       {
970         _cupsLangPrintf(stdout, _("members of class %s:"), printer);
971
972         if (members)
973         {
974           for (i = 0; i < members->num_values; i ++)
975             _cupsLangPrintf(stdout, "\t%s", members->values[i].string.text);
976         }
977         else
978           _cupsLangPuts(stdout, "\tunknown");
979       }
980
981       if (response2)
982         ippDelete(response2);
983
984       if (attr == NULL)
985         break;
986     }
987
988     ippDelete(response);
989   }
990   else
991   {
992     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
993     return (1);
994   }
995
996   return (0);
997 }
998
999
1000 /*
1001  * 'show_default()' - Show default destination.
1002  */
1003
1004 static void
1005 show_default(cups_dest_t *dest)         /* I - Default destination */
1006 {
1007   const char    *printer,               /* Printer name */
1008                 *val;                   /* Environment variable name */
1009
1010
1011   if (dest)
1012   {
1013     if (dest->instance)
1014       _cupsLangPrintf(stdout, _("system default destination: %s/%s"),
1015                       dest->name, dest->instance);
1016     else
1017       _cupsLangPrintf(stdout, _("system default destination: %s"),
1018                       dest->name);
1019   }
1020   else
1021   {
1022     val = NULL;
1023
1024     if ((printer = getenv("LPDEST")) == NULL)
1025     {
1026       if ((printer = getenv("PRINTER")) != NULL)
1027       {
1028         if (!strcmp(printer, "lp"))
1029           printer = NULL;
1030         else
1031           val = "PRINTER";
1032       }
1033     }
1034     else
1035       val = "LPDEST";
1036
1037     if (printer)
1038       _cupsLangPrintf(stdout,
1039                       _("lpstat: error - %s environment variable names "
1040                         "non-existent destination \"%s\"."),
1041                       val, printer);
1042     else
1043       _cupsLangPuts(stdout, _("no system default destination"));
1044   }
1045 }
1046
1047
1048 /*
1049  * 'show_devices()' - Show printer devices.
1050  */
1051
1052 static int                              /* O - 0 on success, 1 on fail */
1053 show_devices(const char  *printers,     /* I - Destinations */
1054              int         num_dests,     /* I - Number of user-defined dests */
1055              cups_dest_t *dests)        /* I - User-defined destinations */
1056 {
1057   int           i;                      /* Looping var */
1058   ipp_t         *request,               /* IPP Request */
1059                 *response;              /* IPP Response */
1060   ipp_attribute_t *attr;                /* Current attribute */
1061   const char    *printer,               /* Printer name */
1062                 *uri,                   /* Printer URI */
1063                 *device;                /* Printer device URI */
1064   static const char *pattrs[] =         /* Attributes we need for printers... */
1065                 {
1066                   "printer-name",
1067                   "printer-uri-supported",
1068                   "device-uri"
1069                 };
1070
1071
1072   DEBUG_printf(("show_devices(printers=\"%s\")\n", printers));
1073
1074   if (printers != NULL && !strcmp(printers, "all"))
1075     printers = NULL;
1076
1077  /*
1078   * Build a CUPS_GET_PRINTERS request, which requires the following
1079   * attributes:
1080   *
1081   *    attributes-charset
1082   *    attributes-natural-language
1083   *    requested-attributes
1084   *    requesting-user-name
1085   */
1086
1087   request = ippNewRequest(CUPS_GET_PRINTERS);
1088
1089   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1090                 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
1091                 NULL, pattrs);
1092
1093   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1094                NULL, cupsUser());
1095
1096  /*
1097   * Do the request and get back a response...
1098   */
1099
1100   if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
1101   {
1102     DEBUG_puts("show_devices: request succeeded...");
1103
1104     if (response->request.status.status_code > IPP_OK_CONFLICT)
1105     {
1106       _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
1107       ippDelete(response);
1108       return (1);
1109     }
1110
1111    /*
1112     * Loop through the printers returned in the list and display
1113     * their devices...
1114     */
1115
1116     for (attr = response->attrs; attr != NULL; attr = attr->next)
1117     {
1118      /*
1119       * Skip leading attributes until we hit a job...
1120       */
1121
1122       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1123         attr = attr->next;
1124
1125       if (attr == NULL)
1126         break;
1127
1128      /*
1129       * Pull the needed attributes from this job...
1130       */
1131
1132       printer = NULL;
1133       device  = NULL;
1134       uri     = NULL;
1135
1136       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
1137       {
1138         if (!strcmp(attr->name, "printer-name") &&
1139             attr->value_tag == IPP_TAG_NAME)
1140           printer = attr->values[0].string.text;
1141
1142         if (!strcmp(attr->name, "printer-uri-supported") &&
1143             attr->value_tag == IPP_TAG_URI)
1144           uri = attr->values[0].string.text;
1145
1146         if (!strcmp(attr->name, "device-uri") &&
1147             attr->value_tag == IPP_TAG_URI)
1148           device = attr->values[0].string.text;
1149
1150         attr = attr->next;
1151       }
1152
1153      /*
1154       * See if we have everything needed...
1155       */
1156
1157       if (printer == NULL)
1158       {
1159         if (attr == NULL)
1160           break;
1161         else
1162           continue;
1163       }
1164
1165      /*
1166       * Display the printer entry if needed...
1167       */
1168
1169       if (match_list(printers, printer))
1170       {
1171 #ifdef __osf__ /* Compaq/Digital like to do it their own way... */
1172         char    scheme[HTTP_MAX_URI],   /* Components of printer URI */
1173                 username[HTTP_MAX_URI],
1174                 hostname[HTTP_MAX_URI],
1175                 resource[HTTP_MAX_URI];
1176         int     port;
1177
1178
1179         if (device == NULL)
1180         {
1181           httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
1182                           username, sizeof(username), hostname,
1183                           sizeof(hostname), &port, resource, sizeof(resource));
1184           _cupsLangPrintf(stdout,
1185                           _("Output for printer %s is sent to remote "
1186                             "printer %s on %s"),
1187                           printer, strrchr(resource, '/') + 1, hostname);
1188         }
1189         else if (!strncmp(device, "file:", 5))
1190           _cupsLangPrintf(stdout,
1191                           _("Output for printer %s is sent to %s"),
1192                           printer, device + 5);
1193         else
1194           _cupsLangPrintf(stdout,
1195                           _("Output for printer %s is sent to %s"),
1196                           printer, device);
1197
1198         for (i = 0; i < num_dests; i ++)
1199           if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance)
1200           {
1201             if (device == NULL)
1202               _cupsLangPrintf(stdout,
1203                               _("Output for printer %s/%s is sent to "
1204                                 "remote printer %s on %s"),
1205                               printer, dests[i].instance,
1206                               strrchr(resource, '/') + 1, hostname);
1207             else if (!strncmp(device, "file:", 5))
1208               _cupsLangPrintf(stdout,
1209                               _("Output for printer %s/%s is sent to %s"),
1210                               printer, dests[i].instance, device + 5);
1211             else
1212               _cupsLangPrintf(stdout,
1213                               _("Output for printer %s/%s is sent to %s"),
1214                               printer, dests[i].instance, device);
1215           }
1216 #else
1217         if (device == NULL)
1218           _cupsLangPrintf(stdout, _("device for %s: %s"),
1219                           printer, uri);
1220         else if (!strncmp(device, "file:", 5))
1221           _cupsLangPrintf(stdout, _("device for %s: %s"),
1222                           printer, device + 5);
1223         else
1224           _cupsLangPrintf(stdout, _("device for %s: %s"),
1225                           printer, device);
1226
1227         for (i = 0; i < num_dests; i ++)
1228           if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance)
1229           {
1230             if (device == NULL)
1231               _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
1232                               printer, dests[i].instance, uri);
1233             else if (!strncmp(device, "file:", 5))
1234               _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
1235                               printer, dests[i].instance, device + 5);
1236             else
1237               _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
1238                               printer, dests[i].instance, device);
1239           }
1240 #endif /* __osf__ */
1241       }
1242
1243       if (attr == NULL)
1244         break;
1245     }
1246
1247     ippDelete(response);
1248   }
1249   else
1250   {
1251     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
1252     return (1);
1253   }
1254
1255   return (0);
1256 }
1257
1258
1259 /*
1260  * 'show_jobs()' - Show active print jobs.
1261  */
1262
1263 static int                              /* O - 0 on success, 1 on fail */
1264 show_jobs(const char *dests,            /* I - Destinations */
1265           const char *users,            /* I - Users */
1266           int        long_status,       /* I - Show long status? */
1267           int        ranking,           /* I - Show job ranking? */
1268           const char *which)            /* I - Show which jobs? */
1269 {
1270   int           i;                      /* Looping var */
1271   ipp_t         *request,               /* IPP Request */
1272                 *response;              /* IPP Response */
1273   ipp_attribute_t *attr,                /* Current attribute */
1274                 *reasons;               /* Job state reasons attribute */
1275   const char    *dest,                  /* Pointer into job-printer-uri */
1276                 *username,              /* Pointer to job-originating-user-name */
1277                 *title,                 /* Pointer to job-name */
1278                 *message;               /* Pointer to job-printer-state-message */
1279   int           rank,                   /* Rank in queue */
1280                 jobid,                  /* job-id */
1281                 size;                   /* job-k-octets */
1282   time_t        jobtime;                /* time-at-creation */
1283   struct tm     *jobdate;               /* Date & time */
1284   char          temp[255],              /* Temporary buffer */
1285                 date[255];              /* Date buffer */
1286   static const char *jattrs[] =         /* Attributes we need for jobs... */
1287                 {
1288                   "job-id",
1289                   "job-k-octets",
1290                   "job-name",
1291                   "job-originating-user-name",
1292                   "job-printer-state-message",
1293                   "job-printer-uri",
1294                   "job-state-reasons",
1295                   "time-at-creation"
1296                 };
1297
1298
1299   DEBUG_printf(("show_jobs(dests=\"%s\", users=\"%s\", long_status=%d, "
1300                 "ranking=%d, which=\"%s\")\n", dests, users, long_status,
1301                 ranking, which));
1302
1303   if (dests != NULL && !strcmp(dests, "all"))
1304     dests = NULL;
1305
1306  /*
1307   * Build a IPP_GET_JOBS request, which requires the following
1308   * attributes:
1309   *
1310   *    attributes-charset
1311   *    attributes-natural-language
1312   *    printer-uri
1313   *    requested-attributes
1314   *    requesting-user-name
1315   *    which-jobs
1316   */
1317
1318   request = ippNewRequest(IPP_GET_JOBS);
1319
1320   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1321                NULL, "ipp://localhost/");
1322
1323   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1324                 "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
1325                 NULL, jattrs);
1326
1327   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1328                NULL, cupsUser());
1329
1330   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
1331                NULL, which);
1332
1333  /*
1334   * Do the request and get back a response...
1335   */
1336
1337   if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
1338   {
1339    /*
1340     * Loop through the job list and display them...
1341     */
1342
1343     if (response->request.status.status_code > IPP_OK_CONFLICT)
1344     {
1345       _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
1346       ippDelete(response);
1347       return (1);
1348     }
1349
1350     rank = -1;
1351
1352     for (attr = response->attrs; attr != NULL; attr = attr->next)
1353     {
1354      /*
1355       * Skip leading attributes until we hit a job...
1356       */
1357
1358       while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1359         attr = attr->next;
1360
1361       if (attr == NULL)
1362         break;
1363
1364      /*
1365       * Pull the needed attributes from this job...
1366       */
1367
1368       jobid    = 0;
1369       size     = 0;
1370       username = NULL;
1371       dest     = NULL;
1372       jobtime  = 0;
1373       title    = "no title";
1374       message  = NULL;
1375       reasons  = NULL;
1376
1377       while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
1378       {
1379         if (!strcmp(attr->name, "job-id") &&
1380             attr->value_tag == IPP_TAG_INTEGER)
1381           jobid = attr->values[0].integer;
1382         else if (!strcmp(attr->name, "job-k-octets") &&
1383                  attr->value_tag == IPP_TAG_INTEGER)
1384           size = attr->values[0].integer;
1385         else if (!strcmp(attr->name, "time-at-creation") &&
1386                  attr->value_tag == IPP_TAG_INTEGER)
1387           jobtime = attr->values[0].integer;
1388         else if (!strcmp(attr->name, "job-printer-state-message") &&
1389                  attr->value_tag == IPP_TAG_TEXT)
1390           message = attr->values[0].string.text;
1391         else if (!strcmp(attr->name, "job-printer-uri") &&
1392                  attr->value_tag == IPP_TAG_URI)
1393         {
1394           if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
1395             dest ++;
1396         }
1397         else if (!strcmp(attr->name, "job-originating-user-name") &&
1398                  attr->value_tag == IPP_TAG_NAME)
1399           username = attr->values[0].string.text;
1400         else if (!strcmp(attr->name, "job-name") &&
1401                  attr->value_tag == IPP_TAG_NAME)
1402           title = attr->values[0].string.text;
1403         else if (!strcmp(attr->name, "job-state-reasons") &&
1404                  attr->value_tag == IPP_TAG_KEYWORD)
1405           reasons = attr;
1406
1407         attr = attr->next;
1408       }
1409
1410      /*
1411       * See if we have everything needed...
1412       */
1413
1414       if (dest == NULL || jobid == 0)
1415       {
1416         if (attr == NULL)
1417           break;
1418         else
1419           continue;
1420       }
1421
1422      /*
1423       * Display the job...
1424       */
1425
1426       rank ++;
1427
1428       if (match_list(dests, dest) && match_list(users, username))
1429       {
1430         jobdate = localtime(&jobtime);
1431         snprintf(temp, sizeof(temp), "%s-%d", dest, jobid);
1432
1433         if (long_status == 3)
1434         {
1435          /*
1436           * Show the consolidated output format for the SGI tools...
1437           */
1438
1439           if (!strftime(date, sizeof(date), "%b %d %H:%M", jobdate))
1440             strcpy(date, "Unknown");
1441
1442           _cupsLangPrintf(stdout, "%s;%s;%d;%s;%s",
1443                           temp, username ? username : "unknown",
1444                           size, title ? title : "unknown", date);
1445         }
1446         else
1447         {
1448           if (!strftime(date, sizeof(date), "%c", jobdate))
1449             strcpy(date, "Unknown");
1450
1451           if (ranking)
1452             _cupsLangPrintf(stdout, "%3d %-21s %-13s %8.0f %s",
1453                             rank, temp, username ? username : "unknown",
1454                             1024.0 * size, date);
1455           else
1456             _cupsLangPrintf(stdout, "%-23s %-13s %8.0f   %s",
1457                             temp, username ? username : "unknown",
1458                             1024.0 * size, date);
1459           if (long_status)
1460           {
1461             if (message)
1462               _cupsLangPrintf(stdout, _("\tStatus: %s"), message);
1463
1464             if (reasons)
1465             {
1466               char      alerts[1024],   /* Alerts string */
1467                         *aptr;          /* Pointer into alerts string */
1468
1469               for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
1470               {
1471                 if (i)
1472                   snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s",
1473                            reasons->values[i].string.text);
1474                 else
1475                   strlcpy(alerts, reasons->values[i].string.text,
1476                           sizeof(alerts));
1477
1478                 aptr += strlen(aptr);
1479               }
1480
1481               _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
1482             }
1483
1484             _cupsLangPrintf(stdout, _("\tqueued for %s"), dest);
1485           }
1486         }
1487       }
1488
1489       if (attr == NULL)
1490         break;
1491     }
1492
1493     ippDelete(response);
1494   }
1495   else
1496   {
1497     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
1498     return (1);
1499   }
1500
1501   return (0);
1502 }
1503
1504
1505 /*
1506  * 'show_printers()' - Show printers.
1507  */
1508
1509 static int                              /* O - 0 on success, 1 on fail */
1510 show_printers(const char  *printers,    /* I - Destinations */
1511               int         num_dests,    /* I - Number of user-defined dests */
1512               cups_dest_t *dests,       /* I - User-defined destinations */
1513               int         long_status)  /* I - Show long status? */
1514 {
1515   int           i, j;                   /* Looping vars */
1516   ipp_t         *request,               /* IPP Request */
1517                 *response,              /* IPP Response */
1518                 *jobs;                  /* IPP Get Jobs response */
1519   ipp_attribute_t *attr,                /* Current attribute */
1520                 *jobattr,               /* Job ID attribute */
1521                 *reasons;               /* Job state reasons attribute */
1522   const char    *printer,               /* Printer name */
1523                 *message,               /* Printer state message */
1524                 *description,           /* Description of printer */
1525                 *location,              /* Location of printer */
1526                 *make_model,            /* Make and model of printer */
1527                 *uri;                   /* URI of printer */
1528   ipp_attribute_t *allowed,             /* requesting-user-name-allowed */
1529                 *denied;                /* requestint-user-name-denied */
1530   ipp_pstate_t  pstate;                 /* Printer state */
1531   cups_ptype_t  ptype;                  /* Printer type */
1532   time_t        ptime;                  /* Printer state time */
1533   struct tm     *pdate;                 /* Printer state date & time */
1534   int           jobid;                  /* Job ID of current job */
1535   char          printer_uri[HTTP_MAX_URI],
1536                                         /* Printer URI */
1537                 printer_state_time[255];/* Printer state time */
1538   _cups_globals_t *cg = _cupsGlobals(); /* Global data */
1539   static const char *pattrs[] =         /* Attributes we need for printers... */
1540                 {
1541                   "printer-name",
1542                   "printer-state",
1543                   "printer-state-message",
1544                   "printer-state-reasons",
1545                   "printer-state-change-time",
1546                   "printer-type",
1547                   "printer-info",
1548                   "printer-location",
1549                   "printer-make-and-model",
1550                   "printer-uri-supported",
1551                   "requesting-user-name-allowed",
1552                   "requesting-user-name-denied"
1553                 };
1554   static const char *jattrs[] =         /* Attributes we need for jobs... */
1555                 {
1556                   "job-id",
1557                   "job-state"
1558                 };
1559
1560
1561   DEBUG_printf(("show_printers(printers=\"%s\", num_dests=%d, dests=%p, "
1562                 "long_status=%d)\n", printers, num_dests, dests, long_status));
1563
1564   if (printers != NULL && !strcmp(printers, "all"))
1565     printers = NULL;
1566
1567  /*
1568   * Build a CUPS_GET_PRINTERS request, which requires the following
1569   * attributes:
1570   *
1571   *    attributes-charset
1572   *    attributes-natural-language
1573   *    requested-attributes
1574   *    requesting-user-name
1575   */
1576
1577   request = ippNewRequest(CUPS_GET_PRINTERS);
1578
1579   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1580                 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
1581                 NULL, pattrs);
1582
1583   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1584                NULL, cupsUser());
1585
1586  /*
1587   * Do the request and get back a response...
1588   */
1589
1590   if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
1591   {
1592     DEBUG_puts("show_printers: request succeeded...");
1593
1594     if (response->request.status.status_code > IPP_OK_CONFLICT)
1595     {
1596       _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
1597       ippDelete(response);
1598       return (1);
1599     }
1600
1601    /*
1602     * Loop through the printers returned in the list and display
1603     * their status...
1604     */
1605
1606     for (attr = response->attrs; attr != NULL; attr = attr->next)
1607     {
1608      /*
1609       * Skip leading attributes until we hit a job...
1610       */
1611
1612       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1613         attr = attr->next;
1614
1615       if (attr == NULL)
1616         break;
1617
1618      /*
1619       * Pull the needed attributes from this job...
1620       */
1621
1622       printer     = NULL;
1623       ptime       = 0;
1624       ptype       = CUPS_PRINTER_LOCAL;
1625       pstate      = IPP_PRINTER_IDLE;
1626       message     = NULL;
1627       description = NULL;
1628       location    = NULL;
1629       make_model  = NULL;
1630       reasons     = NULL;
1631       uri         = NULL;
1632       jobid       = 0;
1633       allowed     = NULL;
1634       denied      = NULL;
1635
1636       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
1637       {
1638         if (!strcmp(attr->name, "printer-name") &&
1639             attr->value_tag == IPP_TAG_NAME)
1640           printer = attr->values[0].string.text;
1641         else if (!strcmp(attr->name, "printer-state") &&
1642                  attr->value_tag == IPP_TAG_ENUM)
1643           pstate = (ipp_pstate_t)attr->values[0].integer;
1644         else if (!strcmp(attr->name, "printer-type") &&
1645                  attr->value_tag == IPP_TAG_ENUM)
1646           ptype = (cups_ptype_t)attr->values[0].integer;
1647         else if (!strcmp(attr->name, "printer-state-message") &&
1648                  attr->value_tag == IPP_TAG_TEXT)
1649           message = attr->values[0].string.text;
1650         else if (!strcmp(attr->name, "printer-state-change-time") &&
1651                  attr->value_tag == IPP_TAG_INTEGER)
1652           ptime = (time_t)attr->values[0].integer;
1653         else if (!strcmp(attr->name, "printer-info") &&
1654                  attr->value_tag == IPP_TAG_TEXT)
1655           description = attr->values[0].string.text;
1656         else if (!strcmp(attr->name, "printer-location") &&
1657                  attr->value_tag == IPP_TAG_TEXT)
1658           location = attr->values[0].string.text;
1659         else if (!strcmp(attr->name, "printer-make-and-model") &&
1660                  attr->value_tag == IPP_TAG_TEXT)
1661           make_model = attr->values[0].string.text;
1662         else if (!strcmp(attr->name, "printer-uri-supported") &&
1663                  attr->value_tag == IPP_TAG_URI)
1664           uri = attr->values[0].string.text;
1665         else if (!strcmp(attr->name, "printer-state-reasons") &&
1666                  attr->value_tag == IPP_TAG_KEYWORD)
1667           reasons = attr;
1668         else if (!strcmp(attr->name, "requesting-user-name-allowed") &&
1669                  attr->value_tag == IPP_TAG_NAME)
1670           allowed = attr;
1671         else if (!strcmp(attr->name, "requesting-user-name-denied") &&
1672                  attr->value_tag == IPP_TAG_NAME)
1673           denied = attr;
1674
1675         attr = attr->next;
1676       }
1677
1678      /*
1679       * See if we have everything needed...
1680       */
1681
1682       if (printer == NULL)
1683       {
1684         if (attr == NULL)
1685           break;
1686         else
1687           continue;
1688       }
1689
1690      /*
1691       * Display the printer entry if needed...
1692       */
1693
1694       if (match_list(printers, printer))
1695       {
1696        /*
1697         * If the printer state is "IPP_PRINTER_PROCESSING", then grab the
1698         * current job for the printer.
1699         */
1700
1701         if (pstate == IPP_PRINTER_PROCESSING)
1702         {
1703          /*
1704           * Build an IPP_GET_JOBS request, which requires the following
1705           * attributes:
1706           *
1707           *    attributes-charset
1708           *    attributes-natural-language
1709           *    printer-uri
1710           *    limit
1711           *    requested-attributes
1712           */
1713
1714           request = ippNewRequest(IPP_GET_JOBS);
1715
1716           request->request.op.operation_id = IPP_GET_JOBS;
1717           request->request.op.request_id   = 1;
1718
1719           ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1720                         "requested-attributes",
1721                         sizeof(jattrs) / sizeof(jattrs[0]), NULL, jattrs);
1722
1723           httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
1724                            "ipp", NULL, "localhost", 0, "/printers/%s", printer);
1725           ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1726                        "printer-uri", NULL, printer_uri);
1727
1728           if ((jobs = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
1729           {
1730            /*
1731             * Get the current active job on this queue...
1732             */
1733
1734             ipp_jstate_t jobstate = IPP_JOB_PENDING;
1735             jobid = 0;
1736
1737             for (jobattr = jobs->attrs; jobattr; jobattr = jobattr->next)
1738             {
1739               if (!jobattr->name)
1740               {
1741                 if (jobstate == IPP_JOB_PROCESSING)
1742                   break;
1743                 else
1744                   continue;
1745               }
1746
1747               if (!strcmp(jobattr->name, "job-id") &&
1748                   jobattr->value_tag == IPP_TAG_INTEGER)
1749                 jobid = jobattr->values[0].integer;
1750               else if (!strcmp(jobattr->name, "job-state") &&
1751                        jobattr->value_tag == IPP_TAG_ENUM)
1752                 jobstate = jobattr->values[0].integer;
1753             }
1754
1755             if (jobstate != IPP_JOB_PROCESSING)
1756               jobid = 0;
1757
1758             ippDelete(jobs);
1759           }
1760         }
1761
1762        /*
1763         * Display it...
1764         */
1765
1766         pdate = localtime(&ptime);
1767         strftime(printer_state_time, sizeof(printer_state_time), "%c", pdate);
1768
1769         switch (pstate)
1770         {
1771           case IPP_PRINTER_IDLE :
1772               _cupsLangPrintf(stdout,
1773                               _("printer %s is idle.  enabled since %s"),
1774                               printer, printer_state_time);
1775               break;
1776           case IPP_PRINTER_PROCESSING :
1777               _cupsLangPrintf(stdout,
1778                               _("printer %s now printing %s-%d.  "
1779                                 "enabled since %s"),
1780                               printer, printer, jobid, printer_state_time);
1781               break;
1782           case IPP_PRINTER_STOPPED :
1783               _cupsLangPrintf(stdout,
1784                               _("printer %s disabled since %s -"),
1785                               printer, printer_state_time);
1786               break;
1787         }
1788
1789         if ((message && *message) || pstate == IPP_PRINTER_STOPPED)
1790         {
1791           if (!message || !*message)
1792             _cupsLangPuts(stdout, _("\treason unknown"));
1793           else
1794             _cupsLangPrintf(stdout, "\t%s", message);
1795         }
1796
1797         if (long_status > 1)
1798         {
1799           _cupsLangPuts(stdout, _("\tForm mounted:"));
1800           _cupsLangPuts(stdout, _("\tContent types: any"));
1801           _cupsLangPuts(stdout, _("\tPrinter types: unknown"));
1802         }
1803
1804         if (long_status)
1805         {
1806           _cupsLangPrintf(stdout, _("\tDescription: %s"),
1807                           description ? description : "");
1808
1809           if (reasons)
1810           {
1811             char        alerts[1024],   /* Alerts string */
1812                         *aptr;          /* Pointer into alerts string */
1813
1814             for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
1815             {
1816               if (i)
1817                 snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s",
1818                          reasons->values[i].string.text);
1819               else
1820                 strlcpy(alerts, reasons->values[i].string.text,
1821                         sizeof(alerts));
1822
1823               aptr += strlen(aptr);
1824             }
1825
1826             _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
1827           }
1828         }
1829         if (long_status > 1)
1830         {
1831           _cupsLangPrintf(stdout, _("\tLocation: %s"),
1832                           location ? location : "");
1833
1834           if (ptype & CUPS_PRINTER_REMOTE)
1835           {
1836             _cupsLangPuts(stdout, _("\tConnection: remote"));
1837
1838             if (make_model && !strstr(make_model, "System V Printer") &&
1839                      !strstr(make_model, "Raw Printer") && uri)
1840               _cupsLangPrintf(stdout, _("\tInterface: %s.ppd"),
1841                               uri);
1842           }
1843           else
1844           {
1845             _cupsLangPuts(stdout, _("\tConnection: direct"));
1846
1847             if (make_model && strstr(make_model, "System V Printer"))
1848               _cupsLangPrintf(stdout,
1849                               _("\tInterface: %s/interfaces/%s"),
1850                               cg->cups_serverroot, printer);
1851             else if (make_model && !strstr(make_model, "Raw Printer"))
1852               _cupsLangPrintf(stdout,
1853                               _("\tInterface: %s/ppd/%s.ppd"),
1854                               cg->cups_serverroot, printer);
1855           }
1856           _cupsLangPuts(stdout, _("\tOn fault: no alert"));
1857           _cupsLangPuts(stdout, _("\tAfter fault: continue"));
1858               /* TODO update to use printer-error-policy */
1859           if (allowed)
1860           {
1861             _cupsLangPuts(stdout, _("\tUsers allowed:"));
1862             for (j = 0; j < allowed->num_values; j ++)
1863               _cupsLangPrintf(stdout, "\t\t%s",
1864                               allowed->values[j].string.text);
1865           }
1866           else if (denied)
1867           {
1868             _cupsLangPuts(stdout, _("\tUsers denied:"));
1869             for (j = 0; j < denied->num_values; j ++)
1870               _cupsLangPrintf(stdout, "\t\t%s",
1871                               denied->values[j].string.text);
1872           }
1873           else
1874           {
1875             _cupsLangPuts(stdout, _("\tUsers allowed:"));
1876             _cupsLangPuts(stdout, _("\t\t(all)"));
1877           }
1878           _cupsLangPuts(stdout, _("\tForms allowed:"));
1879           _cupsLangPuts(stdout, _("\t\t(none)"));
1880           _cupsLangPuts(stdout, _("\tBanner required"));
1881           _cupsLangPuts(stdout, _("\tCharset sets:"));
1882           _cupsLangPuts(stdout, _("\t\t(none)"));
1883           _cupsLangPuts(stdout, _("\tDefault pitch:"));
1884           _cupsLangPuts(stdout, _("\tDefault page size:"));
1885           _cupsLangPuts(stdout, _("\tDefault port settings:"));
1886         }
1887
1888         for (i = 0; i < num_dests; i ++)
1889           if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance)
1890           {
1891             switch (pstate)
1892             {
1893               case IPP_PRINTER_IDLE :
1894                   _cupsLangPrintf(stdout,
1895                                   _("printer %s/%s is idle.  "
1896                                     "enabled since %s"),
1897                                   printer, dests[i].instance,
1898                                   printer_state_time);
1899                   break;
1900               case IPP_PRINTER_PROCESSING :
1901                   _cupsLangPrintf(stdout,
1902                                   _("printer %s/%s now printing %s-%d.  "
1903                                     "enabled since %s"),
1904                                   printer, dests[i].instance, printer, jobid,
1905                                   printer_state_time);
1906                   break;
1907               case IPP_PRINTER_STOPPED :
1908                   _cupsLangPrintf(stdout,
1909                                   _("printer %s/%s disabled since %s -"),
1910                                   printer, dests[i].instance,
1911                                   printer_state_time);
1912                   break;
1913             }
1914
1915             if ((message && *message) || pstate == IPP_PRINTER_STOPPED)
1916             {
1917               if (!message || !*message)
1918                 _cupsLangPuts(stdout, _("\treason unknown"));
1919               else
1920                 _cupsLangPrintf(stdout, "\t%s", message);
1921             }
1922
1923             if (long_status > 1)
1924             {
1925               _cupsLangPuts(stdout, _("\tForm mounted:"));
1926               _cupsLangPuts(stdout, _("\tContent types: any"));
1927               _cupsLangPuts(stdout, _("\tPrinter types: unknown"));
1928             }
1929
1930             if (long_status)
1931             {
1932               _cupsLangPrintf(stdout, _("\tDescription: %s"),
1933                               description ? description : "");
1934
1935               if (reasons)
1936               {
1937                 char    alerts[1024],   /* Alerts string */
1938                         *aptr;          /* Pointer into alerts string */
1939
1940                 for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
1941                 {
1942                   if (i)
1943                     snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s",
1944                              reasons->values[i].string.text);
1945                   else
1946                     strlcpy(alerts, reasons->values[i].string.text,
1947                             sizeof(alerts));
1948
1949                   aptr += strlen(aptr);
1950                 }
1951
1952                 _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
1953               }
1954             }
1955             if (long_status > 1)
1956             {
1957               _cupsLangPrintf(stdout, _("\tLocation: %s"),
1958                               location ? location : "");
1959
1960               if (ptype & CUPS_PRINTER_REMOTE)
1961               {
1962                 _cupsLangPuts(stdout, _("\tConnection: remote"));
1963
1964                 if (make_model && !strstr(make_model, "System V Printer") &&
1965                          !strstr(make_model, "Raw Printer") && uri)
1966                   _cupsLangPrintf(stdout, _("\tInterface: %s.ppd"), uri);
1967               }
1968               else
1969               {
1970                 _cupsLangPuts(stdout, _("\tConnection: direct"));
1971
1972                 if (make_model && strstr(make_model, "System V Printer"))
1973                   _cupsLangPrintf(stdout,
1974                                   _("\tInterface: %s/interfaces/%s"),
1975                                   cg->cups_serverroot, printer);
1976                 else if (make_model && !strstr(make_model, "Raw Printer"))
1977                   _cupsLangPrintf(stdout,
1978                                   _("\tInterface: %s/ppd/%s.ppd"),
1979                                   cg->cups_serverroot, printer);
1980               }
1981               _cupsLangPuts(stdout, _("\tOn fault: no alert"));
1982               _cupsLangPuts(stdout, _("\tAfter fault: continue"));
1983                   /* TODO update to use printer-error-policy */
1984               if (allowed)
1985               {
1986                 _cupsLangPuts(stdout, _("\tUsers allowed:"));
1987                 for (j = 0; j < allowed->num_values; j ++)
1988                   _cupsLangPrintf(stdout, "\t\t%s",
1989                                   allowed->values[j].string.text);
1990               }
1991               else if (denied)
1992               {
1993                 _cupsLangPuts(stdout, _("\tUsers denied:"));
1994                 for (j = 0; j < denied->num_values; j ++)
1995                   _cupsLangPrintf(stdout, "\t\t%s",
1996                                   denied->values[j].string.text);
1997               }
1998               else
1999               {
2000                 _cupsLangPuts(stdout, _("\tUsers allowed:"));
2001                 _cupsLangPuts(stdout, _("\t\t(all)"));
2002               }
2003               _cupsLangPuts(stdout, _("\tForms allowed:"));
2004               _cupsLangPuts(stdout, _("\t\t(none)"));
2005               _cupsLangPuts(stdout, _("\tBanner required"));
2006               _cupsLangPuts(stdout, _("\tCharset sets:"));
2007               _cupsLangPuts(stdout, _("\t\t(none)"));
2008               _cupsLangPuts(stdout, _("\tDefault pitch:"));
2009               _cupsLangPuts(stdout, _("\tDefault page size:"));
2010               _cupsLangPuts(stdout, _("\tDefault port settings:"));
2011             }
2012           }
2013       }
2014
2015       if (attr == NULL)
2016         break;
2017     }
2018
2019     ippDelete(response);
2020   }
2021   else
2022   {
2023     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
2024     return (1);
2025   }
2026
2027   return (0);
2028 }
2029
2030
2031 /*
2032  * 'show_scheduler()' - Show scheduler status.
2033  */
2034
2035 static void
2036 show_scheduler(void)
2037 {
2038   http_t        *http;                  /* Connection to server */
2039
2040
2041   if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
2042                                  cupsEncryption())) != NULL)
2043   {
2044     _cupsLangPuts(stdout, _("scheduler is running"));
2045     httpClose(http);
2046   }
2047   else
2048     _cupsLangPuts(stdout, _("scheduler is not running"));
2049 }
2050
2051
2052 /*
2053  * End of "$Id: lpstat.c 10064 2011-10-07 21:41:07Z mike $".
2054  */