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