2 * "$Id: lpstat.c,v 1.50 2002/12/17 19:00:21 swdev Exp $"
4 * "lpstat" command for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2003 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Parse options and show status information.
27 * check_dest() - Verify that the named destination(s) exists.
28 * show_accepting() - Show acceptance status.
29 * show_classes() - Show printer classes.
30 * show_default() - Show default destination.
31 * show_devices() - Show printer devices.
32 * show_jobs() - Show active print jobs.
33 * show_printers() - Show printers.
34 * show_scheduler() - Show scheduler status.
38 * Include necessary headers...
44 #include <cups/cups.h>
45 #include <cups/language.h>
46 #include <cups/debug.h>
47 #include <cups/string.h>
54 static void check_dest(const char *, int *, cups_dest_t
**);
55 static int show_accepting(http_t
*, const char *, int, cups_dest_t
*);
56 static int show_classes(http_t
*, const char *);
57 static void show_default(int, cups_dest_t
*);
58 static int show_devices(http_t
*, const char *, int, cups_dest_t
*);
59 static int show_jobs(http_t
*, const char *, const char *, int, int,
61 static int show_printers(http_t
*, const char *, int, cups_dest_t
*, int);
62 static void show_scheduler(http_t
*);
66 * 'main()' - Parse options and show status information.
70 main(int argc
, /* I - Number of command-line arguments */
71 char *argv
[]) /* I - Command-line arguments */
73 int i
, /* Looping var */
74 status
; /* Exit status */
75 http_t
*http
; /* Connection to server */
76 int num_dests
; /* Number of user destinations */
77 cups_dest_t
*dests
; /* User destinations */
78 int long_status
; /* Long status report? */
79 int ranking
; /* Show job ranking? */
80 const char *which
; /* Which jobs to show? */
84 setlocale(LC_TIME
, "");
93 which
= "not-completed";
95 for (i
= 1; i
< argc
; i
++)
96 if (argv
[i
][0] == '-')
99 case 'D' : /* Show description */
103 case 'E' : /* Encrypt */
105 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED
);
108 httpEncryption(http
, HTTP_ENCRYPT_REQUIRED
);
110 fprintf(stderr
, "%s: Sorry, no encryption support compiled in!\n",
112 #endif /* HAVE_LIBSSL */
115 case 'P' : /* Show paper types */
118 case 'R' : /* Show ranking */
122 case 'S' : /* Show charsets */
127 case 'W' : /* Show which jobs? */
136 fputs("lpstat: Need \"completed\" or \"not-completed\" after -W!\n",
144 if (strcmp(which
, "completed") && strcmp(which
, "not-completed"))
146 fputs("lpstat: Need \"completed\" or \"not-completed\" after -W!\n",
152 case 'a' : /* Show acceptance status */
155 http
= httpConnectEncrypt(cupsServer(), ippPort(),
160 perror("lpstat: Unable to connect to server");
165 if (argv
[i
][2] != '\0')
167 check_dest(argv
[i
] + 2, &num_dests
, &dests
);
169 status
|= show_accepting(http
, argv
[i
] + 2, num_dests
, dests
);
171 else if ((i
+ 1) < argc
&& argv
[i
+ 1][0] != '-')
175 check_dest(argv
[i
], &num_dests
, &dests
);
177 status
|= show_accepting(http
, argv
[i
], num_dests
, dests
);
182 num_dests
= cupsGetDests(&dests
);
184 status
|= show_accepting(http
, NULL
, num_dests
, dests
);
189 case 'b' : /* Show both the local and remote status */
192 http
= httpConnectEncrypt(cupsServer(), ippPort(),
197 perror("lpstat: Unable to connect to server");
202 if (argv
[i
][2] != '\0')
205 * The local and remote status are separated by a blank line;
206 * since all CUPS jobs are networked, we only output the
207 * second list for now... In the future, we might further
208 * emulate this by listing the remote server's queue, but
209 * for now this is enough to make the SGI printstatus program
213 check_dest(argv
[i
] + 2, &num_dests
, &dests
);
216 status
|= show_jobs(http
, argv
[i
] + 2, NULL
, 3, ranking
, which
);
220 fputs("lpstat: The -b option requires a destination argument.\n",
228 case 'c' : /* Show classes and members */
231 http
= httpConnectEncrypt(cupsServer(), ippPort(),
236 perror("lpstat: Unable to connect to server");
241 if (argv
[i
][2] != '\0')
243 check_dest(argv
[i
] + 2, &num_dests
, &dests
);
245 status
|= show_classes(http
, argv
[i
] + 2);
247 else if ((i
+ 1) < argc
&& argv
[i
+ 1][0] != '-')
251 check_dest(argv
[i
], &num_dests
, &dests
);
253 status
|= show_classes(http
, argv
[i
]);
256 status
|= show_classes(http
, NULL
);
259 case 'd' : /* Show default destination */
261 num_dests
= cupsGetDests(&dests
);
263 show_default(num_dests
, dests
);
266 case 'f' : /* Show forms */
271 case 'h' : /* Connect to host */
278 if (argv
[i
][2] != '\0')
279 cupsSetServer(argv
[i
] + 2);
286 fputs("Error: need hostname after \'-h\' option!\n", stderr
);
290 cupsSetServer(argv
[i
]);
294 case 'l' : /* Long status or long job status */
298 http
= httpConnectEncrypt(cupsServer(), ippPort(),
303 perror("lpstat: Unable to connect to server");
308 if (argv
[i
][2] != '\0')
310 check_dest(argv
[i
] + 2, &num_dests
, &dests
);
312 status
|= show_jobs(http
, argv
[i
] + 2, NULL
, 3, ranking
, which
);
319 case 'o' : /* Show jobs by destination */
322 http
= httpConnectEncrypt(cupsServer(), ippPort(),
327 perror("lpstat: Unable to connect to server");
332 if (argv
[i
][2] != '\0')
334 check_dest(argv
[i
] + 2, &num_dests
, &dests
);
336 status
|= show_jobs(http
, argv
[i
] + 2, NULL
, long_status
,
339 else if ((i
+ 1) < argc
&& argv
[i
+ 1][0] != '-')
343 check_dest(argv
[i
], &num_dests
, &dests
);
345 status
|= show_jobs(http
, argv
[i
], NULL
, long_status
,
349 status
|= show_jobs(http
, NULL
, NULL
, long_status
,
353 case 'p' : /* Show printers */
356 http
= httpConnectEncrypt(cupsServer(), ippPort(),
361 perror("lpstat: Unable to connect to server");
366 if (argv
[i
][2] != '\0')
368 check_dest(argv
[i
] + 2, &num_dests
, &dests
);
370 status
|= show_printers(http
, argv
[i
] + 2, num_dests
, dests
, long_status
);
372 else if ((i
+ 1) < argc
&& argv
[i
+ 1][0] != '-')
376 check_dest(argv
[i
], &num_dests
, &dests
);
378 status
|= show_printers(http
, argv
[i
], num_dests
, dests
, long_status
);
383 num_dests
= cupsGetDests(&dests
);
385 status
|= show_printers(http
, NULL
, num_dests
, dests
, long_status
);
389 case 'r' : /* Show scheduler status */
392 http
= httpConnectEncrypt(cupsServer(), ippPort(),
397 perror("lpstat: Unable to connect to server");
402 show_scheduler(http
);
405 case 's' : /* Show summary */
408 http
= httpConnectEncrypt(cupsServer(), ippPort(),
413 perror("lpstat: Unable to connect to server");
419 num_dests
= cupsGetDests(&dests
);
421 show_default(num_dests
, dests
);
422 status
|= show_classes(http
, NULL
);
423 status
|= show_devices(http
, NULL
, num_dests
, dests
);
426 case 't' : /* Show all info */
429 http
= httpConnectEncrypt(cupsServer(), ippPort(),
434 perror("lpstat: Unable to connect to server");
440 num_dests
= cupsGetDests(&dests
);
442 show_scheduler(http
);
443 show_default(num_dests
, dests
);
444 status
|= show_classes(http
, NULL
);
445 status
|= show_devices(http
, NULL
, num_dests
, dests
);
446 status
|= show_accepting(http
, NULL
, num_dests
, dests
);
447 status
|= show_printers(http
, NULL
, num_dests
, dests
, long_status
);
448 status
|= show_jobs(http
, NULL
, NULL
, long_status
, ranking
, which
);
451 case 'u' : /* Show jobs by user */
454 http
= httpConnectEncrypt(cupsServer(), ippPort(),
459 perror("lpstat: Unable to connect to server");
464 if (argv
[i
][2] != '\0')
465 status
|= show_jobs(http
, NULL
, argv
[i
] + 2, long_status
,
467 else if ((i
+ 1) < argc
&& argv
[i
+ 1][0] != '-')
470 status
|= show_jobs(http
, NULL
, argv
[i
], long_status
,
474 status
|= show_jobs(http
, NULL
, NULL
, long_status
,
478 case 'v' : /* Show printer devices */
481 http
= httpConnectEncrypt(cupsServer(), ippPort(),
486 perror("lpstat: Unable to connect to server");
491 if (argv
[i
][2] != '\0')
493 check_dest(argv
[i
] + 2, &num_dests
, &dests
);
495 status
|= show_devices(http
, argv
[i
] + 2, num_dests
, dests
);
497 else if ((i
+ 1) < argc
&& argv
[i
+ 1][0] != '-')
501 check_dest(argv
[i
], &num_dests
, &dests
);
503 status
|= show_devices(http
, argv
[i
], num_dests
, dests
);
508 num_dests
= cupsGetDests(&dests
);
510 status
|= show_devices(http
, NULL
, num_dests
, dests
);
516 fprintf(stderr
, "lpstat: Unknown option \'%c\'!\n", argv
[i
][1]);
523 http
= httpConnectEncrypt(cupsServer(), ippPort(),
528 perror("lpstat: Unable to connect to server");
533 status
|= show_jobs(http
, argv
[i
], NULL
, long_status
, ranking
, which
);
540 http
= httpConnectEncrypt(cupsServer(), ippPort(),
545 perror("lpstat: Unable to connect to server");
550 status
|= show_jobs(http
, NULL
, cupsUser(), long_status
, ranking
, which
);
558 * 'check_dest()' - Verify that the named destination(s) exists.
562 check_dest(const char *name
, /* I - Name of printer/class(es) */
563 int *num_dests
, /* IO - Number of destinations */
564 cups_dest_t
**dests
) /* IO - Destinations */
572 * Load the destination list as necessary...
576 *num_dests
= cupsGetDests(dests
);
579 * Scan the name string for printer/class name(s)...
582 for (dptr
= name
; *dptr
!= '\0';)
585 * Skip leading whitespace and commas...
588 while (isspace(*dptr
) || *dptr
== ',')
595 * Extract a single destination name from the name string...
598 for (pptr
= printer
; !isspace(*dptr
) && *dptr
!= ',' && *dptr
!= '\0';)
600 if ((pptr
- printer
) < (sizeof(printer
) - 1))
604 fprintf(stderr
, "lpstat: Invalid destination name in list \"%s\"!\n", name
);
612 * Check the destination...
615 if (cupsGetDest(printer
, NULL
, *num_dests
, *dests
) == NULL
)
617 fprintf(stderr
, "lpstat: Unknown destination \"%s\"!\n", printer
);
625 * 'show_accepting()' - Show acceptance status.
628 static int /* O - 0 on success, 1 on fail */
629 show_accepting(http_t
*http
, /* I - HTTP connection to server */
630 const char *printers
, /* I - Destinations */
631 int num_dests
, /* I - Number of user-defined dests */
632 cups_dest_t
*dests
) /* I - User-defined destinations */
634 int i
; /* Looping var */
635 ipp_t
*request
, /* IPP Request */
636 *response
; /* IPP Response */
637 ipp_attribute_t
*attr
; /* Current attribute */
638 cups_lang_t
*language
; /* Default language */
639 const char *printer
, /* Printer name */
640 *message
; /* Printer device URI */
641 int accepting
; /* Accepting requests? */
642 const char *dptr
, /* Pointer into destination list */
643 *ptr
; /* Pointer into printer name */
644 int match
; /* Non-zero if this job matches */
645 static const char *pattrs
[] = /* Attributes we need for printers... */
648 "printer-state-message",
649 "printer-is-accepting-jobs"
653 DEBUG_printf(("show_accepting(%p, %p)\n", http
, printers
));
658 if (printers
!= NULL
&& strcmp(printers
, "all") == 0)
662 * Build a CUPS_GET_PRINTERS request, which requires the following
666 * attributes-natural-language
667 * requested-attributes
672 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
673 request
->request
.op
.request_id
= 1;
675 language
= cupsLangDefault();
677 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
678 "attributes-charset", NULL
, cupsLangEncoding(language
));
680 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
681 "attributes-natural-language", NULL
, language
->language
);
683 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
684 "requested-attributes", sizeof(pattrs
) / sizeof(pattrs
[0]),
688 * Do the request and get back a response...
691 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
693 DEBUG_puts("show_accepting: request succeeded...");
695 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
697 fprintf(stderr
, "lpstat: get-printers failed: %s\n",
698 ippErrorString(response
->request
.status
.status_code
));
704 * Loop through the printers returned in the list and display
708 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
711 * Skip leading attributes until we hit a printer...
714 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
721 * Pull the needed attributes from this printer...
728 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
730 if (strcmp(attr
->name
, "printer-name") == 0 &&
731 attr
->value_tag
== IPP_TAG_NAME
)
732 printer
= attr
->values
[0].string
.text
;
734 if (strcmp(attr
->name
, "printer-state-message") == 0 &&
735 attr
->value_tag
== IPP_TAG_TEXT
)
736 message
= attr
->values
[0].string
.text
;
738 if (strcmp(attr
->name
, "printer-is-accepting-jobs") == 0 &&
739 attr
->value_tag
== IPP_TAG_BOOLEAN
)
740 accepting
= attr
->values
[0].boolean
;
746 * See if we have everything needed...
758 * See if this is a printer we're interested in...
761 match
= printers
== NULL
;
763 if (printers
!= NULL
)
765 for (dptr
= printers
; *dptr
!= '\0';)
768 * Skip leading whitespace and commas...
771 while (isspace(*dptr
) || *dptr
== ',')
782 *ptr
!= '\0' && *dptr
!= '\0' && tolower(*ptr
) == tolower(*dptr
);
785 if (*ptr
== '\0' && (*dptr
== '\0' || *dptr
== ',' || isspace(*dptr
)))
792 * Skip trailing junk...
795 while (!isspace(*dptr
) && *dptr
!= ',' && *dptr
!= '\0')
797 while (isspace(*dptr
) || *dptr
== ',')
806 * Display the printer entry if needed...
812 printf("%s accepting requests since Jan 01 00:00\n", printer
);
814 printf("%s not accepting requests since Jan 01 00:00 -\n\t%s\n", printer
,
815 message
== NULL
? "reason unknown" : message
);
817 for (i
= 0; i
< num_dests
; i
++)
818 if (strcasecmp(dests
[i
].name
, printer
) == 0 && dests
[i
].instance
)
821 printf("%s/%s accepting requests since Jan 01 00:00\n", printer
, dests
[i
].instance
);
823 printf("%s/%s not accepting requests since Jan 01 00:00 -\n\t%s\n", printer
,
825 message
== NULL
? "reason unknown" : message
);
837 fprintf(stderr
, "lpstat: get-printers failed: %s\n",
838 ippErrorString(cupsLastError()));
847 * 'show_classes()' - Show printer classes.
850 static int /* O - 0 on success, 1 on fail */
851 show_classes(http_t
*http
, /* I - HTTP connection to server */
852 const char *dests
) /* I - Destinations */
854 int i
; /* Looping var */
855 ipp_t
*request
, /* IPP Request */
856 *response
, /* IPP Response */
857 *response2
; /* IPP response from remote server */
858 http_t
*http2
; /* Remote server */
859 ipp_attribute_t
*attr
; /* Current attribute */
860 cups_lang_t
*language
; /* Default language */
861 const char *printer
, /* Printer class name */
862 *printer_uri
; /* Printer class URI */
863 ipp_attribute_t
*members
; /* Printer members */
864 char method
[HTTP_MAX_URI
], /* Request method */
865 username
[HTTP_MAX_URI
], /* Username:password */
866 server
[HTTP_MAX_URI
], /* Server name */
867 resource
[HTTP_MAX_URI
]; /* Resource name */
868 int port
; /* Port number */
869 const char *dptr
, /* Pointer into destination list */
870 *ptr
; /* Pointer into printer name */
871 int match
; /* Non-zero if this job matches */
872 static const char *cattrs
[] = /* Attributes we need for classes... */
875 "printer-uri-supported",
880 DEBUG_printf(("show_classes(%p, %p)\n", http
, dests
));
885 if (dests
!= NULL
&& strcmp(dests
, "all") == 0)
889 * Build a CUPS_GET_CLASSES request, which requires the following
893 * attributes-natural-language
894 * requested-attributes
899 request
->request
.op
.operation_id
= CUPS_GET_CLASSES
;
900 request
->request
.op
.request_id
= 1;
902 language
= cupsLangDefault();
904 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
905 "attributes-charset", NULL
, cupsLangEncoding(language
));
907 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
908 "attributes-natural-language", NULL
, language
->language
);
910 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
911 "requested-attributes", sizeof(cattrs
) / sizeof(cattrs
[0]),
915 * Do the request and get back a response...
918 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
920 DEBUG_puts("show_classes: request succeeded...");
922 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
924 fprintf(stderr
, "lpstat: get-classes failed: %s\n",
925 ippErrorString(response
->request
.status
.status_code
));
931 * Loop through the printers returned in the list and display
935 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
938 * Skip leading attributes until we hit a job...
941 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
948 * Pull the needed attributes from this job...
955 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
957 if (strcmp(attr
->name
, "printer-name") == 0 &&
958 attr
->value_tag
== IPP_TAG_NAME
)
959 printer
= attr
->values
[0].string
.text
;
961 if (strcmp(attr
->name
, "printer-uri-supported") == 0 &&
962 attr
->value_tag
== IPP_TAG_URI
)
963 printer_uri
= attr
->values
[0].string
.text
;
965 if (strcmp(attr
->name
, "member-names") == 0 &&
966 attr
->value_tag
== IPP_TAG_NAME
)
973 * If this is a remote class, grab the class info from the
978 if (members
== NULL
&& printer_uri
!= NULL
)
980 httpSeparate(printer_uri
, method
, username
, server
, &port
, resource
);
982 if ((http2
= httpConnectEncrypt(server
, port
, cupsEncryption())) != NULL
)
985 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
986 * following attributes:
989 * attributes-natural-language
991 * requested-attributes
996 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
997 request
->request
.op
.request_id
= 1;
999 language
= cupsLangDefault();
1001 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1002 "attributes-charset", NULL
, cupsLangEncoding(language
));
1004 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1005 "attributes-natural-language", NULL
, language
->language
);
1007 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1008 "printer-uri", NULL
, printer_uri
);
1010 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1011 "requested-attributes", sizeof(cattrs
) / sizeof(cattrs
[0]),
1014 if ((response2
= cupsDoRequest(http2
, request
, "/")) != NULL
)
1015 members
= ippFindAttribute(response2
, "member-names", IPP_TAG_NAME
);
1022 * See if we have everything needed...
1025 if (printer
== NULL
)
1028 ippDelete(response2
);
1037 * See if this is a printer we're interested in...
1040 match
= dests
== NULL
;
1044 for (dptr
= dests
; *dptr
!= '\0';)
1047 * Skip leading whitespace and commas...
1050 while (isspace(*dptr
) || *dptr
== ',')
1061 *ptr
!= '\0' && *dptr
!= '\0' && tolower(*ptr
) == tolower(*dptr
);
1064 if (*ptr
== '\0' && (*dptr
== '\0' || *dptr
== ',' || isspace(*dptr
)))
1071 * Skip trailing junk...
1074 while (!isspace(*dptr
) && *dptr
!= ',' && *dptr
!= '\0')
1076 while (isspace(*dptr
) || *dptr
== ',')
1085 * Display the printer entry if needed...
1090 printf("members of class %s:\n", printer
);
1094 for (i
= 0; i
< members
->num_values
; i
++)
1095 printf("\t%s\n", members
->values
[i
].string
.text
);
1102 ippDelete(response2
);
1108 ippDelete(response
);
1112 fprintf(stderr
, "lpstat: get-classes failed: %s\n",
1113 ippErrorString(cupsLastError()));
1122 * 'show_default()' - Show default destination.
1126 show_default(int num_dests
, /* I - Number of user-defined dests */
1127 cups_dest_t
*dests
) /* I - User-defined destinations */
1129 int i
; /* Looping var */
1132 for (i
= 0; i
< num_dests
; i
++)
1133 if (dests
[i
].is_default
)
1138 if (dests
[i
].instance
)
1139 printf("system default destination: %s/%s\n", dests
[i
].name
,
1142 printf("system default destination: %s\n", dests
[i
].name
);
1145 puts("no system default destination");
1150 * 'show_devices()' - Show printer devices.
1153 static int /* O - 0 on success, 1 on fail */
1154 show_devices(http_t
*http
, /* I - HTTP connection to server */
1155 const char *printers
, /* I - Destinations */
1156 int num_dests
, /* I - Number of user-defined dests */
1157 cups_dest_t
*dests
) /* I - User-defined destinations */
1159 int i
; /* Looping var */
1160 ipp_t
*request
, /* IPP Request */
1161 *response
; /* IPP Response */
1162 ipp_attribute_t
*attr
; /* Current attribute */
1163 cups_lang_t
*language
; /* Default language */
1164 const char *printer
, /* Printer name */
1165 *uri
, /* Printer URI */
1166 *device
, /* Printer device URI */
1167 *dptr
, /* Pointer into destination list */
1168 *ptr
; /* Pointer into printer name */
1169 int match
; /* Non-zero if this job matches */
1170 static const char *pattrs
[] = /* Attributes we need for printers... */
1173 "printer-uri-supported",
1178 DEBUG_printf(("show_devices(%p, %p)\n", http
, dests
));
1183 if (printers
!= NULL
&& strcmp(printers
, "all") == 0)
1187 * Build a CUPS_GET_PRINTERS request, which requires the following
1190 * attributes-charset
1191 * attributes-natural-language
1192 * requested-attributes
1197 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
1198 request
->request
.op
.request_id
= 1;
1200 language
= cupsLangDefault();
1202 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1203 "attributes-charset", NULL
, cupsLangEncoding(language
));
1205 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1206 "attributes-natural-language", NULL
, language
->language
);
1208 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1209 "requested-attributes", sizeof(pattrs
) / sizeof(pattrs
[0]),
1213 * Do the request and get back a response...
1216 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1218 DEBUG_puts("show_devices: request succeeded...");
1220 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1222 fprintf(stderr
, "lpstat: get-printers failed: %s\n",
1223 ippErrorString(response
->request
.status
.status_code
));
1224 ippDelete(response
);
1229 * Loop through the printers returned in the list and display
1233 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1236 * Skip leading attributes until we hit a job...
1239 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
1246 * Pull the needed attributes from this job...
1253 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
1255 if (strcmp(attr
->name
, "printer-name") == 0 &&
1256 attr
->value_tag
== IPP_TAG_NAME
)
1257 printer
= attr
->values
[0].string
.text
;
1259 if (strcmp(attr
->name
, "printer-uri-supported") == 0 &&
1260 attr
->value_tag
== IPP_TAG_URI
)
1261 uri
= attr
->values
[0].string
.text
;
1263 if (strcmp(attr
->name
, "device-uri") == 0 &&
1264 attr
->value_tag
== IPP_TAG_URI
)
1265 device
= attr
->values
[0].string
.text
;
1271 * See if we have everything needed...
1274 if (printer
== NULL
)
1283 * See if this is a printer we're interested in...
1286 match
= printers
== NULL
;
1288 if (printers
!= NULL
)
1290 for (dptr
= printers
; *dptr
!= '\0';)
1293 * Skip leading whitespace and commas...
1296 while (isspace(*dptr
) || *dptr
== ',')
1307 *ptr
!= '\0' && *dptr
!= '\0' && tolower(*ptr
) == tolower(*dptr
);
1310 if (*ptr
== '\0' && (*dptr
== '\0' || *dptr
== ',' || isspace(*dptr
)))
1317 * Skip trailing junk...
1320 while (!isspace(*dptr
) && *dptr
!= ',' && *dptr
!= '\0')
1322 while (isspace(*dptr
) || *dptr
== ',')
1331 * Display the printer entry if needed...
1336 #ifdef __osf__ /* Compaq/Digital like to do it their own way... */
1337 char method
[HTTP_MAX_URI
], /* Components of printer URI */
1338 username
[HTTP_MAX_URI
],
1339 hostname
[HTTP_MAX_URI
],
1340 resource
[HTTP_MAX_URI
];
1346 httpSeparate(uri
, method
, username
, hostname
, &port
, resource
);
1347 printf("Output for printer %s is sent to remote printer %s on %s\n",
1348 printer
, strrchr(resource
, '/') + 1, hostname
);
1350 else if (strncmp(device
, "file:", 5) == 0)
1351 printf("Output for printer %s is sent to %s\n", printer
, device
+ 5);
1353 printf("Output for printer %s is sent to %s\n", printer
, device
);
1355 for (i
= 0; i
< num_dests
; i
++)
1356 if (strcasecmp(printer
, dests
[i
].name
) == 0 && dests
[i
].instance
)
1359 printf("Output for printer %s/%s is sent to remote printer %s on %s\n",
1360 printer
, dests
[i
].instance
, strrchr(resource
, '/') + 1,
1362 else if (strncmp(device
, "file:", 5) == 0)
1363 printf("Output for printer %s/%s is sent to %s\n", printer
, dests
[i
].instance
, device
+ 5);
1365 printf("Output for printer %s/%s is sent to %s\n", printer
, dests
[i
].instance
, device
);
1369 printf("device for %s: %s\n", printer
, uri
);
1370 else if (strncmp(device
, "file:", 5) == 0)
1371 printf("device for %s: %s\n", printer
, device
+ 5);
1373 printf("device for %s: %s\n", printer
, device
);
1375 for (i
= 0; i
< num_dests
; i
++)
1376 if (strcasecmp(printer
, dests
[i
].name
) == 0 && dests
[i
].instance
)
1379 printf("device for %s/%s: %s\n", printer
, dests
[i
].instance
, uri
);
1380 else if (strncmp(device
, "file:", 5) == 0)
1381 printf("device for %s/%s: %s\n", printer
, dests
[i
].instance
, device
+ 5);
1383 printf("device for %s/%s: %s\n", printer
, dests
[i
].instance
, device
);
1385 #endif /* __osf__ */
1392 ippDelete(response
);
1396 fprintf(stderr
, "lpstat: get-printers failed: %s\n",
1397 ippErrorString(cupsLastError()));
1406 * 'show_jobs()' - Show active print jobs.
1409 static int /* O - 0 on success, 1 on fail */
1410 show_jobs(http_t
*http
, /* I - HTTP connection to server */
1411 const char *dests
, /* I - Destinations */
1412 const char *users
, /* I - Users */
1413 int long_status
, /* I - Show long status? */
1414 int ranking
, /* I - Show job ranking? */
1415 const char *which
) /* I - Show which jobs? */
1417 ipp_t
*request
, /* IPP Request */
1418 *response
; /* IPP Response */
1419 ipp_attribute_t
*attr
; /* Current attribute */
1420 cups_lang_t
*language
; /* Default language */
1421 const char *dest
, /* Pointer into job-printer-uri */
1422 *username
, /* Pointer to job-originating-user-name */
1423 *title
; /* Pointer to job-name */
1424 int rank
, /* Rank in queue */
1426 size
; /* job-k-octets */
1427 time_t jobtime
; /* time-at-creation */
1428 struct tm
*jobdate
; /* Date & time */
1429 const char *dptr
, /* Pointer into destination list */
1430 *ptr
; /* Pointer into printer name */
1431 int match
; /* Non-zero if this job matches */
1432 char temp
[255], /* Temporary buffer */
1433 date
[32]; /* Date buffer */
1434 static const char *jattrs
[] = /* Attributes we need for jobs... */
1441 "job-originating-user-name"
1445 DEBUG_printf(("show_jobs(%p, %p, %p)\n", http
, dests
, users
));
1450 if (dests
!= NULL
&& strcmp(dests
, "all") == 0)
1454 * Build a IPP_GET_JOBS request, which requires the following
1457 * attributes-charset
1458 * attributes-natural-language
1460 * requested-attributes
1465 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
1466 request
->request
.op
.request_id
= 1;
1468 language
= cupsLangDefault();
1470 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1471 "attributes-charset", NULL
, cupsLangEncoding(language
));
1473 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1474 "attributes-natural-language", NULL
, language
->language
);
1476 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1477 "requested-attributes", sizeof(jattrs
) / sizeof(jattrs
[0]),
1480 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
1481 NULL
, "ipp://localhost/jobs/");
1483 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
, "which-jobs",
1487 * Do the request and get back a response...
1490 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1493 * Loop through the job list and display them...
1496 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1498 fprintf(stderr
, "lpstat: get-jobs failed: %s\n",
1499 ippErrorString(response
->request
.status
.status_code
));
1500 ippDelete(response
);
1506 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1509 * Skip leading attributes until we hit a job...
1512 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
1519 * Pull the needed attributes from this job...
1529 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
1531 if (strcmp(attr
->name
, "job-id") == 0 &&
1532 attr
->value_tag
== IPP_TAG_INTEGER
)
1533 jobid
= attr
->values
[0].integer
;
1535 if (strcmp(attr
->name
, "job-k-octets") == 0 &&
1536 attr
->value_tag
== IPP_TAG_INTEGER
)
1537 size
= attr
->values
[0].integer
* 1024;
1539 if (strcmp(attr
->name
, "time-at-creation") == 0 &&
1540 attr
->value_tag
== IPP_TAG_INTEGER
)
1541 jobtime
= attr
->values
[0].integer
;
1543 if (strcmp(attr
->name
, "job-printer-uri") == 0 &&
1544 attr
->value_tag
== IPP_TAG_URI
)
1545 if ((dest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
1548 if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
1549 attr
->value_tag
== IPP_TAG_NAME
)
1550 username
= attr
->values
[0].string
.text
;
1552 if (strcmp(attr
->name
, "job-name") == 0 &&
1553 attr
->value_tag
== IPP_TAG_NAME
)
1554 title
= attr
->values
[0].string
.text
;
1560 * See if we have everything needed...
1563 if (dest
== NULL
|| jobid
== 0)
1572 * See if this is a job we're interested in...
1575 match
= (dests
== NULL
&& users
== NULL
);
1580 for (dptr
= dests
; *dptr
!= '\0';)
1583 * Skip leading whitespace and commas...
1586 while (isspace(*dptr
) || *dptr
== ',')
1597 *ptr
!= '\0' && *dptr
!= '\0' && tolower(*ptr
) == tolower(*dptr
);
1600 if (*ptr
== '\0' && (*dptr
== '\0' || *dptr
== ',' || isspace(*dptr
)))
1607 * Skip trailing junk...
1610 while (!isspace(*dptr
) && *dptr
!= ',' && *dptr
!= '\0')
1612 while (isspace(*dptr
) || *dptr
== ',')
1620 if (users
!= NULL
&& username
!= NULL
)
1622 for (dptr
= users
; *dptr
!= '\0';)
1625 * Skip leading whitespace and commas...
1628 while (isspace(*dptr
) || *dptr
== ',')
1638 for (ptr
= username
;
1639 *ptr
!= '\0' && *dptr
!= '\0' && *ptr
== *dptr
;
1642 if (*ptr
== '\0' && (*dptr
== '\0' || *dptr
== ',' || isspace(*dptr
)))
1649 * Skip trailing junk...
1652 while (!isspace(*dptr
) && *dptr
!= ',' && *dptr
!= '\0')
1654 while (isspace(*dptr
) || *dptr
== ',')
1663 * Display the job...
1668 jobdate
= localtime(&jobtime
);
1669 snprintf(temp
, sizeof(temp
), "%s-%d", dest
, jobid
);
1671 if (long_status
== 3)
1674 * Show the consolidated output format for the SGI tools...
1677 strftime(date
, sizeof(date
), "%b %d %H:%M", jobdate
);
1679 printf("%s;%s;%d;%s;%s\n", temp
, username
? username
: "unknown",
1680 size
, title
? title
: "unknown", date
);
1684 strftime(date
, sizeof(date
), CUPS_STRFTIME_FORMAT
, jobdate
);
1687 printf("%3d %-21s %-13s %8d %s\n", rank
, temp
,
1688 username
? username
: "unknown", size
, date
);
1690 printf("%-23s %-13s %8d %s\n", temp
,
1691 username
? username
: "unknown", size
, date
);
1693 printf("\tqueued for %s\n", dest
);
1701 ippDelete(response
);
1705 fprintf(stderr
, "lpstat: get-jobs failed: %s\n",
1706 ippErrorString(cupsLastError()));
1715 * 'show_printers()' - Show printers.
1718 static int /* O - 0 on success, 1 on fail */
1719 show_printers(http_t
*http
, /* I - HTTP connection to server */
1720 const char *printers
, /* I - Destinations */
1721 int num_dests
, /* I - Number of user-defined dests */
1722 cups_dest_t
*dests
, /* I - User-defined destinations */
1723 int long_status
) /* I - Show long status? */
1725 int i
; /* Looping var */
1726 ipp_t
*request
, /* IPP Request */
1727 *response
, /* IPP Response */
1728 *jobs
; /* IPP Get Jobs response */
1729 ipp_attribute_t
*attr
; /* Current attribute */
1730 ipp_attribute_t
*jobattr
; /* Job ID attribute */
1731 cups_lang_t
*language
; /* Default language */
1732 const char *printer
, /* Printer name */
1733 *message
, /* Printer state message */
1734 *description
, /* Description of printer */
1735 *location
; /* Location of printer */
1736 ipp_pstate_t pstate
; /* Printer state */
1737 cups_ptype_t ptype
; /* Printer type */
1738 int jobid
; /* Job ID of current job */
1739 const char *dptr
, /* Pointer into destination list */
1740 *ptr
; /* Pointer into printer name */
1741 int match
; /* Non-zero if this job matches */
1742 char printer_uri
[HTTP_MAX_URI
];
1744 const char *root
; /* Server root directory... */
1745 static const char *pattrs
[] = /* Attributes we need for printers... */
1749 "printer-state-message",
1754 static const char *jattrs
[] = /* Attributes we need for jobs... */
1760 DEBUG_printf(("show_printers(%p, %p)\n", http
, dests
));
1765 if ((root
= getenv("CUPS_SERVERROOT")) == NULL
)
1766 root
= CUPS_SERVERROOT
;
1768 if (printers
!= NULL
&& strcmp(printers
, "all") == 0)
1772 * Build a CUPS_GET_PRINTERS request, which requires the following
1775 * attributes-charset
1776 * attributes-natural-language
1777 * requested-attributes
1782 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
1783 request
->request
.op
.request_id
= 1;
1785 language
= cupsLangDefault();
1787 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1788 "attributes-charset", NULL
, cupsLangEncoding(language
));
1790 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1791 "attributes-natural-language", NULL
, language
->language
);
1793 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1794 "requested-attributes", sizeof(pattrs
) / sizeof(pattrs
[0]),
1798 * Do the request and get back a response...
1801 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1803 DEBUG_puts("show_printers: request succeeded...");
1805 if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1807 fprintf(stderr
, "lpstat: get-printers failed: %s\n",
1808 ippErrorString(response
->request
.status
.status_code
));
1809 ippDelete(response
);
1814 * Loop through the printers returned in the list and display
1818 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1821 * Skip leading attributes until we hit a job...
1824 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
1831 * Pull the needed attributes from this job...
1835 ptype
= CUPS_PRINTER_LOCAL
;
1836 pstate
= IPP_PRINTER_IDLE
;
1842 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
1844 if (strcmp(attr
->name
, "printer-name") == 0 &&
1845 attr
->value_tag
== IPP_TAG_NAME
)
1846 printer
= attr
->values
[0].string
.text
;
1848 if (strcmp(attr
->name
, "printer-state") == 0 &&
1849 attr
->value_tag
== IPP_TAG_ENUM
)
1850 pstate
= (ipp_pstate_t
)attr
->values
[0].integer
;
1852 if (strcmp(attr
->name
, "printer-type") == 0 &&
1853 attr
->value_tag
== IPP_TAG_ENUM
)
1854 ptype
= (cups_ptype_t
)attr
->values
[0].integer
;
1856 if (strcmp(attr
->name
, "printer-state-message") == 0 &&
1857 attr
->value_tag
== IPP_TAG_TEXT
)
1858 message
= attr
->values
[0].string
.text
;
1860 if (strcmp(attr
->name
, "printer-info") == 0 &&
1861 attr
->value_tag
== IPP_TAG_TEXT
)
1862 description
= attr
->values
[0].string
.text
;
1864 if (strcmp(attr
->name
, "printer-location") == 0 &&
1865 attr
->value_tag
== IPP_TAG_TEXT
)
1866 location
= attr
->values
[0].string
.text
;
1872 * See if we have everything needed...
1875 if (printer
== NULL
)
1884 * See if this is a printer we're interested in...
1887 match
= printers
== NULL
;
1889 if (printers
!= NULL
)
1891 for (dptr
= printers
; *dptr
!= '\0';)
1894 * Skip leading whitespace and commas...
1897 while (isspace(*dptr
) || *dptr
== ',')
1908 *ptr
!= '\0' && *dptr
!= '\0' && tolower(*ptr
) == tolower(*dptr
);
1911 if (*ptr
== '\0' && (*dptr
== '\0' || *dptr
== ',' || isspace(*dptr
)))
1918 * Skip trailing junk...
1921 while (!isspace(*dptr
) && *dptr
!= ',' && *dptr
!= '\0')
1923 while (isspace(*dptr
) || *dptr
== ',')
1932 * Display the printer entry if needed...
1938 * If the printer state is "IPP_PRINTER_PROCESSING", then grab the
1939 * current job for the printer.
1942 if (pstate
== IPP_PRINTER_PROCESSING
)
1945 * Build an IPP_GET_JOBS request, which requires the following
1948 * attributes-charset
1949 * attributes-natural-language
1952 * requested-attributes
1957 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
1958 request
->request
.op
.request_id
= 1;
1960 language
= cupsLangDefault();
1962 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1963 "attributes-charset", NULL
,
1964 cupsLangEncoding(language
));
1966 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1967 "attributes-natural-language", NULL
,
1968 language
->language
);
1970 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1971 "requested-attributes",
1972 sizeof(jattrs
) / sizeof(jattrs
[0]), NULL
, jattrs
);
1974 snprintf(printer_uri
, sizeof(printer_uri
), "ipp://%s/printers/%s",
1975 http
->hostname
, printer
);
1976 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1977 "printer-uri", NULL
, printer_uri
);
1979 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
,
1982 if ((jobs
= cupsDoRequest(http
, request
, "/")) != NULL
)
1984 if ((jobattr
= ippFindAttribute(jobs
, "job-id", IPP_TAG_INTEGER
)) != NULL
)
1985 jobid
= jobattr
->values
[0].integer
;
1997 case IPP_PRINTER_IDLE
:
1998 printf("printer %s is idle. enabled since Jan 01 00:00\n", printer
);
2000 case IPP_PRINTER_PROCESSING
:
2001 printf("printer %s now printing %s-%d. enabled since Jan 01 00:00\n", printer
, printer
, jobid
);
2003 case IPP_PRINTER_STOPPED
:
2004 printf("printer %s disabled since Jan 01 00:00 -\n\t%s\n", printer
,
2005 message
== NULL
? "reason unknown" : message
);
2009 if (long_status
> 1)
2011 puts("\tForm mounted:");
2012 puts("\tContent types: any");
2013 puts("\tPrinter types: unknown");
2016 printf("\tDescription: %s\n", description
? description
: "");
2017 if (long_status
> 1)
2019 printf("\tLocation: %s\n", location
? location
: "");
2020 printf("\tConnection: %s\n",
2021 (ptype
& CUPS_PRINTER_REMOTE
) ? "remote" : "direct");
2022 if (!(ptype
& CUPS_PRINTER_REMOTE
))
2023 printf("\tInterface: %s/ppd/%s.ppd\n", root
, printer
);
2024 puts("\tOn fault: no alert");
2025 puts("\tAfter fault: continue");
2026 puts("\tUsers allowed:");
2028 puts("\tForms allowed:");
2030 puts("\tBanner required");
2031 puts("\tCharset sets:");
2033 puts("\tDefault pitch:");
2034 puts("\tDefault page size:");
2035 puts("\tDefault port settings:");
2038 for (i
= 0; i
< num_dests
; i
++)
2039 if (strcasecmp(printer
, dests
[i
].name
) == 0 && dests
[i
].instance
)
2043 case IPP_PRINTER_IDLE
:
2044 printf("printer %s/%s is idle. enabled since Jan 01 00:00\n", printer
, dests
[i
].instance
);
2046 case IPP_PRINTER_PROCESSING
:
2047 printf("printer %s/%s now printing %s-%d. enabled since Jan 01 00:00\n", printer
,
2048 dests
[i
].instance
, printer
, jobid
);
2050 case IPP_PRINTER_STOPPED
:
2051 printf("printer %s/%s disabled since Jan 01 00:00 -\n\t%s\n", printer
,
2053 message
== NULL
? "reason unknown" : message
);
2057 if (long_status
> 1)
2059 puts("\tForm mounted:");
2060 puts("\tContent types: any");
2061 puts("\tPrinter types: unknown");
2064 printf("\tDescription: %s\n", description
? description
: "");
2065 if (long_status
> 1)
2067 printf("\tLocation: %s\n", location
? location
: "");
2068 printf("\tConnection: %s\n",
2069 (ptype
& CUPS_PRINTER_REMOTE
) ? "remote" : "direct");
2070 if (!(ptype
& CUPS_PRINTER_REMOTE
))
2071 printf("\tInterface: %s/ppd/%s.ppd\n", root
, printer
);
2072 puts("\tOn fault: no alert");
2073 puts("\tAfter fault: continue");
2074 puts("\tUsers allowed:");
2076 puts("\tForms allowed:");
2078 puts("\tBanner required");
2079 puts("\tCharset sets:");
2081 puts("\tDefault pitch:");
2082 puts("\tDefault page size:");
2083 puts("\tDefault port settings:");
2092 ippDelete(response
);
2096 fprintf(stderr
, "lpstat: get-printers failed: %s\n",
2097 ippErrorString(cupsLastError()));
2106 * 'show_scheduler()' - Show scheduler status.
2110 show_scheduler(http_t
*http
) /* I - HTTP connection to server */
2112 printf("scheduler is %srunning\n", http
== NULL
? "not " : "");
2117 * End of "$Id: lpstat.c,v 1.50 2002/12/17 19:00:21 swdev Exp $".