xref: /illumos-gate/usr/src/cmd/print/bsd-sysv-commands/lpstat.c (revision 92a0208178405fef708b0283ffcaa02fbc3468ff)
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 2008 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <locale.h>
37 #include <libintl.h>
38 #include <ctype.h>
39 #include <pwd.h>
40 #include <papi.h>
41 #include <uri.h>
42 #include "common.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 char *report_device_keys[] = { "printer-name", "printer-uri-supported",
162 					NULL };
163 /* ARGSUSED2 */
164 static int
165 report_device(papi_service_t svc, char *name, papi_printer_t printer,
166 		int verbose, int description)
167 {
168 	papi_status_t status;
169 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
170 	char *uri = NULL;
171 	char *device = NULL;
172 	uri_t *u = NULL;
173 
174 	if (name == NULL) {
175 		status = papiAttributeListGetString(attrs, NULL,
176 					"printer-name", &name);
177 		if (status != PAPI_OK)
178 			status = papiAttributeListGetString(attrs, NULL,
179 					"printer-uri-supported", &name);
180 	}
181 
182 	if (name == NULL)
183 		return (-1);
184 
185 	(void) papiAttributeListGetString(attrs, NULL,
186 					"printer-uri-supported", &uri);
187 
188 	if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
189 		char *nodename = localhostname();
190 
191 		if ((u->host == NULL) ||
192 		    (strcasecmp(u->host, "localhost") == 0) ||
193 		    (strcasecmp(u->host, nodename) == 0))
194 			device = get_device_uri(svc, name);
195 
196 		if (device != NULL) {
197 			printf(gettext("device for %s: %s\n"), name, device);
198 			return (0);
199 		} else if (uri != NULL) {
200 			printf(gettext("system for %s: %s (as %s)\n"), name,
201 				u->host, uri);
202 			return (0);
203 		}
204 
205 		uri_free(u);
206 	}
207 
208 	return (0);
209 }
210 
211 static char *report_accepting_keys[] = { "printer-name",
212 			"printer-uri-supported", "printer-is-accepting-jobs",
213 			"printer-up-time", "printer-state-time",
214 			"lpsched-reject-date", "lpsched-reject-reason", NULL };
215 /* ARGSUSED2 */
216 static int
217 report_accepting(papi_service_t svc, char *name, papi_printer_t printer,
218 		int verbose, int description)
219 {
220 	papi_status_t status;
221 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
222 	time_t curr;
223 	char boolean = PAPI_FALSE;
224 
225 	if (name == NULL) {
226 		status = papiAttributeListGetString(attrs, NULL,
227 					"printer-name", &name);
228 		if (status != PAPI_OK)
229 			status = papiAttributeListGetString(attrs, NULL,
230 					"printer-uri-supported", &name);
231 	}
232 	if (name == NULL)
233 		return (-1);
234 
235 	(void) papiAttributeListGetBoolean(attrs, NULL,
236 				"printer-is-accepting-jobs", &boolean);
237 	(void) time(&curr);
238 	(void) papiAttributeListGetDatetime(attrs, NULL,
239 					"printer-up-time", &curr);
240 	(void) papiAttributeListGetDatetime(attrs, NULL,
241 					"printer-state-time", &curr);
242 	(void) papiAttributeListGetDatetime(attrs, NULL,
243 					"lpsched-reject-date", &curr);
244 
245 	if (boolean == PAPI_TRUE) {
246 		printf(gettext("%s accepting requests since %s\n"),
247 			name, nctime(&curr));
248 	} else {
249 		char *reason = "unknown reason";
250 
251 		(void) papiAttributeListGetString(attrs, NULL,
252 					"lpsched-reject-reason", &reason);
253 
254 		printf(gettext("%s not accepting requests since %s\n\t%s\n"),
255 			name, nctime(&curr), reason);
256 	}
257 
258 	return (0);
259 }
260 
261 static char *report_class_keys[] = { "printer-name", "printer-uri-supported",
262 					"member-names", NULL };
263 /* ARGSUSED2 */
264 static int
265 report_class(papi_service_t svc, char *name, papi_printer_t printer,
266 		int verbose, int description)
267 {
268 	papi_status_t status;
269 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
270 	char *member = NULL;
271 	void *iter = NULL;
272 
273 	status = papiAttributeListGetString(attrs, &iter,
274 				"member-names", &member);
275 	if (status == PAPI_NOT_FOUND)	/* it's not a class */
276 		return (0);
277 
278 	if (name == NULL) {
279 		status = papiAttributeListGetString(attrs, NULL,
280 					"printer-name", &name);
281 		if (status != PAPI_OK)
282 			status = papiAttributeListGetString(attrs, NULL,
283 					"printer-uri-supported", &name);
284 	}
285 	if (name == NULL)
286 		return (-1);
287 
288 	printf(gettext("members of class %s:\n\t%s\n"), name, member);
289 	while (papiAttributeListGetString(attrs, &iter, NULL, &member)
290 			== PAPI_OK)
291 		printf("\t%s\n", member);
292 
293 	return (0);
294 }
295 
296 static char *report_printer_keys[] = { "printer-name",
297 			"printer-uri-supported", "printer-state",
298 			"printer-up-time", "printer-state-time",
299 			"lpsched-disable-date", "printer-state-reasons",
300 			"lpsched-disable-reason", NULL };
301 /* ARGSUSED2 */
302 static int
303 report_printer(papi_service_t svc, char *name, papi_printer_t printer,
304 		int verbose, int description)
305 {
306 	papi_status_t status;
307 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
308 	time_t curr;
309 	int32_t pstat = 0;
310 	char *member = NULL;
311 
312 	status = papiAttributeListGetString(attrs, NULL,
313 				"member-names", &member);
314 	if (status == PAPI_OK)	/* it's a class */
315 		return (0);
316 
317 	if (name == NULL) {
318 		status = papiAttributeListGetString(attrs, NULL,
319 					"printer-name", &name);
320 		if (status != PAPI_OK)
321 			status = papiAttributeListGetString(attrs, NULL,
322 					"printer-uri-supported", &name);
323 	}
324 	if (name == NULL)
325 		return (-1);
326 
327 	printf(gettext("printer %s "), name);
328 
329 	status = papiAttributeListGetInteger(attrs, NULL,
330 					"printer-state", &pstat);
331 
332 	switch (pstat) {
333 	case 0x03:	/* idle */
334 		printf(gettext("idle. enabled"));
335 		break;
336 	case 0x04: {	/* processing */
337 		char *requested[] = { "job-id", NULL };
338 		papi_job_t *j = NULL;
339 		int32_t jobid = 0;
340 
341 		(void) papiPrinterListJobs(svc, name, requested, 0, 1, &j);
342 		if ((j != NULL) && (j[0] != NULL))
343 			jobid = papiJobGetId(j[0]);
344 		papiJobListFree(j);
345 
346 		printf(gettext("now printing %s-%d. enabled"), name, jobid);
347 		}
348 		break;
349 	case 0x05:	/* stopped */
350 		printf(gettext("disabled"));
351 		break;
352 	default:
353 		printf(gettext("unknown state(0x%x)."), pstat);
354 		break;
355 	}
356 
357 	(void) time(&curr);
358 	(void) papiAttributeListGetDatetime(attrs, NULL,
359 					"printer-up-time", &curr);
360 	(void) papiAttributeListGetDatetime(attrs, NULL,
361 					"printer-state-time", &curr);
362 	(void) papiAttributeListGetDatetime(attrs, NULL,
363 					"lpsched-disable-date", &curr);
364 	printf(gettext(" since %s. available.\n"), nctime(&curr));
365 
366 	if (pstat == 0x05) {
367 		char *reason = "unknown reason";
368 
369 		(void) papiAttributeListGetString(attrs, NULL,
370 					"printer-state-reasons", &reason);
371 		(void) papiAttributeListGetString(attrs, NULL,
372 					"lpsched-disable-reason", &reason);
373 		printf(gettext("\t%s\n"), reason);
374 	}
375 
376 	if (verbose == 1) {
377 		void *iter;
378 		char *str;
379 
380 		str = "";
381 		(void) papiAttributeListGetString(attrs, NULL,
382 					"form-ready", &str);
383 		printf(gettext("\tForm mounted: %s\n"), str);
384 
385 		str = "";
386 		iter = NULL;
387 		(void) papiAttributeListGetString(attrs, &iter,
388 					"document-format-supported", &str);
389 		printf(gettext("\tContent types: %s"), str);
390 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
391 				== PAPI_OK)
392 			printf(", %s", str);
393 		printf("\n");
394 
395 		str = "";
396 		(void) papiAttributeListGetString(attrs, NULL,
397 					"printer-info", &str);
398 		printf(gettext("\tDescription: %s\n"), str);
399 
400 		str = "";
401 		iter = NULL;
402 		(void) papiAttributeListGetString(attrs, &iter,
403 		    "lpsched-printer-type", &str);
404 		printf(gettext("\tPrinter types: %s"), str);
405 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
406 		    == PAPI_OK)
407 			printf(", %s", str);
408 		printf("\n");
409 
410 		str = "";
411 		(void) papiAttributeListGetString(attrs, NULL,
412 					"lpsched-dial-info", &str);
413 		printf(gettext("\tConnection: %s\n"),
414 			((str[0] != '\0') ? gettext("direct") : str));
415 
416 		str = "";
417 		(void) papiAttributeListGetString(attrs, NULL,
418 					"lpsched-interface-script", &str);
419 		printf(gettext("\tInterface: %s\n"), str);
420 
421 		str = NULL;
422 		(void) papiAttributeListGetString(attrs, NULL,
423 					"ppd-file-uri", &str);
424 		(void) papiAttributeListGetString(attrs, NULL,
425 					"lpsched-ppd-source-path", &str);
426 		if (str != NULL)
427 			printf(gettext("\tPPD: %s\n"), str);
428 
429 		str = NULL;
430 		(void) papiAttributeListGetString(attrs, NULL,
431 					"lpsched-fault-alert-command", &str);
432 		if (str != NULL)
433 			printf(gettext("\tOn fault: %s\n"), str);
434 
435 		str = "";
436 		(void) papiAttributeListGetString(attrs, NULL,
437 					"lpsched-fault-recovery", &str);
438 		printf(gettext("\tAfter fault: %s\n"),
439 			((str[0] == '\0') ? gettext("continue") : str));
440 
441 		str = "(all)";
442 		iter = NULL;
443 		(void) papiAttributeListGetString(attrs, &iter,
444 					"requesting-user-name-allowed", &str);
445 		printf(gettext("\tUsers allowed:\n\t\t%s\n"),
446 			((str[0] == '\0') ? gettext("(none)") : str));
447 		if ((str != NULL) && (str[0] != '\0'))
448 			while (papiAttributeListGetString(attrs, &iter, NULL,
449 					&str) == PAPI_OK)
450 				printf("\t\t%s\n", str);
451 
452 		str = NULL;
453 		iter = NULL;
454 		(void) papiAttributeListGetString(attrs, &iter,
455 					"requesting-user-name-denied", &str);
456 		if (str != NULL) {
457 			printf(gettext("\tUsers denied:\n\t\t%s\n"),
458 				((str[0] == '\0') ? gettext("(none)") : str));
459 			if ((str != NULL) && (str[0] != '\0'))
460 				while (papiAttributeListGetString(attrs, &iter,
461 						NULL, &str) == PAPI_OK)
462 					printf("\t\t%s\n", str);
463 		}
464 
465 		str = "(none)";
466 		iter = NULL;
467 		(void) papiAttributeListGetString(attrs, &iter,
468 					"form-supported", &str);
469 		printf(gettext("\tForms allowed:\n\t\t%s\n"),
470 			((str[0] == '\0') ? gettext("(none)") : str));
471 		if ((str != NULL) && (str[0] != '\0'))
472 			while (papiAttributeListGetString(attrs, &iter, NULL,
473 					&str) == PAPI_OK)
474 				printf("\t\t%s\n", str);
475 
476 		str = "";
477 		iter = NULL;
478 		(void) papiAttributeListGetString(attrs, &iter,
479 					"media-supported", &str);
480 		printf(gettext("\tMedia supported:\n\t\t%s\n"),
481 			((str[0] == '\0') ? gettext("(none)") : str));
482 		if ((str != NULL) && (str[0] != '\0'))
483 			while (papiAttributeListGetString(attrs, &iter, NULL,
484 					&str) == PAPI_OK)
485 				printf("\t\t%s\n", str);
486 
487 		str = "";
488 		(void) papiAttributeListGetString(attrs, NULL,
489 					"job-sheets-supported", &str);
490 		if ((strcasecmp(str, "none")) == 0)
491 			str = gettext("page never printed");
492 		else if (strcasecmp(str, "optional") == 0)
493 			str = gettext("not required");
494 		else
495 			str = gettext("required");
496 
497 		printf(gettext("\tBanner %s\n"), str);
498 
499 
500 		str = "";
501 		iter = NULL;
502 		(void) papiAttributeListGetString(attrs, &iter,
503 					"lpsched-print-wheels", &str);
504 		printf(gettext("\tCharacter sets:\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 		printf(gettext("\tDefault pitch:\n"));
512 		printf(gettext("\tDefault page size:\n"));
513 		printf(gettext("\tDefault port setting:\n"));
514 
515 		str = "";
516 		iter = NULL;
517 		(void) papiAttributeListGetString(attrs, &iter,
518 					"lpsched-options", &str);
519 		if (str != NULL) {
520 			printf(gettext("\tOptions: %s"), str);
521 			while (papiAttributeListGetString(attrs, &iter, NULL,
522 						&str) == PAPI_OK)
523 				printf(", %s", str);
524 			printf("\n");
525 		}
526 
527 	} else if (description == 1) {
528 		char *str = "";
529 		(void) papiAttributeListGetString(attrs, NULL,
530 					"printer-description", &str);
531 		printf(gettext("\tDescription: %s\n"), str);
532 	} else if (verbose > 1)
533 		papiAttributeListPrint(stdout, attrs, "\t");
534 
535 	if (verbose > 0)
536 		printf("\n");
537 
538 	return (0);
539 }
540 
541 static int
542 printer_query(char *name, int (*report)(papi_service_t, char *, papi_printer_t,
543 					int, int), papi_encryption_t encryption,
544 		int verbose, int description)
545 {
546 	int result = 0;
547 	papi_status_t status;
548 	papi_service_t svc = NULL;
549 
550 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
551 					encryption, NULL);
552 	if (status != PAPI_OK) {
553 		if (status == PAPI_NOT_FOUND)
554 			fprintf(stderr, gettext("%s: unknown printer\n"),
555 				name ? name : "(NULL)");
556 		else
557 			fprintf(stderr, gettext(
558 				"Failed to contact service for %s: %s\n"),
559 				name ? name : "(NULL)",
560 				verbose_papi_message(svc, status));
561 		papiServiceDestroy(svc);
562 		return (-1);
563 	}
564 
565 	if (name == NULL) { /* all */
566 		char **interest = interest_list(svc);
567 
568 		if (interest != NULL) {
569 			int i;
570 
571 			for (i = 0; interest[i] != NULL; i++)
572 				result += printer_query(interest[i], report,
573 							encryption, verbose,
574 							description);
575 		}
576 	} else {
577 		papi_printer_t printer = NULL;
578 		char **keys = NULL;
579 
580 		/*
581 		 * Limit the query to only required data to reduce the need
582 		 * to go remote for information.
583 		 */
584 		if (report == report_device)
585 			keys = report_device_keys;
586 		else if (report == report_class)
587 			keys = report_class_keys;
588 		else if (report == report_accepting)
589 			keys = report_accepting_keys;
590 		else if ((report == report_printer) && (verbose == 0))
591 			keys = report_printer_keys;
592 
593 		status = papiPrinterQuery(svc, name, keys, NULL, &printer);
594 		if (status != PAPI_OK) {
595 			fprintf(stderr, gettext(
596 				"Failed to get printer info for %s: %s\n"),
597 				name, verbose_papi_message(svc, status));
598 			papiServiceDestroy(svc);
599 			return (-1);
600 		}
601 
602 		if (printer != NULL)
603 			result = report(svc, name, printer, verbose,
604 					description);
605 
606 		papiPrinterFree(printer);
607 	}
608 
609 	papiServiceDestroy(svc);
610 
611 	return (result);
612 }
613 
614 static int
615 match_user(char *user, char **list)
616 {
617 	int i;
618 
619 	for (i = 0; list[i] != NULL; i++) {
620 		if (strcmp(user, list[i]) == 0)
621 			return (0);
622 	}
623 
624 	return (-1);
625 }
626 
627 static char **users = NULL;
628 
629 static int
630 report_job(papi_job_t job, int show_rank, int verbose)
631 {
632 	papi_attribute_t **attrs = papiJobGetAttributeList(job);
633 	time_t clock = 0;
634 	char date[24];
635 	char request[26];
636 	char *user = "unknown";
637 	int32_t size = 0;
638 	int32_t jstate = 0;
639 
640 	char *destination = "unknown";
641 	int32_t id = -1;
642 
643 	(void) papiAttributeListGetString(attrs, NULL,
644 				"job-originating-user-name", &user);
645 
646 	if ((users != NULL) && (match_user(user, users) < 0))
647 		return (0);
648 
649 	(void) papiAttributeListGetInteger(attrs, NULL, "job-k-octets", &size);
650 	size *= 1024;	/* for the approximate byte size */
651 	(void) papiAttributeListGetInteger(attrs, NULL, "job-octets", &size);
652 
653 	(void) time(&clock);
654 	(void) papiAttributeListGetInteger(attrs, NULL,
655 				"time-at-creation", (int32_t *)&clock);
656 	(void) strftime(date, sizeof (date), "%b %d %R", localtime(&clock));
657 
658 	(void) papiAttributeListGetString(attrs, NULL,
659 				"job-printer-uri", &destination);
660 	(void) papiAttributeListGetString(attrs, NULL,
661 				"printer-name", &destination);
662 	(void) papiAttributeListGetInteger(attrs, NULL,
663 				"job-id", &id);
664 	snprintf(request, sizeof (request), "%s-%d", destination, id);
665 
666 	if (show_rank != 0) {
667 		int32_t rank = -1;
668 
669 		(void) papiAttributeListGetInteger(attrs, NULL,
670 				"number-of-intervening-jobs", &rank);
671 		rank++;
672 
673 		printf("%3d %-21s %-14s %7ld %s",
674 			rank, request, user, size, date);
675 	} else
676 		printf("%-23s %-14s %7ld   %s", request, user, size, date);
677 
678 	(void) papiAttributeListGetInteger(attrs, NULL,
679 				"job-state", &jstate);
680 	if (jstate == 0x04)
681 		printf(gettext(", being held"));
682 	else if (jstate == 0x07)
683 		printf(gettext(", cancelled"));
684 	else if (jstate == 0x09)
685 		printf(gettext(", complete"));
686 
687 	if (verbose == 1) {
688 		char *form = NULL;
689 
690 		(void) papiAttributeListGetString(attrs, NULL,
691 				"output-device-assigned", &destination);
692 		printf("\n\t assigned %s", destination);
693 
694 		(void) papiAttributeListGetString(attrs, NULL, "form", &form);
695 		if (form != NULL)
696 			printf(", form %s", form);
697 	} else if (verbose > 1) {
698 		printf("\n");
699 		papiAttributeListPrint(stdout, attrs, "\t");
700 	}
701 
702 	printf("\n");
703 
704 	return (0);
705 }
706 
707 static int
708 job_query(char *request, int (*report)(papi_job_t, int, int),
709 		papi_encryption_t encryption, int show_rank, int verbose)
710 {
711 	int result = 0;
712 	papi_status_t status;
713 	papi_service_t svc = NULL;
714 	char *printer = NULL;
715 	int32_t id = -1;
716 
717 	get_printer_id(request, &printer, &id);
718 
719 	status = papiServiceCreate(&svc, printer, NULL, NULL, cli_auth_callback,
720 					encryption, NULL);
721 	if (status != PAPI_OK) {
722 		fprintf(stderr, gettext(
723 			"Failed to contact service for %s: %s\n"),
724 			(printer ? printer : "all"),
725 			verbose_papi_message(svc, status));
726 		return (-1);
727 	}
728 
729 	if (printer == NULL) { /* all */
730 		char **interest = interest_list(svc);
731 
732 		if (interest != NULL) {
733 			int i;
734 
735 			for (i = 0; interest[i] != NULL; i++)
736 				result += job_query(interest[i], report,
737 						encryption, show_rank, verbose);
738 		}
739 	} else if (id == -1) { /* a printer */
740 		papi_job_t *jobs = NULL;
741 
742 		status = papiPrinterListJobs(svc, printer, NULL, 0, 0, &jobs);
743 		if (status != PAPI_OK) {
744 			fprintf(stderr, gettext(
745 				"Failed to get job list: %s\n"),
746 				verbose_papi_message(svc, status));
747 			papiServiceDestroy(svc);
748 			return (-1);
749 		}
750 
751 		if (jobs != NULL) {
752 			int i;
753 
754 			for (i = 0; jobs[i] != NULL; i++)
755 				result += report(jobs[i], show_rank, verbose);
756 		}
757 
758 		papiJobListFree(jobs);
759 	} else {	/* a job */
760 		papi_job_t job = NULL;
761 
762 		status = papiJobQuery(svc, printer, id, NULL, &job);
763 		if (status != PAPI_OK) {
764 			fprintf(stderr, gettext(
765 				"Failed to get job info for %s: %s\n"),
766 				request, verbose_papi_message(svc, status));
767 			papiServiceDestroy(svc);
768 			return (-1);
769 		}
770 
771 		if (job != NULL)
772 			result = report(job, show_rank, verbose);
773 
774 		papiJobFree(job);
775 	}
776 
777 	papiServiceDestroy(svc);
778 
779 	return (result);
780 }
781 
782 static int
783 report_form(char *name, papi_attribute_t **attrs, int verbose)
784 {
785 	papi_status_t status;
786 	char *form = NULL;
787 	void *iter = NULL;
788 
789 	for (status = papiAttributeListGetString(attrs, &iter,
790 					"form-supported", &form);
791 		status == PAPI_OK;
792 		status = papiAttributeListGetString(attrs, &iter,
793 							NULL, &form)) {
794 		if ((name == NULL) || (strcmp(name, form) == 0)) {
795 			printf(gettext("form %s is available to you\n"), form);
796 			if (verbose != 0) {
797 				char *detail = NULL;
798 				status = papiAttributeListGetString(attrs, NULL,
799 						"form-supported-detail",
800 						&detail);
801 				if (status == PAPI_OK)
802 					printf("%s\n", detail);
803 			}
804 		}
805 	}
806 
807 	return (0);
808 }
809 
810 static int
811 report_print_wheels(char *name, papi_attribute_t **attrs, int verbose)
812 {
813 	papi_status_t status;
814 	char *pw = NULL;
815 	void *iter = NULL;
816 
817 	for (status = papiAttributeListGetString(attrs, &iter,
818 					"pw-supported", &pw);
819 		status == PAPI_OK;
820 		status = papiAttributeListGetString(attrs, &iter, NULL, &pw)) {
821 		if ((name == NULL) || (strcmp(name, pw) == 0)) {
822 			printf(gettext("charset %s is available\n"), pw);
823 			if (verbose != 0) {
824 				char *info = NULL;
825 				status = papiAttributeListGetString(attrs, NULL,
826 						"pw-supported-extra", &info);
827 				if (status == PAPI_OK)
828 					printf("%s\n", info);
829 			}
830 		}
831 	}
832 
833 	return (0);
834 }
835 
836 static int
837 service_query(char *name, int (*report)(char *, papi_attribute_t **, int),
838 		papi_encryption_t encryption, int verbose)
839 {
840 	int result = 0;
841 	papi_status_t status;
842 	papi_service_t svc = NULL;
843 	papi_attribute_t **attrs = NULL;
844 
845 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
846 					encryption, NULL);
847 	if (status != PAPI_OK) {
848 		papiServiceDestroy(svc);
849 		return (-1);
850 	}
851 
852 	attrs = papiServiceGetAttributeList(svc);
853 	if (attrs != NULL) {
854 		result = report(name, attrs, verbose);
855 
856 		if (verbose > 1) {
857 			printf("\n");
858 			papiAttributeListPrint(stdout, attrs, "\t");
859 			printf("\n");
860 		}
861 	}
862 
863 	papiServiceDestroy(svc);
864 
865 	return (result);
866 }
867 
868 int
869 main(int ac, char *av[])
870 {
871 	int exit_code = 0;
872 	papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
873 	int rank = 0;
874 	int verbose = 0;
875 	int description = 0;
876 	int c;
877 	char **argv;
878 
879 	(void) setlocale(LC_ALL, "");
880 	(void) textdomain("SUNW_OST_OSCMD");
881 
882 	argv = (char **)calloc((ac + 1), sizeof (char *));
883 	for (c = 0; c < ac; c++) {
884 		if ((av[c][0] == '-') && (av[c][1] == 'l') &&
885 			(isalpha(av[c][2]) != 0)) {
886 			/* preserve old "-l[po...]" behavior */
887 			argv[c] = &av[c][1];
888 			argv[c][0] = '-';
889 			verbose = 1;
890 
891 		} else
892 			argv[c] = av[c];
893 	}
894 
895 	argv[c++] = "--";
896 	ac = c;
897 
898 	/* preprocess argument list looking for '-l' or '-R' so it can trail */
899 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF)
900 		switch (c) {
901 		case 'l':
902 			if ((optarg == NULL) || (optarg[0] == '-'))
903 				optarg = "1";
904 			verbose = atoi(optarg);
905 			break;
906 		case 'D':
907 			description = 1;
908 			break;
909 		case 'R':
910 			rank = 1;
911 			break;
912 		case 'E':
913 			encryption = PAPI_ENCRYPT_REQUIRED;
914 			break;
915 		default:
916 			break;
917 		}
918 	optind = 1;
919 
920 	/* process command line arguments */
921 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
922 		switch (c) {	/* these may or may not have an option */
923 		case 'a':
924 		case 'c':
925 		case 'p':
926 		case 'o':
927 		case 'R':
928 		case 'u':
929 		case 'v':
930 		case 'l':
931 		case 'f':
932 		case 'S':
933 			if (optarg[0] == '-') {
934 				/* this check stop a possible infinite loop */
935 				if ((optind > 1) && (argv[optind-1][1] != c))
936 					optind--;
937 				optarg = NULL;
938 			} else if (strcmp(optarg, "all") == 0)
939 				optarg = NULL;
940 		}
941 
942 		switch (c) {
943 		case 'a':
944 			exit_code += printer_query(optarg, report_accepting,
945 						encryption, verbose, 0);
946 			break;
947 		case 'c':
948 			exit_code += printer_query(optarg, report_class,
949 						encryption, verbose, 0);
950 			break;
951 		case 'p':
952 			exit_code += printer_query(optarg, report_printer,
953 						encryption, verbose,
954 						description);
955 			break;
956 		case 'd':
957 			exit_code += lpstat_default_printer(encryption);
958 			break;
959 		case 'r':
960 			exit_code += lpstat_service_status(encryption);
961 			break;
962 		case 'u':
963 			if (optarg != NULL)
964 				users = strsplit(optarg, ", \n");
965 			exit_code += job_query(NULL, report_job,
966 						encryption, rank, verbose);
967 			if (users != NULL) {
968 				free(users);
969 				users = NULL;
970 			}
971 			break;
972 		case 'v':
973 			exit_code += printer_query(optarg, report_device,
974 						encryption, verbose, 0);
975 			break;
976 		case 'o':
977 			exit_code += job_query(optarg, report_job,
978 						encryption, rank, verbose);
979 			break;
980 		case 'f':
981 			exit_code += service_query(optarg, report_form,
982 						encryption, verbose);
983 			break;
984 		case 'S':
985 			exit_code += service_query(optarg, report_print_wheels,
986 						encryption, verbose);
987 			break;
988 		case 's':
989 			exit_code += lpstat_service_status(encryption);
990 			exit_code += lpstat_default_printer(encryption);
991 			exit_code += printer_query(NULL, report_class,
992 						encryption, verbose, 0);
993 			exit_code += printer_query(NULL, report_device,
994 						encryption, verbose, 0);
995 			exit_code += service_query(optarg, report_form,
996 						encryption, verbose);
997 			exit_code += service_query(optarg, report_print_wheels,
998 						encryption, verbose);
999 			break;
1000 		case 't':
1001 			exit_code += lpstat_service_status(encryption);
1002 			exit_code += lpstat_default_printer(encryption);
1003 			exit_code += printer_query(NULL, report_class,
1004 						encryption, verbose, 0);
1005 			exit_code += printer_query(NULL, report_device,
1006 						encryption, verbose, 0);
1007 			exit_code += printer_query(NULL, report_accepting,
1008 						encryption, verbose, 0);
1009 			exit_code += printer_query(NULL, report_printer,
1010 						encryption, verbose, 0);
1011 			exit_code += service_query(optarg, report_form,
1012 						encryption, verbose);
1013 			exit_code += service_query(optarg, report_print_wheels,
1014 						encryption, verbose);
1015 			exit_code += job_query(NULL, report_job,
1016 						encryption, rank, verbose);
1017 			break;
1018 		case 'L':	/* local-only, ignored */
1019 		case 'l':	/* increased verbose level in first pass */
1020 		case 'D':	/* set "description" flag in first pass */
1021 		case 'R':	/* set "rank" flag in first pass */
1022 		case 'E':	/* set encryption in the first pass */
1023 			break;
1024 		default:
1025 			usage(av[0]);
1026 		}
1027 	}
1028 	ac--;
1029 
1030 	if (ac == 1) {	/* report on my jobs */
1031 		struct passwd *pw = getpwuid(getuid());
1032 
1033 		if (pw != NULL)
1034 			users = strsplit(pw->pw_name, "");
1035 		exit_code += job_query(NULL, report_job, encryption,
1036 					rank, verbose);
1037 		if (users != NULL) {
1038 			free(users);
1039 			users = NULL;
1040 		}
1041 	} else {
1042 		for (c = optind; c < ac; c++)
1043 			exit_code += job_query(argv[c], report_job, encryption,
1044 					rank, verbose);
1045 	}
1046 
1047 
1048 	if (exit_code != 0)
1049 		exit_code = 1;
1050 
1051 	return (exit_code);
1052 }
1053