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