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