xref: /illumos-gate/usr/src/cmd/print/bsd-sysv-commands/lpstat.c (revision 8fd04b8338ed5093ec2d1e668fa620b7de44c177)
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("is 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 
418 				for (i = 0; j[i] != NULL; ++i) {
419 					papi_attribute_t **attr =
420 					    papiJobGetAttributeList(j[i]);
421 
422 					papiAttributeListGetInteger(attr,
423 					    NULL, "job-state", &jstate);
424 					papiAttributeListGetInteger(attr,
425 					    NULL, "job-id", &jobid);
426 					/*
427 					 * For lpd protocol "job-id-requested"
428 					 * should be read.
429 					 */
430 					papiAttributeListGetInteger(attr,
431 					    NULL, "job-id-requested", &jobid);
432 
433 					/*
434 					 * When lpd protocol is used job-state
435 					 * cannot be retrieved, therefore
436 					 * job-state will be 0.
437 					 * When ipp protocol is used, the
438 					 * active/printing job-state will be
439 					 * RS_PRINTING (0x0008) post s10u5.
440 					 * For pre-s10u5 job-state will be
441 					 * RS_ACTIVE (0x05). So print only when
442 					 * the job-state is RS_PRINTING (0x0008)
443 					 * or RS_ACTIVE (0x05) or 0
444 					 */
445 					if ((jstate == 0x0008) ||
446 					    (jstate == 0x05) ||
447 					    (jstate == 0)) {
448 						printf(gettext
449 						    ("now printing"\
450 						    " %s-%d. enabled"),
451 						    name, jobid);
452 						break;
453 					}
454 				}
455 				papiJobListFree(j);
456 			}
457 		}
458 		break;
459 	case 0x05:	/* stopped */
460 		printf(gettext("disabled"));
461 		break;
462 	default:
463 		printf(gettext("unknown state(0x%x)."), pstat);
464 		break;
465 	}
466 
467 	(void) time(&curr);
468 	(void) papiAttributeListGetDatetime(attrs, NULL,
469 	    "printer-up-time", &curr);
470 	(void) papiAttributeListGetDatetime(attrs, NULL,
471 	    "printer-state-time", &curr);
472 	(void) papiAttributeListGetDatetime(attrs, NULL,
473 	    "lpsched-disable-date", &curr);
474 	printf(gettext(" since %s. available.\n"), nctime(&curr));
475 
476 	if (pstat == 0x05) {
477 		char *reason = "unknown reason";
478 
479 		(void) papiAttributeListGetString(attrs, NULL,
480 		    "printer-state-reasons", &reason);
481 		(void) papiAttributeListGetString(attrs, NULL,
482 		    "lpsched-disable-reason", &reason);
483 		printf(gettext("\t%s\n"), reason);
484 	}
485 
486 	if (verbose == 1) {
487 		void *iter;
488 		char *str;
489 		char *host = NULL;
490 
491 		if ((get_remote_hostname(attrs, &host)) != 0) {
492 			(void) printf(
493 			    gettext("\tRemote Name: %s\n\tRemote Server: "
494 			    "%s\n"), name, host);
495 			free(host);
496 			return (0);
497 		}
498 		str = "";
499 		(void) papiAttributeListGetString(attrs, NULL,
500 		    "form-ready", &str);
501 		printf(gettext("\tForm mounted: %s\n"), str);
502 
503 		str = "";
504 		iter = NULL;
505 		(void) papiAttributeListGetString(attrs, &iter,
506 		    "document-format-supported", &str);
507 		printf(gettext("\tContent types: %s"), str);
508 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
509 		    == PAPI_OK)
510 			printf(", %s", str);
511 		printf("\n");
512 
513 		/* Display the printer description */
514 		print_description(attrs, name);
515 
516 		str = "";
517 		iter = NULL;
518 		(void) papiAttributeListGetString(attrs, &iter,
519 		    "lpsched-printer-type", &str);
520 		printf(gettext("\tPrinter types: %s"), str);
521 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
522 		    == PAPI_OK)
523 			printf(", %s", str);
524 		printf("\n");
525 
526 		str = "";
527 		(void) papiAttributeListGetString(attrs, NULL,
528 		    "lpsched-dial-info", &str);
529 		printf(gettext("\tConnection: %s\n"),
530 		    ((str[0] == '\0') ? gettext("direct") : str));
531 
532 		str = "";
533 		(void) papiAttributeListGetString(attrs, NULL,
534 		    "lpsched-interface-script", &str);
535 		printf(gettext("\tInterface: %s\n"), str);
536 
537 		str = NULL;
538 		(void) papiAttributeListGetString(attrs, NULL,
539 		    "ppd-file-uri", &str);
540 		(void) papiAttributeListGetString(attrs, NULL,
541 		    "lpsched-ppd-source-path", &str);
542 		if (str != NULL)
543 			printf(gettext("\tPPD: %s\n"), str);
544 
545 		str = NULL;
546 		(void) papiAttributeListGetString(attrs, NULL,
547 		    "lpsched-fault-alert-command", &str);
548 		if (str != NULL)
549 			printf(gettext("\tOn fault: %s\n"), str);
550 
551 		str = "";
552 		(void) papiAttributeListGetString(attrs, NULL,
553 		    "lpsched-fault-recovery", &str);
554 		printf(gettext("\tAfter fault: %s\n"),
555 		    ((str[0] == '\0') ? gettext("continue") : str));
556 
557 		str = "(all)";
558 		iter = NULL;
559 		(void) papiAttributeListGetString(attrs, &iter,
560 		    "requesting-user-name-allowed", &str);
561 		printf(gettext("\tUsers allowed:\n\t\t%s\n"),
562 		    ((str[0] == '\0') ? gettext("(none)") : str));
563 		if ((str != NULL) && (str[0] != '\0'))
564 			while (papiAttributeListGetString(attrs, &iter, NULL,
565 			    &str) == PAPI_OK)
566 				printf("\t\t%s\n", str);
567 
568 		str = NULL;
569 		iter = NULL;
570 		(void) papiAttributeListGetString(attrs, &iter,
571 		    "requesting-user-name-denied", &str);
572 		if (str != NULL) {
573 			printf(gettext("\tUsers denied:\n\t\t%s\n"),
574 			    ((str[0] == '\0') ? gettext("(none)") : str));
575 			if ((str != NULL) && (str[0] != '\0'))
576 				while (papiAttributeListGetString(attrs, &iter,
577 				    NULL, &str) == PAPI_OK)
578 					printf("\t\t%s\n", str);
579 		}
580 
581 		str = "none";
582 		iter = NULL;
583 		(void) papiAttributeListGetString(attrs, &iter,
584 		    "form-supported", &str);
585 		printf(gettext("\tForms allowed:\n\t\t(%s)\n"),
586 		    ((str[0] == '\0') ? gettext("none") : str));
587 		if ((str != NULL) && (str[0] != '\0'))
588 			while (papiAttributeListGetString(attrs, &iter, NULL,
589 			    &str) == PAPI_OK)
590 				printf("\t\t(%s)\n", str);
591 
592 		str = "";
593 		iter = NULL;
594 		(void) papiAttributeListGetString(attrs, &iter,
595 		    "media-supported", &str);
596 		printf(gettext("\tMedia supported:\n\t\t%s\n"),
597 		    ((str[0] == '\0') ? gettext("(none)") : str));
598 		if ((str != NULL) && (str[0] != '\0'))
599 			while (papiAttributeListGetString(attrs, &iter, NULL,
600 			    &str) == PAPI_OK)
601 				printf("\t\t%s\n", str);
602 
603 		str = "";
604 		(void) papiAttributeListGetString(attrs, NULL,
605 		    "job-sheets-supported", &str);
606 		if ((strcasecmp(str, "none")) == 0)
607 			str = gettext("page never printed");
608 		else if (strcasecmp(str, "optional") == 0)
609 			str = gettext("not required");
610 		else
611 			str = gettext("required");
612 
613 		printf(gettext("\tBanner %s\n"), str);
614 
615 
616 		str = "";
617 		iter = NULL;
618 		(void) papiAttributeListGetString(attrs, &iter,
619 		    "lpsched-print-wheels", &str);
620 		printf(gettext("\tCharacter sets:\n\t\t%s\n"),
621 		    ((str[0] == '\0') ? gettext("(none)") : str));
622 		if ((str != NULL) && (str[0] != '\0'))
623 			while (papiAttributeListGetString(attrs, &iter, NULL,
624 			    &str) == PAPI_OK)
625 				printf("\t\t%s\n", str);
626 
627 		printf(gettext("\tDefault pitch:\n"));
628 		printf(gettext("\tDefault page size:\n"));
629 		printf(gettext("\tDefault port setting:\n"));
630 
631 		str = "";
632 		iter = NULL;
633 		(void) papiAttributeListGetString(attrs, &iter,
634 		    "lpsched-options", &str);
635 		if (str != NULL) {
636 			printf(gettext("\tOptions: %s"), str);
637 			while (papiAttributeListGetString(attrs, &iter, NULL,
638 			    &str) == PAPI_OK)
639 				printf(", %s", str);
640 			printf("\n");
641 		}
642 
643 	} else if (description == 1)
644 		/* Display printer description */
645 		print_description(attrs, name);
646 	else if (verbose > 1)
647 		papiAttributeListPrint(stdout, attrs, "\t");
648 
649 	if (verbose > 0)
650 		printf("\n");
651 
652 	return (0);
653 }
654 
655 static int
656 printer_query(char *name, int (*report)(papi_service_t, char *, papi_printer_t,
657 					int, int), papi_encryption_t encryption,
658 		int verbose, int description)
659 {
660 	int result = 0, i = 0;
661 	papi_status_t status;
662 	papi_service_t svc = NULL;
663 	char **list = getlist(name, LP_WS, LP_SEP);
664 
665 	if (list == NULL) {
666 		list = (char **)malloc(sizeof (char *));
667 		list[0] = name;
668 	}
669 
670 	/*
671 	 * The for loop executes once for every printer
672 	 * entry in list. If list is NULL that implies
673 	 * name is also NULL, the loop runs only one time.
674 	 */
675 
676 	for (i = 0; name == NULL || list[i] != NULL; i++) {
677 		name = list[i];
678 
679 		status = papiServiceCreate(&svc, name, NULL, NULL,
680 		    cli_auth_callback, encryption, NULL);
681 		if (status != PAPI_OK) {
682 			if (status == PAPI_NOT_FOUND)
683 				fprintf(stderr,
684 				    gettext("%s: unknown printer\n"),
685 				    name ? name : "(NULL)");
686 			else
687 				fprintf(stderr, gettext(
688 				    "Failed to contact service for %s: %s\n"),
689 				    name ? name : "(NULL)",
690 				    verbose_papi_message(svc, status));
691 			papiServiceDestroy(svc);
692 			result--;
693 			continue;
694 		}
695 
696 		if (name == NULL) { /* all */
697 			char **interest = interest_list(svc);
698 
699 			if (interest != NULL) {
700 				int i;
701 
702 				for (i = 0; interest[i] != NULL; i++)
703 					result += printer_query(interest[i],
704 					    report, encryption, verbose,
705 					    description);
706 			}
707 		} else {
708 			papi_printer_t printer = NULL;
709 			char **keys = NULL;
710 
711 			/*
712 			 * Limit the query to only required data
713 			 * to reduce the need to go remote for
714 			 * information.
715 			 */
716 			if (report == report_device)
717 				keys = report_device_keys;
718 			else if (report == report_class)
719 				keys = report_class_keys;
720 			else if (report == report_accepting)
721 				keys = report_accepting_keys;
722 			else if ((report == report_printer) && (verbose == 0))
723 				keys = report_printer_keys;
724 
725 			status = papiPrinterQuery(svc, name, keys,
726 			    NULL, &printer);
727 			if (status != PAPI_OK) {
728 				fprintf(stderr, gettext(
729 				    "Failed to get printer info for %s: %s\n"),
730 				    name, verbose_papi_message(svc, status));
731 				papiServiceDestroy(svc);
732 				result--;
733 				continue;
734 			}
735 
736 			if (printer != NULL)
737 				result += report(svc, name, printer, verbose,
738 				    description);
739 
740 			papiPrinterFree(printer);
741 		}
742 
743 		papiServiceDestroy(svc);
744 
745 		if (name == NULL)
746 			break;
747 	}
748 
749 	freelist(list);
750 
751 	return (result);
752 }
753 
754 static int
755 match_user(char *user, char **list)
756 {
757 	int i;
758 
759 	for (i = 0; list[i] != NULL; i++) {
760 		if (strcmp(user, list[i]) == 0)
761 			return (0);
762 	}
763 
764 	return (-1);
765 }
766 
767 static char **users = NULL;
768 
769 static int
770 report_job(char *printer, papi_job_t job, int show_rank, int verbose)
771 {
772 	papi_attribute_t **attrs = papiJobGetAttributeList(job);
773 	time_t clock = 0;
774 	char date[24];
775 	char request[26];
776 	char *user = "unknown";
777 	char *host = NULL;
778 	int32_t size = 0;
779 	int32_t jstate = 0;
780 	char User[50];
781 
782 	char *destination = "unknown";
783 	int32_t id = -1;
784 	static int check = 0;
785 	static char *uri = NULL;
786 	static char *puri = NULL;	/* printer-uri */
787 	static char *pname = NULL;	/* printer-name */
788 
789 	(void) papiAttributeListGetString(attrs, NULL,
790 	    "job-originating-user-name", &user);
791 
792 	if ((users != NULL) && (match_user(user, users) < 0))
793 		return (0);
794 
795 	(void) papiAttributeListGetString(attrs, NULL,
796 	    "job-originating-host-name", &host);
797 
798 	/*
799 	 * When lpstat is called for multiple printers
800 	 * internally the function 'report_job' gets
801 	 * called multiple times with different printer-names.
802 	 * The following block of code handles the case when lpstat is
803 	 * executed for multiple printers. In other words when 'report_job'
804 	 * is called multiple times for different printers for
805 	 * one lpstat command
806 	 * For e.g: lpstat printer1 printer2 printer3
807 	 */
808 	if (pname == NULL) {
809 		/*
810 		 * When lpstat is queried for the first time
811 		 * pname is NULL so this part of the code gets executed.
812 		 * Read the attribute "job-printer-uri"
813 		 * first time
814 		 */
815 		(void) papiAttributeListGetString(attrs, NULL,
816 		    "job-printer-uri", &uri);
817 
818 		if (printer != NULL) {
819 			/*
820 			 * Set pname to the printer that is being
821 			 * queried so that this can be used later
822 			 * if 'report_job' is called multiple times for
823 			 * different printers for one lpstat command
824 			 */
825 			pname = printer;
826 		}
827 
828 		if (uri != NULL) {
829 			/*
830 			 * Set puri so that "job-printer-uri" corresponding
831 			 * to a particular printer can be used later when
832 			 * lpstat is queried for the same printer as
833 			 * "job-printer-uri" for a printer is read just once.
834 			 */
835 			puri = strdup(uri);
836 		}
837 	} else {
838 		/*
839 		 * This part of the code will get executed when
840 		 * 'report_job' is called more than once for the same
841 		 * lpstat command
842 		 */
843 		if (printer != NULL) {
844 			if (strcasecmp(pname, printer) != 0) {
845 				/*
846 				 * Read the job-printer-uri as
847 				 * it will be different for
848 				 * different printers
849 				 */
850 				uri = NULL;
851 				(void) papiAttributeListGetString(attrs,
852 				    NULL, "job-printer-uri", &uri);
853 				pname = printer;
854 				if (uri != NULL)
855 					puri = strdup(uri);
856 				else
857 					puri = NULL;
858 			} else {
859 				/*
860 				 * Same printer queried twice
861 				 * uri should be the same as
862 				 * already read in the previous call
863 				 * to 'report_job'.
864 				 * For the same printer 'job-printer-uri'
865 				 * is read just once because only in the
866 				 * first call it contains the host information
867 				 */
868 				uri = puri;
869 			}
870 		}
871 	}
872 
873 	if (host) {
874 		/* Check if it is local printer or remote printer */
875 		uri_t *u = NULL;
876 
877 		if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
878 			char *nodename = localhostname();
879 
880 			if ((u->host == NULL) ||
881 			    (strcasecmp(u->host, "localhost") == 0) ||
882 			    (strcasecmp(u->host, nodename) == 0)) {
883 
884 				if (strcasecmp(host, nodename) == 0) {
885 					/*
886 					 * Request submitted locally
887 					 * for the local queue.
888 					 * Hostname will not be displayed
889 					 */
890 					snprintf(User, sizeof (User), "%s",
891 					    user);
892 				}
893 				else
894 					snprintf(User, sizeof (User), "%s@%s",
895 					    user, host);
896 			} else if (uri != NULL) {
897 				/*
898 				 * It's a remote printer.
899 				 * In case of remote printers hostname is
900 				 * always displayed.
901 				 */
902 				snprintf(User, sizeof (User), "%s@%s",
903 				    user, host);
904 			}
905 			uri_free(u);
906 		} else {
907 			/*
908 			 * If attribute "job-printer-uri"
909 			 * cannot be read
910 			 * by default append the hostname
911 			 */
912 			snprintf(User, sizeof (User), "%s@%s", user, host);
913 		}
914 	} else {
915 		/*
916 		 * When print server is s10u4 and ipp service is used
917 		 * "job-originating-hostname" attribute is not set
918 		 * So get the host information from the uri
919 		 */
920 		uri_t *u = NULL;
921 		if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
922 			if ((u != NULL) && (u->host != NULL))
923 				snprintf(User, sizeof (User), "%s@%s",
924 				    user, u->host);
925 			else
926 				snprintf(User, sizeof (User), "%s", user);
927 
928 			uri_free(u);
929 		} else
930 			snprintf(User, sizeof (User), "%s", user);
931 	}
932 	(void) papiAttributeListGetInteger(attrs, NULL, "job-k-octets", &size);
933 	size *= 1024;	/* for the approximate byte size */
934 	(void) papiAttributeListGetInteger(attrs, NULL, "job-octets", &size);
935 
936 	(void) time(&clock);
937 	(void) papiAttributeListGetInteger(attrs, NULL,
938 	    "time-at-creation", (int32_t *)&clock);
939 	(void) strftime(date, sizeof (date), "%b %d %R", localtime(&clock));
940 
941 	(void) papiAttributeListGetString(attrs, NULL,
942 	    "job-printer-uri", &destination);
943 	(void) papiAttributeListGetString(attrs, NULL,
944 	    "printer-name", &destination);
945 	(void) papiAttributeListGetInteger(attrs, NULL,
946 	    "job-id", &id);
947 	(void) papiAttributeListGetInteger(attrs, NULL,
948 	    "job-id-requested", &id);
949 
950 
951 	snprintf(request, sizeof (request), "%s-%d", printer, id);
952 
953 	if (show_rank != 0) {
954 		int32_t rank = -1;
955 
956 		(void) papiAttributeListGetInteger(attrs, NULL,
957 		    "number-of-intervening-jobs", &rank);
958 		rank++;
959 
960 		printf("%3d %-21s %-14s %7ld %s",
961 		    rank, request, User, size, date);
962 	} else
963 		printf("%-23s %-14s %7ld   %s", request, User, size, date);
964 
965 	(void) papiAttributeListGetInteger(attrs, NULL,
966 	    "job-state", &jstate);
967 
968 	if (jstate == 0x0001)
969 		printf(gettext(" being held"));
970 	else if (jstate == 0x0800)
971 		printf(gettext(" notifying user"));
972 	else if (jstate == 0x0040)
973 		printf(gettext(" cancelled"));
974 	else if (jstate == 0x0010)
975 		printf(gettext(" finished printing"));
976 	else if (jstate == 0x0008)
977 		printf(gettext(" on %s"), destination);
978 	else if (jstate == 0x2000)
979 		printf(gettext(" held by admin"));
980 	else if (jstate == 0x0002)
981 		printf(gettext(" being filtered"));
982 	else if (jstate == 0x0004)
983 		printf(gettext(" filtered"));
984 	else if (jstate == 0x0020)
985 		printf(gettext(" held for change"));
986 
987 	if (verbose == 1) {
988 		char *form = NULL;
989 
990 		(void) papiAttributeListGetString(attrs, NULL,
991 		    "output-device-assigned", &destination);
992 		printf("\n\t assigned %s", destination);
993 
994 		(void) papiAttributeListGetString(attrs, NULL, "form", &form);
995 		if (form != NULL)
996 			printf(", form %s", form);
997 	} else if (verbose > 1) {
998 		printf("\n");
999 		papiAttributeListPrint(stdout, attrs, "\t");
1000 	}
1001 
1002 	printf("\n");
1003 
1004 	return (0);
1005 }
1006 
1007 static int
1008 job_query(char *request, int (*report)(char *, papi_job_t, int, int),
1009 		papi_encryption_t encryption, int show_rank, int verbose)
1010 {
1011 	int result = 0;
1012 	papi_status_t status;
1013 	papi_service_t svc = NULL;
1014 	char *printer = request;
1015 	int32_t id = -1;
1016 	int flag1 = 0;
1017 	int flag = 1;
1018 	int print_flag = 0;
1019 
1020 	do {
1021 		status = papiServiceCreate(&svc, printer, NULL, NULL,
1022 		    cli_auth_callback, encryption, NULL);
1023 
1024 		if ((status == PAPI_OK) && (printer != NULL))
1025 			print_flag = 1;
1026 
1027 		/* <name>-# printer name does not exist */
1028 		if (status != PAPI_OK) {
1029 			/*
1030 			 * Check if <name>-# is a request-id
1031 			 * Once this check is done flag1 is set
1032 			 */
1033 			if (flag1 == 1)
1034 				break;
1035 
1036 			get_printer_id(printer, &printer, &id);
1037 
1038 			status = papiServiceCreate(&svc, printer, NULL, NULL,
1039 			    cli_auth_callback, encryption, NULL);
1040 
1041 			if (status != PAPI_OK) {
1042 				fprintf(stderr, gettext(
1043 				    "Failed to contact service for %s: %s\n"),
1044 				    (printer ? printer : "all"),
1045 				    verbose_papi_message(svc, status));
1046 				return (-1);
1047 			}
1048 		}
1049 
1050 		if (printer == NULL) { /* all */
1051 			char **interest = interest_list(svc);
1052 
1053 			if (interest != NULL) {
1054 				int i;
1055 
1056 				for (i = 0; interest[i] != NULL; i++)
1057 					result += job_query(interest[i], report,
1058 					    encryption, show_rank, verbose);
1059 			}
1060 		} else if (id == -1) { /* a printer */
1061 			papi_job_t *jobs = NULL;
1062 
1063 			status = papiPrinterListJobs(svc, printer, NULL,
1064 			    0, 0, &jobs);
1065 			if (status != PAPI_OK) {
1066 				fprintf(stderr, gettext(
1067 				    "Failed to get job list: %s\n"),
1068 				    verbose_papi_message(svc, status));
1069 				papiServiceDestroy(svc);
1070 				return (-1);
1071 			}
1072 
1073 			if (jobs != NULL) {
1074 				int i;
1075 
1076 				for (i = 0; jobs[i] != NULL; i++)
1077 					result += report(printer,
1078 					    jobs[i], show_rank,
1079 					    verbose);
1080 			}
1081 
1082 			papiJobListFree(jobs);
1083 		} else {	/* a job */
1084 			papi_job_t job = NULL;
1085 
1086 			/* Once a job has been found stop processing */
1087 			flag = 0;
1088 
1089 			/*
1090 			 * Job-id could be the job-id requested
1091 			 * Check if it is job-id or job-id-requested
1092 			 */
1093 			id = job_to_be_queried(svc, printer, id);
1094 
1095 			if (id >= 0)
1096 				status = papiJobQuery(svc, printer, id,
1097 				    NULL, &job);
1098 			else
1099 				/* id not found */
1100 				status = PAPI_NOT_FOUND;
1101 
1102 			if (status != PAPI_OK) {
1103 				if (!print_flag)
1104 					fprintf(stderr, gettext(
1105 					    "Failed to get job"\
1106 					    " info for %s: %s\n"),
1107 					    request,
1108 					    verbose_papi_message(svc, status));
1109 				papiServiceDestroy(svc);
1110 				return (-1);
1111 			}
1112 
1113 			if (job != NULL)
1114 				result = report(printer, job,
1115 				    show_rank, verbose);
1116 
1117 			papiJobFree(job);
1118 		}
1119 
1120 		if (flag) {
1121 			id = -1;
1122 			get_printer_id(printer, &printer, &id);
1123 			if (id == -1)
1124 				flag = 0;
1125 			else
1126 				flag1 = 1;
1127 		}
1128 	} while (flag);
1129 
1130 	papiServiceDestroy(svc);
1131 
1132 	return (result);
1133 }
1134 
1135 static int
1136 report_form(char *name, papi_attribute_t **attrs, int verbose)
1137 {
1138 	papi_status_t status;
1139 	char *form = NULL;
1140 	void *iter = NULL;
1141 
1142 	for (status = papiAttributeListGetString(attrs, &iter,
1143 	    "form-supported", &form);
1144 	    status == PAPI_OK;
1145 	    status = papiAttributeListGetString(attrs, &iter,
1146 	    NULL, &form)) {
1147 		if ((name == NULL) || (strcmp(name, form) == 0)) {
1148 			printf(gettext("form %s is available to you\n"), form);
1149 			if (verbose != 0) {
1150 				char *detail = NULL;
1151 				status = papiAttributeListGetString(attrs, NULL,
1152 				    "form-supported-detail", &detail);
1153 				if (status == PAPI_OK)
1154 					printf("%s\n", detail);
1155 			}
1156 		}
1157 	}
1158 
1159 	return (0);
1160 }
1161 
1162 static int
1163 report_print_wheels(char *name, papi_attribute_t **attrs, int verbose)
1164 {
1165 	papi_status_t status;
1166 	char *pw = NULL;
1167 	void *iter = NULL;
1168 
1169 	for (status = papiAttributeListGetString(attrs, &iter,
1170 	    "pw-supported", &pw);
1171 	    status == PAPI_OK;
1172 	    status = papiAttributeListGetString(attrs, &iter, NULL, &pw)) {
1173 		if ((name == NULL) || (strcmp(name, pw) == 0)) {
1174 			printf(gettext("charset %s is available\n"), pw);
1175 			if (verbose != 0) {
1176 				char *info = NULL;
1177 				status = papiAttributeListGetString(attrs, NULL,
1178 				    "pw-supported-extra", &info);
1179 				if (status == PAPI_OK)
1180 					printf("%s\n", info);
1181 			}
1182 		}
1183 	}
1184 
1185 	return (0);
1186 }
1187 
1188 static int
1189 service_query(char *name, int (*report)(char *, papi_attribute_t **, int),
1190 		papi_encryption_t encryption, int verbose)
1191 {
1192 	int result = 0;
1193 	papi_status_t status;
1194 	papi_service_t svc = NULL;
1195 	papi_attribute_t **attrs = NULL;
1196 
1197 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
1198 	    encryption, NULL);
1199 	if (status != PAPI_OK) {
1200 		papiServiceDestroy(svc);
1201 		return (-1);
1202 	}
1203 
1204 	attrs = papiServiceGetAttributeList(svc);
1205 	if (attrs != NULL) {
1206 		result = report(name, attrs, verbose);
1207 
1208 		if (verbose > 1) {
1209 			printf("\n");
1210 			papiAttributeListPrint(stdout, attrs, "\t");
1211 			printf("\n");
1212 		}
1213 	}
1214 
1215 	papiServiceDestroy(svc);
1216 
1217 	return (result);
1218 }
1219 
1220 int
1221 main(int ac, char *av[])
1222 {
1223 	int exit_code = 0;
1224 	papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
1225 	int rank = 0;
1226 	int verbose = 0;
1227 	int description = 0;
1228 	int c;
1229 	char **argv;
1230 
1231 	(void) setlocale(LC_ALL, "");
1232 	(void) textdomain("SUNW_OST_OSCMD");
1233 
1234 	argv = (char **)calloc((ac + 1), sizeof (char *));
1235 	for (c = 0; c < ac; c++) {
1236 		if ((av[c][0] == '-') && (av[c][1] == 'l') &&
1237 		    (isalpha(av[c][2]) != 0)) {
1238 			/* preserve old "-l[po...]" behavior */
1239 			argv[c] = &av[c][1];
1240 			argv[c][0] = '-';
1241 			verbose = 1;
1242 
1243 		} else
1244 			argv[c] = av[c];
1245 	}
1246 
1247 	argv[c++] = "--";
1248 	ac = c;
1249 
1250 	/* preprocess argument list looking for '-l' or '-R' so it can trail */
1251 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
1252 		switch (c) {    /* these may or may not have an option */
1253 		case 'a':
1254 		case 'c':
1255 		case 'p':
1256 		case 'o':
1257 		case 'R':
1258 		case 'u':
1259 		case 'v':
1260 		case 'l':
1261 		case 'f':
1262 		case 'S':
1263 			if (optarg[0] == '-') {
1264 				/* this check stop a possible infinite loop */
1265 				if ((optind > 1) && (argv[optind-1][1] != c))
1266 					optind--;
1267 				optarg = NULL;
1268 			} else if (strcmp(optarg, "all") == 0)
1269 				optarg = NULL;
1270 		}
1271 
1272 		switch (c) {
1273 		case 'l':
1274 			if ((optarg == NULL) || (optarg[0] == '-'))
1275 				optarg = "1";
1276 			verbose = atoi(optarg);
1277 			break;
1278 		case 'D':
1279 			description = 1;
1280 			break;
1281 		case 'R':
1282 			rank = 1;
1283 			break;
1284 		case 'E':
1285 			encryption = PAPI_ENCRYPT_REQUIRED;
1286 			break;
1287 		default:
1288 			break;
1289 		}
1290 	}
1291 	optind = 1;
1292 
1293 	/* process command line arguments */
1294 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
1295 		switch (c) {	/* these may or may not have an option */
1296 		case 'a':
1297 		case 'c':
1298 		case 'p':
1299 		case 'o':
1300 		case 'R':
1301 		case 'u':
1302 		case 'v':
1303 		case 'l':
1304 		case 'f':
1305 		case 'S':
1306 			if (optarg[0] == '-') {
1307 				/* this check stop a possible infinite loop */
1308 				if ((optind > 1) && (argv[optind-1][1] != c))
1309 					optind--;
1310 				optarg = NULL;
1311 			} else if (strcmp(optarg, "all") == 0)
1312 				optarg = NULL;
1313 		}
1314 
1315 		switch (c) {
1316 		case 'a':
1317 			exit_code += printer_query(optarg, report_accepting,
1318 			    encryption, verbose, 0);
1319 			break;
1320 		case 'c':
1321 			exit_code += printer_query(optarg, report_class,
1322 			    encryption, verbose, 0);
1323 			break;
1324 		case 'p':
1325 			exit_code += printer_query(optarg, report_printer,
1326 			    encryption, verbose, description);
1327 			break;
1328 		case 'd':
1329 			exit_code += lpstat_default_printer(encryption);
1330 			break;
1331 		case 'r':
1332 			exit_code += lpstat_service_status(encryption);
1333 			break;
1334 		case 'u':
1335 			if (optarg != NULL)
1336 				users = strsplit(optarg, ", \n");
1337 			exit_code += job_query(NULL, report_job,
1338 			    encryption, rank, verbose);
1339 			if (users != NULL) {
1340 				free(users);
1341 				users = NULL;
1342 			}
1343 			break;
1344 		case 'v':
1345 			exit_code += printer_query(optarg, report_device,
1346 			    encryption, verbose, 0);
1347 			break;
1348 		case 'R':	/* set "rank" flag in first pass */
1349 		case 'o':
1350 			exit_code += job_query(optarg, report_job,
1351 			    encryption, rank, verbose);
1352 			break;
1353 		case 'f':
1354 			exit_code += service_query(optarg, report_form,
1355 			    encryption, verbose);
1356 			break;
1357 		case 'S':
1358 			exit_code += service_query(optarg, report_print_wheels,
1359 			    encryption, verbose);
1360 			break;
1361 		case 's':
1362 			exit_code += lpstat_service_status(encryption);
1363 			exit_code += lpstat_default_printer(encryption);
1364 			exit_code += printer_query(NULL, report_class,
1365 			    encryption, verbose, 0);
1366 			exit_code += printer_query(NULL, report_device,
1367 			    encryption, verbose, 0);
1368 			exit_code += service_query(optarg, report_form,
1369 			    encryption, verbose);
1370 			exit_code += service_query(optarg, report_print_wheels,
1371 			    encryption, verbose);
1372 			break;
1373 		case 't':
1374 			exit_code += lpstat_service_status(encryption);
1375 			exit_code += lpstat_default_printer(encryption);
1376 			exit_code += printer_query(NULL, report_class,
1377 			    encryption, verbose, 0);
1378 			exit_code += printer_query(NULL, report_device,
1379 			    encryption, verbose, 0);
1380 			exit_code += printer_query(NULL, report_accepting,
1381 			    encryption, verbose, 0);
1382 			exit_code += printer_query(NULL, report_printer,
1383 			    encryption, verbose, 0);
1384 			exit_code += service_query(optarg, report_form,
1385 			    encryption, verbose);
1386 			exit_code += service_query(optarg, report_print_wheels,
1387 			    encryption, verbose);
1388 			exit_code += job_query(NULL, report_job,
1389 			    encryption, rank, verbose);
1390 			break;
1391 		case 'L':	/* local-only, ignored */
1392 		case 'l':	/* increased verbose level in first pass */
1393 		case 'D':	/* set "description" flag in first pass */
1394 		case 'E':	/* set encryption in the first pass */
1395 			break;
1396 		default:
1397 			usage(av[0]);
1398 		}
1399 	}
1400 	ac--;
1401 
1402 	if (ac == 1) {	/* report on my jobs */
1403 		struct passwd *pw = getpwuid(getuid());
1404 
1405 		if (pw != NULL)
1406 			users = strsplit(pw->pw_name, "");
1407 		exit_code += job_query(NULL, report_job, encryption,
1408 		    rank, verbose);
1409 		if (users != NULL) {
1410 			free(users);
1411 			users = NULL;
1412 		}
1413 	} else {
1414 		for (c = optind; c < ac; c++)
1415 			exit_code += job_query(argv[c], report_job, encryption,
1416 			    rank, verbose);
1417 	}
1418 
1419 
1420 	if (exit_code != 0)
1421 		exit_code = 1;
1422 
1423 	return (exit_code);
1424 }
1425