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