/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include "signal.h" #include "stdio.h" #include "errno.h" #include "lp.h" #include "msgs.h" #include "string.h" void startup(), cleanup(), done(); extern char *getenv(), *malloc(), *realloc(); extern long atol(); extern int atoi(); static void wakeup(); extern char *optarg; extern int optind, opterr, optopt; int optsw; #define PREFIX_STRING "%%[" #define SUFFIX_STRING "]%%" #define PRINTER_ERROR_STRING "PrinterError:" #define STATUS_STRING "status:" #define JOB_STRING "job:" #define STATUS_OK_STRING "ready and printing" #define PAPER_CHANGED_STRING "paper changed:" /* * Some common postscript printer fault messages. * These strings are here so that they get l10ned and then lpstat will * be able to display them in the users language. * This seemed like a good place for them, since lp.tell knows about * postscript msgs. */ char *ps_m1 = "unable to print: out of media (paper)"; char *ps_m2 = "out of media (paper)"; char *ps_m3 = "unable to print: tray not (properly) installed"; char *ps_m4 = "tray not (properly) installed"; char *ps_m5 = "unable to print: paper out for the selected tray"; char *ps_m6 = "paper out for the selected tray"; char *ps_m7 = "unable to print: cartridge life expiring"; char *ps_m8 = "cartridge life expiring"; char *ps_m9 = "unable to print: printer cover not locked"; char *ps_m10 = "printer cover not locked"; char *ps_m11 = "unable to print: media (paper) jam in exit path"; char *ps_m12 = "media (paper) jam in exit path"; char *ps_m13 = "unable to print: media (paper) jam in feed path"; char *ps_m14 = "media (paper) jam in feed path"; char *ps_m15 = "unable to print: drum assembly almost expended"; char *ps_m16 = "drum assembly almost expended"; char *ps_m17 = "unable to print: toner cartridge almost expended"; char *ps_m18 = "toner cartridge almost expended"; char *ps_m19 = "unable to print: drum assembly not (properly) installed"; char *ps_m20 = "drum assembly not (properly) installed"; char *ps_m21 = "unable to print: toner cartridge not (properly) installed"; char *ps_m22 = "toner cartridge not (properly) installed"; char *ps_m23 = "unable to print: drum assembly requires replacement"; char *ps_m24 = "drum assembly requires replacement"; char *ps_m25 = "unable to print: toner cartridge requires replacement"; char *ps_m26 = "toner cartridge requires replacement"; char *ps_m27 = "unable to print: fuser warming up"; char *ps_m28 = "fuser warming up"; char *ps_m29 = "unable to print: printer not responding"; char *ps_m30 = "printer not responding"; char *ps_m31 = "unable to print: fuser pausing"; char *ps_m32 = "fuser pausing"; char *ps_m33 = "unable to print: printer turned off"; char *ps_m34 = "printer turned off"; char *ps_m35 = "unable to print: printer warming up"; char *ps_m36 = "printer warming up"; char *ps_m37 = "unable to print: interlock open"; char *ps_m38 = "interlock open"; char *ps_m39 = "unable to print: selected tray out"; char *ps_m40 = "selected tray out"; char *ps_m41 = "unable to print: paper out for the manual tray"; char *ps_m42 = "paper out for the manual tray"; char *ps_m43 = "unable to print: paper exit jam"; char *ps_m44 = "paper exit jam"; char *ps_m45 = "unable to print: paper misfeed jam"; char *ps_m46 = "paper misfeed jam"; char *ps_m47 = "unable to print: paper jam between registration & heat rollers"; char *ps_m48 = "paper jam between registration & heat rollers"; char *ps_m49 = "unable to print: paper jam at registration roller"; char *ps_m50 = "paper jam at registration roller"; char *ps_m51 = "unable to print: no cartridge"; char *ps_m52 = "no cartridge"; char *ps_m53 = "unable to print: cartridge out"; char *ps_m54 = "cartridge out"; /** ** main() **/ int main(int argc, char *argv[]) { char *alert_text, buf[BUFSIZ], msgbuf[MSGMAX], *bufPtr, *printer, *s_key; char *printerErrorString = NULL; char *statusString = NULL; char *paperChangedString = NULL; char *suffixString = NULL; char *jobString = NULL; char *prefixString = NULL; char *statusOkString = NULL; int mtype, doStdOut, doDebug, first, oldalarm; short status; long key,clearKey; char *ptr1,*ptr2,*ptr3,*ptr4,*ptr5; int trayNum = 0; int mode = 0; int pagesPrinted = 0; char *paperType = NULL; short mesgRetType; int useLaserWriterMessages; int pLen,sLen,peLen,jLen,pcLen ; void (*oldsignal)(); /* * Run immune from typical interruptions, so that * we stand a chance to get the fault message. * EOF (or startup error) is the only way out. */ signal (SIGHUP, SIG_IGN); signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); signal (SIGTERM, SIG_IGN); /* * Do we have a key? */ if ( argc < 2 || !(s_key = getenv("SPOOLER_KEY")) || !*s_key || (key = atol(s_key)) <= 0 ) { printf( "Usage: lptell [-lodk] [-X String] printer\n"); printf("Options (where X is P,S,e,s, O or c )\n"); printf(" environment variable SPOOLER_KEY: must be defined and > 0\n"); printf(" printer: name of printer to give status for.\n"); printf(" -l: expect laser writer type messages (NeWSprint does)\n"); printf(" -o: send input to stdout\n"); printf(" -d: send additional debugging output to stdout\n"); printf(" -P String: string for prefix, default: '%%%%['\n"); printf(" -S String: string for suffix, default: ']%%%%'\n"); printf(" -e String: string to detect printer error,\n"); printf(" default: 'PrinterError:', send S_SEND_FAULT to lpsched\n"); printf( " -c String: string to detect paper change in context of printer error,\n"); printf(" default: 'paper changed:', send S_PAPER_CHANGED to lpsched\n"); printf(" -s String: string to detect printer ok status, \n"); printf(" default: 'status:', send S_CLEAR_FAULT to lpsched\n"); printf(" -k: do not use the key for making status ok\n"); printf(" -O String: string sent as status message to lpsched,\n"); printf(" default: 'ready and printing:'\n"); exit (90); } doStdOut = 0; doDebug = 0; useLaserWriterMessages = 0; clearKey = key; prefixString = PREFIX_STRING; pLen = strlen(prefixString); suffixString = SUFFIX_STRING; printerErrorString = PRINTER_ERROR_STRING; peLen = strlen(printerErrorString); statusString = STATUS_STRING; sLen = strlen(statusString); jobString = JOB_STRING; jLen = strlen(jobString); paperChangedString = PAPER_CHANGED_STRING; pcLen = strlen(paperChangedString); statusOkString = STATUS_OK_STRING; while ((optsw = getopt(argc, argv, "le:s:c:okdO:S:P:")) != EOF) { switch ( optsw ) { case 'l': useLaserWriterMessages = 1; break; case 'P': prefixString = (optarg ? strdup(optarg) : NULL); pLen = strlen(prefixString ); break; case 'S': suffixString = (optarg ? strdup(optarg) : NULL); break; case 'e': printerErrorString = (optarg ? strdup(optarg) : NULL); peLen = strlen(printerErrorString); break; case 's': statusString = (optarg ? strdup(optarg) : NULL); sLen = strlen(statusString); break; case 'O': statusOkString = (optarg ? strdup(optarg) : NULL); break; case 'c': paperChangedString = (optarg ? strdup(optarg) : NULL); pcLen = strlen(paperChangedString ); break; case 'k': clearKey = -1; break; case 'o': doStdOut = 1; break; case 'd': doDebug = 1; break; } } /* * Which printer is this? Do we have a key? */ if ( !(printer = argv[optind]) || !*printer ) { exit (90); } if (doDebug) { printf( "start lp.tell for %s key %d mode %s %s\n", printer,key,(useLaserWriterMessages ? "LW" : "standard"), (doStdOut ? "doStdOut" : "no output")); printf( "prefix (%s) suffix (%s) printerError (%s)\n", prefixString,suffixString,printerErrorString); printf( "paper_changed (%s) status (%s) key %d \n", paperChangedString,statusString , clearKey); fflush(stdout); } /* * Wait for a message on the standard input. When a single line * comes in, take a couple of more seconds to get any other lines * that may be ready, then send them to the Spooler. */ while (fgets(buf, BUFSIZ, stdin)) { if (useLaserWriterMessages) { /* NeWSprint style processing (which simulates the LaserWriter *There are four types of messages: * 1) fault messages: printer error message from handler * 2) clear fault messages: printer ok messages from handler * 3) paper changed messages: printer handler detected paper change * 4) server messages: xnews problems */ bufPtr = buf; if (strncmp(prefixString, bufPtr, pLen) == 0) { bufPtr += pLen; while (*bufPtr == ' ') bufPtr++; if (strncmp(printerErrorString, bufPtr, peLen) == 0) { bufPtr += peLen; while (*bufPtr == ' ') bufPtr++; if ((strncmp(bufPtr,paperChangedString,pcLen) == 0) && (ptr1 = bufPtr +pcLen) && (ptr2 = strchr(ptr1+1,':')) && (ptr3 = strchr(ptr2+1,':')) && (ptr4 = strchr(ptr3+1,':')) && (ptr5 = strchr(ptr4+1,'\n'))) { if (doStdOut) printf("%s",buf); *ptr2 =0; *ptr3= 0; *ptr4= 0; *ptr5= 0; trayNum = atoi(ptr1+1); paperType = ptr2+1; mode = atoi(ptr3+1); pagesPrinted = atoi(ptr4+1); if (doDebug) { printf("Paper changed: %s tray %d paper %s md %d pages %d\n", printer,trayNum,paperType,mode,pagesPrinted); } startup (); mesgRetType = R_PAPER_CHANGED; (void)putmessage ( msgbuf, S_PAPER_CHANGED, printer, trayNum, paperType, mode, pagesPrinted); } else { if (doStdOut) printf("%s",buf); if (ptr1 = strstr(bufPtr,suffixString)) *ptr1 = 0; if ( doDebug ) { printf("Send fault: %s key %d (%s)\n",printer,key,bufPtr); } mesgRetType = R_SEND_FAULT; startup (); (void)putmessage (msgbuf,S_SEND_FAULT,printer,key,bufPtr); } } else if ((first = (strncmp(statusString,bufPtr,sLen) == 0)) || (strncmp(jobString,bufPtr,jLen) == 0)) { bufPtr += (first ? sLen : jLen); if (doStdOut) printf("%s",buf); if (ptr1 = strstr(bufPtr,suffixString)) *ptr1 = 0; if ( doDebug ) { printf("Clear fault: %s key %d (%s)\n",printer, clearKey, bufPtr); } mesgRetType = R_CLEAR_FAULT; startup (); (void)putmessage( msgbuf,S_CLEAR_FAULT,printer,clearKey, statusOkString); } else { if (doStdOut) printf("%s",buf); if (ptr1 = strstr(bufPtr,suffixString)) *ptr1 = 0; if ( doDebug ) { printf("Server error: %s key %d (%s)\n",printer,key, buf); } mesgRetType = 0; } } else { if (doStdOut) printf("%s",buf); if (ptr1 = strstr(bufPtr,suffixString)) *ptr1 = 0; if (doDebug) { printf("Server error: %s key %d (%s)\n", printer, key, buf); } mesgRetType = 0; } } else { /* not generic PostScript style messages */ oldsignal = signal(SIGALRM, wakeup); oldalarm = alarm(2); alert_text = 0; do { if (alert_text) alert_text = realloc(alert_text, strlen(alert_text)+strlen(buf)+1 ); else { alert_text = malloc(strlen(buf) + 1); alert_text[0] = 0; } strcat (alert_text, buf); } while (fgets(buf, BUFSIZ, stdin)); alarm (oldalarm); signal (SIGALRM, oldsignal); if (doStdOut) { if ( doDebug ) { printf("Send generic fault: %s key %d (%s)\n",printer,key, alert_text); } else { printf("%s\n",alert_text); } } if (strcmp(alert_text, "printer ok\n") == 0) { mesgRetType = R_CLEAR_FAULT; startup (); (void)putmessage(msgbuf, S_CLEAR_FAULT, printer, clearKey, statusOkString); } else { mesgRetType = R_SEND_FAULT; startup (); (void)putmessage(msgbuf, S_SEND_FAULT, printer, key, alert_text); } } if (mesgRetType) { if (msend(msgbuf) == -1) done (91); if (mrecv(msgbuf, sizeof(msgbuf)) == -1) done (92); mtype = getmessage(msgbuf, mesgRetType, &status); /* * check for R_CLEAR_FAULT here and 3 lines below * because older lpsched doesn't pass S_CLEAR_FAULT */ if ((mtype != mesgRetType) && (mesgRetType != R_CLEAR_FAULT)) done (93); if ((status != MOK) && (mesgRetType != R_CLEAR_FAULT)) done (94); } } done (0); return (0); } /** ** startup() - OPEN MESSAGE QUEUE TO SPOOLER ** cleanup() - CLOSE THE MESSAGE QUEUE TO THE SPOOLER **/ static int have_contacted_spooler = 0; void startup () { void catch(); /* * Open a message queue to the Spooler. * An error is deadly. */ if (!have_contacted_spooler) { if (mopen() == -1) { switch (errno) { case ENOMEM: case ENOSPC: break; default: break; } exit (1); } have_contacted_spooler = 1; } return; } void cleanup () { if (have_contacted_spooler) mclose (); return; } /** ** wakeup() - TRAP ALARM **/ static void wakeup () { return; } /** ** done() - CLEANUP AND EXIT **/ void done (ec) int ec; { cleanup (); exit (ec); }