Home | History | Annotate | Download | only in lpsched
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     22 /*	  All Rights Reserved  	*/
     23 
     24 
     25 /*
     26  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     27  * Use is subject to license terms.
     28  */
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31 
     32 #include "lpsched.h"
     33 #include <syslog.h>
     34 
     35 static int	max_requests_needing_form_mounted ( FSTATUS * );
     36 static int	max_requests_needing_pwheel_mounted ( char * );
     37 
     38 /**
     39  ** queue_form() - ADD A REQUEST TO A FORM QUEUE
     40  **/
     41 
     42 void
     43 queue_form(RSTATUS *prs, FSTATUS *pfs)
     44 {
     45 	if ((prs->form = pfs) != NULL) {
     46 		prs->form->requests++;
     47 		if (prs->printer)
     48 			check_form_alert (prs->form, (_FORM *)0);
     49 	}
     50 	return;
     51 }
     52 
     53 /**
     54  ** unqueue_form() - REMOVE A REQUEST FROM A FORM QUEUE
     55  **/
     56 
     57 void
     58 unqueue_form(RSTATUS *prs)
     59 {
     60 	FSTATUS *		pfs	= prs->form;
     61 
     62 	prs->form = 0;
     63 	if (pfs) {
     64 		pfs->requests--;
     65 		if (prs->printer)
     66 			check_form_alert (pfs, (_FORM *)0);
     67 	}
     68 	return;
     69 }
     70 
     71 /**
     72  ** queue_pwheel() - ADD A REQUEST TO A PRINT WHEEL QUEUE
     73  **/
     74 
     75 void
     76 queue_pwheel(RSTATUS *prs, char *name)
     77 {
     78 	if (name) {
     79 		prs->pwheel_name = Strdup(name);
     80 		/*
     81 		 * Don't bother queueing the request for
     82 		 * a print wheel if this request is destined for
     83 		 * only this printer and the printer doesn't take
     84 		 * print wheels.
     85 		 */
     86 		if (
     87 			!one_printer_with_charsets(prs)
     88 		     && (prs->pwheel = search_pwstatus(name))
     89 		) {
     90 			prs->pwheel->requests++;
     91 			check_pwheel_alert (prs->pwheel, (PWHEEL *)0);
     92 		}
     93 	}
     94 	return;
     95 }
     96 
     97 /**
     98  ** unqueue_pwheel() - REMOVE A REQUEST FROM A PRINT WHEEL QUEUE
     99  **/
    100 
    101 void
    102 unqueue_pwheel(RSTATUS *prs)
    103 {
    104 	PWSTATUS *		ppws	= prs->pwheel;
    105 
    106 	prs->pwheel = 0;
    107 	unload_str (&(prs->pwheel_name));
    108 	if (ppws) {
    109 		ppws->requests--;
    110 		check_pwheel_alert (ppws, (PWHEEL *)0);
    111 	}
    112 	return;
    113 }
    114 
    115 /**
    116  ** check_form_alert() - CHECK CHANGES TO MOUNT FORM ALERT
    117  **/
    118 
    119 void
    120 check_form_alert(FSTATUS *pfs, _FORM *pf)
    121 {
    122 	short			trigger,
    123 				fire_off_alert	= 0;
    124 
    125 	int			requests_waiting;
    126 
    127 
    128 	/*
    129 	 * Call this routine whenever a requests has been queued
    130 	 * or dequeued for a form, and whenever the form changes.
    131 	 * If a pointer to a new _FORM is passed, the FSTATUS
    132 	 * structure is updated with the changes. Use a second
    133 	 * argument of 0 if no change.
    134 	 *
    135 	 * WARNING: It is valid to call this routine when adding
    136 	 * a NEW form (not just changing it). Thus the members of
    137 	 * the structure "pfs->form" may not be set.
    138 	 * In this case, though, "pf" MUST be set, and there can
    139 	 * be NO alert active.
    140 	 */
    141 
    142 	syslog(LOG_DEBUG, "check_form_alert:\n");
    143 	if (pfs)
    144 		syslog(LOG_DEBUG, "check_form_alert: pfs->name <%s>\n",
    145 			(pfs->form->name != NULL) ? pfs->form->name : "null");
    146 	if (pf)
    147 		syslog(LOG_DEBUG, "check_form_alert: pf->name <%s>\n",
    148 			(pf->name != NULL) ? pf->name : "null");
    149 
    150 
    151 	if (pf) {
    152 		if ((trigger = pf->alert.Q) <= 0)
    153 			trigger = 1;
    154 	} else
    155 		trigger = pfs->trigger;
    156 
    157 	if (Starting)
    158 		goto Return;
    159 
    160 #define	OALERT	pfs->form->alert
    161 #define NALERT	pf->alert
    162 
    163 	requests_waiting = max_requests_needing_form_mounted(pfs);
    164 
    165 	/*
    166 	 * Cancel an active alert if the number of requests queued
    167 	 * has dropped below the threshold (or the threshold has been
    168 	 * raised), or if the alert command or period has changed.
    169 	 * In the latter case we'll reactive the alert later.
    170 	 */
    171 	if (pfs->alert->active)
    172 		if (!requests_waiting || requests_waiting < trigger)
    173 			cancel_alert (A_FORM, pfs);
    174 
    175 		else if (
    176 			pf
    177 		     && (
    178 				!SAME(NALERT.shcmd, OALERT.shcmd)
    179 			     || NALERT.W != OALERT.W
    180 			     || NALERT.Q != OALERT.Q
    181 			)
    182 		)
    183 			cancel_alert (A_FORM, pfs);
    184 
    185 	/*
    186 	 * If we still have the condition for an alert, we'll fire
    187 	 * one off. It is possible the alert is still running, but
    188 	 * that's okay. First, we may want to change the alert message;
    189 	 * second, the "alert()" routine doesn't execute an alert
    190 	 * if it is already running.
    191 	 */
    192 	if (trigger > 0 && requests_waiting >= trigger)
    193 		if ((pf && NALERT.shcmd) || OALERT.shcmd)
    194 			fire_off_alert = 1;
    195 
    196 #undef	OALERT
    197 #undef	NALERT
    198 
    199 Return:	if (pf) {
    200 
    201 		 pfs->form = pf;
    202 
    203 		pfs->trigger = trigger;
    204 	}
    205 
    206 	/*
    207 	 * Have to do this after updating the changes.
    208 	 */
    209 	if (fire_off_alert)
    210 		alert (A_FORM, pfs);
    211 
    212 	return;
    213 }
    214 
    215 /**
    216  ** check_pwheel_alert() - CHECK CHANGES TO MOUNT PRINTWHEEL ALERT
    217  **/
    218 
    219 void
    220 check_pwheel_alert(PWSTATUS *ppws, PWHEEL *ppw)
    221 {
    222 	short			trigger,
    223 				fire_off_alert	= 0;
    224 	int			requests_waiting;
    225 
    226 
    227 	/*
    228 	 * Call this routine whenever a request has been queued
    229 	 * or dequeued for a print-wheel, and whenever the print-wheel
    230 	 * changes. If a pointer to a new PWHEEL is passed, the
    231 	 * PWSTATUS structure is updated with the changes. Use a
    232 	 * second argument of 0 if no change.
    233 	 *
    234 	 * WARNING: It is valid to call this routine when adding
    235 	 * a NEW print wheel (not just changing it). Thus the members
    236 	 * of the structure "ppws->pwheel" may not be set.
    237 	 * In this case, though, "ppw" MUST be set, and there can
    238 	 * be NO alert active.
    239 	 */
    240 
    241 	if (ppw) {
    242 		if ((trigger = ppw->alert.Q) <= 0)
    243 			trigger = 1;
    244 	} else
    245 		trigger = ppws->trigger;
    246 
    247 	if (Starting)
    248 		goto Return;
    249 
    250 #define	OALERT	ppws->pwheel->alert
    251 #define NALERT	ppw->alert
    252 
    253 	requests_waiting = max_requests_needing_pwheel_mounted(ppws->pwheel->name);
    254 
    255 	/*
    256 	 * Cancel an active alert if the number of requests queued
    257 	 * has dropped below the threshold (or the threshold has been
    258 	 * raised), or if the alert command or period has changed.
    259 	 * In the latter case we'll reactive the alert later.
    260 	 */
    261 	if (ppws->alert->active)
    262 		if (!requests_waiting || requests_waiting < trigger)
    263 			cancel_alert (A_PWHEEL, ppws);
    264 
    265 		else if (
    266 			ppw
    267 		     && (
    268 				!SAME(NALERT.shcmd, OALERT.shcmd)
    269 			     || NALERT.W != OALERT.W
    270 			     || NALERT.Q != OALERT.Q
    271 			)
    272 		)
    273 			cancel_alert (A_PWHEEL, ppws);
    274 
    275 	/*
    276 	 * If we still have the condition for an alert, we'll fire
    277 	 * one off. It is possible the alert is still running, but
    278 	 * that's okay. First, we may want to change the alert message;
    279 	 * second, the "alert()" routine doesn't execute an alert
    280 	 * if it is already running.
    281 	 */
    282 	if (trigger > 0 && requests_waiting >= trigger)
    283 		if ((ppw && NALERT.shcmd) || OALERT.shcmd)
    284 			fire_off_alert = 1;
    285 
    286 #undef	OALERT
    287 #undef	NALERT
    288 
    289 Return:	if (ppw) {
    290 
    291 		ppws->pwheel = ppw;
    292 		ppws->trigger = trigger;
    293 	}
    294 
    295 	/*
    296 	 * Have to do this after updating the changes.
    297 	 */
    298 	if (fire_off_alert)
    299 		alert (A_PWHEEL, ppws);
    300 
    301 	return;
    302 }
    303 
    304 static int
    305 trayWithForm(PSTATUS *pps, FSTATUS *pfs, int startingTray, int checkAvail)
    306 {
    307 	int i;
    308 	PFSTATUS *ppfs;
    309 
    310 	ppfs = pps->forms;
    311 	if (startingTray < 0)
    312 		startingTray = 0;
    313 
    314 	if (ppfs) {
    315 		for (i = startingTray; i < pps->numForms; i++)
    316 			if ((!checkAvail || ppfs[i].isAvailable) &&
    317 			    (ppfs[i].form == pfs))
    318 					return(i);
    319 	}
    320 	else if (!pfs)
    321 		/* no form request matches no form mounted */
    322 		return(0);
    323 
    324 	return(-1);
    325 }
    326 
    327 char *
    328 allTraysWithForm(PSTATUS *pps, FSTATUS *pfs)
    329 {
    330 
    331 	int tray = 0;
    332 	char *ptr, *p;
    333 	char trayList[MAX_INPUT];
    334 	int n;
    335 
    336 	ptr = trayList;
    337 	if (pfs && pfs->form && pfs->form->paper)
    338 		p = pfs->form->paper;
    339 	else
    340 		p = "";
    341 
    342 	n = sizeof (trayList);
    343 	snprintf(ptr, n, "LP_TRAY_ARG=%s:", p);
    344 
    345 	ptr += strlen(ptr);
    346 	n -= strlen(ptr);
    347 
    348 	while ((tray = trayWithForm(pps, pfs, tray, 1)) > 0) {
    349 		tray++;
    350 		snprintf(ptr, n, "%d,", tray);
    351 		ptr += strlen(ptr);
    352 		n -= strlen(ptr);
    353 	}
    354 	if (*(ptr-1) == ',')
    355 		*(ptr-1) = 0;
    356 
    357 	putenv(trayList);
    358 	return(NULL);
    359 }
    360 
    361 int
    362 isFormUsableOnPrinter(PSTATUS *pps, FSTATUS *pfs)
    363 {
    364 	return (trayWithForm(pps,pfs,0,1) >= 0 );
    365 }
    366 int
    367 isFormMountedOnPrinter(PSTATUS *pps, FSTATUS *pfs)
    368 {
    369 	return (trayWithForm(pps,pfs,0,0) >= 0 );
    370 }
    371 
    372 /**
    373  ** max_requests_needing_form_mounted()
    374  ** max_requests_needing_pwheel_mounted()
    375  **/
    376 
    377 static int
    378 max_requests_needing_form_mounted(FSTATUS *pfs)
    379 {
    380 	PSTATUS *		pps;
    381 	RSTATUS *		prs;
    382 	int			max	= 0;
    383 	int			i;
    384 
    385 	/*
    386 	 * For each printer that doesn't have this form mounted,
    387 	 * count the number of requests needing this form and
    388 	 * assigned to the printer. Find the maximum across all such
    389 	 * printers. Sorry, the code actually has a different loop
    390 	 * (it steps through the requests) but the description of what
    391 	 * happens below is easier to understand as given. (Looping
    392 	 * through the printers would result in #printers x #requests
    393 	 * steps, whereas this entails #requests steps.)
    394 	 */
    395 	for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
    396 		PStatus[i]->nrequests = 0;
    397 
    398 	for (prs = Request_List; prs != NULL; prs = prs->next)
    399 		if ((prs->form == pfs) && ((pps = prs->printer) != NULL) &&
    400 	    	    (!isFormMountedOnPrinter(pps,pfs)) &&
    401 		    (++pps->nrequests >= max))
    402 			max = pps->nrequests;
    403 
    404 	if (NewRequest)
    405 		if (((pps = NewRequest->printer) != NULL) &&
    406 		    (!isFormMountedOnPrinter(pps,pfs)))
    407 			if (++pps->nrequests >= max)
    408 				max = pps->nrequests;
    409 	return (max);
    410 }
    411 
    412 static int
    413 max_requests_needing_pwheel_mounted(char *pwheel_name)
    414 {
    415 	PSTATUS *		pps;
    416 	RSTATUS *		prs;
    417 	int			max	= 0;
    418 	int			i;
    419 
    420 
    421 	/*
    422 	 * For each printer that doesn't have this print-wheel mounted,
    423 	 * count the number of requests needing this print-wheel and
    424 	 * assigned to the printer. Find the maximum across all such
    425 	 * printers. Sorry, the code actually has a different loop
    426 	 * (it steps through the requests) but the description of what
    427 	 * happens below is easier to understand as given. (Looping
    428 	 * through the printers would result in #printers x #requests
    429 	 * steps, whereas this entails #requests steps.)
    430 	 */
    431 	for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
    432 		PStatus[i]->nrequests = 0;
    433 
    434 	for (prs = Request_List; prs != NULL; prs = prs->next)
    435 		if ((prs->pwheel_name != NULL) &&
    436 		    (STREQU(prs->pwheel_name, pwheel_name)) &&
    437 		    ((pps = prs->printer) != NULL) && pps->printer->daisy &&
    438 		    (!SAME(pps->pwheel_name, pwheel_name)))
    439 			if (++pps->nrequests >= max)
    440 				max = pps->nrequests;
    441 
    442 	if (NewRequest)
    443 		if (
    444 			((pps = NewRequest->printer) != NULL)
    445 		     && pps->printer->daisy
    446 		     && !SAME(pps->pwheel_name, pwheel_name)
    447 		)
    448 			if (++pps->nrequests >= max)
    449 				max = pps->nrequests;
    450 	return (max);
    451 }
    452 
    453 /**
    454  ** one_printer_with_charsets()
    455  **/
    456 
    457 int
    458 one_printer_with_charsets(RSTATUS *prs)
    459 {
    460 	/*
    461 	 * This little function answers the question: Is a request
    462 	 * that needs a character set destined for a particular
    463 	 * printer that has selectable character sets instead of
    464 	 * mountable print wheels?
    465 	 */
    466 	return (
    467 	    STREQU(prs->request->destination, prs->printer->printer->name)
    468 	 && !prs->printer->printer->daisy
    469 	);
    470 }
    471