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 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 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 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 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 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 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 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 * 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 360 isFormUsableOnPrinter(PSTATUS *pps, FSTATUS *pfs) 361 { 362 return (trayWithForm(pps,pfs,0,1) >= 0 ); 363 } 364 int 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 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 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 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