xref: /illumos-gate/usr/src/lib/print/libpapi-lpd/common/lpd-job.c (revision 646e55b6807cdf761fecd1e4095d73116cdefdb5)
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 2006 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 		{ "plain/text", '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 /*
288  * lpd_add_svr4_attributes
289  *	Solaris 2.x LP - BSD protocol extensions
290  */
291 static papi_status_t
292 lpd_add_svr4_attributes(service_t *svc, papi_attribute_t **attributes,
293 		char **metadata, papi_attribute_t ***used)
294 {
295 	char *s;
296 	int integer;
297 
298 	if (svc == NULL)
299 		return (PAPI_BAD_REQUEST);
300 
301 	/* media */
302 	s = NULL;
303 	papiAttributeListGetString(attributes, NULL, "media", &s);
304 	if (s != NULL) {
305 		add_svr4_control_line(metadata, 'f', s);
306 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
307 				"media", s);
308 	}
309 
310 	/* Handling */
311 	s = NULL;
312 	papiAttributeListGetString(attributes, NULL, "job_hold_until", &s);
313 	if ((s != NULL) && (strcmp(s, "indefinite"))) {
314 		add_svr4_control_line(metadata, 'H', "hold");
315 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
316 				"media", "hold");
317 	} else if ((s != NULL) && (strcmp(s, "no-hold"))) {
318 		add_svr4_control_line(metadata, 'H', "release");
319 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
320 				"media", "release");
321 	} else if ((s != NULL) && (strcmp(s, "immediate"))) {
322 		add_int_control_line(metadata, 'q', 0, LPD_SVR4);
323 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
324 				"media", "immediate");
325 	}
326 
327 	/* Pages */
328 	s = NULL;
329 	papiAttributeListGetString(attributes, NULL, "page-ranges", &s);
330 	if (s != NULL) {
331 		add_svr4_control_line(metadata, 'P', s);
332 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
333 				"page-ranges", s);
334 	}
335 
336 	/* Priority : lp -q */
337 	integer = -1;
338 	papiAttributeListGetInteger(attributes, NULL, "priority", &integer);
339 	if (integer != -1) {
340 		add_int_control_line(metadata, 'q', integer, LPD_SVR4);
341 		papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
342 				"priority", integer);
343 	}
344 
345 	/* Charset : lp -S */
346 	s = NULL;
347 	papiAttributeListGetString(attributes, NULL, "lp-charset", &s);
348 	if (s != NULL) {
349 		add_svr4_control_line(metadata, 'S', s);
350 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
351 				"lp-charset", s);
352 	}
353 
354 	/* Type : done when adding file  */
355 
356 	/* Mode : lp -y */
357 	s = NULL;
358 	papiAttributeListGetString(attributes, NULL, "lp-modes", &s);
359 	if (s != NULL) {
360 		add_svr4_control_line(metadata, 'y', s);
361 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
362 				"lp-modes", s);
363 	}
364 
365 	/* Options lp -o */
366 	s = NULL;
367 	papiAttributeListGetString(attributes, NULL, "lp-options", &s);
368 	if (s != NULL) {
369 		add_svr4_control_line(metadata, 'o', s);
370 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
371 				"lp-options", s);
372 	}
373 
374 	return (PAPI_OK);
375 }
376 
377 papi_status_t
378 lpd_add_hpux_attributes(service_t *svc, papi_attribute_t **attributes,
379 		char **metadata, papi_attribute_t ***used)
380 {
381 	char *s = NULL;
382 
383 	/* Options lp -o */
384 	s = NULL;
385 	papiAttributeListGetString(attributes, NULL, "lp-options", &s);
386 	if (s != NULL) {
387 		add_hpux_control_line(metadata, s);
388 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
389 				"lp-options", s);
390 	}
391 
392 	return (PAPI_OK);
393 }
394 
395 papi_status_t
396 lpd_job_add_attributes(service_t *svc, papi_attribute_t **attributes,
397 		char **metadata, papi_attribute_t ***used)
398 {
399 	if ((svc == NULL) || (metadata == NULL))
400 		return (PAPI_BAD_REQUEST);
401 
402 	lpd_add_rfc1179_attributes(svc, attributes, metadata, used);
403 
404 	if (svc->uri->fragment != NULL) {
405 		if ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
406 		    (strcasecmp(svc->uri->fragment, "svr4") == 0))
407 			lpd_add_svr4_attributes(svc, attributes, metadata,
408 					used);
409 		else if (strcasecmp(svc->uri->fragment, "hpux") == 0)
410 			lpd_add_hpux_attributes(svc, attributes, metadata,
411 						used);
412 		/*
413 		 * others could be added here:
414 		 *	lprng, sco, aix, digital unix, xerox, ...
415 		 */
416 	}
417 
418 	return (PAPI_OK);
419 }
420 
421 papi_status_t
422 lpd_job_add_files(service_t *svc, papi_attribute_t **attributes,
423 		char **files, char **metadata, papi_attribute_t ***used)
424 {
425 	char *format = "plain/text";
426 	char rfc_fmt = 'l';
427 	int copies = 1;
428 	char host[BUFSIZ];
429 	int i;
430 
431 	if ((svc == NULL) || (attributes == NULL) || (files == NULL) ||
432 	    (metadata == NULL))
433 		return (PAPI_BAD_ARGUMENT);
434 
435 	papiAttributeListGetString(attributes, NULL, "document-format",
436 			&format);
437 	papiAttributeListAddString(used, PAPI_ATTR_EXCL,
438 			"document-format", format);
439 	if ((rfc_fmt = mime_type_to_rfc1179_type(format)) == '\0') {
440 		if ((svc->uri->fragment != NULL) &&
441 		    ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
442 		     (strcasecmp(svc->uri->fragment, "svr4") == 0)))
443 			add_svr4_control_line(metadata, 'T', format);
444 		rfc_fmt = 'l';
445 	}
446 
447 	papiAttributeListGetInteger(attributes, NULL, "copies", &copies);
448 	if (copies < 1)
449 		copies = 1;
450 	papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, "copies", copies);
451 
452 	gethostname(host, sizeof (host));
453 
454 	for (i = 0; files[i] != NULL; i++) {
455 		char name[BUFSIZ];
456 		char key;
457 		int j;
458 
459 		if ((strcmp("standard input", files[i]) != 0) &&
460 		    (access(files[i], R_OK) < 0)) {
461 			detailed_error(svc, gettext("aborting request, %s: %s"),
462 				files[i], strerror(errno));
463 			return (PAPI_NOT_AUTHORIZED);
464 		}
465 
466 		if (i < 26)
467 			key = 'A' + i;
468 		else if (i < 52)
469 			key = 'a' + (i - 26);
470 		else if (i < 62)
471 			key = '0' + (i - 52);
472 		else {
473 			detailed_error(svc,
474 				gettext("too many files, truncated at 62"));
475 			return (PAPI_OK_SUBST);
476 		}
477 
478 		snprintf(name, sizeof (name), "df%cXXX%s", key, host);
479 
480 		for (j = 0; j < copies; j++)
481 			add_lpd_control_line(metadata, rfc_fmt, name);
482 		add_lpd_control_line(metadata, 'U', name);
483 		add_lpd_control_line(metadata, 'N', (char *)files[i]);
484 	}
485 
486 	return (PAPI_OK);
487 }
488 
489 papi_status_t
490 lpd_submit_job(service_t *svc, char *metadata, papi_attribute_t ***attributes,
491 		int *ofd)
492 {
493 	papi_status_t status = PAPI_INTERNAL_ERROR;
494 	int fd;
495 	char path[32];
496 	char *list[2];
497 
498 	if ((svc == NULL) || (metadata == NULL))
499 		return (PAPI_BAD_ARGUMENT);
500 
501 	strcpy(path, "/tmp/lpd-job-XXXXXX");
502 	fd = mkstemp(path);
503 	write(fd, metadata, strlen(metadata));
504 	close(fd);
505 
506 	list[0] = path;
507 	list[1] = NULL;
508 
509 	if (((fd = lpd_open(svc, 's', list, 3)) < 0) && (errno != EBADMSG)) {
510 		switch (errno) {
511 		case ENOSPC:
512 			status = PAPI_TEMPORARY_ERROR;
513 			break;
514 		case EIO:
515 			status = PAPI_TEMPORARY_ERROR;
516 			break;
517 		case ECONNREFUSED:
518 			status = PAPI_SERVICE_UNAVAILABLE;
519 			break;
520 		case ENOENT:
521 			status = PAPI_NOT_ACCEPTING;
522 			break;
523 		case EBADMSG:
524 		case EBADF:
525 			status = PAPI_OK;
526 			break;
527 		default:
528 			status = PAPI_TIMEOUT;
529 			break;
530 		}
531 	} else
532 		status = PAPI_OK;
533 
534 	if (ofd != NULL)
535 		*ofd = fd;
536 	else
537 		close(fd);
538 
539 	/* read the ID and add it to to the job */
540 	if ((fd = open(path, O_RDONLY)) >= 0) {
541 		int job_id = 0;
542 		read(fd, &job_id, sizeof (job_id));
543 		papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
544 				"job-id", job_id);
545 		close(fd);
546 	}
547 
548 	unlink(path);
549 
550 	return (status);
551 }
552