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