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