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