1*2264Sjacobs /*
2*2264Sjacobs  * CDDL HEADER START
3*2264Sjacobs  *
4*2264Sjacobs  * The contents of this file are subject to the terms of the
5*2264Sjacobs  * Common Development and Distribution License (the "License").
6*2264Sjacobs  * You may not use this file except in compliance with the License.
7*2264Sjacobs  *
8*2264Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2264Sjacobs  * or http://www.opensolaris.org/os/licensing.
10*2264Sjacobs  * See the License for the specific language governing permissions
11*2264Sjacobs  * and limitations under the License.
12*2264Sjacobs  *
13*2264Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
14*2264Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2264Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
16*2264Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
17*2264Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2264Sjacobs  *
19*2264Sjacobs  * CDDL HEADER END
20*2264Sjacobs  */
21*2264Sjacobs 
22*2264Sjacobs /*
23*2264Sjacobs  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*2264Sjacobs  * Use is subject to license terms.
25*2264Sjacobs  *
26*2264Sjacobs  */
27*2264Sjacobs 
28*2264Sjacobs /* $Id: in.lpd.c 170 2006-05-20 05:58:49Z njacobs $ */
29*2264Sjacobs 
30*2264Sjacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*2264Sjacobs 
32*2264Sjacobs #include <stdio.h>
33*2264Sjacobs #include <stdlib.h>
34*2264Sjacobs #include <stdarg.h>
35*2264Sjacobs #include <string.h>
36*2264Sjacobs #include <errno.h>
37*2264Sjacobs #include <syslog.h>
38*2264Sjacobs #include <libintl.h>
39*2264Sjacobs 
40*2264Sjacobs #include <papi.h>
41*2264Sjacobs #include "common.h"
42*2264Sjacobs 
43*2264Sjacobs #define	ACK(fp)		{ (void) fputc('\0', fp); (void) fflush(fp); }
44*2264Sjacobs #define	NACK(fp)	{ (void) fputc('\1', fp); (void) fflush(fp); }
45*2264Sjacobs 
46*2264Sjacobs /*
47*2264Sjacobs  * This file contains the front-end of the BSD Print Protocol adaptor.  This
48*2264Sjacobs  * code assumes a BSD Socket interface to the networking side.
49*2264Sjacobs  */
50*2264Sjacobs 
51*2264Sjacobs void
52*2264Sjacobs fatal(FILE *fp, char *fmt, ...)
53*2264Sjacobs {
54*2264Sjacobs 	va_list ap;
55*2264Sjacobs 
56*2264Sjacobs 	va_start(ap, fmt);
57*2264Sjacobs 	vsyslog(LOG_DEBUG, fmt, ap);
58*2264Sjacobs 	vfprintf(fp, fmt, ap);
59*2264Sjacobs 	va_end(ap);
60*2264Sjacobs }
61*2264Sjacobs 
62*2264Sjacobs static void
63*2264Sjacobs cleanup(char **files)
64*2264Sjacobs {
65*2264Sjacobs 	if (files != NULL) {
66*2264Sjacobs 		int i;
67*2264Sjacobs 
68*2264Sjacobs 		for (i = 0; files[i] != NULL; i++)
69*2264Sjacobs 			unlink(files[i]);
70*2264Sjacobs 	}
71*2264Sjacobs }
72*2264Sjacobs 
73*2264Sjacobs static void
74*2264Sjacobs berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp)
75*2264Sjacobs {
76*2264Sjacobs 	char line[BUFSIZ];
77*2264Sjacobs 	char **files = NULL;	/* the job data files */
78*2264Sjacobs 
79*2264Sjacobs 	/* This should actually implement transfer job from RFC-1179 */
80*2264Sjacobs 	ACK(ofp);
81*2264Sjacobs 
82*2264Sjacobs 	while (fgets(line, sizeof (line), ifp) != NULL) {
83*2264Sjacobs 		switch (line[0]) {
84*2264Sjacobs 		case 0x01:	/* Abort */
85*2264Sjacobs 			cleanup(files);
86*2264Sjacobs 			break;
87*2264Sjacobs 		case 0x02:	/* Receive control file */
88*2264Sjacobs 
89*2264Sjacobs 			break;
90*2264Sjacobs 		case 0x03: {	/* Receive data file */
91*2264Sjacobs 			char file[] = "lpdXXXXXX";
92*2264Sjacobs 			int fd;
93*2264Sjacobs 
94*2264Sjacobs 			fd = mkstemp(file);
95*2264Sjacobs 
96*2264Sjacobs 			list_append(&files, strdup(file));
97*2264Sjacobs 			}
98*2264Sjacobs 			break;
99*2264Sjacobs 		default:
100*2264Sjacobs 			fatal(ofp, "protocol screwup");
101*2264Sjacobs 			cleanup(files);
102*2264Sjacobs 			break;
103*2264Sjacobs 		}
104*2264Sjacobs 	}
105*2264Sjacobs 
106*2264Sjacobs 	cleanup(files);
107*2264Sjacobs }
108*2264Sjacobs 
109*2264Sjacobs static void
110*2264Sjacobs berkeley_transfer_files(papi_service_t svc, FILE *ifp, FILE *ofp,
111*2264Sjacobs 		char *printer)
112*2264Sjacobs {
113*2264Sjacobs 	papi_status_t status;
114*2264Sjacobs 	papi_printer_t p = NULL;
115*2264Sjacobs 	char *keys[] = { "printer-is-accepting", NULL };
116*2264Sjacobs 
117*2264Sjacobs 	status = papiPrinterQuery(svc, printer, keys, NULL, &p);
118*2264Sjacobs 	if ((status == PAPI_OK) && (p != NULL)) {
119*2264Sjacobs 		papi_attribute_t **attrs = papiPrinterGetAttributeList(p);
120*2264Sjacobs 		char accepting = PAPI_FALSE;
121*2264Sjacobs 
122*2264Sjacobs 		papiAttributeListGetBoolean(attrs, NULL,
123*2264Sjacobs 				"printer-is-accepting", &accepting);
124*2264Sjacobs 
125*2264Sjacobs 		if (accepting == PAPI_TRUE)
126*2264Sjacobs 			berkeley_receive_files(svc, ifp, ofp);
127*2264Sjacobs 		else
128*2264Sjacobs 			NACK(ofp);
129*2264Sjacobs 
130*2264Sjacobs 		papiPrinterFree(p);
131*2264Sjacobs 	} else
132*2264Sjacobs 		NACK(ofp);
133*2264Sjacobs }
134*2264Sjacobs 
135*2264Sjacobs /*
136*2264Sjacobs  * This is the entry point for this program.  The program takes the
137*2264Sjacobs  * following options:
138*2264Sjacobs  * 	(none)
139*2264Sjacobs  */
140*2264Sjacobs int
141*2264Sjacobs main(int ac, char *av[])
142*2264Sjacobs {
143*2264Sjacobs 	papi_status_t status;
144*2264Sjacobs 	papi_service_t svc = NULL;
145*2264Sjacobs 	papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
146*2264Sjacobs 	FILE	*ifp = stdin,
147*2264Sjacobs 		*ofp = stdout;
148*2264Sjacobs 	int	c;
149*2264Sjacobs 	char	buf[BUFSIZ],
150*2264Sjacobs 		**args,
151*2264Sjacobs 		*printer;
152*2264Sjacobs 
153*2264Sjacobs 	openlog("bsd-gw", LOG_PID, LOG_LPR);
154*2264Sjacobs 
155*2264Sjacobs 	while ((c = getopt(ac, av, "d")) != EOF)
156*2264Sjacobs 		switch (c) {
157*2264Sjacobs 		case 'E':
158*2264Sjacobs 			encryption = PAPI_ENCRYPT_ALWAYS;
159*2264Sjacobs 			break;
160*2264Sjacobs 		case 'd':
161*2264Sjacobs 		default:
162*2264Sjacobs 			;
163*2264Sjacobs 		}
164*2264Sjacobs 
165*2264Sjacobs 	if (fgets(buf, sizeof (buf), ifp) == NULL) {
166*2264Sjacobs 		if (feof(ifp) == 0)
167*2264Sjacobs 			syslog(LOG_ERR, "Error reading from connection: %s",
168*2264Sjacobs 				strerror(errno));
169*2264Sjacobs 		exit(1);
170*2264Sjacobs 	}
171*2264Sjacobs 
172*2264Sjacobs 	if ((buf[0] < 1) || (buf[0] > 5)) {
173*2264Sjacobs 		fatal(ofp, "Invalid protocol request (%d): %c%s\n",
174*2264Sjacobs 			buf[0], buf[0], buf);
175*2264Sjacobs 		exit(1);
176*2264Sjacobs 	}
177*2264Sjacobs 
178*2264Sjacobs 	args = strsplit(&buf[1], "\t\n ");
179*2264Sjacobs 	printer = *args++;
180*2264Sjacobs 
181*2264Sjacobs 	if (printer == NULL) {
182*2264Sjacobs 		fatal(ofp, "Can't determine requested printer");
183*2264Sjacobs 		exit(1);
184*2264Sjacobs 	}
185*2264Sjacobs 
186*2264Sjacobs 	status = papiServiceCreate(&svc, printer, NULL, NULL, NULL,
187*2264Sjacobs 					encryption, NULL);
188*2264Sjacobs 	if (status != PAPI_OK) {
189*2264Sjacobs 		fatal(ofp, "Failed to contact service for %s: %s\n", printer,
190*2264Sjacobs 			verbose_papi_message(svc, status));
191*2264Sjacobs 		exit(1);
192*2264Sjacobs 	}
193*2264Sjacobs 
194*2264Sjacobs #ifdef HAVE_IS_SYSTEM_LABELED
195*2264Sjacobs 	if (is_system_labeled()) {
196*2264Sjacobs 		int fd = fileno(ifp);
197*2264Sjacobs 
198*2264Sjacobs 		(void) papiServiceSetPeer(svc, fd);
199*2264Sjacobs 	}
200*2264Sjacobs #endif
201*2264Sjacobs 
202*2264Sjacobs 	switch (buf[0]) {
203*2264Sjacobs 	case '\1':	/* restart printer */
204*2264Sjacobs 		ACK(ofp);	/* there is no equivalent */
205*2264Sjacobs 		break;
206*2264Sjacobs 	case '\2':	/* transfer job(s) */
207*2264Sjacobs 		berkeley_transfer_files(svc, ifp, ofp, printer);
208*2264Sjacobs 		break;
209*2264Sjacobs 	case '\3':	/* show queue (short) */
210*2264Sjacobs 	case '\4': {	/* show queue (long) */
211*2264Sjacobs 		int count;
212*2264Sjacobs 
213*2264Sjacobs 		for (count = 0; args[count] != 0; count++);
214*2264Sjacobs 
215*2264Sjacobs 		berkeley_queue_report(svc, ofp, printer, buf[0], count, args);
216*2264Sjacobs 		}
217*2264Sjacobs 		break;
218*2264Sjacobs 	case '\5': {	/* cancel job(s) */
219*2264Sjacobs 		char *requestor = *args++;
220*2264Sjacobs 		int count;
221*2264Sjacobs 
222*2264Sjacobs 		status = papiServiceSetUserName(svc, requestor);
223*2264Sjacobs 		for (count = 0; args[count] != 0; count++);
224*2264Sjacobs 
225*2264Sjacobs 		berkeley_cancel_request(svc, ofp, printer, count, args);
226*2264Sjacobs 		}
227*2264Sjacobs 		break;
228*2264Sjacobs 	default:
229*2264Sjacobs 		fatal(ofp, "unsupported protocol request (%c), %s",
230*2264Sjacobs 			buf[0], &buf[1]);
231*2264Sjacobs 	}
232*2264Sjacobs 
233*2264Sjacobs 	(void) fflush(ofp);
234*2264Sjacobs 
235*2264Sjacobs 	syslog(LOG_DEBUG, "protocol request(%d) for %s completed: %s",
236*2264Sjacobs 		buf[0], printer, papiStatusString(status));
237*2264Sjacobs 	syslog(LOG_DEBUG, "detail: %s", verbose_papi_message(svc, status));
238*2264Sjacobs 
239*2264Sjacobs 	papiServiceDestroy(svc);
240*2264Sjacobs 
241*2264Sjacobs 	return (0);
242*2264Sjacobs }
243