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