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