xref: /illumos-gate/usr/src/cmd/lp/lib/papi/job.c (revision 43b9c05035ac59f7f7a8e7827598db5a15f30ed3)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*LINTLIBRARY*/
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <libintl.h>
34 #include <pwd.h>
35 #include <sys/stat.h>
36 #include <papi_impl.h>
37 
38 
39 /*
40  * for an older application that may have been linked with a pre-v1.0
41  * PAPI implementation.
42  */
43 papi_status_t
44 papiAttributeListAdd(papi_attribute_t ***attrs, int flags, char *name,
45 		papi_attribute_value_type_t type, papi_attribute_value_t *value)
46 {
47 	return (papiAttributeListAddValue(attrs, flags, name, type, value));
48 }
49 
50 #ifdef LP_USE_PAPI_ATTR
51 static papi_status_t psm_modifyAttrsFile(papi_attribute_t **attrs, char *file);
52 static papi_status_t psm_modifyAttrsList(char *file, papi_attribute_t **attrs,
53 					papi_attribute_t ***newAttrs);
54 #endif
55 
56 
57 void
58 papiJobFree(papi_job_t job)
59 {
60 	job_t *tmp = (job_t *)job;
61 
62 	if (tmp != NULL) {
63 		papiAttributeListFree(tmp->attributes);
64 		free(tmp);
65 	}
66 }
67 
68 void
69 papiJobListFree(papi_job_t *jobs)
70 {
71 	if (jobs != NULL) {
72 		int i;
73 
74 		for (i = 0; jobs[i] != NULL; i++) {
75 			papiJobFree(jobs[i]);
76 		}
77 		free(jobs);
78 	}
79 }
80 
81 papi_attribute_t **
82 papiJobGetAttributeList(papi_job_t job)
83 {
84 	job_t *tmp = (job_t *)job;
85 
86 	if (tmp != NULL)
87 		return (tmp->attributes);
88 
89 	return (NULL);
90 }
91 
92 char *
93 papiJobGetPrinterName(papi_job_t job)
94 {
95 	job_t *tmp = (job_t *)job;
96 	char *result = NULL;
97 
98 	if (tmp != NULL)
99 		papiAttributeListGetString(tmp->attributes, NULL,
100 					"printer-name", &result);
101 
102 	return (result);
103 }
104 
105 int32_t
106 papiJobGetId(papi_job_t job)
107 {
108 	job_t *tmp = (job_t *)job;
109 	int result = -1;
110 
111 	if (tmp != NULL)
112 		papiAttributeListGetInteger(tmp->attributes, NULL, "job-id",
113 					&result);
114 
115 	return (result);
116 }
117 
118 static REQUEST *
119 create_request(papi_service_t svc, char *printer, papi_attribute_t **attributes)
120 {
121 	static REQUEST r;
122 
123 	memset(&r, 0, sizeof (r));
124 	r.priority = -1;
125 	r.destination = printer_name_from_uri_id(printer, -1);
126 	job_attributes_to_lpsched_request(svc, &r, attributes);
127 
128 	return (&r);
129 }
130 
131 static papi_status_t
132 authorized(service_t *svc, int32_t id)
133 {
134 	papi_status_t result = PAPI_NOT_AUTHORIZED;	/* assume the worst */
135 	char file[32];
136 	REQUEST *r;
137 
138 	snprintf(file, sizeof (file), "%d-0", id);
139 	if ((r = getrequest(file)) != NULL) {
140 		uid_t uid = getuid();
141 		struct passwd *pw = NULL;
142 		char *user = "intruder";	/* assume an intruder */
143 
144 		if ((pw = getpwuid(uid)) != NULL)
145 			user = pw->pw_name;	/* use the process owner */
146 
147 		if ((uid == 0) || (uid == 71)) { /* root/lp can forge this */
148 			papi_status_t s;
149 			s = papiAttributeListGetString(svc->attributes, NULL,
150 					"user-name", &user);
151 			if (s != PAPI_OK)	/* true root/lp are almighty */
152 				result = PAPI_OK;
153 		}
154 
155 		if ((result != PAPI_OK) && (strcmp(user, r->user) == 0))
156 			result = PAPI_OK;
157 
158 		freerequest(r);
159 	} else
160 		result = PAPI_NOT_FOUND;
161 
162 	return (result);
163 }
164 
165 static papi_status_t
166 copy_file(char *from, char *to)
167 {
168 	int ifd, ofd;
169 	char buf[BUFSIZ];
170 	int rc;
171 
172 	if ((ifd = open(from, O_RDONLY)) < 0)
173 		return (PAPI_DOCUMENT_ACCESS_ERROR);
174 
175 	if ((ofd = open(to, O_WRONLY)) < 0) {
176 		close(ifd);
177 		return (PAPI_NOT_POSSIBLE);
178 	}
179 
180 	while ((rc = read(ifd, buf, sizeof (buf))) > 0)
181 		write(ofd, buf, rc);
182 
183 	close(ifd);
184 	close(ofd);
185 
186 	return (PAPI_OK);
187 }
188 
189 
190 #ifdef LP_USE_PAPI_ATTR
191 /*
192  * *****************************************************************************
193  *
194  * Description: Create a file containing all the attributes in the attribute
195  *              list passed to this function.
196  *              This file is then passed through lpsched and given to either
197  *              a slow-filter or to the printer's interface script to process
198  *              the attributes.
199  *
200  * Parameters:  attrs - list of attributes and their values
201  *              file  - file pathname to create and put the attributes into.
202  *
203  * *****************************************************************************
204  */
205 
206 static papi_status_t
207 psm_copy_attrsToFile(papi_attribute_t **attrs, char *file)
208 
209 {
210 	papi_status_t result = PAPI_OK;
211 
212 	if ((attrs != NULL) && (*attrs != NULL)) {
213 		FILE *out = NULL;
214 
215 		if ((out = fopen(file, "w")) != NULL) {
216 			papiAttributeListPrint(out, attrs, "");
217 			fclose(out);
218 		} else {
219 			result = PAPI_NOT_POSSIBLE;
220 		}
221 	}
222 
223 	return (result);
224 } /* psm_copy_attrsToFile */
225 
226 
227 /*
228  * *****************************************************************************
229  *
230  * Description: Modify the given attribute 'file' with the attributes from the
231  *              'attrs' list. Attributes already in the file will be replaced
232  *              with the new value. New attributes will be added into the file.
233  *
234  * Parameters:  attrs - list of attributes and their values
235  *              file  - file pathname to create and put the attributes into.
236  *
237  * *****************************************************************************
238  */
239 
240 static papi_status_t
241 psm_modifyAttrsFile(papi_attribute_t **attrs, char *file)
242 
243 {
244 	papi_status_t result = PAPI_OK;
245 	papi_attribute_t **newAttrs = NULL;
246 	struct stat   tmpBuf;
247 	FILE *fd = NULL;
248 
249 	if ((attrs != NULL) && (*attrs != NULL) && (file != NULL)) {
250 
251 		/*
252 		 * check file exist before try to modify it, if it doesn't
253 		 * exist assume there is an error
254 		 */
255 		if (stat(file, &tmpBuf) == 0) {
256 			/*
257 			 * if file is currently empty just write the given
258 			 * attributes to the file otherwise exact the attributes
259 			 * from the file and modify them accordingly before
260 			 * writing them back to the file
261 			 */
262 			if (tmpBuf.st_size == 0) {
263 				newAttrs = (papi_attribute_t **)attrs;
264 
265 				fd = fopen(file, "w");
266 				if (fd != NULL) {
267 					papiAttributeListPrint(fd,
268 							newAttrs, "");
269 					fclose(fd);
270 				} else {
271 					result = PAPI_NOT_POSSIBLE;
272 				}
273 			} else {
274 				result =
275 				    psm_modifyAttrsList(file, attrs, &newAttrs);
276 
277 				fd = fopen(file, "w");
278 				if (fd != NULL) {
279 					papiAttributeListPrint(fd,
280 								newAttrs, "");
281 					fclose(fd);
282 				} else {
283 					result = PAPI_NOT_POSSIBLE;
284 				}
285 
286 				papiAttributeListFree(newAttrs);
287 			}
288 		} else {
289 			result = PAPI_NOT_POSSIBLE;
290 		}
291 	}
292 
293 	return (result);
294 } /* psm_modifyAttrsFile */
295 
296 
297 /*
298  * *****************************************************************************
299  *
300  * Description: Extracts the attributes in the given attribute 'file' and
301  *              creates a new list 'newAttrs' containing the modified list of
302  *              attributes.
303  *
304  * Parameters:  file  - pathname of file containing attributes to be modified
305  *              attrs - list of attributes and their values to modify
306  *              newAttrs - returns the modified list of attributes
307  *
308  * *****************************************************************************
309  */
310 
311 static papi_status_t
312 psm_modifyAttrsList(char *file, papi_attribute_t **attrs,
313     papi_attribute_t ***newAttrs)
314 
315 {
316 	papi_status_t result = PAPI_OK;
317 	papi_attribute_t  *nextAttr = NULL;
318 	papi_attribute_value_t  **values = NULL;
319 	void *iter = NULL;
320 	FILE *fd = NULL;
321 	register int fD = 0;
322 	char aBuff[200];
323 	char *a = NULL;
324 	char *p = NULL;
325 	int count = 0;
326 	int n = 0;
327 
328 	fd = fopen(file, "r");
329 	if (fd != NULL) {
330 		fD = fileno(fd);
331 		a = &aBuff[0];
332 		p = &aBuff[0];
333 		count = read(fD, &aBuff[0], sizeof (aBuff) - 1);
334 		while ((result == PAPI_OK) && (count > 0)) {
335 			aBuff[count+n] = '\0';
336 			if (count == sizeof (aBuff) - n - 1) {
337 				p = strrchr(aBuff, '\n');
338 				if (p != NULL) {
339 					/* terminate at last complete line */
340 					*p = '\0';
341 				}
342 			}
343 			result = papiAttributeListFromString(
344 				newAttrs, PAPI_ATTR_EXCL, aBuff);
345 
346 			if (result == PAPI_OK) {
347 				/*
348 				 * handle any part lines and then read the next
349 				 * buffer from the file
350 				 */
351 				n = 0;
352 				if (p != a) {
353 					p++; /* skip NL */
354 					n = sizeof (aBuff) - 1 - (p - a);
355 					strncpy(aBuff, p, n);
356 				}
357 				count = read(fD, &aBuff[n],
358 					sizeof (aBuff) - n - 1);
359 				p = &aBuff[0];
360 			}
361 		}
362 		fclose(fd);
363 	}
364 
365 	/* now modify the attribute list with the new attributes in 'attrs' */
366 
367 	nextAttr = papiAttributeListGetNext((papi_attribute_t **)attrs, &iter);
368 	while ((result == PAPI_OK) && (nextAttr != NULL)) {
369 		values = nextAttr->values;
370 
371 		if ((values != NULL) && (*values != NULL)) {
372 			result = papiAttributeListAddValue(newAttrs,
373 						    PAPI_ATTR_REPLACE,
374 						    nextAttr->name,
375 						    nextAttr->type, *values);
376 			values++;
377 		}
378 
379 		while ((result == PAPI_OK) &&
380 			(values != NULL) && (*values != NULL)) {
381 			result = papiAttributeListAddValue(newAttrs,
382 						    PAPI_ATTR_APPEND,
383 						    nextAttr->name,
384 						    nextAttr->type, *values);
385 			values++;
386 		}
387 		nextAttr =
388 		    papiAttributeListGetNext((papi_attribute_t **)attrs, &iter);
389 	}
390 
391 	return (result);
392 } /* papi_modifyAttrsList() */
393 #endif
394 
395 
396 papi_status_t
397 papiJobSubmit(papi_service_t handle, char *printer,
398 		papi_attribute_t **job_attributes,
399 		papi_job_ticket_t *job_ticket,
400 		char **files, papi_job_t *job)
401 {
402 	papi_status_t status;
403 	service_t *svc = handle;
404 	job_t *j;
405 	int file_no;
406 	char *request_id = NULL;
407 	REQUEST *request;
408 	int i;
409 	char *c;
410 	char *tmp = NULL;
411 	char lpfile[BUFSIZ];
412 
413 	if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
414 	    (job == NULL))
415 		return (PAPI_BAD_ARGUMENT);
416 
417 	if (job_ticket != NULL)
418 		return (PAPI_OPERATION_NOT_SUPPORTED);
419 
420 	if (files != NULL)
421 		for (file_no = 0; files[file_no] != NULL; file_no++)
422 			if (access(files[file_no], R_OK) < 0) {
423 				detailed_error(svc,
424 					gettext("Cannot access file: %s: %s"),
425 					files[file_no], strerror(errno));
426 				return (PAPI_BAD_ARGUMENT);
427 			}
428 
429 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
430 		return (PAPI_TEMPORARY_ERROR);
431 
432 	/* file_no + 1 for the control file (-0) */
433 	status = lpsched_alloc_files(svc, file_no + 1, &request_id);
434 	if (status != PAPI_OK)
435 		return (status);
436 
437 	request = create_request(svc, (char *)printer,
438 				(papi_attribute_t **)job_attributes);
439 
440 	for (i = 0; files[i] != NULL; i++) {
441 		papi_status_t status;
442 		snprintf(lpfile, sizeof (lpfile), "%s%s-%d",
443 			"/var/spool/lp/temp/", request_id, i+1);
444 		status = copy_file(files[i], lpfile);
445 		if (status != PAPI_OK) {
446 			detailed_error(svc,
447 				gettext("unable to copy: %s -> %s: %s"),
448 				files[i], lpfile, strerror(errno));
449 				freerequest(request);
450 			return (PAPI_DEVICE_ERROR);
451 		}
452 		addlist(&(request->file_list), lpfile);
453 	}
454 
455 #ifdef LP_USE_PAPI_ATTR
456 	/*
457 	 * store the job attributes in the PAPI job attribute file that was
458 	 * created by lpsched_alloc_files(), the attributes will then pass
459 	 * through lpsched and be given to the slow-filters and the printer's
460 	 * interface script to process them
461 	 */
462 	snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
463 		"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
464 	status = psm_copy_attrsToFile(job_attributes, lpfile);
465 	if (status != PAPI_OK) {
466 		detailed_error(svc, "unable to copy attributes to file: %s: %s",
467 				lpfile, strerror(errno));
468 		return (PAPI_DEVICE_ERROR);
469 	}
470 #endif
471 
472 	/* store the meta-data file */
473 	snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
474 	if (putrequest(lpfile, request) < 0) {
475 		detailed_error(svc, gettext("unable to save request: %s: %s"),
476 			lpfile, strerror(errno));
477 		freerequest(request);
478 		return (PAPI_DEVICE_ERROR);
479 	}
480 
481 	status = lpsched_commit_job(svc, lpfile, &tmp);
482 	if (status != PAPI_OK) {
483 		unlink(lpfile);
484 		freerequest(request);
485 		return (status);
486 	}
487 
488 	lpsched_request_to_job_attributes(request, j);
489 	freerequest(request);
490 
491 	if ((c = strrchr(tmp, '-')) != NULL)
492 		c++;
493 	papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
494 			"job-id", atoi(c));
495 	papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
496 			"job-uri", tmp);
497 
498 	return (PAPI_OK);
499 }
500 
501 papi_status_t
502 papiJobSubmitByReference(papi_service_t handle, char *printer,
503 		papi_attribute_t **job_attributes,
504 		papi_job_ticket_t *job_ticket,
505 		char **files, papi_job_t *job)
506 {
507 	service_t *svc = handle;
508 	job_t *j;
509 	int file_no;
510 	short status;
511 	char *request_id = NULL;
512 	REQUEST *request;
513 	char *c;
514 	char *tmp = NULL;
515 	char lpfile[BUFSIZ];
516 	char **file_list = NULL;
517 
518 	if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
519 	    (job == NULL))
520 		return (PAPI_BAD_ARGUMENT);
521 
522 	if (job_ticket != NULL)
523 		return (PAPI_OPERATION_NOT_SUPPORTED);
524 
525 	if (files != NULL)
526 		for (file_no = 0; files[file_no] != NULL; file_no++) {
527 			if (access(files[file_no], R_OK) < 0) {
528 				detailed_error(svc,
529 					gettext("Cannot access file: %s: %s"),
530 					files[file_no], strerror(errno));
531 				return (PAPI_DOCUMENT_ACCESS_ERROR);
532 			}
533 			if (files[file_no][0] != '/') {
534 				char path[MAXPATHLEN];
535 
536 				if (getcwd(path, sizeof (path)) == NULL) {
537 					detailed_error(svc, gettext(
538 						"getcwd for file: %s: %s"),
539 						files[file_no],
540 						strerror(errno));
541 					return (PAPI_DOCUMENT_ACCESS_ERROR);
542 				}
543 				strlcat(path, "/", sizeof (path));
544 				if (strlcat(path, files[file_no], sizeof (path))
545 						>= sizeof (path)) {
546 					detailed_error(svc, gettext(
547 						"pathname too long: %s"),
548 						files[file_no]);
549 					return (PAPI_DOCUMENT_ACCESS_ERROR);
550 				}
551 				addlist(&file_list, path);
552 			} else
553 				addlist(&file_list, (char *)files[file_no]);
554 		}
555 
556 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
557 		return (PAPI_TEMPORARY_ERROR);
558 
559 	/* 1 for the control file (-0) */
560 	status = lpsched_alloc_files(svc, 1, &request_id);
561 	if (status != PAPI_OK)
562 		return (status);
563 
564 	request = create_request(svc, (char *)printer,
565 				(papi_attribute_t **)job_attributes);
566 	request->file_list = file_list;
567 
568 #ifdef LP_USE_PAPI_ATTR
569 	/*
570 	 * store the job attributes in the PAPI job attribute file that was
571 	 * created by lpsched_alloc_files(), the attributes will then pass
572 	 * through lpsched and be given to the slow-filters and the printer's
573 	 * interface script to process them
574 	 */
575 	snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
576 		"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
577 	status = psm_copy_attrsToFile(job_attributes, lpfile);
578 	if (status != PAPI_OK) {
579 		detailed_error(svc, "unable to copy attributes to file: %s: %s",
580 				lpfile, strerror(errno));
581 		return (PAPI_DEVICE_ERROR);
582 	}
583 #endif
584 
585 	/* store the meta-data file */
586 	snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
587 	if (putrequest(lpfile, request) < 0) {
588 		detailed_error(svc, gettext("unable to save request: %s: %s"),
589 			lpfile, strerror(errno));
590 		freerequest(request);
591 		return (PAPI_DEVICE_ERROR);
592 	}
593 
594 	status = lpsched_commit_job(svc, lpfile, &tmp);
595 	if (status != PAPI_OK) {
596 		unlink(lpfile);
597 		freerequest(request);
598 		return (status);
599 	}
600 
601 	lpsched_request_to_job_attributes(request, j);
602 
603 	freerequest(request);
604 
605 	if ((c = strrchr(tmp, '-')) != NULL)
606 		c++;
607 	papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
608 			"job-id", atoi(c));
609 	papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
610 			"job-uri", tmp);
611 
612 	return (PAPI_OK);
613 }
614 
615 papi_status_t
616 papiJobValidate(papi_service_t handle, char *printer,
617 		papi_attribute_t **job_attributes,
618 		papi_job_ticket_t *job_ticket,
619 		char **files, papi_job_t *job)
620 {
621 	papi_status_t status;
622 	papi_attribute_t **attributes = NULL;
623 	int i;
624 
625 	papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
626 			"job-hold-until", "indefinite");
627 	for (i = 0; job_attributes[i]; i++)
628 		list_append(&attributes, job_attributes[i]);
629 
630 	status = papiJobSubmitByReference(handle, printer,
631 				(papi_attribute_t **)attributes,
632 				job_ticket, files, job);
633 	if (status == PAPI_OK) {
634 		int id = papiJobGetId(*job);
635 
636 		if (id != -1)
637 			papiJobCancel(handle, printer, id);
638 	}
639 
640 	attributes[1] = NULL;	/* after attr[0], they are in another list */
641 	papiAttributeListFree(attributes);
642 
643 	return (status);
644 }
645 
646 papi_status_t
647 papiJobStreamOpen(papi_service_t handle, char *printer,
648 		papi_attribute_t **job_attributes,
649 		papi_job_ticket_t *job_ticket, papi_stream_t *stream)
650 {
651 	papi_status_t status;
652 	service_t *svc = handle;
653 	job_stream_t *s = NULL;
654 	char *request_id = NULL;
655 	char lpfile[BUFSIZ];
656 
657 	if ((svc == NULL) || (printer == NULL) || (stream == NULL))
658 		return (PAPI_BAD_ARGUMENT);
659 
660 	if (job_ticket != NULL)
661 		return (PAPI_OPERATION_NOT_SUPPORTED);
662 
663 	if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
664 		return (PAPI_TEMPORARY_ERROR);
665 
666 	/* 1 for data, 1 for the meta-data (-0) */
667 	status = lpsched_alloc_files(svc, 2, &request_id);
668 	if (status != PAPI_OK)
669 		return (status);
670 
671 	s->request = create_request(svc, (char *)printer,
672 				(papi_attribute_t **)job_attributes);
673 	snprintf(lpfile, sizeof (lpfile), "/var/spool/lp/temp/%s-1",
674 							request_id);
675 	s->fd = open(lpfile, O_WRONLY);
676 	addlist(&(s->request->file_list), lpfile);
677 
678 #ifdef LP_USE_PAPI_ATTR
679 	/*
680 	 * store the job attributes in the PAPI job attribute file that was
681 	 * created by lpsched_alloc_files(), the attributes will then pass
682 	 * through lpsched and be given to the slow-filters and the printer's
683 	 * interface script to process them
684 	 */
685 	snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
686 		"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
687 	status = psm_copy_attrsToFile(job_attributes, lpfile);
688 	if (status != PAPI_OK) {
689 		detailed_error(svc, "unable to copy attributes to file: %s: %s",
690 				lpfile, strerror(errno));
691 		close(s->fd);
692 		free(s);
693 		return (PAPI_DEVICE_ERROR);
694 	}
695 #endif
696 
697 	/* store the meta-data file */
698 	snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
699 	s->meta_data_file = strdup(lpfile);
700 	if (putrequest(lpfile, s->request) < 0) {
701 		detailed_error(svc, gettext("unable to save request: %s: %s"),
702 			lpfile, strerror(errno));
703 		s->request = NULL;
704 		return (PAPI_DEVICE_ERROR);
705 	}
706 
707 	return (PAPI_OK);
708 }
709 
710 papi_status_t
711 papiJobStreamWrite(papi_service_t handle,
712 		papi_stream_t stream, void *buffer, size_t buflen)
713 {
714 	service_t *svc = handle;
715 	job_stream_t *s = stream;
716 
717 	if ((svc == NULL) || (stream == NULL) || (buffer == NULL))
718 		return (PAPI_BAD_ARGUMENT);
719 
720 	if (write(s->fd, buffer, buflen) != buflen)
721 		return (PAPI_DEVICE_ERROR);
722 
723 	return (PAPI_OK);
724 }
725 papi_status_t
726 papiJobStreamClose(papi_service_t handle,
727 		papi_stream_t stream, papi_job_t *job)
728 {
729 	papi_status_t status = PAPI_OK;
730 	service_t *svc = handle;
731 	job_stream_t *s = stream;
732 	job_t *j = NULL;
733 	char *tmp = NULL, *c;
734 
735 	if ((svc == NULL) || (stream == NULL) || (job == NULL))
736 		return (PAPI_BAD_ARGUMENT);
737 
738 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
739 		return (PAPI_TEMPORARY_ERROR);
740 
741 	close(s->fd);
742 
743 	lpsched_request_to_job_attributes(s->request, j);
744 
745 	if (s->meta_data_file != NULL) {
746 		status = lpsched_commit_job(svc, s->meta_data_file, &tmp);
747 		if (status != PAPI_OK) {
748 			unlink(s->meta_data_file);
749 			return (status);
750 		}
751 		if ((c = strrchr(tmp, '-')) != NULL)
752 			c++;
753 		papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
754 			"job-id", atoi(c));
755 		papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
756 			"job-uri", tmp);
757 		free(s->meta_data_file);
758 	}
759 	free(s);
760 
761 	return (PAPI_OK);
762 }
763 
764 papi_status_t
765 papiJobQuery(papi_service_t handle, char *printer, int32_t job_id,
766 		char **requested_attrs,
767 		papi_job_t *job)
768 {
769 	service_t *svc = handle;
770 	job_t *j;
771 	char *dest;
772 	char req_id[32];
773 	short rc;
774 	char *form = NULL,
775 		*request_id = NULL,
776 		*charset = NULL,
777 		*user = NULL,
778 		*slabel = NULL,
779 		*file = NULL;
780 	time_t date = 0;
781 	size_t size = 0;
782 	short  rank = 0,
783 		state = 0;
784 
785 	if ((handle == NULL) || (printer == NULL) || (job_id < 0))
786 		return (PAPI_BAD_ARGUMENT);
787 
788 	dest = printer_name_from_uri_id(printer, job_id);
789 	snprintf(req_id, sizeof (req_id), "%s-%d", dest, job_id);
790 	free(dest);
791 
792 	rc = snd_msg(svc, S_INQUIRE_REQUEST_RANK, 0, "", "", req_id, "", "");
793 	if (rc < 0)
794 		return (PAPI_SERVICE_UNAVAILABLE);
795 
796 	if (rcv_msg(svc, R_INQUIRE_REQUEST_RANK, &rc, &request_id,
797 			&user, &slabel, &size, &date, &state, &dest, &form,
798 			&charset, &rank, &file) < 0) {
799 		detailed_error(svc,
800 			gettext("failed to read response from scheduler"));
801 		return (PAPI_DEVICE_ERROR);
802 	}
803 
804 	if ((request_id == NULL) || (request_id[0] == NULL))
805 		return (PAPI_NOT_FOUND);
806 
807 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
808 		return (PAPI_TEMPORARY_ERROR);
809 
810 	job_status_to_attributes(j, request_id, user, slabel, size, date, state,
811 				dest, form, charset, rank, file);
812 
813 	snprintf(req_id, sizeof (req_id), "%d-0", job_id);
814 	lpsched_read_job_configuration(svc, j, req_id);
815 
816 	return (PAPI_OK);
817 }
818 
819 papi_status_t
820 papiJobMove(papi_service_t handle, char *printer, int32_t job_id,
821 		char *destination)
822 {
823 	papi_status_t result = PAPI_OK;
824 	service_t *svc = handle;
825 	char req_id[64];
826 	char *queue;
827 	char *user = NULL;
828 
829 	if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
830 	    (destination == NULL))
831 		return (PAPI_BAD_ARGUMENT);
832 
833 	queue = printer_name_from_uri_id(printer, job_id);
834 	snprintf(req_id, sizeof (req_id), "%s-%d", queue, job_id);
835 	free(queue);
836 
837 	if (papiAttributeListGetString(svc->attributes, NULL, "user-name",
838 			&user) == PAPI_OK) {
839 		REQUEST *r = getrequest(req_id);
840 
841 		if ((r != NULL) && (r->user != NULL) &&
842 		    (strcmp(r->user, user) != 0))
843 			result = PAPI_NOT_AUTHORIZED;
844 		freerequest(r);
845 	}
846 
847 	if (result == PAPI_OK) {
848 		short status = MOK;
849 		char *dest = printer_name_from_uri_id(destination, -1);
850 
851 		if ((snd_msg(svc, S_MOVE_REQUEST, req_id, dest) < 0) ||
852 		    (rcv_msg(svc, R_MOVE_REQUEST, &status) < 0))
853 			status = MTRANSMITERR;
854 
855 		free(dest);
856 
857 		result = lpsched_status_to_papi_status(status);
858 	}
859 
860 	return (result);
861 }
862 
863 papi_status_t
864 papiJobCancel(papi_service_t handle, char *printer, int32_t job_id)
865 {
866 	papi_status_t result = PAPI_OK;
867 	service_t *svc = handle;
868 	char req_id[64];
869 	char *dest;
870 	char *user = NULL;
871 
872 	if ((svc == NULL) || (printer == NULL) || (job_id < 0))
873 		return (PAPI_BAD_ARGUMENT);
874 
875 	dest = printer_name_from_uri_id(printer, job_id);
876 	snprintf(req_id, sizeof (req_id), "%s-%d", dest, job_id);
877 	free(dest);
878 
879 	if (papiAttributeListGetString(svc->attributes, NULL, "user-name",
880 			&user) == PAPI_OK) {
881 		REQUEST *r = getrequest(req_id);
882 
883 		if ((r != NULL) && (r->user != NULL) &&
884 		    (strcmp(r->user, user) != 0))
885 			result = PAPI_NOT_AUTHORIZED;
886 		freerequest(r);
887 	}
888 
889 	if (result == PAPI_OK) {
890 		short status = MOK;
891 
892 		if ((snd_msg(svc, S_CANCEL_REQUEST, req_id) < 0) ||
893 		    (rcv_msg(svc, R_CANCEL_REQUEST, &status) < 0))
894 			status = MTRANSMITERR;
895 
896 		result = lpsched_status_to_papi_status(status);
897 	}
898 
899 	return (result);
900 }
901 
902 papi_status_t
903 hold_release_job(papi_service_t handle, char *printer,
904 		int32_t job_id, int flag)
905 {
906 	papi_status_t status;
907 	service_t *svc = handle;
908 	REQUEST *r = NULL;
909 	char *file;
910 	char *dest;
911 
912 	if ((svc == NULL) || (printer == NULL) || (job_id < 0))
913 		return (PAPI_BAD_ARGUMENT);
914 
915 	if ((status = authorized(svc, job_id)) != PAPI_OK)
916 		return (status);
917 
918 	dest = printer_name_from_uri_id(printer, job_id);
919 	status = lpsched_start_change(svc, dest, job_id, &file);
920 	if (status != PAPI_OK)
921 		return (status);
922 
923 	if ((r = getrequest(file)) != NULL) {
924 		r->actions &= ~ACT_RESUME;
925 		switch (flag) {
926 		case 0:
927 			r->actions |= ACT_HOLD;
928 			break;
929 		case 1:
930 			r->actions |= ACT_RESUME;
931 			break;
932 		case 2:
933 			r->actions |= ACT_IMMEDIATE;
934 			break;
935 		}
936 		if (putrequest(file, r) < 0) {
937 			detailed_error(svc,
938 				gettext("failed to write job: %s: %s"),
939 				file, strerror(errno));
940 			freerequest(r);
941 			return (PAPI_DEVICE_ERROR);
942 		}
943 		freerequest(r);
944 	} else {
945 		detailed_error(svc, gettext("failed to read job: %s: %s"),
946 				file, strerror(errno));
947 		return (PAPI_DEVICE_ERROR);
948 	}
949 
950 	status = lpsched_end_change(svc, dest, job_id);
951 
952 	return (status);
953 }
954 
955 papi_status_t
956 papiJobHold(papi_service_t handle, char *printer, int32_t job_id)
957 {
958 	return (hold_release_job(handle, printer, job_id, 0));
959 }
960 
961 papi_status_t
962 papiJobRelease(papi_service_t handle, char *printer, int32_t job_id)
963 {
964 	return (hold_release_job(handle, printer, job_id, 1));
965 }
966 
967 papi_status_t
968 papiJobPromote(papi_service_t handle, char *printer, int32_t job_id)
969 {
970 	return (hold_release_job(handle, printer, job_id, 2));
971 }
972 
973 papi_status_t
974 papiJobModify(papi_service_t handle, char *printer, int32_t job_id,
975 		papi_attribute_t **attributes, papi_job_t *job)
976 {
977 	papi_status_t status;
978 	job_t *j = NULL;
979 	service_t *svc = handle;
980 	char *file = NULL;
981 	char *dest;
982 	REQUEST *r = NULL;
983 	char lpfile[BUFSIZ];
984 
985 	if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
986 	    (attributes == NULL))
987 		return (PAPI_BAD_ARGUMENT);
988 
989 	if ((status = authorized(svc, job_id)) != PAPI_OK)
990 		return (status);
991 
992 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
993 		return (PAPI_TEMPORARY_ERROR);
994 
995 	dest = printer_name_from_uri_id(printer, job_id);
996 	status = lpsched_start_change(svc, dest, job_id, &file);
997 	if (status != PAPI_OK)
998 		return (status);
999 
1000 	if ((r = getrequest(file)) != NULL) {
1001 		job_attributes_to_lpsched_request(handle, r,
1002 				(papi_attribute_t **)attributes);
1003 #ifdef LP_USE_PAPI_ATTR
1004 		/*
1005 		 * store the job attributes in the PAPI job attribute file
1006 		 * that was created by the origonal job request. We need to
1007 		 * modify the attributes in the file as per the new attributes
1008 		 */
1009 		snprintf(lpfile, sizeof (lpfile), "%s%d-%s",
1010 			"/var/spool/lp/temp/", job_id, LP_PAPIATTRNAME);
1011 		status = psm_modifyAttrsFile(attributes, lpfile);
1012 		if (status != PAPI_OK) {
1013 			detailed_error(svc,
1014 				"unable to modify the attributes file: %s: %s",
1015 				lpfile, strerror(errno));
1016 			return (PAPI_DEVICE_ERROR);
1017 		}
1018 #endif
1019 
1020 		if (putrequest(file, r) < 0) {
1021 			detailed_error(svc,
1022 				gettext("failed to write job: %s: %s"),
1023 				file, strerror(errno));
1024 			freerequest(r);
1025 			return (PAPI_DEVICE_ERROR);
1026 		}
1027 	} else {
1028 		detailed_error(svc, gettext("failed to read job: %s: %s"),
1029 				file, strerror(errno));
1030 		return (PAPI_DEVICE_ERROR);
1031 	}
1032 
1033 	status = lpsched_end_change(svc, dest, job_id);
1034 	lpsched_request_to_job_attributes(r, j);
1035 
1036 	papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
1037 			"job-id", job_id);
1038 
1039 	freerequest(r);
1040 
1041 	return (status);
1042 }
1043 
1044 /*
1045  * Extension to PAPI, a variation of this is slated for post-1.0
1046  */
1047 #define	DUMMY_FILE	"/var/spool/lp/fifos/FIFO"
1048 
1049 papi_status_t
1050 papiJobCreate(papi_service_t handle, char *printer,
1051 		papi_attribute_t **job_attributes,
1052 		papi_job_ticket_t *job_ticket, papi_job_t *job)
1053 {
1054 	papi_status_t status;
1055 	service_t *svc = handle;
1056 	job_t *j = NULL;
1057 	REQUEST *request;
1058 	char *request_id = NULL;
1059 	char *c;
1060 	char *tmp = NULL;
1061 	char metadata_file[MAXPATHLEN];
1062 
1063 	if ((svc == NULL) || (printer == NULL) || (job == NULL))
1064 		return (PAPI_BAD_ARGUMENT);
1065 
1066 	if (job_ticket != NULL)
1067 		return (PAPI_JOB_TICKET_NOT_SUPPORTED);
1068 
1069 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
1070 		return (PAPI_TEMPORARY_ERROR);
1071 
1072 	/* 1 for the control file (-0) */
1073 	status = lpsched_alloc_files(svc, 1, &request_id);
1074 	if (status != PAPI_OK)
1075 		return (status);
1076 
1077 	/* convert the attributes to an lpsched REQUEST structure */
1078 	request = create_request(svc, (char *)printer,
1079 				(papi_attribute_t **)job_attributes);
1080 	if (request == NULL)
1081 		return (PAPI_TEMPORARY_ERROR);
1082 	addlist(&request->file_list, DUMMY_FILE);	/* add a dummy file */
1083 	request->actions |= ACT_HOLD;			/* hold the job */
1084 
1085 #ifdef LP_USE_PAPI_ATTR
1086 	/*
1087 	 * store the job attributes in the PAPI job attribute file that was
1088 	 * created by lpsched_alloc_files(), the attributes will then pass
1089 	 * through lpsched and be given to the slow-filters and the printer's
1090 	 * interface script to process them
1091 	 */
1092 	snprintf(metadata_file, sizeof (metadata_file), "%s%s-%s",
1093 		"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
1094 	status = psm_copy_attrsToFile(job_attributes, metadata_file);
1095 	if (status != PAPI_OK) {
1096 		detailed_error(svc, "unable to copy attributes to file: %s: %s",
1097 				metadata_file, strerror(errno));
1098 		free(request_id);
1099 		return (PAPI_DEVICE_ERROR);
1100 	}
1101 #endif
1102 
1103 	/* store the REQUEST on disk */
1104 	snprintf(metadata_file, sizeof (metadata_file), "%s-0", request_id);
1105 	free(request_id);
1106 	if (putrequest(metadata_file, request) < 0) {
1107 		detailed_error(svc, gettext("unable to save request: %s: %s"),
1108 			metadata_file, strerror(errno));
1109 		return (PAPI_DEVICE_ERROR);
1110 	}
1111 
1112 	status = lpsched_commit_job(svc, metadata_file, &tmp);
1113 	if (status != PAPI_OK) {
1114 		unlink(metadata_file);
1115 		return (status);
1116 	}
1117 
1118 	lpsched_request_to_job_attributes(request, j);
1119 
1120 	if ((c = strrchr(tmp, '-')) != NULL)
1121 		c++;
1122 	papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
1123 			"job-id", atoi(c));
1124 	papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
1125 			"job-uri", tmp);
1126 
1127 	return (PAPI_OK);
1128 }
1129 
1130 papi_status_t
1131 papiJobCommit(papi_service_t handle, char *printer, int32_t id)
1132 {
1133 	papi_status_t status = PAPI_OK;
1134 	service_t *svc = handle;
1135 	REQUEST *r = NULL;
1136 	char *metadata_file;
1137 	char *dest;
1138 
1139 	if ((svc == NULL) || (printer == NULL))
1140 		return (PAPI_BAD_ARGUMENT);
1141 
1142 	dest = printer_name_from_uri_id(printer, id);
1143 	/* tell the scheduler that we want to change the job */
1144 	status = lpsched_start_change(svc, dest, id, &metadata_file);
1145 	if (status != PAPI_OK)
1146 		return (status);
1147 
1148 	if ((r = getrequest(metadata_file)) != NULL) {
1149 		r->actions &= ~ACT_RESUME;
1150 		r->actions |= ACT_RESUME;
1151 		dellist(&r->file_list, DUMMY_FILE);
1152 
1153 		if (putrequest(metadata_file, r) < 0) {
1154 			detailed_error(svc,
1155 				gettext("failed to write job: %s: %s"),
1156 				metadata_file, strerror(errno));
1157 			freerequest(r);
1158 			return (PAPI_DEVICE_ERROR);
1159 		}
1160 	} else {
1161 		detailed_error(svc, gettext("failed to read job: %s: %s"),
1162 				metadata_file, strerror(errno));
1163 		return (PAPI_DEVICE_ERROR);
1164 	}
1165 
1166 	status = lpsched_end_change(svc, dest, id);
1167 	freerequest(r);
1168 
1169 	return (status);
1170 }
1171 
1172 papi_status_t
1173 papiJobStreamAdd(papi_service_t handle, char *printer, int32_t id,
1174 		papi_stream_t *stream)
1175 {
1176 	papi_status_t status;
1177 	service_t *svc = handle;
1178 	job_stream_t *s = NULL;
1179 	char *metadata_file = NULL;
1180 	char *dest;
1181 	char path[MAXPATHLEN];
1182 
1183 	/* allocate space for the stream */
1184 	if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
1185 		return (PAPI_TEMPORARY_ERROR);
1186 
1187 	dest = printer_name_from_uri_id(printer, id);
1188 	/* create/open data file (only root or lp can really do this */
1189 	snprintf(path, sizeof (path), "/var/spool/lp/temp/%d-XXXXXX", id);
1190 	if ((s->fd = mkstemp(path)) < 0) {
1191 		detailed_error(svc, gettext("unable to create sink (%s): %s"),
1192 			path, strerror(errno));
1193 		free(s);
1194 		return (PAPI_NOT_AUTHORIZED);
1195 	}
1196 
1197 	/* add data file to job */
1198 	status = lpsched_start_change(svc, dest, id, &metadata_file);
1199 	if (status != PAPI_OK) {
1200 		close(s->fd);
1201 		free(s);
1202 		unlink(path);
1203 		return (status);
1204 	}
1205 
1206 	if ((s->request = getrequest(metadata_file)) == NULL) {
1207 		detailed_error(svc, gettext("unable to load request: %s: %s"),
1208 			metadata_file, strerror(errno));
1209 		close(s->fd);
1210 		free(s);
1211 		unlink(path);
1212 		return (PAPI_NOT_POSSIBLE);
1213 	}
1214 
1215 	addlist(&(s->request->file_list), path);
1216 
1217 	if (putrequest(metadata_file, s->request) < 0) {
1218 		detailed_error(svc, gettext("unable to save request: %s: %s"),
1219 			metadata_file, strerror(errno));
1220 		close(s->fd);
1221 		free(s);
1222 		unlink(path);
1223 		return (PAPI_NOT_POSSIBLE);
1224 	}
1225 
1226 	status = lpsched_end_change(svc, dest, id);
1227 
1228 	if (status != PAPI_OK)
1229 		return (status);
1230 
1231 	return (PAPI_OK);
1232 }
1233