/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "lpsched.h" #include static int max_requests_needing_form_mounted ( FSTATUS * ); static int max_requests_needing_pwheel_mounted ( char * ); /** ** queue_form() - ADD A REQUEST TO A FORM QUEUE **/ void queue_form(RSTATUS *prs, FSTATUS *pfs) { if ((prs->form = pfs) != NULL) { prs->form->requests++; if (prs->printer) check_form_alert (prs->form, (_FORM *)0); } return; } /** ** unqueue_form() - REMOVE A REQUEST FROM A FORM QUEUE **/ void unqueue_form(RSTATUS *prs) { FSTATUS * pfs = prs->form; prs->form = 0; if (pfs) { pfs->requests--; if (prs->printer) check_form_alert (pfs, (_FORM *)0); } return; } /** ** queue_pwheel() - ADD A REQUEST TO A PRINT WHEEL QUEUE **/ void queue_pwheel(RSTATUS *prs, char *name) { if (name) { prs->pwheel_name = Strdup(name); /* * Don't bother queueing the request for * a print wheel if this request is destined for * only this printer and the printer doesn't take * print wheels. */ if ( !one_printer_with_charsets(prs) && (prs->pwheel = search_pwstatus(name)) ) { prs->pwheel->requests++; check_pwheel_alert (prs->pwheel, (PWHEEL *)0); } } return; } /** ** unqueue_pwheel() - REMOVE A REQUEST FROM A PRINT WHEEL QUEUE **/ void unqueue_pwheel(RSTATUS *prs) { PWSTATUS * ppws = prs->pwheel; prs->pwheel = 0; unload_str (&(prs->pwheel_name)); if (ppws) { ppws->requests--; check_pwheel_alert (ppws, (PWHEEL *)0); } return; } /** ** check_form_alert() - CHECK CHANGES TO MOUNT FORM ALERT **/ void check_form_alert(FSTATUS *pfs, _FORM *pf) { short trigger, fire_off_alert = 0; int requests_waiting; /* * Call this routine whenever a requests has been queued * or dequeued for a form, and whenever the form changes. * If a pointer to a new _FORM is passed, the FSTATUS * structure is updated with the changes. Use a second * argument of 0 if no change. * * WARNING: It is valid to call this routine when adding * a NEW form (not just changing it). Thus the members of * the structure "pfs->form" may not be set. * In this case, though, "pf" MUST be set, and there can * be NO alert active. */ syslog(LOG_DEBUG, "check_form_alert:\n"); if (pfs) syslog(LOG_DEBUG, "check_form_alert: pfs->name <%s>\n", (pfs->form->name != NULL) ? pfs->form->name : "null"); if (pf) syslog(LOG_DEBUG, "check_form_alert: pf->name <%s>\n", (pf->name != NULL) ? pf->name : "null"); if (pf) { if ((trigger = pf->alert.Q) <= 0) trigger = 1; } else trigger = pfs->trigger; if (Starting) goto Return; #define OALERT pfs->form->alert #define NALERT pf->alert requests_waiting = max_requests_needing_form_mounted(pfs); /* * Cancel an active alert if the number of requests queued * has dropped below the threshold (or the threshold has been * raised), or if the alert command or period has changed. * In the latter case we'll reactive the alert later. */ if (pfs->alert->active) if (!requests_waiting || requests_waiting < trigger) cancel_alert (A_FORM, pfs); else if ( pf && ( !SAME(NALERT.shcmd, OALERT.shcmd) || NALERT.W != OALERT.W || NALERT.Q != OALERT.Q ) ) cancel_alert (A_FORM, pfs); /* * If we still have the condition for an alert, we'll fire * one off. It is possible the alert is still running, but * that's okay. First, we may want to change the alert message; * second, the "alert()" routine doesn't execute an alert * if it is already running. */ if (trigger > 0 && requests_waiting >= trigger) if ((pf && NALERT.shcmd) || OALERT.shcmd) fire_off_alert = 1; #undef OALERT #undef NALERT Return: if (pf) { pfs->form = pf; pfs->trigger = trigger; } /* * Have to do this after updating the changes. */ if (fire_off_alert) alert (A_FORM, pfs); return; } /** ** check_pwheel_alert() - CHECK CHANGES TO MOUNT PRINTWHEEL ALERT **/ void check_pwheel_alert(PWSTATUS *ppws, PWHEEL *ppw) { short trigger, fire_off_alert = 0; int requests_waiting; /* * Call this routine whenever a request has been queued * or dequeued for a print-wheel, and whenever the print-wheel * changes. If a pointer to a new PWHEEL is passed, the * PWSTATUS structure is updated with the changes. Use a * second argument of 0 if no change. * * WARNING: It is valid to call this routine when adding * a NEW print wheel (not just changing it). Thus the members * of the structure "ppws->pwheel" may not be set. * In this case, though, "ppw" MUST be set, and there can * be NO alert active. */ if (ppw) { if ((trigger = ppw->alert.Q) <= 0) trigger = 1; } else trigger = ppws->trigger; if (Starting) goto Return; #define OALERT ppws->pwheel->alert #define NALERT ppw->alert requests_waiting = max_requests_needing_pwheel_mounted(ppws->pwheel->name); /* * Cancel an active alert if the number of requests queued * has dropped below the threshold (or the threshold has been * raised), or if the alert command or period has changed. * In the latter case we'll reactive the alert later. */ if (ppws->alert->active) if (!requests_waiting || requests_waiting < trigger) cancel_alert (A_PWHEEL, ppws); else if ( ppw && ( !SAME(NALERT.shcmd, OALERT.shcmd) || NALERT.W != OALERT.W || NALERT.Q != OALERT.Q ) ) cancel_alert (A_PWHEEL, ppws); /* * If we still have the condition for an alert, we'll fire * one off. It is possible the alert is still running, but * that's okay. First, we may want to change the alert message; * second, the "alert()" routine doesn't execute an alert * if it is already running. */ if (trigger > 0 && requests_waiting >= trigger) if ((ppw && NALERT.shcmd) || OALERT.shcmd) fire_off_alert = 1; #undef OALERT #undef NALERT Return: if (ppw) { ppws->pwheel = ppw; ppws->trigger = trigger; } /* * Have to do this after updating the changes. */ if (fire_off_alert) alert (A_PWHEEL, ppws); return; } static int trayWithForm(PSTATUS *pps, FSTATUS *pfs, int startingTray, int checkAvail) { int i; PFSTATUS *ppfs; ppfs = pps->forms; if (startingTray < 0) startingTray = 0; if (ppfs) { for (i = startingTray; i < pps->numForms; i++) if ((!checkAvail || ppfs[i].isAvailable) && (ppfs[i].form == pfs)) return(i); } else if (!pfs) /* no form request matches no form mounted */ return(0); return(-1); } char * allTraysWithForm(PSTATUS *pps, FSTATUS *pfs) { int tray = 0; char *ptr, *p; char trayList[MAX_INPUT]; int n; ptr = trayList; if (pfs && pfs->form && pfs->form->paper) p = pfs->form->paper; else p = ""; n = sizeof (trayList); snprintf(ptr, n, "LP_TRAY_ARG=%s:", p); ptr += strlen(ptr); n -= strlen(ptr); while ((tray = trayWithForm(pps, pfs, tray, 1)) > 0) { tray++; snprintf(ptr, n, "%d,", tray); ptr += strlen(ptr); n -= strlen(ptr); } if (*(ptr-1) == ',') *(ptr-1) = 0; putenv(trayList); return(NULL); } int isFormUsableOnPrinter(PSTATUS *pps, FSTATUS *pfs) { return (trayWithForm(pps,pfs,0,1) >= 0 ); } int isFormMountedOnPrinter(PSTATUS *pps, FSTATUS *pfs) { return (trayWithForm(pps,pfs,0,0) >= 0 ); } /** ** max_requests_needing_form_mounted() ** max_requests_needing_pwheel_mounted() **/ static int max_requests_needing_form_mounted(FSTATUS *pfs) { PSTATUS * pps; RSTATUS * prs; int max = 0; int i; /* * For each printer that doesn't have this form mounted, * count the number of requests needing this form and * assigned to the printer. Find the maximum across all such * printers. Sorry, the code actually has a different loop * (it steps through the requests) but the description of what * happens below is easier to understand as given. (Looping * through the printers would result in #printers x #requests * steps, whereas this entails #requests steps.) */ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) PStatus[i]->nrequests = 0; for (prs = Request_List; prs != NULL; prs = prs->next) if ((prs->form == pfs) && ((pps = prs->printer) != NULL) && (!isFormMountedOnPrinter(pps,pfs)) && (++pps->nrequests >= max)) max = pps->nrequests; if (NewRequest) if (((pps = NewRequest->printer) != NULL) && (!isFormMountedOnPrinter(pps,pfs))) if (++pps->nrequests >= max) max = pps->nrequests; return (max); } static int max_requests_needing_pwheel_mounted(char *pwheel_name) { PSTATUS * pps; RSTATUS * prs; int max = 0; int i; /* * For each printer that doesn't have this print-wheel mounted, * count the number of requests needing this print-wheel and * assigned to the printer. Find the maximum across all such * printers. Sorry, the code actually has a different loop * (it steps through the requests) but the description of what * happens below is easier to understand as given. (Looping * through the printers would result in #printers x #requests * steps, whereas this entails #requests steps.) */ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) PStatus[i]->nrequests = 0; for (prs = Request_List; prs != NULL; prs = prs->next) if ((prs->pwheel_name != NULL) && (STREQU(prs->pwheel_name, pwheel_name)) && ((pps = prs->printer) != NULL) && pps->printer->daisy && (!SAME(pps->pwheel_name, pwheel_name))) if (++pps->nrequests >= max) max = pps->nrequests; if (NewRequest) if ( ((pps = NewRequest->printer) != NULL) && pps->printer->daisy && !SAME(pps->pwheel_name, pwheel_name) ) if (++pps->nrequests >= max) max = pps->nrequests; return (max); } /** ** one_printer_with_charsets() **/ int one_printer_with_charsets(RSTATUS *prs) { /* * This little function answers the question: Is a request * that needs a character set destined for a particular * printer that has selectable character sets instead of * mountable print wheels? */ return ( STREQU(prs->request->destination, prs->printer->printer->name) && !prs->printer->printer->daisy ); }