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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  */
27 
28 /* $Id: printer.c 146 2006-03-24 00:26:54Z njacobs $ */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 /*LINTLIBRARY*/
33 
34 #include <stdlib.h>
35 #include <papi_impl.h>
36 
37 #include <config-site.h>
38 
39 void
40 papiPrinterFree(papi_printer_t printer)
41 {
42 	printer_t *tmp = printer;
43 
44 	if (tmp != NULL) {
45 		if (tmp->attributes != NULL)
46 			papiAttributeListFree(tmp->attributes);
47 		free(tmp);
48 	}
49 }
50 
51 void
52 papiPrinterListFree(papi_printer_t *printers)
53 {
54 	if (printers != NULL) {
55 		int i;
56 
57 		for (i = 0; printers[i] != NULL; i++)
58 			papiPrinterFree(printers[i]);
59 		free(printers);
60 	}
61 }
62 
63 /*
64  * Enumeration of printers is not part of the IPP specification, so many
65  * servers will probably not respond back with a list of printers, but
66  * CUPS has implemented an extension to IPP to enumerate printers and
67  * classes. the Apache/mod_ipp IPP listener module available in Solaris
68  * implements this IPP extension, so CUPS and Solaris can provide this
69  * to IPP clients.
70  */
71 #ifndef	OPID_CUPS_GET_PRINTERS		/* for servers that will enumerate */
72 #define	OPID_CUPS_GET_PRINTERS		0x4002
73 #endif	/* OPID_CUPS_GET_PRINTERS */
74 #ifndef	OPID_CUPS_DELETE_PRINTER	/* for servers that can delete */
75 #define	OPID_CUPS_DELETE_PRINTER	0x4004
76 #endif	/* OPID_CUPS_DELETE_PRINTER */
77 #ifndef	OPID_CUPS_GET_CLASSES		/* for servers that will enumerate */
78 #define	OPID_CUPS_GET_CLASSES		0x4005
79 #endif	/* OPID_CUPS_GET_CLASSES */
80 
81 papi_status_t
82 papiPrintersList(papi_service_t handle, char **requested_attrs,
83 		papi_filter_t *filter, papi_printer_t **printers)
84 {
85 	papi_status_t status, result = PAPI_INTERNAL_ERROR;
86 	service_t *svc = handle;
87 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
88 	void *iter = NULL;
89 
90 	if ((svc == NULL) || (printers == NULL))
91 		return (PAPI_BAD_ARGUMENT);
92 
93 	/* if we are already connected, use that connection. */
94 	if (svc->connection == NULL)
95 		if ((result = service_connect(svc, DEFAULT_DEST)) != PAPI_OK)
96 			return (result);
97 	ipp_initialize_request(svc, &request, OPID_CUPS_GET_PRINTERS);
98 
99 	ipp_initialize_operational_attributes(svc, &op, NULL, -1);
100 
101 	if (requested_attrs != NULL) {
102 		int i;
103 
104 		for (i = 0; requested_attrs[i] != NULL; i++)
105 			papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
106 				"requested-attributes", requested_attrs[i]);
107 	}
108 
109 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
110 			"operational-attributes-group", op);
111 	papiAttributeListFree(op);
112 	result = ipp_send_request(svc, request, &response);
113 	papiAttributeListFree(request);
114 
115 	op = NULL;
116 	for (status = papiAttributeListGetCollection(response, &iter,
117 				"printer-attributes-group", &op);
118 	     status == PAPI_OK;
119 	     status = papiAttributeListGetCollection(response, &iter,
120 				NULL, &op)) {
121 		printer_t *p = NULL;
122 
123 		if ((p = calloc(1, sizeof (*p))) == NULL)
124 			return (PAPI_TEMPORARY_ERROR);
125 
126 		copy_attributes(&p->attributes, op);
127 		op = NULL;
128 		list_append(printers, p);
129 	}
130 	papiAttributeListFree(response);
131 
132 	return (result);
133 }
134 
135 papi_status_t
136 papiPrinterQuery(papi_service_t handle, char *name,
137 		char **requested_attrs,
138 		papi_attribute_t **job_attributes,
139 		papi_printer_t *printer)
140 {
141 	papi_status_t result = PAPI_INTERNAL_ERROR;
142 	service_t *svc = handle;
143 	printer_t *p = NULL;
144 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
145 
146 	if ((svc == NULL) || (name == NULL) || (printer == NULL))
147 		return (PAPI_BAD_ARGUMENT);
148 
149 	/* if we are already connected, use that connection. */
150 	if (svc->connection == NULL)
151 		if ((result = service_connect(svc, name)) != PAPI_OK)
152 			return (result);
153 
154 	if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
155 		return (PAPI_TEMPORARY_ERROR);
156 
157 	ipp_initialize_request(svc, &request, OPID_GET_PRINTER_ATTRIBUTES);
158 
159 	ipp_initialize_operational_attributes(svc, &op, name, -1);
160 
161 	if (requested_attrs != NULL) {
162 		int i;
163 
164 		for (i = 0; requested_attrs[i] != NULL; i++)
165 			papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
166 				"requested-attributes", requested_attrs[i]);
167 	}
168 
169 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
170 			"operational-attributes-group", op);
171 	papiAttributeListFree(op);
172 	result = ipp_send_request(svc, request, &response);
173 	papiAttributeListFree(request);
174 
175 	op = NULL;
176 	papiAttributeListGetCollection(response, NULL,
177 			"printer-attributes-group", &op);
178 	copy_attributes(&p->attributes, op);
179 	papiAttributeListFree(response);
180 
181 	return (result);
182 }
183 
184 static papi_status_t
185 _printer_enable_disable_pause_resume_delete(papi_service_t handle, char *name,
186 		char *message, uint16_t type)
187 {
188 	papi_status_t result = PAPI_INTERNAL_ERROR;
189 	service_t *svc = handle;
190 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
191 
192 	if ((svc == NULL) || (name == NULL))
193 		return (PAPI_BAD_ARGUMENT);
194 
195 	/* if we are already connected, use that connection. */
196 	if (svc->connection == NULL)
197 		if ((result = service_connect(svc, name)) != PAPI_OK)
198 			return (result);
199 
200 	ipp_initialize_request(svc, &request, type);
201 
202 	ipp_initialize_operational_attributes(svc, &op, name, -1);
203 
204 	switch (type) {
205 	case OPID_DISABLE_PRINTER:
206 		papiAttributeListAddString(&op, PAPI_ATTR_REPLACE,
207 				"printer-message-from-operator", message);
208 		break;
209 	case OPID_PAUSE_PRINTER:
210 		papiAttributeListAddString(&op, PAPI_ATTR_REPLACE,
211 				"printer-state-message", message);
212 		break;
213 	default: /* a message value is of no use */
214 		break;
215 	}
216 
217 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
218 			"operational-attributes-group", op);
219 	papiAttributeListFree(op);
220 	result = ipp_send_request(svc, request, &response);
221 	papiAttributeListFree(request);
222 	papiAttributeListFree(response);
223 
224 	return (result);
225 }
226 
227 papi_status_t
228 papiPrinterEnable(papi_service_t handle, char *name)
229 {
230 	return (_printer_enable_disable_pause_resume_delete(handle, name,
231 				NULL, OPID_ENABLE_PRINTER));
232 }
233 
234 papi_status_t
235 papiPrinterResume(papi_service_t handle, char *name)
236 {
237 	return (_printer_enable_disable_pause_resume_delete(handle, name,
238 				NULL, OPID_RESUME_PRINTER));
239 }
240 
241 papi_status_t
242 papiPrinterPause(papi_service_t handle, char *name, char *message)
243 {
244 	return (_printer_enable_disable_pause_resume_delete(handle, name,
245 				message, OPID_PAUSE_PRINTER));
246 }
247 
248 papi_status_t
249 papiPrinterDisable(papi_service_t handle, char *name, char *message)
250 {
251 	return (_printer_enable_disable_pause_resume_delete(handle, name,
252 				message, OPID_PAUSE_PRINTER));
253 }
254 
255 /*
256  * there is no IPP create operation, the set-printer-attibutes operation
257  * is the closest we have, so we will assume that the server will create
258  * a printer and set attributes if there is none.
259  */
260 papi_status_t
261 papiPrinterAdd(papi_service_t handle, char *name,
262 		papi_attribute_t **attributes, papi_printer_t *printer)
263 {
264 	return (papiPrinterModify(handle, name, attributes, printer));
265 }
266 
267 papi_status_t
268 papiPrinterModify(papi_service_t handle, char *name,
269 		papi_attribute_t **attributes, papi_printer_t *printer)
270 {
271 	papi_status_t result = PAPI_INTERNAL_ERROR;
272 	service_t *svc = handle;
273 	printer_t *p = NULL;
274 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
275 
276 	if ((svc == NULL) || (name == NULL) || (printer == NULL))
277 		return (PAPI_BAD_ARGUMENT);
278 
279 	/* if we are already connected, use that connection. */
280 	if (svc->connection == NULL)
281 		if ((result = service_connect(svc, name)) != PAPI_OK)
282 			return (result);
283 
284 	if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
285 		return (PAPI_TEMPORARY_ERROR);
286 
287 	ipp_initialize_request(svc, &request, OPID_SET_PRINTER_ATTRIBUTES);
288 
289 	ipp_initialize_operational_attributes(svc, &op, name, -1);
290 
291 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
292 			"operational-attributes-group", op);
293 	papiAttributeListFree(op);
294 
295 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
296 			"printer-attributes-group", attributes);
297 	result = ipp_send_request(svc, request, &response);
298 	papiAttributeListFree(request);
299 
300 	op = NULL;
301 	papiAttributeListGetCollection(response, NULL,
302 			"printer-attributes-group", &op);
303 	copy_attributes(&p->attributes, op);
304 	papiAttributeListFree(response);
305 
306 	return (result);
307 }
308 
309 papi_status_t
310 papiPrinterRemove(papi_service_t handle, char *name)
311 {
312 	return (_printer_enable_disable_pause_resume_delete(handle, name,
313 				NULL, OPID_CUPS_DELETE_PRINTER));
314 }
315 
316 papi_status_t
317 papiPrinterPurgeJobs(papi_service_t handle, char *name,
318 		papi_job_t **jobs)
319 {
320 	papi_status_t status, result = PAPI_INTERNAL_ERROR;
321 	service_t *svc = handle;
322 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
323 	void *iter = NULL;
324 
325 
326 	if ((svc == NULL) || (name == NULL))
327 		return (PAPI_BAD_ARGUMENT);
328 
329 	/* if we are already connected, use that connection. */
330 	if (svc->connection == NULL)
331 		if ((result = service_connect(svc, name)) != PAPI_OK)
332 			return (result);
333 
334 	ipp_initialize_request(svc, &request, OPID_PURGE_JOBS);
335 
336 	ipp_initialize_operational_attributes(svc, &op, name, -1);
337 
338 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
339 			"operational-attributes-group", op);
340 	papiAttributeListFree(op);
341 	result = ipp_send_request(svc, request, &response);
342 	papiAttributeListFree(request);
343 
344 	op = NULL;
345 	for (status = papiAttributeListGetCollection(response, &iter,
346 				"job-attributes-group", &op);
347 	     status == PAPI_OK;
348 	     status = papiAttributeListGetCollection(response, &iter,
349 				NULL, &op)) {
350 		job_t *j = NULL;
351 
352 		if ((j = calloc(1, sizeof (*j))) == NULL)
353 			return (PAPI_TEMPORARY_ERROR);
354 
355 		copy_attributes(&j->attributes, op);
356 		op = NULL;
357 		list_append(jobs, j);
358 	}
359 	papiAttributeListFree(response);
360 
361 	return (result);
362 }
363 
364 papi_status_t
365 papiPrinterListJobs(papi_service_t handle, char *name,
366 		char **requested_attrs, int type_mask,
367 		int max_num_jobs, papi_job_t **jobs)
368 {
369 	papi_status_t status, result = PAPI_INTERNAL_ERROR;
370 	service_t *svc = handle;
371 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
372 	void *iter = NULL;
373 
374 	if ((svc == NULL) || (name == NULL))
375 		return (PAPI_BAD_ARGUMENT);
376 
377 	/* if we are already connected, use that connection. */
378 	if (svc->connection == NULL)
379 		if ((result = service_connect(svc, name)) != PAPI_OK)
380 			return (result);
381 
382 	ipp_initialize_request(svc, &request, OPID_GET_JOBS);
383 
384 	ipp_initialize_operational_attributes(svc, &op, name, -1);
385 
386 	if (requested_attrs != NULL) {
387 		int i;
388 
389 		for (i = 0; requested_attrs[i] != NULL; i++)
390 			papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
391 				"requested-attributes", requested_attrs[i]);
392 	}
393 
394 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
395 			"operational-attributes-group", op);
396 	papiAttributeListFree(op);
397 	result = ipp_send_request(svc, request, &response);
398 	papiAttributeListFree(request);
399 
400 	op = NULL;
401 	for (status = papiAttributeListGetCollection(response, &iter,
402 				"job-attributes-group", &op);
403 	     status == PAPI_OK;
404 	     status = papiAttributeListGetCollection(response, &iter,
405 				NULL, &op)) {
406 		job_t *j = NULL;
407 
408 		if ((j = calloc(1, sizeof (*j))) == NULL)
409 			return (PAPI_TEMPORARY_ERROR);
410 
411 		copy_attributes(&j->attributes, op);
412 		op = NULL;
413 		list_append(jobs, j);
414 	}
415 	papiAttributeListFree(response);
416 
417 	return (result);
418 }
419 
420 papi_attribute_t **
421 papiPrinterGetAttributeList(papi_printer_t printer)
422 {
423 	papi_attribute_t **result = NULL;
424 	printer_t *p = printer;
425 
426 	if (p != NULL)
427 		result = p->attributes;
428 
429 	return (result);
430 }
431