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
queue_form(RSTATUS * prs,FSTATUS * pfs)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
unqueue_form(RSTATUS * prs)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
queue_pwheel(RSTATUS * prs,char * name)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
unqueue_pwheel(RSTATUS * prs)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
check_form_alert(FSTATUS * pfs,_FORM * pf)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
check_pwheel_alert(PWSTATUS * ppws,PWHEEL * ppw)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
trayWithForm(PSTATUS * pps,FSTATUS * pfs,int startingTray,int checkAvail)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 *
allTraysWithForm(PSTATUS * pps,FSTATUS * pfs)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
isFormUsableOnPrinter(PSTATUS * pps,FSTATUS * pfs)362 isFormUsableOnPrinter(PSTATUS *pps, FSTATUS *pfs)
363 {
364 return (trayWithForm(pps,pfs,0,1) >= 0 );
365 }
366 int
isFormMountedOnPrinter(PSTATUS * pps,FSTATUS * pfs)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
max_requests_needing_form_mounted(FSTATUS * pfs)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
max_requests_needing_pwheel_mounted(char * pwheel_name)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
one_printer_with_charsets(RSTATUS * prs)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