xref: /illumos-gate/usr/src/lib/print/libpapi-lpd/common/lpd-job.c (revision ca9327a6de44d69ddab3668cc1e143ce781387a3)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  */
27 
28 /* $Id: lpd-job.c 157 2006-04-26 15:07:55Z ktou $ */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #define	__EXTENSIONS__	/* for strtok_r() */
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #include <pwd.h>
43 #include <libintl.h>
44 #include <papi_impl.h>
45 
46 enum { LPD_RFC, LPD_SVR4 };
47 
48 static char
49 mime_type_to_rfc1179_type(char *mime)
50 {
51 	static struct { char *mime; char rfc; } cvt[] = {
52 		{ "text/plain", 'f' },
53 		{ "application/octet-stream", 'l' },
54 		{ "application/postscript", 'f' }, /* rfc incorrectly has 'o' */
55 		{ "application/x-pr", 'p' },
56 		{ "application/x-cif", 'c' },
57 		{ "application/x-dvi", 'd' },
58 		{ "application/x-fortran", 'r' },
59 		{ "application/x-plot", 'g' },
60 		{ "application/x-ditroff", 'n' },
61 		{ "application/x-troff", 't' },
62 		{ "application/x-raster", 'v' },
63 		{ NULL, 0}
64 	};
65 	char result = '\0';
66 
67 	if (mime != NULL) {
68 		int i;
69 
70 		for (i = 0; cvt[i].mime != NULL; i++)
71 			if (strcasecmp(cvt[i].mime, mime) == 0) {
72 				result = cvt[i].rfc;
73 				break;
74 			}
75 	}
76 
77 	return (result);
78 }
79 
80 static papi_status_t
81 add_lpd_control_line(char **metadata, char code, char *value)
82 {
83 	size_t size = 0;
84 	char line[BUFSIZ];
85 
86 	if ((metadata == NULL) || (value == NULL))
87 		return (PAPI_BAD_REQUEST);
88 
89 	if (*metadata != NULL)
90 		size = strlen(*metadata);
91 	size += strlen(value) + 3;
92 
93 	if (*metadata == NULL) {
94 		*metadata = (char *)calloc(1, size);
95 	} else {
96 		void *tmp;
97 		tmp = realloc(*metadata, size);
98 		if (tmp)
99 			*metadata = (char *)tmp;
100 		else
101 			return (PAPI_TEMPORARY_ERROR);
102 	}
103 
104 	snprintf(line, sizeof (line), "%c%s\n", code, value);
105 	strlcat(*metadata, line, size);
106 
107 	return (PAPI_OK);
108 }
109 
110 static papi_status_t
111 add_svr4_control_line(char **metadata, char code, char *value)
112 {
113 
114 	char line[BUFSIZ];
115 
116 	if ((metadata == NULL) || (value == NULL))
117 		return (PAPI_BAD_REQUEST);
118 
119 	snprintf(line, sizeof (line), "%c%s", code, value);
120 
121 	return (add_lpd_control_line(metadata, '5', line));
122 }
123 
124 static papi_status_t
125 add_hpux_control_line(char **metadata, char *value)
126 {
127 
128 	char line[BUFSIZ];
129 
130 	if ((metadata == NULL) || (value == NULL))
131 		return (PAPI_BAD_REQUEST);
132 
133 	snprintf(line, sizeof (line), " O%s", value);
134 
135 	return (add_lpd_control_line(metadata, 'N', line));
136 }
137 
138 static papi_status_t
139 add_int_control_line(char **metadata, char code, int value, int flag)
140 {
141 	char buf[16];
142 
143 	snprintf(buf, sizeof (buf), "%d", value);
144 
145 	if (flag == LPD_SVR4)
146 		return (add_svr4_control_line(metadata, code, buf));
147 	else
148 		return (add_lpd_control_line(metadata, code, buf));
149 }
150 
151 static papi_status_t
152 lpd_add_rfc1179_attributes(service_t *svc, papi_attribute_t **attributes,
153 		char **metadata, papi_attribute_t ***used)
154 {
155 	papi_status_t status = PAPI_OK;
156 	char *s;
157 	int integer;
158 	char bool;
159 	char host[BUFSIZ];
160 	char *user = "nobody";
161 	uid_t uid = getuid();
162 	struct passwd *pw;
163 
164 	if (svc == NULL)
165 		return (PAPI_BAD_REQUEST);
166 
167 	/* There is nothing to do */
168 	if (attributes == NULL)
169 		return (PAPI_OK);
170 
171 	gethostname(host, sizeof (host));
172 	add_lpd_control_line(metadata, 'H', host);
173 	papiAttributeListAddString(used, PAPI_ATTR_EXCL,
174 			"job-originating-host-name", host);
175 
176 	if ((pw = getpwuid(uid)) != NULL)
177 		user = pw->pw_name;
178 	if (uid == 0)
179 		papiAttributeListGetString(svc->attributes, NULL, "username",
180 			&user);
181 	add_lpd_control_line(metadata, 'P', user);
182 	papiAttributeListAddString(used, PAPI_ATTR_EXCL,
183 			"job-originating-user-name", user);
184 
185 	/* Class for Banner Page */
186 	s = NULL;
187 	papiAttributeListGetString(attributes, NULL, "rfc-1179-class", &s);
188 	if (s != NULL) {
189 		add_lpd_control_line(metadata, 'C', s);
190 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
191 				"rfc-1179-class", s);
192 	}
193 
194 	/* Print Banner Page */
195 	s = NULL;
196 	papiAttributeListGetString(attributes, NULL, "job-sheets", &s);
197 	if ((s != NULL) && (strcmp(s, "standard") == 0)) {
198 		add_lpd_control_line(metadata, 'L', user);
199 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
200 				"job-sheets", s);
201 	}
202 
203 	/* Jobname */
204 	s = NULL;
205 	papiAttributeListGetString(attributes, NULL, "job-name", &s);
206 	if (s != NULL) {
207 		add_lpd_control_line(metadata, 'J', s);
208 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
209 				"job-name", s);
210 	}
211 
212 	/* User to mail when job is done - lpr -m */
213 	bool = PAPI_FALSE;
214 	papiAttributeListGetBoolean(attributes, NULL, "rfc-1179-mail", &bool);
215 	if (bool == PAPI_TRUE) {
216 		add_lpd_control_line(metadata, 'M', user);
217 		papiAttributeListAddBoolean(used, PAPI_ATTR_EXCL,
218 				"rfc-1179-mail", bool);
219 	}
220 
221 	/* Title for pr */
222 	s = NULL;
223 	papiAttributeListGetString(attributes, NULL, "pr-title", &s);
224 	if (s != NULL) {
225 		add_lpd_control_line(metadata, 'T', s);
226 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
227 				"pr-title", s);
228 	}
229 
230 	/* Indent - used with pr filter */
231 	integer = 0;
232 	papiAttributeListGetInteger(attributes, NULL, "pr-indent", &integer);
233 	if (integer >= 1) {
234 		add_int_control_line(metadata, 'I', integer, LPD_RFC);
235 		papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
236 				"pr-indent", integer);
237 	}
238 
239 	/* Width - used with pr filter */
240 	integer = 0;
241 	papiAttributeListGetInteger(attributes, NULL, "pr-width", &integer);
242 	if (integer >= 1) {
243 		add_int_control_line(metadata, 'W', integer, LPD_RFC);
244 		papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
245 				"pr-width", integer);
246 	}
247 
248 	/* file with Times Roman font lpr -1	*/
249 	s = NULL;
250 	papiAttributeListGetString(attributes, NULL, "rfc-1179-font-r", &s);
251 	if (s != NULL) {
252 		add_lpd_control_line(metadata, '1', s);
253 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
254 				"rfc-1179-font-r", s);
255 	}
256 
257 	/* file with Times Roman font lpr -2	*/
258 	s = NULL;
259 	papiAttributeListGetString(attributes, NULL, "rfc-1179-font-i", &s);
260 	if (s != NULL) {
261 		add_lpd_control_line(metadata, '2', s);
262 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
263 				"rfc-1179-font-i", s);
264 	}
265 
266 	/* file with Times Roman font lpr -3	*/
267 	s = NULL;
268 	papiAttributeListGetString(attributes, NULL, "rfc-1179-font-b", &s);
269 	if (s != NULL) {
270 		add_lpd_control_line(metadata, '3', s);
271 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
272 				"rfc-1179-font-b", s);
273 	}
274 
275 	/* file with Times Roman font lpr -4	*/
276 	s = NULL;
277 	papiAttributeListGetString(attributes, NULL, "rfc-1179-font-s", &s);
278 	if (s != NULL) {
279 		add_lpd_control_line(metadata, '4', s);
280 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
281 				"rfc-1179-font-s", s);
282 	}
283 
284 	return (status);
285 }
286 
287 static char *
288 unused_attributes(papi_attribute_t **list, papi_attribute_t **used)
289 {
290 	char *result = NULL;
291 	char **names = NULL;
292 	int i;
293 
294 	if ((list == NULL) || (used == NULL))
295 		return (NULL);
296 
297 	for (i = 0; used[i] != NULL; i++)
298 		list_append(&names, used[i]->name);
299 
300 	if (names != NULL) {
301 		papi_attribute_t **unused = NULL;
302 
303 		/* add these to the list of things to ignore */
304 		list_append(&names, "document-format");
305 		list_append(&names, "copies");
306 
307 		split_and_copy_attributes(names, list, NULL, &unused);
308 		if (unused != NULL) {
309 			size_t size = 0;
310 
311 			do {
312 				size += 1024;
313 				if (result != NULL)
314 					free(result);
315 				result = calloc(1, size);
316 			} while (papiAttributeListToString(unused, " ",
317 					result, size) != PAPI_OK);
318 			papiAttributeListFree(unused);
319 		}
320 		free(names);
321 	}
322 
323 	return (result);
324 }
325 
326 /*
327  * lpd_add_svr4_attributes
328  *	Solaris 2.x LP - BSD protocol extensions
329  */
330 static papi_status_t
331 lpd_add_svr4_attributes(service_t *svc, papi_attribute_t **attributes,
332 		char **metadata, papi_attribute_t ***used)
333 {
334 	char *s;
335 	int integer;
336 
337 	if (svc == NULL)
338 		return (PAPI_BAD_REQUEST);
339 
340 	/* media */
341 	s = NULL;
342 	papiAttributeListGetString(attributes, NULL, "media", &s);
343 	if (s != NULL) {
344 		add_svr4_control_line(metadata, 'f', s);
345 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
346 				"media", s);
347 	}
348 
349 	/* Handling */
350 	s = NULL;
351 	papiAttributeListGetString(attributes, NULL, "job_hold_until", &s);
352 	if ((s != NULL) && (strcmp(s, "indefinite"))) {
353 		add_svr4_control_line(metadata, 'H', "hold");
354 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
355 				"media", "hold");
356 	} else if ((s != NULL) && (strcmp(s, "no-hold"))) {
357 		add_svr4_control_line(metadata, 'H', "release");
358 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
359 				"media", "release");
360 	} else if ((s != NULL) && (strcmp(s, "immediate"))) {
361 		add_int_control_line(metadata, 'q', 0, LPD_SVR4);
362 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
363 				"media", "immediate");
364 	}
365 
366 	/* Pages */
367 	s = NULL;
368 	papiAttributeListGetString(attributes, NULL, "page-ranges", &s);
369 	if (s != NULL) {
370 		add_svr4_control_line(metadata, 'P', s);
371 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
372 				"page-ranges", s);
373 	}
374 
375 	/* Priority : lp -q */
376 	integer = -1;
377 	papiAttributeListGetInteger(attributes, NULL, "priority", &integer);
378 	if (integer != -1) {
379 		add_int_control_line(metadata, 'q', integer, LPD_SVR4);
380 		papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
381 				"priority", integer);
382 	}
383 
384 	/* Charset : lp -S */
385 	s = NULL;
386 	papiAttributeListGetString(attributes, NULL, "lp-charset", &s);
387 	if (s != NULL) {
388 		add_svr4_control_line(metadata, 'S', s);
389 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
390 				"lp-charset", s);
391 	}
392 
393 	/* Type : done when adding file  */
394 
395 	/* Mode : lp -y */
396 	s = NULL;
397 	papiAttributeListGetString(attributes, NULL, "lp-modes", &s);
398 	if (s != NULL) {
399 		add_svr4_control_line(metadata, 'y', s);
400 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
401 				"lp-modes", s);
402 	}
403 
404 	/* Options lp -o are handled elsewhere */
405 	if ((s = unused_attributes(attributes, *used)) != NULL) {
406 		add_lpd_control_line(metadata, 'O', s);
407 		free(s);
408 	}
409 
410 	return (PAPI_OK);
411 }
412 
413 papi_status_t
414 lpd_add_hpux_attributes(service_t *svc, papi_attribute_t **attributes,
415 		char **metadata, papi_attribute_t ***used)
416 {
417 	char *s = NULL;
418 
419 	/* Options lp -o */
420 	if ((s = unused_attributes(attributes, *used)) != NULL) {
421 		add_hpux_control_line(metadata, s);
422 		free(s);
423 	}
424 
425 	return (PAPI_OK);
426 }
427 
428 papi_status_t
429 lpd_job_add_attributes(service_t *svc, papi_attribute_t **attributes,
430 		char **metadata, papi_attribute_t ***used)
431 {
432 	if ((svc == NULL) || (metadata == NULL))
433 		return (PAPI_BAD_REQUEST);
434 
435 	lpd_add_rfc1179_attributes(svc, attributes, metadata, used);
436 
437 	/* add protocol extensions if applicable */
438 	if (svc->uri->fragment != NULL) {
439 		if ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
440 		    (strcasecmp(svc->uri->fragment, "svr4") == 0))
441 			lpd_add_svr4_attributes(svc, attributes, metadata,
442 					used);
443 		else if (strcasecmp(svc->uri->fragment, "hpux") == 0)
444 			lpd_add_hpux_attributes(svc, attributes, metadata,
445 						used);
446 		/*
447 		 * others could be added here:
448 		 *	lprng, sco, aix, digital unix, xerox, ...
449 		 */
450 	}
451 
452 	return (PAPI_OK);
453 }
454 
455 papi_status_t
456 lpd_job_add_files(service_t *svc, papi_attribute_t **attributes,
457 		char **files, char **metadata, papi_attribute_t ***used)
458 {
459 	char *format = "text/plain";
460 	char rfc_fmt = 'l';
461 	int copies = 1;
462 	char host[BUFSIZ];
463 	int i;
464 
465 	if ((svc == NULL) || (attributes == NULL) || (files == NULL) ||
466 	    (metadata == NULL))
467 		return (PAPI_BAD_ARGUMENT);
468 
469 	papiAttributeListGetString(attributes, NULL, "document-format",
470 			&format);
471 	papiAttributeListAddString(used, PAPI_ATTR_EXCL,
472 			"document-format", format);
473 	if ((rfc_fmt = mime_type_to_rfc1179_type(format)) == '\0') {
474 		if ((svc->uri->fragment != NULL) &&
475 		    ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
476 		     (strcasecmp(svc->uri->fragment, "svr4") == 0)))
477 			add_svr4_control_line(metadata, 'T', format);
478 		rfc_fmt = 'l';
479 	}
480 
481 	papiAttributeListGetInteger(attributes, NULL, "copies", &copies);
482 	if (copies < 1)
483 		copies = 1;
484 	papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, "copies", copies);
485 
486 	gethostname(host, sizeof (host));
487 
488 	for (i = 0; files[i] != NULL; i++) {
489 		char name[BUFSIZ];
490 		char key;
491 		int j;
492 
493 		if ((strcmp("standard input", files[i]) != 0) &&
494 		    (access(files[i], R_OK) < 0)) {
495 			detailed_error(svc, gettext("aborting request, %s: %s"),
496 				files[i], strerror(errno));
497 			return (PAPI_NOT_AUTHORIZED);
498 		}
499 
500 		if (i < 26)
501 			key = 'A' + i;
502 		else if (i < 52)
503 			key = 'a' + (i - 26);
504 		else if (i < 62)
505 			key = '0' + (i - 52);
506 		else {
507 			detailed_error(svc,
508 				gettext("too many files, truncated at 62"));
509 			return (PAPI_OK_SUBST);
510 		}
511 
512 		snprintf(name, sizeof (name), "df%cXXX%s", key, host);
513 
514 		for (j = 0; j < copies; j++)
515 			add_lpd_control_line(metadata, rfc_fmt, name);
516 		add_lpd_control_line(metadata, 'U', name);
517 		add_lpd_control_line(metadata, 'N', (char *)files[i]);
518 	}
519 
520 	return (PAPI_OK);
521 }
522 
523 papi_status_t
524 lpd_submit_job(service_t *svc, char *metadata, papi_attribute_t ***attributes,
525 		int *ofd)
526 {
527 	papi_status_t status = PAPI_INTERNAL_ERROR;
528 	int fd;
529 	char path[32];
530 	char *list[2];
531 
532 	if ((svc == NULL) || (metadata == NULL))
533 		return (PAPI_BAD_ARGUMENT);
534 
535 	strcpy(path, "/tmp/lpd-job-XXXXXX");
536 	fd = mkstemp(path);
537 	write(fd, metadata, strlen(metadata));
538 	close(fd);
539 
540 	list[0] = path;
541 	list[1] = NULL;
542 
543 	if (((fd = lpd_open(svc, 's', list, 15)) < 0) && (errno != EBADMSG)) {
544 		switch (errno) {
545 		case ENOSPC:
546 			status = PAPI_TEMPORARY_ERROR;
547 			break;
548 		case EIO:
549 			status = PAPI_TEMPORARY_ERROR;
550 			break;
551 		case ECONNREFUSED:
552 			status = PAPI_SERVICE_UNAVAILABLE;
553 			break;
554 		case ENOENT:
555 			status = PAPI_NOT_ACCEPTING;
556 			break;
557 		case EBADMSG:
558 		case EBADF:
559 			status = PAPI_OK;
560 			break;
561 		default:
562 			status = PAPI_TIMEOUT;
563 			break;
564 		}
565 	} else
566 		status = PAPI_OK;
567 
568 	if (ofd != NULL)
569 		*ofd = fd;
570 	else
571 		close(fd);
572 
573 	/* read the ID and add it to to the job */
574 	if ((fd = open(path, O_RDONLY)) >= 0) {
575 		int job_id = 0;
576 		read(fd, &job_id, sizeof (job_id));
577 		papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
578 				"job-id", job_id);
579 		close(fd);
580 	}
581 
582 	unlink(path);
583 
584 	return (status);
585 }
586