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