]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/classes.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / classes.c
CommitLineData
ef416fc2 1/*
fa73b229 2 * "$Id: classes.c 4988 2006-01-26 00:53:00Z mike $"
ef416fc2 3 *
4 * Printer class routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * cupsdAddClass() - Add a class to the system.
27 * cupsdAddPrinterToClass() - Add a printer to a class...
28 * cupsdDeletePrinterFromClass() - Delete a printer from a class.
29 * cupsdDeletePrinterFromClasses() - Delete a printer from all classes.
30 * cupsdDeleteAllClasses() - Remove all classes from the system.
31 * cupsdFindAvailablePrinter() - Find an available printer in a class.
32 * cupsdFindClass() - Find the named class.
33 * cupsdLoadAllClasses() - Load classes from the classes.conf file.
34 * cupsdSaveAllClasses() - Save classes to the classes.conf file.
35 * cupsdUpdateImplicitClasses() - Update the accepting state of implicit
36 * classes.
37 */
38
39/*
40 * Include necessary headers...
41 */
42
43#include "cupsd.h"
44
45
46/*
47 * 'cupsdAddClass()' - Add a class to the system.
48 */
49
50cupsd_printer_t * /* O - New class */
51cupsdAddClass(const char *name) /* I - Name of class */
52{
53 cupsd_printer_t *c; /* New class */
54
55
56 /*
57 * Add the printer and set the type to "class"...
58 */
59
60 if ((c = cupsdAddPrinter(name)) != NULL)
61 {
62 /*
63 * Change from a printer to a class...
64 */
65
66 c->type = CUPS_PRINTER_CLASS;
67
68 cupsdSetStringf(&c->uri, "ipp://%s:%d/classes/%s", ServerName, LocalPort,
69 name);
70 cupsdSetString(&c->error_policy, "retry-job");
71 }
72
73 return (c);
74}
75
76
77/*
78 * 'cupsdAddPrinterToClass()' - Add a printer to a class...
79 */
80
81void
82cupsdAddPrinterToClass(
83 cupsd_printer_t *c, /* I - Class to add to */
84 cupsd_printer_t *p) /* I - Printer to add */
85{
86 int i; /* Looping var */
87 cupsd_printer_t **temp; /* Pointer to printer array */
88
89
90 /*
91 * See if this printer is already a member of the class...
92 */
93
94 for (i = 0; i < c->num_printers; i ++)
95 if (c->printers[i] == p)
96 return;
97
98 /*
99 * Allocate memory as needed...
100 */
101
102 if (c->num_printers == 0)
103 temp = malloc(sizeof(cupsd_printer_t *));
104 else
105 temp = realloc(c->printers, sizeof(cupsd_printer_t *) * (c->num_printers + 1));
106
107 if (temp == NULL)
108 {
109 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add printer %s to class %s!",
110 p->name, c->name);
111 return;
112 }
113
114 /*
115 * Add the printer to the end of the array and update the number of printers.
116 */
117
118 c->printers = temp;
119 temp += c->num_printers;
120 c->num_printers ++;
121
122 *temp = p;
123}
124
125
126/*
127 * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
128 */
129
130void
131cupsdDeletePrinterFromClass(
132 cupsd_printer_t *c, /* I - Class to delete from */
133 cupsd_printer_t *p) /* I - Printer to delete */
134{
135 int i; /* Looping var */
136 cups_ptype_t type, /* Class type */
137 oldtype; /* Old class type */
138
139
140 /*
141 * See if the printer is in the class...
142 */
143
144 for (i = 0; i < c->num_printers; i ++)
145 if (p == c->printers[i])
146 break;
147
148 /*
149 * If it is, remove it from the list...
150 */
151
152 if (i < c->num_printers)
153 {
154 /*
155 * Yes, remove the printer...
156 */
157
158 c->num_printers --;
159 if (i < c->num_printers)
160 memmove(c->printers + i, c->printers + i + 1,
161 (c->num_printers - i) * sizeof(cupsd_printer_t *));
162 }
163 else
164 return;
165
166 /*
167 * Recompute the printer type mask as needed...
168 */
169
170 if (c->num_printers > 0)
171 {
172 oldtype = c->type;
173 type = c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT);
174 c->type = ~CUPS_PRINTER_REMOTE;
175
176 for (i = 0; i < c->num_printers; i ++)
177 c->type &= c->printers[i]->type;
178
179 c->type |= type;
180
181 /*
182 * Update the IPP attributes...
183 */
184
185 if (c->type != oldtype)
186 cupsdSetPrinterAttrs(c);
187 }
188}
189
190
191/*
192 * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
193 */
194
195void
196cupsdDeletePrinterFromClasses(
197 cupsd_printer_t *p) /* I - Printer to delete */
198{
199 cupsd_printer_t *c; /* Pointer to current class */
200
201
202 /*
203 * Loop through the printer/class list and remove the printer
204 * from each class listed...
205 */
206
207 for (c = (cupsd_printer_t *)cupsArrayFirst(Printers);
208 c;
209 c = (cupsd_printer_t *)cupsArrayNext(Printers))
210 if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
211 cupsdDeletePrinterFromClass(c, p);
212
213 /*
214 * Then clean out any empty implicit classes...
215 */
216
217 for (c = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters);
218 c;
219 c = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters))
220 if (c->num_printers == 0)
221 {
222 cupsArrayRemove(ImplicitPrinters, c);
223 cupsdDeletePrinter(c, 0);
224 }
225}
226
227
228/*
229 * 'cupsdDeleteAllClasses()' - Remove all classes from the system.
230 */
231
232void
233cupsdDeleteAllClasses(void)
234{
235 cupsd_printer_t *c; /* Pointer to current printer/class */
236
237
238 for (c = (cupsd_printer_t *)cupsArrayFirst(Printers);
239 c;
240 c = (cupsd_printer_t *)cupsArrayNext(Printers))
241 if (c->type & CUPS_PRINTER_CLASS)
242 cupsdDeletePrinter(c, 0);
243}
244
245
246/*
247 * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
248 */
249
250cupsd_printer_t * /* O - Available printer or NULL */
251cupsdFindAvailablePrinter(
252 const char *name) /* I - Class to check */
253{
254 int i; /* Looping var */
255 cupsd_printer_t *c; /* Printer class */
256
257
258 /*
259 * Find the class...
260 */
261
262 if ((c = cupsdFindClass(name)) == NULL)
263 {
264 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to find class \"%s\"!", name);
265 return (NULL);
266 }
267
268 /*
269 * Loop through the printers in the class and return the first idle
270 * printer... We keep track of the last printer that we used so that
271 * a "round robin" type of scheduling is realized (otherwise the first
272 * server might be saturated with print jobs...)
273 *
274 * Thanks to Joel Fredrikson for helping us get this right!
275 */
276
277 for (i = c->last_printer + 1; ; i ++)
278 {
279 if (i >= c->num_printers)
280 i = 0;
281
282 if (c->printers[i]->accepting &&
283 (c->printers[i]->state == IPP_PRINTER_IDLE ||
284 ((c->printers[i]->type & CUPS_PRINTER_REMOTE) && !c->printers[i]->job)))
285 {
286 c->last_printer = i;
287 return (c->printers[i]);
288 }
289
290 if (i == c->last_printer)
291 break;
292 }
293
294 return (NULL);
295}
296
297
298/*
299 * 'cupsdFindClass()' - Find the named class.
300 */
301
302cupsd_printer_t * /* O - Matching class or NULL */
303cupsdFindClass(const char *name) /* I - Name of class */
304{
305 cupsd_printer_t *c; /* Current class/printer */
306
307
308 if ((c = cupsdFindDest(name)) != NULL &&
309 (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)))
310 return (c);
311 else
312 return (NULL);
313}
314
315
316/*
317 * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
318 */
319
320void
321cupsdLoadAllClasses(void)
322{
323 cups_file_t *fp; /* classes.conf file */
324 int linenum; /* Current line number */
325 char line[1024], /* Line from file */
326 *value, /* Pointer to value */
327 *valueptr; /* Pointer into value */
328 cupsd_printer_t *p, /* Current printer class */
329 *temp; /* Temporary pointer to printer */
330
331
332 /*
333 * Open the classes.conf file...
334 */
335
336 snprintf(line, sizeof(line), "%s/classes.conf", ServerRoot);
337 if ((fp = cupsFileOpen(line, "r")) == NULL)
338 {
fa73b229 339 if (errno != ENOENT)
340 cupsdLogMessage(CUPSD_LOG_ERROR,
341 "cupsdLoadAllClasses: Unable to open %s - %s", line,
342 strerror(errno));
ef416fc2 343 return;
344 }
345
346 /*
347 * Read class configurations until we hit EOF...
348 */
349
350 linenum = 0;
351 p = NULL;
352
353 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
354 {
355 /*
356 * Decode the directive...
357 */
358
359 if (!strcasecmp(line, "<Class") ||
360 !strcasecmp(line, "<DefaultClass"))
361 {
362 /*
363 * <Class name> or <DefaultClass name>
364 */
365
366 if (p == NULL && value)
367 {
368 cupsdLogMessage(CUPSD_LOG_DEBUG,
369 "cupsdLoadAllClasses: Loading class %s...", value);
370
371 p = cupsdAddClass(value);
372 p->accepting = 1;
373 p->state = IPP_PRINTER_IDLE;
374
375 if (!strcasecmp(line, "<DefaultClass"))
376 DefaultPrinter = p;
377 }
378 else
379 {
380 cupsdLogMessage(CUPSD_LOG_ERROR,
381 "Syntax error on line %d of classes.conf.", linenum);
382 return;
383 }
384 }
385 else if (!strcasecmp(line, "</Class>"))
386 {
387 if (p != NULL)
388 {
389 cupsdSetPrinterAttrs(p);
390 p = NULL;
391 }
392 else
393 {
394 cupsdLogMessage(CUPSD_LOG_ERROR,
395 "Syntax error on line %d of classes.conf.", linenum);
396 return;
397 }
398 }
399 else if (!p)
400 {
401 cupsdLogMessage(CUPSD_LOG_ERROR,
402 "Syntax error on line %d of classes.conf.", linenum);
403 return;
404 }
405 else if (!strcasecmp(line, "Info"))
406 {
407 if (value)
408 cupsdSetString(&p->info, value);
409 }
410 else if (!strcasecmp(line, "Location"))
411 {
412 if (value)
413 cupsdSetString(&p->location, value);
414 }
415 else if (!strcasecmp(line, "Printer"))
416 {
417 if (!value)
418 {
419 cupsdLogMessage(CUPSD_LOG_ERROR,
420 "Syntax error on line %d of classes.conf.", linenum);
421 return;
422 }
423 else if ((temp = cupsdFindPrinter(value)) == NULL)
424 {
425 cupsdLogMessage(CUPSD_LOG_WARN,
426 "Unknown printer %s on line %d of classes.conf.",
427 value, linenum);
428
429 /*
430 * Add the missing remote printer...
431 */
432
433 if ((temp = cupsdAddPrinter(value)) != NULL)
434 {
435 cupsdSetString(&temp->make_model, "Remote Printer on unknown");
436
437 temp->state = IPP_PRINTER_STOPPED;
438 temp->type |= CUPS_PRINTER_REMOTE;
439 temp->browse_time = 2147483647;
440
441 cupsdSetString(&temp->location, "Location Unknown");
442 cupsdSetString(&temp->info, "No Information Available");
443 temp->hostname[0] = '\0';
444
445 cupsdSetPrinterAttrs(temp);
446 }
447 }
448
449 if (temp)
450 cupsdAddPrinterToClass(p, temp);
451 }
452 else if (!strcasecmp(line, "State"))
453 {
454 /*
455 * Set the initial queue state...
456 */
457
458 if (!strcasecmp(value, "idle"))
459 p->state = IPP_PRINTER_IDLE;
460 else if (!strcasecmp(value, "stopped"))
461 p->state = IPP_PRINTER_STOPPED;
462 else
463 {
464 cupsdLogMessage(CUPSD_LOG_ERROR,
465 "Syntax error on line %d of classes.conf.",
466 linenum);
467 return;
468 }
469 }
470 else if (!strcasecmp(line, "StateMessage"))
471 {
472 /*
473 * Set the initial queue state message...
474 */
475
476 if (value)
477 strlcpy(p->state_message, value, sizeof(p->state_message));
478 }
479 else if (!strcasecmp(line, "StateTime"))
480 {
481 /*
482 * Set the state time...
483 */
484
485 if (value)
486 p->state_time = atoi(value);
487 }
488 else if (!strcasecmp(line, "Accepting"))
489 {
490 /*
491 * Set the initial accepting state...
492 */
493
494 if (value &&
495 (!strcasecmp(value, "yes") ||
496 !strcasecmp(value, "on") ||
497 !strcasecmp(value, "true")))
498 p->accepting = 1;
499 else if (value &&
500 (!strcasecmp(value, "no") ||
501 !strcasecmp(value, "off") ||
502 !strcasecmp(value, "false")))
503 p->accepting = 0;
504 else
505 {
506 cupsdLogMessage(CUPSD_LOG_ERROR,
507 "Syntax error on line %d of classes.conf.",
508 linenum);
509 return;
510 }
511 }
512 else if (!strcasecmp(line, "Shared"))
513 {
514 /*
515 * Set the initial shared state...
516 */
517
518 if (value &&
519 (!strcasecmp(value, "yes") ||
520 !strcasecmp(value, "on") ||
521 !strcasecmp(value, "true")))
522 p->shared = 1;
523 else if (value &&
524 (!strcasecmp(value, "no") ||
525 !strcasecmp(value, "off") ||
526 !strcasecmp(value, "false")))
527 p->shared = 0;
528 else
529 {
530 cupsdLogMessage(CUPSD_LOG_ERROR,
531 "Syntax error on line %d of printers.conf.",
532 linenum);
533 return;
534 }
535 }
536 else if (!strcasecmp(line, "JobSheets"))
537 {
538 /*
539 * Set the initial job sheets...
540 */
541
542 if (value)
543 {
544 for (valueptr = value;
545 *valueptr && !isspace(*valueptr & 255);
546 valueptr ++);
547
548 if (*valueptr)
549 *valueptr++ = '\0';
550
551 cupsdSetString(&p->job_sheets[0], value);
552
553 while (isspace(*valueptr & 255))
554 valueptr ++;
555
556 if (*valueptr)
557 {
558 for (value = valueptr;
559 *valueptr && !isspace(*valueptr & 255);
560 valueptr ++);
561
562 if (*valueptr)
563 *valueptr++ = '\0';
564
565 cupsdSetString(&p->job_sheets[1], value);
566 }
567 }
568 else
569 {
570 cupsdLogMessage(CUPSD_LOG_ERROR,
571 "Syntax error on line %d of classes.conf.", linenum);
572 return;
573 }
574 }
575 else if (!strcasecmp(line, "AllowUser"))
576 {
577 if (value)
578 {
579 p->deny_users = 0;
580 cupsdAddPrinterUser(p, value);
581 }
582 else
583 {
584 cupsdLogMessage(CUPSD_LOG_ERROR,
585 "Syntax error on line %d of classes.conf.", linenum);
586 return;
587 }
588 }
589 else if (!strcasecmp(line, "DenyUser"))
590 {
591 if (value)
592 {
593 p->deny_users = 1;
594 cupsdAddPrinterUser(p, value);
595 }
596 else
597 {
598 cupsdLogMessage(CUPSD_LOG_ERROR,
599 "Syntax error on line %d of classes.conf.", linenum);
600 return;
601 }
602 }
603 else if (!strcasecmp(line, "QuotaPeriod"))
604 {
605 if (value)
606 p->quota_period = atoi(value);
607 else
608 {
609 cupsdLogMessage(CUPSD_LOG_ERROR,
610 "Syntax error on line %d of classes.conf.", linenum);
611 return;
612 }
613 }
614 else if (!strcasecmp(line, "PageLimit"))
615 {
616 if (value)
617 p->page_limit = atoi(value);
618 else
619 {
620 cupsdLogMessage(CUPSD_LOG_ERROR,
621 "Syntax error on line %d of classes.conf.", linenum);
622 return;
623 }
624 }
625 else if (!strcasecmp(line, "KLimit"))
626 {
627 if (value)
628 p->k_limit = atoi(value);
629 else
630 {
631 cupsdLogMessage(CUPSD_LOG_ERROR,
632 "Syntax error on line %d of classes.conf.", linenum);
633 return;
634 }
635 }
636 else if (!strcasecmp(line, "OpPolicy"))
637 {
638 if (value)
639 cupsdSetString(&p->op_policy, value);
640 else
641 {
642 cupsdLogMessage(CUPSD_LOG_ERROR,
643 "Syntax error on line %d of classes.conf.", linenum);
644 return;
645 }
646 }
647 else if (!strcasecmp(line, "ErrorPolicy"))
648 {
649 if (value)
650 cupsdSetString(&p->error_policy, value);
651 else
652 {
653 cupsdLogMessage(CUPSD_LOG_ERROR,
654 "Syntax error on line %d of classes.conf.", linenum);
655 return;
656 }
657 }
658 else
659 {
660 /*
661 * Something else we don't understand...
662 */
663
664 cupsdLogMessage(CUPSD_LOG_ERROR,
665 "Unknown configuration directive %s on line %d of classes.conf.",
666 line, linenum);
667 }
668 }
669
670 cupsFileClose(fp);
671}
672
673
674/*
675 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
676 */
677
678void
679cupsdSaveAllClasses(void)
680{
681 cups_file_t *fp; /* classes.conf file */
682 char temp[1024]; /* Temporary string */
683 char backup[1024]; /* classes.conf.O file */
684 cupsd_printer_t *pclass; /* Current printer class */
685 int i; /* Looping var */
686 time_t curtime; /* Current time */
687 struct tm *curdate; /* Current date */
688
689
690 /*
691 * Create the classes.conf file...
692 */
693
694 snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot);
695 snprintf(backup, sizeof(backup), "%s/classes.conf.O", ServerRoot);
696
697 if (rename(temp, backup))
698 {
699 if (errno != ENOENT)
700 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup classes.conf - %s",
701 strerror(errno));
702 }
703
704 if ((fp = cupsFileOpen(temp, "w")) == NULL)
705 {
706 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to save classes.conf - %s",
707 strerror(errno));
708
709 if (rename(backup, temp))
710 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to restore classes.conf - %s",
711 strerror(errno));
712 return;
713 }
714 else
715 cupsdLogMessage(CUPSD_LOG_INFO, "Saving classes.conf...");
716
717 /*
718 * Restrict access to the file...
719 */
720
721 fchown(cupsFileNumber(fp), RunUser, Group);
fa73b229 722 fchmod(cupsFileNumber(fp), 0600);
ef416fc2 723
724 /*
725 * Write a small header to the file...
726 */
727
728 curtime = time(NULL);
729 curdate = localtime(&curtime);
730 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
731
732 cupsFilePuts(fp, "# Class configuration file for " CUPS_SVERSION "\n");
733 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
734
735 /*
736 * Write each local class known to the system...
737 */
738
739 for (pclass = (cupsd_printer_t *)cupsArrayFirst(Printers);
740 pclass;
741 pclass = (cupsd_printer_t *)cupsArrayNext(Printers))
742 {
743 /*
744 * Skip remote destinations and regular printers...
745 */
746
747 if ((pclass->type & CUPS_PRINTER_REMOTE) ||
748 (pclass->type & CUPS_PRINTER_IMPLICIT) ||
749 !(pclass->type & CUPS_PRINTER_CLASS))
750 continue;
751
752 /*
753 * Write printers as needed...
754 */
755
756 if (pclass == DefaultPrinter)
757 cupsFilePrintf(fp, "<DefaultClass %s>\n", pclass->name);
758 else
759 cupsFilePrintf(fp, "<Class %s>\n", pclass->name);
760
761 if (pclass->info)
762 cupsFilePrintf(fp, "Info %s\n", pclass->info);
763
764 if (pclass->location)
765 cupsFilePrintf(fp, "Location %s\n", pclass->location);
766
767 if (pclass->state == IPP_PRINTER_STOPPED)
768 {
769 cupsFilePuts(fp, "State Stopped\n");
770 cupsFilePrintf(fp, "StateMessage %s\n", pclass->state_message);
771 }
772 else
773 cupsFilePuts(fp, "State Idle\n");
774
775 cupsFilePrintf(fp, "StateTime %d\n", (int)pclass->state_time);
776
777 if (pclass->accepting)
778 cupsFilePuts(fp, "Accepting Yes\n");
779 else
780 cupsFilePuts(fp, "Accepting No\n");
781
782 if (pclass->shared)
783 cupsFilePuts(fp, "Shared Yes\n");
784 else
785 cupsFilePuts(fp, "Shared No\n");
786
787 cupsFilePrintf(fp, "JobSheets %s %s\n", pclass->job_sheets[0],
788 pclass->job_sheets[1]);
789
790 for (i = 0; i < pclass->num_printers; i ++)
791 cupsFilePrintf(fp, "Printer %s\n", pclass->printers[i]->name);
792
793 cupsFilePrintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
794 cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit);
795 cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit);
796
797 for (i = 0; i < pclass->num_users; i ++)
798 cupsFilePrintf(fp, "%sUser %s\n", pclass->deny_users ? "Deny" : "Allow",
799 pclass->users[i]);
800
801 if (pclass->op_policy)
802 cupsFilePrintf(fp, "OpPolicy %s\n", pclass->op_policy);
803 if (pclass->error_policy)
804 cupsFilePrintf(fp, "ErrorPolicy %s\n", pclass->error_policy);
805
806 cupsFilePuts(fp, "</Class>\n");
807 }
808
809 cupsFileClose(fp);
810}
811
812
813/*
814 * 'cupsdUpdateImplicitClasses()' - Update the accepting state of implicit
815 * classes.
816 */
817
818void
819cupsdUpdateImplicitClasses(void)
820{
821 int i; /* Looping var */
822 cupsd_printer_t *pclass; /* Current class */
823 int accepting; /* printer-is-accepting-jobs value */
824
825
826 for (pclass = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters);
827 pclass;
828 pclass = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters))
829 {
830 /*
831 * Loop through the printers to come up with a composite state...
832 */
833
834 for (i = 0, accepting = 0; i < pclass->num_printers; i ++)
835 if ((accepting = pclass->printers[i]->accepting) != 0)
836 break;
837
838 pclass->accepting = accepting;
839 }
840}
841
842
843/*
fa73b229 844 * End of "$Id: classes.c 4988 2006-01-26 00:53:00Z mike $".
ef416fc2 845 */