xref: /illumos-gate/usr/src/cmd/print/bsd-sysv-commands/lpstat.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  */
27 
28 /* $Id: lpstat.c 173 2006-05-25 04:52:06Z njacobs $ */
29 
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <locale.h>
36 #include <libintl.h>
37 #include <ctype.h>
38 #include <pwd.h>
39 #include <papi.h>
40 #include <uri.h>
41 #include "common.h"
42 #include "lp.h"
43 
44 static void
45 usage(char *program)
46 {
47 	char *name;
48 
49 	if ((name = strrchr(program, '/')) == NULL)
50 		name = program;
51 	else
52 		name++;
53 
54 	fprintf(stdout, gettext("Usage: %s [-d] [-r] [-s] [-t] [-a [list]] "
55 	    "[-c [list]] [-o [list] [-l]] [-R [list] [-l]] "
56 	    "[-p [list] [-D] [-l]] [-v [list]] [-S [list] [-l]] "
57 	    "[-f [list] [-l]] [-u list]\n"),
58 	    name);
59 	exit(1);
60 }
61 
62 static char *
63 nctime(time_t *t)
64 {
65 	static char buf[64];
66 	struct tm *tm = localtime(t);
67 
68 	(void) strftime(buf, sizeof (buf), "%c", tm);
69 
70 	return (buf);
71 }
72 
73 static char *
74 printer_name(papi_printer_t printer)
75 {
76 	papi_attribute_t **attributes = papiPrinterGetAttributeList(printer);
77 	char *result = NULL;
78 
79 	if (attributes != NULL)
80 		papiAttributeListGetString(attributes, NULL,
81 		    "printer-name", &result);
82 
83 	return (result);
84 }
85 
86 static int
87 lpstat_default_printer(papi_encryption_t encryption)
88 {
89 	papi_status_t status;
90 	papi_service_t svc = NULL;
91 	papi_printer_t p = NULL;
92 	char *name = NULL;
93 
94 	status = papiServiceCreate(&svc, NULL, NULL, NULL, cli_auth_callback,
95 	    encryption, NULL);
96 	if (status == PAPI_OK) {
97 		char *req[] = { "printer-name", NULL };
98 
99 		status = papiPrinterQuery(svc, DEFAULT_DEST, req, NULL, &p);
100 		if (p != NULL)
101 			name = printer_name(p);
102 	}
103 	if (name != NULL)
104 		printf(gettext("system default printer: %s\n"), name);
105 	else
106 		printf(gettext("no system default destination\n"));
107 	papiPrinterFree(p);
108 	papiServiceDestroy(svc);
109 
110 	return (0);
111 }
112 
113 static int
114 lpstat_service_status(papi_encryption_t encryption)
115 {
116 	papi_status_t status;
117 	papi_service_t svc = NULL;
118 	char *name = NULL;
119 
120 	if (((name = getenv("PAPI_SERVICE_URI")) == NULL) &&
121 	    ((name = getenv("IPP_SERVER")) == NULL) &&
122 	    ((name = getenv("CUPS_SERVER")) == NULL))
123 		name = DEFAULT_SERVICE_URI;
124 
125 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
126 	    encryption, NULL);
127 	if (status != PAPI_OK) {
128 		printf(gettext("scheduler is not running\n"));
129 	} else
130 		printf(gettext("scheduler is running\n"));
131 	papiServiceDestroy(svc);
132 
133 	return (0);
134 }
135 
136 static char *
137 get_device_uri(papi_service_t svc, char *name)
138 {
139 	papi_status_t status;
140 	papi_printer_t p = NULL;
141 	char *keys[] = { "device-uri", NULL };
142 	char *result = NULL;
143 
144 	status = papiPrinterQuery(svc, name, keys, NULL, &p);
145 	if ((status == PAPI_OK) && (p != NULL)) {
146 		papi_attribute_t **attrs = papiPrinterGetAttributeList(p);
147 
148 		(void) papiAttributeListGetString(attrs, NULL,
149 		    "device-uri", &result);
150 		if (result != NULL)
151 			result = strdup(result);
152 
153 		papiPrinterFree(p);
154 	}
155 
156 	return (result);
157 }
158 
159 static void
160 print_description(papi_attribute_t **list, char *printer_name)
161 {
162 	char *str = "";
163 
164 	(void) papiAttributeListGetString(list, NULL,
165 	    "printer-info", &str);
166 
167 	/*
168 	 * If no printer-info is read then
169 	 * by default the printer-info is <printer-name>@<server>
170 	 */
171 	if (str[0] == '\0') {
172 		char *uri = NULL;
173 		uri_t *u = NULL;
174 
175 		(void) papiAttributeListGetString(list, NULL,
176 		    "printer-uri-supported", &uri);
177 
178 		if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
179 			char *nodename = localhostname();
180 
181 			if ((u->host == NULL) ||
182 			    (strcasecmp(u->host, "localhost") == 0) ||
183 			    (strcasecmp(u->host, nodename) == 0))
184 				printf(gettext("\tDescription:\n"));
185 			else
186 				printf(gettext("\tDescription: %s@%s\n"),
187 				    printer_name, u->host);
188 
189 			uri_free(u);
190 		} else
191 			printf(gettext("\tDescription:\n"));
192 	} else
193 		printf(gettext("\tDescription: %s\n"), str);
194 }
195 
196 static char *report_device_keys[] = { "printer-name", "printer-uri-supported",
197 					NULL };
198 /* ARGSUSED2 */
199 static int
200 report_device(papi_service_t svc, char *name, papi_printer_t printer,
201 		int verbose, int description)
202 {
203 	papi_status_t status;
204 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
205 	char *uri = NULL;
206 	char *device = NULL;
207 	uri_t *u = NULL;
208 
209 	if (name == NULL) {
210 		status = papiAttributeListGetString(attrs, NULL,
211 		    "printer-name", &name);
212 		if (status != PAPI_OK)
213 			status = papiAttributeListGetString(attrs, NULL,
214 			    "printer-uri-supported", &name);
215 	}
216 
217 	if (name == NULL)
218 		return (-1);
219 
220 	(void) papiAttributeListGetString(attrs, NULL,
221 	    "printer-uri-supported", &uri);
222 
223 	if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
224 		char *nodename = localhostname();
225 
226 		if ((u->host == NULL) ||
227 		    (strcasecmp(u->host, "localhost") == 0) ||
228 		    (strcasecmp(u->host, nodename) == 0))
229 			device = get_device_uri(svc, name);
230 
231 		if (device != NULL) {
232 			printf(gettext("device for %s: %s\n"), name, device);
233 			return (0);
234 		} else if (uri != NULL) {
235 			printf(gettext("system for %s: %s (as %s)\n"), name,
236 			    u->host?u->host:"localhost", uri);
237 			return (0);
238 		}
239 
240 		uri_free(u);
241 	}
242 
243 	return (0);
244 }
245 
246 static char *report_accepting_keys[] = { "printer-name",
247 			"printer-uri-supported", "printer-is-accepting-jobs",
248 			"printer-up-time", "printer-state-time",
249 			"lpsched-reject-date", "lpsched-reject-reason", NULL };
250 /* ARGSUSED2 */
251 static int
252 report_accepting(papi_service_t svc, char *name, papi_printer_t printer,
253 		int verbose, int description)
254 {
255 	papi_status_t status;
256 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
257 	time_t curr;
258 	char boolean = PAPI_FALSE;
259 
260 	if (name == NULL) {
261 		status = papiAttributeListGetString(attrs, NULL,
262 		    "printer-name", &name);
263 		if (status != PAPI_OK)
264 			status = papiAttributeListGetString(attrs, NULL,
265 			    "printer-uri-supported", &name);
266 	}
267 	if (name == NULL)
268 		return (-1);
269 
270 	(void) papiAttributeListGetBoolean(attrs, NULL,
271 	    "printer-is-accepting-jobs", &boolean);
272 	(void) time(&curr);
273 	(void) papiAttributeListGetDatetime(attrs, NULL,
274 	    "printer-up-time", &curr);
275 	(void) papiAttributeListGetDatetime(attrs, NULL,
276 	    "printer-state-time", &curr);
277 	(void) papiAttributeListGetDatetime(attrs, NULL,
278 	    "lpsched-reject-date", &curr);
279 
280 	if (boolean == PAPI_TRUE) {
281 		printf(gettext("%s accepting requests since %s\n"),
282 		    name, nctime(&curr));
283 	} else {
284 		char *reason = "unknown reason";
285 
286 		(void) papiAttributeListGetString(attrs, NULL,
287 		    "lpsched-reject-reason", &reason);
288 
289 		printf(gettext("%s not accepting requests since %s\n\t%s\n"),
290 		    name, nctime(&curr), reason);
291 	}
292 
293 	return (0);
294 }
295 
296 static char *report_class_keys[] = { "printer-name", "printer-uri-supported",
297 					"member-names", NULL };
298 /* ARGSUSED2 */
299 static int
300 report_class(papi_service_t svc, char *name, papi_printer_t printer,
301 		int verbose, int description)
302 {
303 	papi_status_t status;
304 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
305 	char *member = NULL;
306 	void *iter = NULL;
307 
308 	status = papiAttributeListGetString(attrs, &iter,
309 	    "member-names", &member);
310 	if (status == PAPI_NOT_FOUND)	/* it's not a class */
311 		return (0);
312 
313 	if (name == NULL) {
314 		status = papiAttributeListGetString(attrs, NULL,
315 		    "printer-name", &name);
316 		if (status != PAPI_OK)
317 			status = papiAttributeListGetString(attrs, NULL,
318 			    "printer-uri-supported", &name);
319 	}
320 	if (name == NULL)
321 		return (-1);
322 
323 	printf(gettext("members of class %s:\n\t%s\n"), name, member);
324 	while (papiAttributeListGetString(attrs, &iter, NULL, &member)
325 	    == PAPI_OK)
326 		printf("\t%s\n", member);
327 
328 	return (0);
329 }
330 
331 static int
332 get_remote_hostname(papi_attribute_t **attrs, char **host)
333 {
334 	char *uri = NULL;
335 	uri_t *u;
336 	char *nodename;
337 
338 	*host = NULL;
339 	(void) papiAttributeListGetString(attrs, NULL,
340 	    "job-originating-host-name", host);
341 	(void) papiAttributeListGetString(attrs, NULL,
342 	    "printer-uri-supported", &uri);
343 	if (*host == NULL) {
344 		if (uri != NULL) {
345 			if (uri_from_string(uri, &u) == 0) {
346 				if (u->host == NULL) {
347 					uri_free(u);
348 					return (0);
349 				}
350 				*host = strdup(u->host);
351 				uri_free(u);
352 			} else {
353 				return (0);
354 			}
355 		} else {
356 			return (0);
357 		}
358 	}
359 	nodename = localhostname();
360 	if ((strcasecmp(*host, "localhost") == 0) ||
361 	    (strcasecmp(*host, nodename) == 0)) {
362 		return (0);
363 	}
364 	return (1);
365 }
366 
367 static char *report_printer_keys[] = { "printer-name",
368 			"printer-uri-supported", "printer-state",
369 			"printer-up-time", "printer-state-time",
370 			"lpsched-disable-date", "printer-state-reasons",
371 			"lpsched-disable-reason", NULL };
372 /* ARGSUSED2 */
373 static int
374 report_printer(papi_service_t svc, char *name, papi_printer_t printer,
375 		int verbose, int description)
376 {
377 	papi_status_t status;
378 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
379 	time_t curr;
380 	int32_t pstat = 0;
381 	char *member = NULL;
382 	papi_job_t *j = NULL;
383 
384 	status = papiAttributeListGetString(attrs, NULL,
385 	    "member-names", &member);
386 	if (status == PAPI_OK)	/* it's a class */
387 		return (0);
388 
389 	if (name == NULL) {
390 		status = papiAttributeListGetString(attrs, NULL,
391 		    "printer-name", &name);
392 		if (status != PAPI_OK)
393 			status = papiAttributeListGetString(attrs, NULL,
394 			    "printer-uri-supported", &name);
395 	}
396 	if (name == NULL)
397 		return (-1);
398 
399 	printf(gettext("printer %s "), name);
400 
401 	status = papiAttributeListGetInteger(attrs, NULL,
402 	    "printer-state", &pstat);
403 
404 	switch (pstat) {
405 	case 0x03:	/* idle */
406 		printf(gettext("idle. enabled"));
407 		break;
408 	case 0x04: /* processing */
409 		status = papiPrinterListJobs(svc, name, NULL,
410 		    0, 0, &j);
411 
412 		if (status == PAPI_OK) {
413 			if (j != NULL) {
414 				int i = 0;
415 				int32_t jobid = 0;
416 				int32_t jstate = 0;
417 
418 				for (i = 0; j[i] != NULL; ++i) {
419 					papi_attribute_t **attr =
420 					    papiJobGetAttributeList(j[i]);
421 
422 					papiAttributeListGetInteger(attr,
423 					    NULL, "job-state", &jstate);
424 					papiAttributeListGetInteger(attr,
425 					    NULL, "job-id", &jobid);
426 					/*
427 					 * For lpd protocol "job-id-requested"
428 					 * should be read.
429 					 */
430 					papiAttributeListGetInteger(attr,
431 					    NULL, "job-id-requested", &jobid);
432 
433 					/*
434 					 * When lpd protocol is used job-state
435 					 * cannot be retrieved, therefore
436 					 * job-state will be 0.
437 					 * When ipp protocol is used, the
438 					 * active/printing job-state will be
439 					 * RS_PRINTING (0x0008) post s10u5.
440 					 * For pre-s10u5 job-state will be
441 					 * RS_ACTIVE (0x05). So print only when
442 					 * the job-state is RS_PRINTING (0x0008)
443 					 * or RS_ACTIVE (0x05) or 0
444 					 */
445 					if ((jstate == 0x0008) ||
446 					    (jstate == 0x05) ||
447 					    (jstate == 0)) {
448 						printf(gettext
449 						    ("now printing"\
450 						    " %s-%d. enabled"),
451 						    name, jobid);
452 						break;
453 					}
454 				}
455 				papiJobListFree(j);
456 			}
457 		}
458 		break;
459 	case 0x05:	/* stopped */
460 		printf(gettext("disabled"));
461 		break;
462 	default:
463 		printf(gettext("unknown state(0x%x)."), pstat);
464 		break;
465 	}
466 
467 	(void) time(&curr);
468 	(void) papiAttributeListGetDatetime(attrs, NULL,
469 	    "printer-up-time", &curr);
470 	(void) papiAttributeListGetDatetime(attrs, NULL,
471 	    "printer-state-time", &curr);
472 	(void) papiAttributeListGetDatetime(attrs, NULL,
473 	    "lpsched-disable-date", &curr);
474 	printf(gettext(" since %s. available.\n"), nctime(&curr));
475 
476 	if (pstat == 0x05) {
477 		char *reason = "unknown reason";
478 
479 		(void) papiAttributeListGetString(attrs, NULL,
480 		    "printer-state-reasons", &reason);
481 		(void) papiAttributeListGetString(attrs, NULL,
482 		    "lpsched-disable-reason", &reason);
483 		printf(gettext("\t%s\n"), reason);
484 	}
485 
486 	if (verbose == 1) {
487 		void *iter;
488 		char *str;
489 		char *host = NULL;
490 
491 		if ((get_remote_hostname(attrs, &host)) != 0) {
492 			(void) printf(
493 			    gettext("\tRemote Name: %s\n\tRemote Server: "
494 			    "%s\n"), name, host);
495 			free(host);
496 			return (0);
497 		}
498 		str = "";
499 		(void) papiAttributeListGetString(attrs, NULL,
500 		    "form-ready", &str);
501 		printf(gettext("\tForm mounted: %s\n"), str);
502 
503 		str = "";
504 		iter = NULL;
505 		(void) papiAttributeListGetString(attrs, &iter,
506 		    "document-format-supported", &str);
507 		printf(gettext("\tContent types: %s"), str);
508 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
509 		    == PAPI_OK)
510 			printf(", %s", str);
511 		printf("\n");
512 
513 		/* Display the printer description */
514 		print_description(attrs, name);
515 
516 		str = "";
517 		iter = NULL;
518 		(void) papiAttributeListGetString(attrs, &iter,
519 		    "lpsched-printer-type", &str);
520 		printf(gettext("\tPrinter types: %s"), str);
521 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
522 		    == PAPI_OK)
523 			printf(", %s", str);
524 		printf("\n");
525 
526 		str = "";
527 		(void) papiAttributeListGetString(attrs, NULL,
528 		    "lpsched-dial-info", &str);
529 		printf(gettext("\tConnection: %s\n"),
530 		    ((str[0] == '\0') ? gettext("direct") : str));
531 
532 		str = "";
533 		(void) papiAttributeListGetString(attrs, NULL,
534 		    "lpsched-interface-script", &str);
535 		printf(gettext("\tInterface: %s\n"), str);
536 
537 		str = NULL;
538 		(void) papiAttributeListGetString(attrs, NULL,
539 		    "ppd-file-uri", &str);
540 		(void) papiAttributeListGetString(attrs, NULL,
541 		    "lpsched-ppd-source-path", &str);
542 		if (str != NULL)
543 			printf(gettext("\tPPD: %s\n"), str);
544 
545 		str = NULL;
546 		(void) papiAttributeListGetString(attrs, NULL,
547 		    "lpsched-fault-alert-command", &str);
548 		if (str != NULL)
549 			printf(gettext("\tOn fault: %s\n"), str);
550 
551 		str = "";
552 		(void) papiAttributeListGetString(attrs, NULL,
553 		    "lpsched-fault-recovery", &str);
554 		printf(gettext("\tAfter fault: %s\n"),
555 		    ((str[0] == '\0') ? gettext("continue") : str));
556 
557 		str = "(all)";
558 		iter = NULL;
559 		(void) papiAttributeListGetString(attrs, &iter,
560 		    "requesting-user-name-allowed", &str);
561 		printf(gettext("\tUsers allowed:\n\t\t%s\n"),
562 		    ((str[0] == '\0') ? gettext("(none)") : str));
563 		if ((str != NULL) && (str[0] != '\0'))
564 			while (papiAttributeListGetString(attrs, &iter, NULL,
565 			    &str) == PAPI_OK)
566 				printf("\t\t%s\n", str);
567 
568 		str = NULL;
569 		iter = NULL;
570 		(void) papiAttributeListGetString(attrs, &iter,
571 		    "requesting-user-name-denied", &str);
572 		if (str != NULL) {
573 			printf(gettext("\tUsers denied:\n\t\t%s\n"),
574 			    ((str[0] == '\0') ? gettext("(none)") : str));
575 			if ((str != NULL) && (str[0] != '\0'))
576 				while (papiAttributeListGetString(attrs, &iter,
577 				    NULL, &str) == PAPI_OK)
578 					printf("\t\t%s\n", str);
579 		}
580 
581 		str = "none";
582 		iter = NULL;
583 		(void) papiAttributeListGetString(attrs, &iter,
584 		    "form-supported", &str);
585 		printf(gettext("\tForms allowed:\n\t\t(%s)\n"),
586 		    ((str[0] == '\0') ? gettext("none") : str));
587 		if ((str != NULL) && (str[0] != '\0'))
588 			while (papiAttributeListGetString(attrs, &iter, NULL,
589 			    &str) == PAPI_OK)
590 				printf("\t\t(%s)\n", str);
591 
592 		str = "";
593 		iter = NULL;
594 		(void) papiAttributeListGetString(attrs, &iter,
595 		    "media-supported", &str);
596 		printf(gettext("\tMedia supported:\n\t\t%s\n"),
597 		    ((str[0] == '\0') ? gettext("(none)") : str));
598 		if ((str != NULL) && (str[0] != '\0'))
599 			while (papiAttributeListGetString(attrs, &iter, NULL,
600 			    &str) == PAPI_OK)
601 				printf("\t\t%s\n", str);
602 
603 		str = "";
604 		(void) papiAttributeListGetString(attrs, NULL,
605 		    "job-sheets-supported", &str);
606 		if ((strcasecmp(str, "none")) == 0)
607 			str = gettext("page never printed");
608 		else if (strcasecmp(str, "optional") == 0)
609 			str = gettext("not required");
610 		else
611 			str = gettext("required");
612 
613 		printf(gettext("\tBanner %s\n"), str);
614 
615 
616 		str = "";
617 		iter = NULL;
618 		(void) papiAttributeListGetString(attrs, &iter,
619 		    "lpsched-print-wheels", &str);
620 		printf(gettext("\tCharacter sets:\n\t\t%s\n"),
621 		    ((str[0] == '\0') ? gettext("(none)") : str));
622 		if ((str != NULL) && (str[0] != '\0'))
623 			while (papiAttributeListGetString(attrs, &iter, NULL,
624 			    &str) == PAPI_OK)
625 				printf("\t\t%s\n", str);
626 
627 		printf(gettext("\tDefault pitch:\n"));
628 		printf(gettext("\tDefault page size:\n"));
629 		printf(gettext("\tDefault port setting:\n"));
630 
631 		str = "";
632 		iter = NULL;
633 		(void) papiAttributeListGetString(attrs, &iter,
634 		    "lpsched-options", &str);
635 		if (str != NULL) {
636 			printf(gettext("\tOptions: %s"), str);
637 			while (papiAttributeListGetString(attrs, &iter, NULL,
638 			    &str) == PAPI_OK)
639 				printf(", %s", str);
640 			printf("\n");
641 		}
642 
643 	} else if (description == 1)
644 		/* Display printer description */
645 		print_description(attrs, name);
646 	else if (verbose > 1)
647 		papiAttributeListPrint(stdout, attrs, "\t");
648 
649 	if (verbose > 0)
650 		printf("\n");
651 
652 	return (0);
653 }
654 
655 static int
656 printer_query(char *name, int (*report)(papi_service_t, char *, papi_printer_t,
657 					int, int), papi_encryption_t encryption,
658 		int verbose, int description)
659 {
660 	int result = 0, i = 0;
661 	papi_status_t status;
662 	papi_service_t svc = NULL;
663 	char **list = getlist(name, LP_WS, LP_SEP);
664 
665 	if (list == NULL) {
666 		list = (char **)malloc(sizeof (char *));
667 		list[0] = name;
668 	}
669 
670 	/*
671 	 * The for loop executes once for every printer
672 	 * entry in list. If list is NULL that implies
673 	 * name is also NULL, the loop runs only one time.
674 	 */
675 
676 	for (i = 0; name == NULL || list[i] != NULL; i++) {
677 		name = list[i];
678 
679 		status = papiServiceCreate(&svc, name, NULL, NULL,
680 		    cli_auth_callback, encryption, NULL);
681 		if (status != PAPI_OK) {
682 			if (status == PAPI_NOT_FOUND)
683 				fprintf(stderr,
684 				    gettext("%s: unknown printer\n"),
685 				    name ? name : "(NULL)");
686 			else
687 				fprintf(stderr, gettext(
688 				    "Failed to contact service for %s: %s\n"),
689 				    name ? name : "(NULL)",
690 				    verbose_papi_message(svc, status));
691 			papiServiceDestroy(svc);
692 			result--;
693 			continue;
694 		}
695 
696 		if (name == NULL) { /* all */
697 			char **interest = interest_list(svc);
698 
699 			if (interest != NULL) {
700 				int i;
701 
702 				for (i = 0; interest[i] != NULL; i++)
703 					result += printer_query(interest[i],
704 					    report, encryption, verbose,
705 					    description);
706 			}
707 		} else {
708 			papi_printer_t printer = NULL;
709 			char **keys = NULL;
710 
711 			/*
712 			 * Limit the query to only required data
713 			 * to reduce the need to go remote for
714 			 * information.
715 			 */
716 			if (report == report_device)
717 				keys = report_device_keys;
718 			else if (report == report_class)
719 				keys = report_class_keys;
720 			else if (report == report_accepting)
721 				keys = report_accepting_keys;
722 			else if ((report == report_printer) && (verbose == 0))
723 				keys = report_printer_keys;
724 
725 			status = papiPrinterQuery(svc, name, keys,
726 			    NULL, &printer);
727 			if (status != PAPI_OK) {
728 				fprintf(stderr, gettext(
729 				    "Failed to get printer info for %s: %s\n"),
730 				    name, verbose_papi_message(svc, status));
731 				papiServiceDestroy(svc);
732 				result--;
733 				continue;
734 			}
735 
736 			if (printer != NULL)
737 				result += report(svc, name, printer, verbose,
738 				    description);
739 
740 			papiPrinterFree(printer);
741 		}
742 
743 		papiServiceDestroy(svc);
744 
745 		if (name == NULL)
746 			break;
747 	}
748 
749 	freelist(list);
750 
751 	return (result);
752 }
753 
754 static int
755 match_user(char *user, char **list)
756 {
757 	int i;
758 
759 	for (i = 0; list[i] != NULL; i++) {
760 		if (strcmp(user, list[i]) == 0)
761 			return (0);
762 	}
763 
764 	return (-1);
765 }
766 
767 static char **users = NULL;
768 
769 static int
770 report_job(char *printer, papi_job_t job, int show_rank, int verbose)
771 {
772 	papi_attribute_t **attrs = papiJobGetAttributeList(job);
773 	time_t clock = 0;
774 	char date[24];
775 	char request[26];
776 	char *user = "unknown";
777 	char *host = NULL;
778 	int32_t size = 0;
779 	int32_t jstate = 0;
780 	char User[50];
781 
782 	char *destination = "unknown";
783 	int32_t id = -1;
784 	static int check = 0;
785 	static char *uri = NULL;
786 
787 	(void) papiAttributeListGetString(attrs, NULL,
788 	    "job-originating-user-name", &user);
789 
790 	if ((users != NULL) && (match_user(user, users) < 0))
791 		return (0);
792 
793 	(void) papiAttributeListGetString(attrs, NULL,
794 	    "job-originating-host-name", &host);
795 
796 	if (check == 0) {
797 		/*
798 		 * Read the attribute "job-printer-uri"
799 		 * just once
800 		 */
801 		(void) papiAttributeListGetString(attrs, NULL,
802 		    "job-printer-uri", &uri);
803 		check = 1;
804 	}
805 
806 	if (host) {
807 		/* Check if it is local printer or remote printer */
808 		uri_t *u = NULL;
809 
810 		if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
811 			char *nodename = localhostname();
812 
813 			if ((u->host == NULL) ||
814 			    (strcasecmp(u->host, "localhost") == 0) ||
815 			    (strcasecmp(u->host, nodename) == 0)) {
816 
817 				if (strcasecmp(host, nodename) == 0) {
818 					/*
819 					 * Request submitted locally
820 					 * for the local queue.
821 					 * Hostname will not be displayed
822 					 */
823 					snprintf(User, sizeof (User), "%s",
824 					    user);
825 				}
826 				else
827 					snprintf(User, sizeof (User), "%s@%s",
828 					    user, host);
829 			} else if (uri != NULL) {
830 				/*
831 				 * It's a remote printer.
832 				 * In case of remote printers hostname is
833 				 * always displayed.
834 				 */
835 				snprintf(User, sizeof (User), "%s@%s",
836 				    user, host);
837 			}
838 			uri_free(u);
839 		} else {
840 			/*
841 			 * If attribute "job-printer-uri"
842 			 * cannot be read
843 			 * by default append the hostname
844 			 */
845 			snprintf(User, sizeof (User), "%s@%s", user, host);
846 		}
847 	} else {
848 		/*
849 		 * When print server is s10u4 and ipp service is used
850 		 * "job-originating-hostname" attribute is not set
851 		 * So get the host information from the uri
852 		 */
853 		uri_t *u = NULL;
854 		if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
855 			if ((u != NULL) && (u->host != NULL))
856 				snprintf(User, sizeof (User), "%s@%s",
857 				    user, u->host);
858 			else
859 				snprintf(User, sizeof (User), "%s", user);
860 
861 			uri_free(u);
862 		} else
863 			snprintf(User, sizeof (User), "%s", user);
864 	}
865 	(void) papiAttributeListGetInteger(attrs, NULL, "job-k-octets", &size);
866 	size *= 1024;	/* for the approximate byte size */
867 	(void) papiAttributeListGetInteger(attrs, NULL, "job-octets", &size);
868 
869 	(void) time(&clock);
870 	(void) papiAttributeListGetInteger(attrs, NULL,
871 	    "time-at-creation", (int32_t *)&clock);
872 	(void) strftime(date, sizeof (date), "%b %d %R", localtime(&clock));
873 
874 	(void) papiAttributeListGetString(attrs, NULL,
875 	    "job-printer-uri", &destination);
876 	(void) papiAttributeListGetString(attrs, NULL,
877 	    "printer-name", &destination);
878 	(void) papiAttributeListGetInteger(attrs, NULL,
879 	    "job-id", &id);
880 	(void) papiAttributeListGetInteger(attrs, NULL,
881 	    "job-id-requested", &id);
882 
883 
884 	snprintf(request, sizeof (request), "%s-%d", printer, id);
885 
886 	if (show_rank != 0) {
887 		int32_t rank = -1;
888 
889 		(void) papiAttributeListGetInteger(attrs, NULL,
890 		    "number-of-intervening-jobs", &rank);
891 		rank++;
892 
893 		printf("%3d %-21s %-14s %7ld %s",
894 		    rank, request, User, size, date);
895 	} else
896 		printf("%-23s %-14s %7ld   %s", request, User, size, date);
897 
898 	(void) papiAttributeListGetInteger(attrs, NULL,
899 	    "job-state", &jstate);
900 
901 	if (jstate == 0x0001)
902 		printf(gettext(" being held"));
903 	else if (jstate == 0x0800)
904 		printf(gettext(" notifying user"));
905 	else if (jstate == 0x0040)
906 		printf(gettext(" cancelled"));
907 	else if (jstate == 0x0010)
908 		printf(gettext(" finished printing"));
909 	else if (jstate == 0x0008)
910 		printf(gettext(" on %s"), destination);
911 	else if (jstate == 0x2000)
912 		printf(gettext(" held by admin"));
913 	else if (jstate == 0x0002)
914 		printf(gettext(" being filtered"));
915 	else if (jstate == 0x0004)
916 		printf(gettext(" filtered"));
917 	else if (jstate == 0x0020)
918 		printf(gettext(" held for change"));
919 
920 	if (verbose == 1) {
921 		char *form = NULL;
922 
923 		(void) papiAttributeListGetString(attrs, NULL,
924 		    "output-device-assigned", &destination);
925 		printf("\n\t assigned %s", destination);
926 
927 		(void) papiAttributeListGetString(attrs, NULL, "form", &form);
928 		if (form != NULL)
929 			printf(", form %s", form);
930 	} else if (verbose > 1) {
931 		printf("\n");
932 		papiAttributeListPrint(stdout, attrs, "\t");
933 	}
934 
935 	printf("\n");
936 
937 	return (0);
938 }
939 
940 static int
941 job_query(char *request, int (*report)(char *, papi_job_t, int, int),
942 		papi_encryption_t encryption, int show_rank, int verbose)
943 {
944 	int result = 0;
945 	papi_status_t status;
946 	papi_service_t svc = NULL;
947 	char *printer = request;
948 	int32_t id = -1;
949 	int flag1 = 0;
950 	int flag = 1;
951 	int print_flag = 0;
952 
953 	do {
954 		status = papiServiceCreate(&svc, printer, NULL, NULL,
955 		    cli_auth_callback, encryption, NULL);
956 
957 		if ((status == PAPI_OK) && (printer != NULL))
958 			print_flag = 1;
959 
960 		/* <name>-# printer name does not exist */
961 		if (status != PAPI_OK) {
962 			/*
963 			 * Check if <name>-# is a request-id
964 			 * Once this check is done flag1 is set
965 			 */
966 			if (flag1 == 1)
967 				break;
968 
969 			get_printer_id(printer, &printer, &id);
970 
971 			status = papiServiceCreate(&svc, printer, NULL, NULL,
972 			    cli_auth_callback, encryption, NULL);
973 
974 			if (status != PAPI_OK) {
975 				fprintf(stderr, gettext(
976 				    "Failed to contact service for %s: %s\n"),
977 				    (printer ? printer : "all"),
978 				    verbose_papi_message(svc, status));
979 				return (-1);
980 			}
981 		}
982 
983 		if (printer == NULL) { /* all */
984 			char **interest = interest_list(svc);
985 
986 			if (interest != NULL) {
987 				int i;
988 
989 				for (i = 0; interest[i] != NULL; i++)
990 					result += job_query(interest[i], report,
991 					    encryption, show_rank, verbose);
992 			}
993 		} else if (id == -1) { /* a printer */
994 			papi_job_t *jobs = NULL;
995 
996 			status = papiPrinterListJobs(svc, printer, NULL,
997 			    0, 0, &jobs);
998 			if (status != PAPI_OK) {
999 				fprintf(stderr, gettext(
1000 				    "Failed to get job list: %s\n"),
1001 				    verbose_papi_message(svc, status));
1002 				papiServiceDestroy(svc);
1003 				return (-1);
1004 			}
1005 
1006 			if (jobs != NULL) {
1007 				int i;
1008 
1009 				for (i = 0; jobs[i] != NULL; i++)
1010 					result += report(printer,
1011 					    jobs[i], show_rank,
1012 					    verbose);
1013 			}
1014 
1015 			papiJobListFree(jobs);
1016 		} else {	/* a job */
1017 			papi_job_t job = NULL;
1018 			int rid = id;
1019 
1020 			/* Once a job has been found stop processing */
1021 			flag = 0;
1022 
1023 			/*
1024 			 * Job-id could be the job-id requested
1025 			 * Check if it is job-id or job-id-requested
1026 			 */
1027 			id = job_to_be_queried(svc, printer, id);
1028 
1029 			if (id > 0)
1030 				status = papiJobQuery(svc, printer, id,
1031 				    NULL, &job);
1032 			else
1033 				status = papiJobQuery(svc, printer, rid,
1034 				    NULL, &job);
1035 
1036 			if (status != PAPI_OK) {
1037 				if (!print_flag)
1038 					fprintf(stderr, gettext(
1039 					    "Failed to get job"\
1040 					    " info for %s: %s\n"),
1041 					    request,
1042 					    verbose_papi_message(svc, status));
1043 				papiServiceDestroy(svc);
1044 				return (-1);
1045 			}
1046 
1047 			if (job != NULL)
1048 				result = report(printer, job,
1049 				    show_rank, verbose);
1050 
1051 			papiJobFree(job);
1052 		}
1053 
1054 		if (flag) {
1055 			id = -1;
1056 			get_printer_id(printer, &printer, &id);
1057 			if (id == -1)
1058 				flag = 0;
1059 			else
1060 				flag1 = 1;
1061 		}
1062 	} while (flag);
1063 
1064 	papiServiceDestroy(svc);
1065 
1066 	return (result);
1067 }
1068 
1069 static int
1070 report_form(char *name, papi_attribute_t **attrs, int verbose)
1071 {
1072 	papi_status_t status;
1073 	char *form = NULL;
1074 	void *iter = NULL;
1075 
1076 	for (status = papiAttributeListGetString(attrs, &iter,
1077 	    "form-supported", &form);
1078 	    status == PAPI_OK;
1079 	    status = papiAttributeListGetString(attrs, &iter,
1080 	    NULL, &form)) {
1081 		if ((name == NULL) || (strcmp(name, form) == 0)) {
1082 			printf(gettext("form %s is available to you\n"), form);
1083 			if (verbose != 0) {
1084 				char *detail = NULL;
1085 				status = papiAttributeListGetString(attrs, NULL,
1086 				    "form-supported-detail", &detail);
1087 				if (status == PAPI_OK)
1088 					printf("%s\n", detail);
1089 			}
1090 		}
1091 	}
1092 
1093 	return (0);
1094 }
1095 
1096 static int
1097 report_print_wheels(char *name, papi_attribute_t **attrs, int verbose)
1098 {
1099 	papi_status_t status;
1100 	char *pw = NULL;
1101 	void *iter = NULL;
1102 
1103 	for (status = papiAttributeListGetString(attrs, &iter,
1104 	    "pw-supported", &pw);
1105 	    status == PAPI_OK;
1106 	    status = papiAttributeListGetString(attrs, &iter, NULL, &pw)) {
1107 		if ((name == NULL) || (strcmp(name, pw) == 0)) {
1108 			printf(gettext("charset %s is available\n"), pw);
1109 			if (verbose != 0) {
1110 				char *info = NULL;
1111 				status = papiAttributeListGetString(attrs, NULL,
1112 				    "pw-supported-extra", &info);
1113 				if (status == PAPI_OK)
1114 					printf("%s\n", info);
1115 			}
1116 		}
1117 	}
1118 
1119 	return (0);
1120 }
1121 
1122 static int
1123 service_query(char *name, int (*report)(char *, papi_attribute_t **, int),
1124 		papi_encryption_t encryption, int verbose)
1125 {
1126 	int result = 0;
1127 	papi_status_t status;
1128 	papi_service_t svc = NULL;
1129 	papi_attribute_t **attrs = NULL;
1130 
1131 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
1132 	    encryption, NULL);
1133 	if (status != PAPI_OK) {
1134 		papiServiceDestroy(svc);
1135 		return (-1);
1136 	}
1137 
1138 	attrs = papiServiceGetAttributeList(svc);
1139 	if (attrs != NULL) {
1140 		result = report(name, attrs, verbose);
1141 
1142 		if (verbose > 1) {
1143 			printf("\n");
1144 			papiAttributeListPrint(stdout, attrs, "\t");
1145 			printf("\n");
1146 		}
1147 	}
1148 
1149 	papiServiceDestroy(svc);
1150 
1151 	return (result);
1152 }
1153 
1154 int
1155 main(int ac, char *av[])
1156 {
1157 	int exit_code = 0;
1158 	papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
1159 	int rank = 0;
1160 	int verbose = 0;
1161 	int description = 0;
1162 	int c;
1163 	char **argv;
1164 
1165 	(void) setlocale(LC_ALL, "");
1166 	(void) textdomain("SUNW_OST_OSCMD");
1167 
1168 	argv = (char **)calloc((ac + 1), sizeof (char *));
1169 	for (c = 0; c < ac; c++) {
1170 		if ((av[c][0] == '-') && (av[c][1] == 'l') &&
1171 		    (isalpha(av[c][2]) != 0)) {
1172 			/* preserve old "-l[po...]" behavior */
1173 			argv[c] = &av[c][1];
1174 			argv[c][0] = '-';
1175 			verbose = 1;
1176 
1177 		} else
1178 			argv[c] = av[c];
1179 	}
1180 
1181 	argv[c++] = "--";
1182 	ac = c;
1183 
1184 	/* preprocess argument list looking for '-l' or '-R' so it can trail */
1185 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
1186 		switch (c) {    /* these may or may not have an option */
1187 		case 'a':
1188 		case 'c':
1189 		case 'p':
1190 		case 'o':
1191 		case 'R':
1192 		case 'u':
1193 		case 'v':
1194 		case 'l':
1195 		case 'f':
1196 		case 'S':
1197 			if (optarg[0] == '-') {
1198 				/* this check stop a possible infinite loop */
1199 				if ((optind > 1) && (argv[optind-1][1] != c))
1200 					optind--;
1201 				optarg = NULL;
1202 			} else if (strcmp(optarg, "all") == 0)
1203 				optarg = NULL;
1204 		}
1205 
1206 		switch (c) {
1207 		case 'l':
1208 			if ((optarg == NULL) || (optarg[0] == '-'))
1209 				optarg = "1";
1210 			verbose = atoi(optarg);
1211 			break;
1212 		case 'D':
1213 			description = 1;
1214 			break;
1215 		case 'R':
1216 			rank = 1;
1217 			break;
1218 		case 'E':
1219 			encryption = PAPI_ENCRYPT_REQUIRED;
1220 			break;
1221 		default:
1222 			break;
1223 		}
1224 	}
1225 	optind = 1;
1226 
1227 	/* process command line arguments */
1228 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
1229 		switch (c) {	/* these may or may not have an option */
1230 		case 'a':
1231 		case 'c':
1232 		case 'p':
1233 		case 'o':
1234 		case 'R':
1235 		case 'u':
1236 		case 'v':
1237 		case 'l':
1238 		case 'f':
1239 		case 'S':
1240 			if (optarg[0] == '-') {
1241 				/* this check stop a possible infinite loop */
1242 				if ((optind > 1) && (argv[optind-1][1] != c))
1243 					optind--;
1244 				optarg = NULL;
1245 			} else if (strcmp(optarg, "all") == 0)
1246 				optarg = NULL;
1247 		}
1248 
1249 		switch (c) {
1250 		case 'a':
1251 			exit_code += printer_query(optarg, report_accepting,
1252 			    encryption, verbose, 0);
1253 			break;
1254 		case 'c':
1255 			exit_code += printer_query(optarg, report_class,
1256 			    encryption, verbose, 0);
1257 			break;
1258 		case 'p':
1259 			exit_code += printer_query(optarg, report_printer,
1260 			    encryption, verbose, description);
1261 			break;
1262 		case 'd':
1263 			exit_code += lpstat_default_printer(encryption);
1264 			break;
1265 		case 'r':
1266 			exit_code += lpstat_service_status(encryption);
1267 			break;
1268 		case 'u':
1269 			if (optarg != NULL)
1270 				users = strsplit(optarg, ", \n");
1271 			exit_code += job_query(NULL, report_job,
1272 			    encryption, rank, verbose);
1273 			if (users != NULL) {
1274 				free(users);
1275 				users = NULL;
1276 			}
1277 			break;
1278 		case 'v':
1279 			exit_code += printer_query(optarg, report_device,
1280 			    encryption, verbose, 0);
1281 			break;
1282 		case 'R':	/* set "rank" flag in first pass */
1283 		case 'o':
1284 			exit_code += job_query(optarg, report_job,
1285 			    encryption, rank, verbose);
1286 			break;
1287 		case 'f':
1288 			exit_code += service_query(optarg, report_form,
1289 			    encryption, verbose);
1290 			break;
1291 		case 'S':
1292 			exit_code += service_query(optarg, report_print_wheels,
1293 			    encryption, verbose);
1294 			break;
1295 		case 's':
1296 			exit_code += lpstat_service_status(encryption);
1297 			exit_code += lpstat_default_printer(encryption);
1298 			exit_code += printer_query(NULL, report_class,
1299 			    encryption, verbose, 0);
1300 			exit_code += printer_query(NULL, report_device,
1301 			    encryption, verbose, 0);
1302 			exit_code += service_query(optarg, report_form,
1303 			    encryption, verbose);
1304 			exit_code += service_query(optarg, report_print_wheels,
1305 			    encryption, verbose);
1306 			break;
1307 		case 't':
1308 			exit_code += lpstat_service_status(encryption);
1309 			exit_code += lpstat_default_printer(encryption);
1310 			exit_code += printer_query(NULL, report_class,
1311 			    encryption, verbose, 0);
1312 			exit_code += printer_query(NULL, report_device,
1313 			    encryption, verbose, 0);
1314 			exit_code += printer_query(NULL, report_accepting,
1315 			    encryption, verbose, 0);
1316 			exit_code += printer_query(NULL, report_printer,
1317 			    encryption, verbose, 0);
1318 			exit_code += service_query(optarg, report_form,
1319 			    encryption, verbose);
1320 			exit_code += service_query(optarg, report_print_wheels,
1321 			    encryption, verbose);
1322 			exit_code += job_query(NULL, report_job,
1323 			    encryption, rank, verbose);
1324 			break;
1325 		case 'L':	/* local-only, ignored */
1326 		case 'l':	/* increased verbose level in first pass */
1327 		case 'D':	/* set "description" flag in first pass */
1328 		case 'E':	/* set encryption in the first pass */
1329 			break;
1330 		default:
1331 			usage(av[0]);
1332 		}
1333 	}
1334 	ac--;
1335 
1336 	if (ac == 1) {	/* report on my jobs */
1337 		struct passwd *pw = getpwuid(getuid());
1338 
1339 		if (pw != NULL)
1340 			users = strsplit(pw->pw_name, "");
1341 		exit_code += job_query(NULL, report_job, encryption,
1342 		    rank, verbose);
1343 		if (users != NULL) {
1344 			free(users);
1345 			users = NULL;
1346 		}
1347 	} else {
1348 		for (c = optind; c < ac; c++)
1349 			exit_code += job_query(argv[c], report_job, encryption,
1350 			    rank, verbose);
1351 	}
1352 
1353 
1354 	if (exit_code != 0)
1355 		exit_code = 1;
1356 
1357 	return (exit_code);
1358 }
1359