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 
348 	status = papiAttributeListGetString(attrs, NULL,
349 				"member-names", &member);
350 	if (status == PAPI_OK)	/* it's a class */
351 		return (0);
352 
353 	if (name == NULL) {
354 		status = papiAttributeListGetString(attrs, NULL,
355 					"printer-name", &name);
356 		if (status != PAPI_OK)
357 			status = papiAttributeListGetString(attrs, NULL,
358 					"printer-uri-supported", &name);
359 	}
360 	if (name == NULL)
361 		return (-1);
362 
363 	printf(gettext("printer %s "), name);
364 
365 	status = papiAttributeListGetInteger(attrs, NULL,
366 					"printer-state", &pstat);
367 
368 	switch (pstat) {
369 	case 0x03:	/* idle */
370 		printf(gettext("idle. enabled"));
371 		break;
372 	case 0x04: {	/* processing */
373 		char *requested[] = { "job-id", NULL };
374 		papi_job_t *j = NULL;
375 		int32_t jobid = 0;
376 
377 		(void) papiPrinterListJobs(svc, name, requested, 0, 1, &j);
378 		if ((j != NULL) && (j[0] != NULL))
379 			jobid = papiJobGetId(j[0]);
380 		papiJobListFree(j);
381 
382 		printf(gettext("now printing %s-%d. enabled"), name, jobid);
383 		}
384 		break;
385 	case 0x05:	/* stopped */
386 		printf(gettext("disabled"));
387 		break;
388 	default:
389 		printf(gettext("unknown state(0x%x)."), pstat);
390 		break;
391 	}
392 
393 	(void) time(&curr);
394 	(void) papiAttributeListGetDatetime(attrs, NULL,
395 					"printer-up-time", &curr);
396 	(void) papiAttributeListGetDatetime(attrs, NULL,
397 					"printer-state-time", &curr);
398 	(void) papiAttributeListGetDatetime(attrs, NULL,
399 					"lpsched-disable-date", &curr);
400 	printf(gettext(" since %s. available.\n"), nctime(&curr));
401 
402 	if (pstat == 0x05) {
403 		char *reason = "unknown reason";
404 
405 		(void) papiAttributeListGetString(attrs, NULL,
406 					"printer-state-reasons", &reason);
407 		(void) papiAttributeListGetString(attrs, NULL,
408 					"lpsched-disable-reason", &reason);
409 		printf(gettext("\t%s\n"), reason);
410 	}
411 
412 	if (verbose == 1) {
413 		void *iter;
414 		char *str;
415 
416 		str = "";
417 		(void) papiAttributeListGetString(attrs, NULL,
418 					"form-ready", &str);
419 		printf(gettext("\tForm mounted: %s\n"), str);
420 
421 		str = "";
422 		iter = NULL;
423 		(void) papiAttributeListGetString(attrs, &iter,
424 					"document-format-supported", &str);
425 		printf(gettext("\tContent types: %s"), str);
426 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
427 				== PAPI_OK)
428 			printf(", %s", str);
429 		printf("\n");
430 
431 		/* Display the printer description */
432 		print_description(attrs, name);
433 
434 		str = "";
435 		iter = NULL;
436 		(void) papiAttributeListGetString(attrs, &iter,
437 		    "lpsched-printer-type", &str);
438 		printf(gettext("\tPrinter types: %s"), str);
439 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
440 		    == PAPI_OK)
441 			printf(", %s", str);
442 		printf("\n");
443 
444 		str = "";
445 		(void) papiAttributeListGetString(attrs, NULL,
446 					"lpsched-dial-info", &str);
447 		printf(gettext("\tConnection: %s\n"),
448 		    ((str[0] == '\0') ? gettext("direct") : str));
449 
450 		str = "";
451 		(void) papiAttributeListGetString(attrs, NULL,
452 					"lpsched-interface-script", &str);
453 		printf(gettext("\tInterface: %s\n"), str);
454 
455 		str = NULL;
456 		(void) papiAttributeListGetString(attrs, NULL,
457 					"ppd-file-uri", &str);
458 		(void) papiAttributeListGetString(attrs, NULL,
459 					"lpsched-ppd-source-path", &str);
460 		if (str != NULL)
461 			printf(gettext("\tPPD: %s\n"), str);
462 
463 		str = NULL;
464 		(void) papiAttributeListGetString(attrs, NULL,
465 					"lpsched-fault-alert-command", &str);
466 		if (str != NULL)
467 			printf(gettext("\tOn fault: %s\n"), str);
468 
469 		str = "";
470 		(void) papiAttributeListGetString(attrs, NULL,
471 					"lpsched-fault-recovery", &str);
472 		printf(gettext("\tAfter fault: %s\n"),
473 			((str[0] == '\0') ? gettext("continue") : str));
474 
475 		str = "(all)";
476 		iter = NULL;
477 		(void) papiAttributeListGetString(attrs, &iter,
478 					"requesting-user-name-allowed", &str);
479 		printf(gettext("\tUsers allowed:\n\t\t%s\n"),
480 			((str[0] == '\0') ? gettext("(none)") : str));
481 		if ((str != NULL) && (str[0] != '\0'))
482 			while (papiAttributeListGetString(attrs, &iter, NULL,
483 					&str) == PAPI_OK)
484 				printf("\t\t%s\n", str);
485 
486 		str = NULL;
487 		iter = NULL;
488 		(void) papiAttributeListGetString(attrs, &iter,
489 					"requesting-user-name-denied", &str);
490 		if (str != NULL) {
491 			printf(gettext("\tUsers denied:\n\t\t%s\n"),
492 				((str[0] == '\0') ? gettext("(none)") : str));
493 			if ((str != NULL) && (str[0] != '\0'))
494 				while (papiAttributeListGetString(attrs, &iter,
495 						NULL, &str) == PAPI_OK)
496 					printf("\t\t%s\n", str);
497 		}
498 
499 		str = "none";
500 		iter = NULL;
501 		(void) papiAttributeListGetString(attrs, &iter,
502 					"form-supported", &str);
503 		printf(gettext("\tForms allowed:\n\t\t(%s)\n"),
504 			((str[0] == '\0') ? gettext("none") : str));
505 		if ((str != NULL) && (str[0] != '\0'))
506 			while (papiAttributeListGetString(attrs, &iter, NULL,
507 					&str) == PAPI_OK)
508 				printf("\t\t(%s)\n", str);
509 
510 		str = "";
511 		iter = NULL;
512 		(void) papiAttributeListGetString(attrs, &iter,
513 					"media-supported", &str);
514 		printf(gettext("\tMedia supported:\n\t\t%s\n"),
515 			((str[0] == '\0') ? gettext("(none)") : str));
516 		if ((str != NULL) && (str[0] != '\0'))
517 			while (papiAttributeListGetString(attrs, &iter, NULL,
518 					&str) == PAPI_OK)
519 				printf("\t\t%s\n", str);
520 
521 		str = "";
522 		(void) papiAttributeListGetString(attrs, NULL,
523 					"job-sheets-supported", &str);
524 		if ((strcasecmp(str, "none")) == 0)
525 			str = gettext("page never printed");
526 		else if (strcasecmp(str, "optional") == 0)
527 			str = gettext("not required");
528 		else
529 			str = gettext("required");
530 
531 		printf(gettext("\tBanner %s\n"), str);
532 
533 
534 		str = "";
535 		iter = NULL;
536 		(void) papiAttributeListGetString(attrs, &iter,
537 					"lpsched-print-wheels", &str);
538 		printf(gettext("\tCharacter sets:\n\t\t%s\n"),
539 			((str[0] == '\0') ? gettext("(none)") : str));
540 		if ((str != NULL) && (str[0] != '\0'))
541 			while (papiAttributeListGetString(attrs, &iter, NULL,
542 					&str) == PAPI_OK)
543 				printf("\t\t%s\n", str);
544 
545 		printf(gettext("\tDefault pitch:\n"));
546 		printf(gettext("\tDefault page size:\n"));
547 		printf(gettext("\tDefault port setting:\n"));
548 
549 		str = "";
550 		iter = NULL;
551 		(void) papiAttributeListGetString(attrs, &iter,
552 					"lpsched-options", &str);
553 		if (str != NULL) {
554 			printf(gettext("\tOptions: %s"), str);
555 			while (papiAttributeListGetString(attrs, &iter, NULL,
556 						&str) == PAPI_OK)
557 				printf(", %s", str);
558 			printf("\n");
559 		}
560 
561 	} else if (description == 1)
562 		/* Display printer description */
563 		print_description(attrs, name);
564 	else if (verbose > 1)
565 		papiAttributeListPrint(stdout, attrs, "\t");
566 
567 	if (verbose > 0)
568 		printf("\n");
569 
570 	return (0);
571 }
572 
573 static int
574 printer_query(char *name, int (*report)(papi_service_t, char *, papi_printer_t,
575 					int, int), papi_encryption_t encryption,
576 		int verbose, int description)
577 {
578 	int result = 0;
579 	papi_status_t status;
580 	papi_service_t svc = NULL;
581 
582 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
583 					encryption, NULL);
584 	if (status != PAPI_OK) {
585 		if (status == PAPI_NOT_FOUND)
586 			fprintf(stderr, gettext("%s: unknown printer\n"),
587 				name ? name : "(NULL)");
588 		else
589 			fprintf(stderr, gettext(
590 				"Failed to contact service for %s: %s\n"),
591 				name ? name : "(NULL)",
592 				verbose_papi_message(svc, status));
593 		papiServiceDestroy(svc);
594 		return (-1);
595 	}
596 
597 	if (name == NULL) { /* all */
598 		char **interest = interest_list(svc);
599 
600 		if (interest != NULL) {
601 			int i;
602 
603 			for (i = 0; interest[i] != NULL; i++)
604 				result += printer_query(interest[i], report,
605 							encryption, verbose,
606 							description);
607 		}
608 	} else {
609 		papi_printer_t printer = NULL;
610 		char **keys = NULL;
611 
612 		/*
613 		 * Limit the query to only required data to reduce the need
614 		 * to go remote for information.
615 		 */
616 		if (report == report_device)
617 			keys = report_device_keys;
618 		else if (report == report_class)
619 			keys = report_class_keys;
620 		else if (report == report_accepting)
621 			keys = report_accepting_keys;
622 		else if ((report == report_printer) && (verbose == 0))
623 			keys = report_printer_keys;
624 
625 		status = papiPrinterQuery(svc, name, keys, NULL, &printer);
626 		if (status != PAPI_OK) {
627 			fprintf(stderr, gettext(
628 				"Failed to get printer info for %s: %s\n"),
629 				name, verbose_papi_message(svc, status));
630 			papiServiceDestroy(svc);
631 			return (-1);
632 		}
633 
634 		if (printer != NULL)
635 			result = report(svc, name, printer, verbose,
636 					description);
637 
638 		papiPrinterFree(printer);
639 	}
640 
641 	papiServiceDestroy(svc);
642 
643 	return (result);
644 }
645 
646 static int
647 match_user(char *user, char **list)
648 {
649 	int i;
650 
651 	for (i = 0; list[i] != NULL; i++) {
652 		if (strcmp(user, list[i]) == 0)
653 			return (0);
654 	}
655 
656 	return (-1);
657 }
658 
659 static char **users = NULL;
660 
661 static int
662 report_job(papi_job_t job, int show_rank, int verbose)
663 {
664 	papi_attribute_t **attrs = papiJobGetAttributeList(job);
665 	time_t clock = 0;
666 	char date[24];
667 	char request[26];
668 	char *user = "unknown";
669 	char *host = NULL;
670 	int32_t size = 0;
671 	int32_t jstate = 0;
672 	char User[50];
673 
674 	char *destination = "unknown";
675 	int32_t id = -1;
676 
677 	(void) papiAttributeListGetString(attrs, NULL,
678 				"job-originating-user-name", &user);
679 
680 	if ((users != NULL) && (match_user(user, users) < 0))
681 		return (0);
682 
683 	(void) papiAttributeListGetString(attrs, NULL,
684 	    "job-originating-host-name", &host);
685 
686 	if (host)
687 		snprintf(User, sizeof (User), "%s@%s", user, host);
688 	else
689 		snprintf(User, sizeof (User), "%s", user);
690 
691 	(void) papiAttributeListGetInteger(attrs, NULL, "job-k-octets", &size);
692 	size *= 1024;	/* for the approximate byte size */
693 	(void) papiAttributeListGetInteger(attrs, NULL, "job-octets", &size);
694 
695 	(void) time(&clock);
696 	(void) papiAttributeListGetInteger(attrs, NULL,
697 				"time-at-creation", (int32_t *)&clock);
698 	(void) strftime(date, sizeof (date), "%b %d %R", localtime(&clock));
699 
700 	(void) papiAttributeListGetString(attrs, NULL,
701 				"job-printer-uri", &destination);
702 	(void) papiAttributeListGetString(attrs, NULL,
703 				"printer-name", &destination);
704 	(void) papiAttributeListGetInteger(attrs, NULL,
705 				"job-id", &id);
706 	snprintf(request, sizeof (request), "%s-%d", destination, id);
707 
708 	if (show_rank != 0) {
709 		int32_t rank = -1;
710 
711 		(void) papiAttributeListGetInteger(attrs, NULL,
712 				"number-of-intervening-jobs", &rank);
713 		rank++;
714 
715 		printf("%3d %-21s %-14s %7ld %s",
716 		    rank, request, User, size, date);
717 	} else
718 		printf("%-23s %-14s %7ld   %s", request, User, size, date);
719 
720 	(void) papiAttributeListGetInteger(attrs, NULL,
721 				"job-state", &jstate);
722 	if (jstate == 0x04)
723 		printf(gettext(", being held"));
724 	else if (jstate == 0x07)
725 		printf(gettext(", cancelled"));
726 	else if (jstate == 0x09)
727 		printf(gettext(", complete"));
728 
729 	if (verbose == 1) {
730 		char *form = NULL;
731 
732 		(void) papiAttributeListGetString(attrs, NULL,
733 				"output-device-assigned", &destination);
734 		printf("\n\t assigned %s", destination);
735 
736 		(void) papiAttributeListGetString(attrs, NULL, "form", &form);
737 		if (form != NULL)
738 			printf(", form %s", form);
739 	} else if (verbose > 1) {
740 		printf("\n");
741 		papiAttributeListPrint(stdout, attrs, "\t");
742 	}
743 
744 	printf("\n");
745 
746 	return (0);
747 }
748 
749 static int
750 job_query(char *request, int (*report)(papi_job_t, int, int),
751 		papi_encryption_t encryption, int show_rank, int verbose)
752 {
753 	int result = 0;
754 	papi_status_t status;
755 	papi_service_t svc = NULL;
756 	char *printer = request;
757 	int32_t id = -1;
758 	int flag1 = 0;
759 	int flag = 1;
760 	int print_flag = 0;
761 
762 	do {
763 		status = papiServiceCreate(&svc, printer, NULL, NULL,
764 			    cli_auth_callback, encryption, NULL);
765 
766 		if ((status == PAPI_OK) && (printer != NULL))
767 			print_flag = 1;
768 
769 		/* <name>-# printer name does not exist */
770 		if (status != PAPI_OK) {
771 			/*
772 			 * Check if <name>-# is a request-id
773 			 * Once this check is done flag1 is set
774 			 */
775 			if (flag1 == 1)
776 				break;
777 
778 			get_printer_id(printer, &printer, &id);
779 
780 			status = papiServiceCreate(&svc, printer, NULL, NULL,
781 				    cli_auth_callback, encryption, NULL);
782 
783 			if (status != PAPI_OK) {
784 				fprintf(stderr, gettext(
785 				    "Failed to contact service for %s: %s\n"),
786 				    (printer ? printer : "all"),
787 				    verbose_papi_message(svc, status));
788 				return (-1);
789 			}
790 		}
791 
792 		if (printer == NULL) { /* all */
793 			char **interest = interest_list(svc);
794 
795 			if (interest != NULL) {
796 				int i;
797 
798 				for (i = 0; interest[i] != NULL; i++)
799 					result += job_query(interest[i], report,
800 						    encryption, show_rank, verbose);
801 			}
802 		} else if (id == -1) { /* a printer */
803 			papi_job_t *jobs = NULL;
804 
805 			status = papiPrinterListJobs(svc, printer, NULL,
806 				    0, 0, &jobs);
807 			if (status != PAPI_OK) {
808 				fprintf(stderr, gettext(
809 				    "Failed to get job list: %s\n"),
810 				    verbose_papi_message(svc, status));
811 				papiServiceDestroy(svc);
812 				return (-1);
813 			}
814 
815 			if (jobs != NULL) {
816 				int i;
817 
818 				for (i = 0; jobs[i] != NULL; i++)
819 					result += report(jobs[i],
820 						    show_rank, verbose);
821 			}
822 
823 			papiJobListFree(jobs);
824 		} else {	/* a job */
825 			papi_job_t job = NULL;
826 
827 			/* Once a job has been found stop processing */
828 			flag = 0;
829 
830 			status = papiJobQuery(svc, printer, id, NULL, &job);
831 			if (status != PAPI_OK) {
832 				if (!print_flag)
833 					fprintf(stderr, gettext(
834 					    "Failed to get job info for %s: %s\n"),
835 					    request, verbose_papi_message(svc, status));
836 				papiServiceDestroy(svc);
837 				return (-1);
838 			}
839 
840 			if (job != NULL)
841 				result = report(job, show_rank, verbose);
842 
843 			papiJobFree(job);
844 		}
845 
846 		if (flag) {
847 			id = -1;
848 			get_printer_id(printer, &printer, &id);
849 			if (id == -1)
850 				flag = 0;
851 			else
852 				flag1 = 1;
853 		}
854 	} while (flag);
855 
856 	papiServiceDestroy(svc);
857 
858 	return (result);
859 }
860 
861 static int
862 report_form(char *name, papi_attribute_t **attrs, int verbose)
863 {
864 	papi_status_t status;
865 	char *form = NULL;
866 	void *iter = NULL;
867 
868 	for (status = papiAttributeListGetString(attrs, &iter,
869 					"form-supported", &form);
870 		status == PAPI_OK;
871 		status = papiAttributeListGetString(attrs, &iter,
872 							NULL, &form)) {
873 		if ((name == NULL) || (strcmp(name, form) == 0)) {
874 			printf(gettext("form %s is available to you\n"), form);
875 			if (verbose != 0) {
876 				char *detail = NULL;
877 				status = papiAttributeListGetString(attrs, NULL,
878 						"form-supported-detail",
879 						&detail);
880 				if (status == PAPI_OK)
881 					printf("%s\n", detail);
882 			}
883 		}
884 	}
885 
886 	return (0);
887 }
888 
889 static int
890 report_print_wheels(char *name, papi_attribute_t **attrs, int verbose)
891 {
892 	papi_status_t status;
893 	char *pw = NULL;
894 	void *iter = NULL;
895 
896 	for (status = papiAttributeListGetString(attrs, &iter,
897 					"pw-supported", &pw);
898 		status == PAPI_OK;
899 		status = papiAttributeListGetString(attrs, &iter, NULL, &pw)) {
900 		if ((name == NULL) || (strcmp(name, pw) == 0)) {
901 			printf(gettext("charset %s is available\n"), pw);
902 			if (verbose != 0) {
903 				char *info = NULL;
904 				status = papiAttributeListGetString(attrs, NULL,
905 						"pw-supported-extra", &info);
906 				if (status == PAPI_OK)
907 					printf("%s\n", info);
908 			}
909 		}
910 	}
911 
912 	return (0);
913 }
914 
915 static int
916 service_query(char *name, int (*report)(char *, papi_attribute_t **, int),
917 		papi_encryption_t encryption, int verbose)
918 {
919 	int result = 0;
920 	papi_status_t status;
921 	papi_service_t svc = NULL;
922 	papi_attribute_t **attrs = NULL;
923 
924 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
925 					encryption, NULL);
926 	if (status != PAPI_OK) {
927 		papiServiceDestroy(svc);
928 		return (-1);
929 	}
930 
931 	attrs = papiServiceGetAttributeList(svc);
932 	if (attrs != NULL) {
933 		result = report(name, attrs, verbose);
934 
935 		if (verbose > 1) {
936 			printf("\n");
937 			papiAttributeListPrint(stdout, attrs, "\t");
938 			printf("\n");
939 		}
940 	}
941 
942 	papiServiceDestroy(svc);
943 
944 	return (result);
945 }
946 
947 int
948 main(int ac, char *av[])
949 {
950 	int exit_code = 0;
951 	papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
952 	int rank = 0;
953 	int verbose = 0;
954 	int description = 0;
955 	int c;
956 	char **argv;
957 
958 	(void) setlocale(LC_ALL, "");
959 	(void) textdomain("SUNW_OST_OSCMD");
960 
961 	argv = (char **)calloc((ac + 1), sizeof (char *));
962 	for (c = 0; c < ac; c++) {
963 		if ((av[c][0] == '-') && (av[c][1] == 'l') &&
964 			(isalpha(av[c][2]) != 0)) {
965 			/* preserve old "-l[po...]" behavior */
966 			argv[c] = &av[c][1];
967 			argv[c][0] = '-';
968 			verbose = 1;
969 
970 		} else
971 			argv[c] = av[c];
972 	}
973 
974 	argv[c++] = "--";
975 	ac = c;
976 
977 	/* preprocess argument list looking for '-l' or '-R' so it can trail */
978 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF)
979 		switch (c) {
980 		case 'l':
981 			if ((optarg == NULL) || (optarg[0] == '-'))
982 				optarg = "1";
983 			verbose = atoi(optarg);
984 			break;
985 		case 'D':
986 			description = 1;
987 			break;
988 		case 'R':
989 			rank = 1;
990 			break;
991 		case 'E':
992 			encryption = PAPI_ENCRYPT_REQUIRED;
993 			break;
994 		default:
995 			break;
996 		}
997 	optind = 1;
998 
999 	/* process command line arguments */
1000 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
1001 		switch (c) {	/* these may or may not have an option */
1002 		case 'a':
1003 		case 'c':
1004 		case 'p':
1005 		case 'o':
1006 		case 'R':
1007 		case 'u':
1008 		case 'v':
1009 		case 'l':
1010 		case 'f':
1011 		case 'S':
1012 			if (optarg[0] == '-') {
1013 				/* this check stop a possible infinite loop */
1014 				if ((optind > 1) && (argv[optind-1][1] != c))
1015 					optind--;
1016 				optarg = NULL;
1017 			} else if (strcmp(optarg, "all") == 0)
1018 				optarg = NULL;
1019 		}
1020 
1021 		switch (c) {
1022 		case 'a':
1023 			exit_code += printer_query(optarg, report_accepting,
1024 						encryption, verbose, 0);
1025 			break;
1026 		case 'c':
1027 			exit_code += printer_query(optarg, report_class,
1028 						encryption, verbose, 0);
1029 			break;
1030 		case 'p':
1031 			exit_code += printer_query(optarg, report_printer,
1032 						encryption, verbose,
1033 						description);
1034 			break;
1035 		case 'd':
1036 			exit_code += lpstat_default_printer(encryption);
1037 			break;
1038 		case 'r':
1039 			exit_code += lpstat_service_status(encryption);
1040 			break;
1041 		case 'u':
1042 			if (optarg != NULL)
1043 				users = strsplit(optarg, ", \n");
1044 			exit_code += job_query(NULL, report_job,
1045 						encryption, rank, verbose);
1046 			if (users != NULL) {
1047 				free(users);
1048 				users = NULL;
1049 			}
1050 			break;
1051 		case 'v':
1052 			exit_code += printer_query(optarg, report_device,
1053 						encryption, verbose, 0);
1054 			break;
1055 		case 'R':	/* set "rank" flag in first pass */
1056 		case 'o':
1057 			exit_code += job_query(optarg, report_job,
1058 						encryption, rank, verbose);
1059 			break;
1060 		case 'f':
1061 			exit_code += service_query(optarg, report_form,
1062 						encryption, verbose);
1063 			break;
1064 		case 'S':
1065 			exit_code += service_query(optarg, report_print_wheels,
1066 						encryption, verbose);
1067 			break;
1068 		case 's':
1069 			exit_code += lpstat_service_status(encryption);
1070 			exit_code += lpstat_default_printer(encryption);
1071 			exit_code += printer_query(NULL, report_class,
1072 						encryption, verbose, 0);
1073 			exit_code += printer_query(NULL, report_device,
1074 						encryption, verbose, 0);
1075 			exit_code += service_query(optarg, report_form,
1076 						encryption, verbose);
1077 			exit_code += service_query(optarg, report_print_wheels,
1078 						encryption, verbose);
1079 			break;
1080 		case 't':
1081 			exit_code += lpstat_service_status(encryption);
1082 			exit_code += lpstat_default_printer(encryption);
1083 			exit_code += printer_query(NULL, report_class,
1084 						encryption, verbose, 0);
1085 			exit_code += printer_query(NULL, report_device,
1086 						encryption, verbose, 0);
1087 			exit_code += printer_query(NULL, report_accepting,
1088 						encryption, verbose, 0);
1089 			exit_code += printer_query(NULL, report_printer,
1090 						encryption, verbose, 0);
1091 			exit_code += service_query(optarg, report_form,
1092 						encryption, verbose);
1093 			exit_code += service_query(optarg, report_print_wheels,
1094 						encryption, verbose);
1095 			exit_code += job_query(NULL, report_job,
1096 						encryption, rank, verbose);
1097 			break;
1098 		case 'L':	/* local-only, ignored */
1099 		case 'l':	/* increased verbose level in first pass */
1100 		case 'D':	/* set "description" flag in first pass */
1101 		case 'E':	/* set encryption in the first pass */
1102 			break;
1103 		default:
1104 			usage(av[0]);
1105 		}
1106 	}
1107 	ac--;
1108 
1109 	if (ac == 1) {	/* report on my jobs */
1110 		struct passwd *pw = getpwuid(getuid());
1111 
1112 		if (pw != NULL)
1113 			users = strsplit(pw->pw_name, "");
1114 		exit_code += job_query(NULL, report_job, encryption,
1115 					rank, verbose);
1116 		if (users != NULL) {
1117 			free(users);
1118 			users = NULL;
1119 		}
1120 	} else {
1121 		for (c = optind; c < ac; c++)
1122 			exit_code += job_query(argv[c], report_job, encryption,
1123 					rank, verbose);
1124 	}
1125 
1126 
1127 	if (exit_code != 0)
1128 		exit_code = 1;
1129 
1130 	return (exit_code);
1131 }
1132