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