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