xref: /titanic_51/usr/src/cmd/lp/model/lp.tell.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.6	*/
32 
33 #include "signal.h"
34 #include "stdio.h"
35 #include "errno.h"
36 
37 #include "lp.h"
38 #include "msgs.h"
39 #include "string.h"
40 
41 void			startup(),
42 			cleanup(),
43 			done();
44 
45 extern char		*getenv(),
46 			*malloc(),
47 			*realloc();
48 
49 extern long		atol();
50 
51 extern int		atoi();
52 
53 static void		wakeup();
54 extern char    *optarg;
55 extern int     optind, opterr, optopt;
56 int optsw;
57 
58 #define PREFIX_STRING "%%["
59 #define SUFFIX_STRING "]%%"
60 #define PRINTER_ERROR_STRING "PrinterError:"
61 #define STATUS_STRING "status:"
62 #define JOB_STRING "job:"
63 #define STATUS_OK_STRING "ready and printing"
64 #define PAPER_CHANGED_STRING "paper changed:"
65 
66 /*
67  * Some common postscript printer fault messages.
68  * These strings are here so that they get l10ned and then lpstat will
69  * be able to display them in the users language.
70  * This seemed like a good place for them, since lp.tell knows about
71  * postscript msgs.
72  */
73 
74 char *ps_m1 = "unable to print: out of media (paper)";
75 char *ps_m2 = "out of media (paper)";
76 char *ps_m3 = "unable to print: tray not (properly) installed";
77 char *ps_m4 = "tray not (properly) installed";
78 char *ps_m5 = "unable to print: paper out for the selected tray";
79 char *ps_m6 = "paper out for the selected tray";
80 char *ps_m7 = "unable to print: cartridge life expiring";
81 char *ps_m8 = "cartridge life expiring";
82 char *ps_m9 = "unable to print: printer cover not locked";
83 char *ps_m10 = "printer cover not locked";
84 char *ps_m11 = "unable to print: media (paper) jam in exit path";
85 char *ps_m12 = "media (paper) jam in exit path";
86 char *ps_m13 = "unable to print: media (paper) jam in feed path";
87 char *ps_m14 = "media (paper) jam in feed path";
88 char *ps_m15 = "unable to print: drum assembly almost expended";
89 char *ps_m16 = "drum assembly almost expended";
90 char *ps_m17 = "unable to print: toner cartridge almost expended";
91 char *ps_m18 = "toner cartridge almost expended";
92 char *ps_m19 = "unable to print: drum assembly not (properly) installed";
93 char *ps_m20 = "drum assembly not (properly) installed";
94 char *ps_m21 = "unable to print: toner cartridge not (properly) installed";
95 char *ps_m22 = "toner cartridge not (properly) installed";
96 char *ps_m23 = "unable to print: drum assembly requires replacement";
97 char *ps_m24 = "drum assembly requires replacement";
98 char *ps_m25 = "unable to print: toner cartridge requires replacement";
99 char *ps_m26 = "toner cartridge requires replacement";
100 char *ps_m27 = "unable to print: fuser warming up";
101 char *ps_m28 = "fuser warming up";
102 char *ps_m29 = "unable to print: printer not responding";
103 char *ps_m30 = "printer not responding";
104 char *ps_m31 = "unable to print: fuser pausing";
105 char *ps_m32 = "fuser pausing";
106 char *ps_m33 = "unable to print: printer turned off";
107 char *ps_m34 = "printer turned off";
108 char *ps_m35 = "unable to print: printer warming up";
109 char *ps_m36 = "printer warming up";
110 char *ps_m37 = "unable to print: interlock open";
111 char *ps_m38 = "interlock open";
112 char *ps_m39 = "unable to print: selected tray out";
113 char *ps_m40 = "selected tray out";
114 char *ps_m41 = "unable to print: paper out for the manual tray";
115 char *ps_m42 = "paper out for the manual tray";
116 char *ps_m43 = "unable to print: paper exit jam";
117 char *ps_m44 = "paper exit jam";
118 char *ps_m45 = "unable to print: paper misfeed jam";
119 char *ps_m46 = "paper misfeed jam";
120 char *ps_m47 = "unable to print: paper jam between registration & heat rollers";
121 char *ps_m48 = "paper jam between registration & heat rollers";
122 char *ps_m49 = "unable to print: paper jam at registration roller";
123 char *ps_m50 = "paper jam at registration roller";
124 char *ps_m51 = "unable to print: no cartridge";
125 char *ps_m52 = "no cartridge";
126 char *ps_m53 = "unable to print: cartridge out";
127 char *ps_m54 = "cartridge out";
128 
129 /**
130  ** main()
131  **/
132 
133 int			main (argc, argv)
134 	int			argc;
135 	char			*argv[];
136 {
137 	char			*alert_text,
138 				buf[BUFSIZ],
139 				msgbuf[MSGMAX],
140 				*bufPtr,
141 				*printer,
142 				*s_key;
143 
144 	char *printerErrorString = NULL;
145 	char *statusString = NULL;
146 	char *paperChangedString = NULL;
147 	char *suffixString = NULL;
148 	char *jobString = NULL;
149 	char *prefixString = NULL;
150 	char *statusOkString = NULL;
151 	int			mtype,
152                doStdOut,
153 					doDebug,
154 					first,
155 				oldalarm;
156 
157 
158 	short			status;
159 
160 	long			key,clearKey;
161 	char *ptr1,*ptr2,*ptr3,*ptr4,*ptr5;
162 	int trayNum = 0;
163 	int mode = 0;
164 	int pagesPrinted = 0;
165 	char *paperType = NULL;
166 	short mesgRetType;
167 	int useLaserWriterMessages;
168 	int pLen,sLen,peLen,jLen,pcLen ;
169 
170 	void			(*oldsignal)();
171 
172 
173 	/*
174 	 * Run immune from typical interruptions, so that
175 	 * we stand a chance to get the fault message.
176 	 * EOF (or startup error) is the only way out.
177 	 */
178 	signal (SIGHUP, SIG_IGN);
179 	signal (SIGINT, SIG_IGN);
180 	signal (SIGQUIT, SIG_IGN);
181 	signal (SIGTERM, SIG_IGN);
182 
183 	/*
184 	 *  Do we have a key?
185 	 */
186 	if (
187 		argc < 2
188 	     || !(s_key = getenv("SPOOLER_KEY"))
189 	     || !*s_key
190 	     || (key = atol(s_key)) <= 0
191 	) {
192 		printf( "Usage: lptell [-lodk] [-X String]  printer\n");
193 		printf("Options (where X is P,S,e,s, O or c )\n");
194 		printf("   environment variable SPOOLER_KEY: must be defined and > 0\n");
195 		printf("   printer: name of printer to give status for.\n");
196 		printf("   -l: expect laser writer type messages (NeWSprint does)\n");
197 		printf("   -o: send input to stdout\n");
198 		printf("   -d: send additional debugging output to stdout\n");
199 		printf("   -P String: string for prefix, default: '%%%%['\n");
200 		printf("   -S String: string for suffix, default: ']%%%%'\n");
201 		printf("   -e String: string to detect printer error,\n");
202 		printf("       default: 'PrinterError:', send S_SEND_FAULT to lpsched\n");
203 		printf(
204 		"   -c String: string to detect paper change in context of printer error,\n");
205 		printf("       default: 'paper changed:', send S_PAPER_CHANGED to lpsched\n");
206 		printf("   -s String: string to detect printer ok status, \n");
207 		printf("       default: 'status:', send S_CLEAR_FAULT to lpsched\n");
208 		printf("       -k: do not use the key for making status ok\n");
209 		printf("   -O String: string sent as status message to lpsched,\n");
210 		printf("                  default: 'ready and printing:'\n");
211 		exit (90);
212 		  }
213 
214 
215 	doStdOut = 0;
216 	doDebug = 0;
217 	useLaserWriterMessages = 0;
218 	clearKey = key;
219 
220 	prefixString = PREFIX_STRING; pLen = strlen(prefixString);
221 	suffixString = SUFFIX_STRING;
222 	printerErrorString = PRINTER_ERROR_STRING;
223 	  peLen = strlen(printerErrorString);
224 	statusString = STATUS_STRING; sLen = strlen(statusString);
225 	jobString = JOB_STRING; jLen = strlen(jobString);
226 	paperChangedString = PAPER_CHANGED_STRING;
227 	  pcLen = strlen(paperChangedString);
228 	statusOkString = STATUS_OK_STRING;
229 
230    while ((optsw = getopt(argc, argv, "le:s:c:okdO:S:P:")) != EOF) {
231 		switch ( optsw ) {
232 			case 'l':
233 				useLaserWriterMessages = 1;
234 				break;
235 			case 'P':
236 				prefixString = (optarg  ? strdup(optarg) : NULL);
237 				pLen = strlen(prefixString );
238 				break;
239 			case 'S':
240 				suffixString = (optarg  ? strdup(optarg) : NULL);
241 				break;
242 			case 'e':
243 				printerErrorString = (optarg  ? strdup(optarg) : NULL);
244 				peLen = strlen(printerErrorString);
245 				break;
246 			case 's':
247 				statusString = (optarg  ? strdup(optarg) : NULL);
248 				sLen = strlen(statusString);
249 				break;
250 			case 'O':
251 				statusOkString = (optarg  ? strdup(optarg) : NULL);
252 				break;
253 			case 'c':
254 				paperChangedString = (optarg  ? strdup(optarg) : NULL);
255 				pcLen = strlen(paperChangedString );
256 				break;
257 			case 'k':
258 				clearKey = -1;
259 				break;
260 			case 'o':
261 				doStdOut = 1;
262 				break;
263 			case 'd':
264 				doDebug = 1;
265 				break;
266 			}
267 		}
268 	/*
269 	 * Which printer is this? Do we have a key?
270 	 */
271 	if (
272 	     !(printer = argv[optind])
273 	     || !*printer
274 	) {
275 		exit (90);
276 		  }
277 	if (doDebug) {
278 		printf( "start lp.tell for %s key %d mode %s %s\n",
279 				printer,key,(useLaserWriterMessages ? "LW" : "standard"),
280 				(doStdOut ? "doStdOut" : "no output"));
281 		printf( "prefix (%s) suffix (%s) printerError (%s)\n",
282 			  prefixString,suffixString,printerErrorString);
283 		printf( "paper_changed (%s) status (%s) key %d \n",
284 			paperChangedString,statusString , clearKey);
285 		fflush(stdout);
286 	   }
287 	/*
288 	 * Wait for a message on the standard input. When a single line
289 	 * comes in, take a couple of more seconds to get any other lines
290 	 * that may be ready, then send them to the Spooler.
291 	 */
292 	while (fgets(buf, BUFSIZ, stdin)) {
293 		if (useLaserWriterMessages) {
294 			/* NeWSprint style processing (which simulates the LaserWriter
295 			 *There are four types of messages:
296 			 * 	1) fault messages: printer error message from handler
297 			 * 	2) clear fault messages: printer ok messages from handler
298 			 * 	3) paper changed messages: printer handler detected paper change
299 			 * 	4) server messages: xnews problems
300 			 */
301 			bufPtr = buf;
302 			if (strncmp(prefixString, bufPtr, pLen) == 0) {
303 				bufPtr += pLen;
304 				while (*bufPtr == ' ')
305 					bufPtr++;
306 
307 				if (strncmp(printerErrorString, bufPtr,
308 						peLen) == 0) {
309 					bufPtr += peLen;
310 					while (*bufPtr == ' ')
311 						bufPtr++;
312 
313 					if ((strncmp(bufPtr,paperChangedString,pcLen) == 0) &&
314 							 (ptr1 = bufPtr +pcLen) &&
315 							 (ptr2 = strchr(ptr1+1,':')) &&
316 							 (ptr3 = strchr(ptr2+1,':')) &&
317 							 (ptr4 = strchr(ptr3+1,':')) &&
318 							 (ptr5 = strchr(ptr4+1,'\n'))) {
319 						if (doStdOut) printf("%s",buf);
320 						*ptr2 =0;
321 						*ptr3= 0;
322 						*ptr4= 0;
323 						*ptr5= 0;
324 						trayNum = atoi(ptr1+1);
325 						paperType = ptr2+1;
326 						mode = atoi(ptr3+1);
327 						pagesPrinted = atoi(ptr4+1);
328 						if (doDebug) {
329 							 printf("Paper changed: %s tray %d paper %s md %d pages %d\n",
330 								printer,trayNum,paperType,mode,pagesPrinted);
331 							}
332 						startup ();
333 						mesgRetType = R_PAPER_CHANGED;
334 						(void)putmessage ( msgbuf, S_PAPER_CHANGED, printer, trayNum,
335 							paperType, mode, pagesPrinted);
336 					} else {
337 						if (doStdOut)  printf("%s",buf);
338 						if (ptr1 = strstr(bufPtr,suffixString))  *ptr1 = 0;
339 						if ( doDebug ) {
340 							printf("Send fault: %s key %d (%s)\n",printer,key,bufPtr);
341 						}
342 						mesgRetType = R_SEND_FAULT;
343 						startup ();
344 						(void)putmessage (msgbuf,S_SEND_FAULT,printer,key,bufPtr);
345 					}
346 				} else if ((first = (strncmp(statusString,bufPtr,sLen) == 0)) ||
347 							 (strncmp(jobString,bufPtr,jLen) == 0)) {
348 					bufPtr += (first ? sLen : jLen);
349 					if (doStdOut)  printf("%s",buf);
350 					if (ptr1 = strstr(bufPtr,suffixString))  *ptr1 = 0;
351 					if ( doDebug ) {
352 						printf("Clear fault: %s key %d (%s)\n",printer, clearKey,
353 							  bufPtr);
354 						}
355 					mesgRetType = R_CLEAR_FAULT;
356 					startup ();
357 					(void)putmessage( msgbuf,S_CLEAR_FAULT,printer,clearKey,
358 						statusOkString);
359 				} else {
360 					if (doStdOut)  printf("%s",buf);
361 					if (ptr1 = strstr(bufPtr,suffixString))  *ptr1 = 0;
362 					if ( doDebug ) {
363 						printf("Server error: %s key %d (%s)\n",printer,key,
364 							 buf);
365 					}
366 					mesgRetType = 0;
367 				}
368 			} else {
369 				if (doStdOut) printf("%s",buf);
370 				if (ptr1 = strstr(bufPtr,suffixString))
371 					*ptr1 = 0;
372 				if (doDebug) {
373 					printf("Server error: %s key %d (%s)\n",
374 						printer, key, buf);
375 				}
376 				mesgRetType = 0;
377 			}
378 		} else {	/* not generic PostScript style messages */
379 			oldsignal = signal(SIGALRM, wakeup);
380 			oldalarm = alarm(2);
381 
382 			alert_text = 0;
383 			do {
384 				if (alert_text)
385 					alert_text = realloc(alert_text,
386 						strlen(alert_text)+strlen(buf)+1
387 					);
388 				else {
389 					alert_text = malloc(strlen(buf) + 1);
390 					alert_text[0] = 0;
391 				}
392 				strcat (alert_text, buf);
393 
394 			} while (fgets(buf, BUFSIZ, stdin));
395 
396 			alarm (oldalarm);
397 			signal (SIGALRM, oldsignal);
398 
399 			if (doStdOut) {
400 				if ( doDebug ) {
401 					printf("Send generic fault: %s key %d (%s)\n",printer,key,
402 						alert_text);
403 					}
404 				else {
405 					printf("%s\n",alert_text);
406 					}
407 				}
408 			if (strcmp(alert_text, "printer ok\n") == 0) {
409 				mesgRetType = R_CLEAR_FAULT;
410 				startup ();
411 				(void)putmessage(msgbuf, S_CLEAR_FAULT, printer,
412 						clearKey, statusOkString);
413 			} else {
414          			mesgRetType = R_SEND_FAULT;
415 				startup ();
416 				(void)putmessage(msgbuf, S_SEND_FAULT, printer,
417 						key, alert_text);
418 			}
419 		}
420 
421 		if (mesgRetType) {
422 			if (msend(msgbuf) == -1)
423 				done (91);
424 			if (mrecv(msgbuf, sizeof(msgbuf)) == -1)
425 				done (92);
426 			mtype = getmessage(msgbuf, mesgRetType, &status);
427 			/*
428 			 * check for R_CLEAR_FAULT here and 3 lines below
429 			 * because older lpsched doesn't pass S_CLEAR_FAULT
430 			 */
431 			if ((mtype != mesgRetType) &&
432 			    (mesgRetType != R_CLEAR_FAULT))
433 				done (93);
434 
435 			if ((status != MOK) && (mesgRetType != R_CLEAR_FAULT))
436 				done (94);
437 		}
438 
439 	}
440 	done (0);
441 }
442 
443 /**
444  ** startup() - OPEN MESSAGE QUEUE TO SPOOLER
445  ** cleanup() - CLOSE THE MESSAGE QUEUE TO THE SPOOLER
446  **/
447 
448 static int		have_contacted_spooler	= 0;
449 
450 void			startup ()
451 {
452 	void			catch();
453 
454 	/*
455 	 * Open a message queue to the Spooler.
456 	 * An error is deadly.
457 	 */
458 	if (!have_contacted_spooler) {
459 		if (mopen() == -1) {
460 
461 			switch (errno) {
462 			case ENOMEM:
463 			case ENOSPC:
464 				break;
465 			default:
466 				break;
467 			}
468 
469 			exit (1);
470 		}
471 		have_contacted_spooler = 1;
472 	}
473 	return;
474 }
475 
476 void			cleanup ()
477 {
478 	if (have_contacted_spooler)
479 		mclose ();
480 	return;
481 }
482 
483 /**
484  ** wakeup() - TRAP ALARM
485  **/
486 
487 static void		wakeup ()
488 {
489 	return;
490 }
491 
492 /**
493  ** done() - CLEANUP AND EXIT
494  **/
495 
496 void			done (ec)
497 	int			ec;
498 {
499 	cleanup ();
500 	exit (ec);
501 }
502