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