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