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