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 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 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 474 void cleanup () 475 { 476 if (have_contacted_spooler) 477 mclose (); 478 return; 479 } 480 481 /** 482 ** wakeup() - TRAP ALARM 483 **/ 484 485 static void wakeup () 486 { 487 return; 488 } 489 490 /** 491 ** done() - CLEANUP AND EXIT 492 **/ 493 494 void done (ec) 495 int ec; 496 { 497 cleanup (); 498 exit (ec); 499 } 500