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