]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / classes.c
1 /*
2 * "$Id: classes.c 6318 2007-03-06 04:36:55Z mike $"
3 *
4 * Printer class routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2007 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
50 cupsd_printer_t * /* O - New class */
51 cupsdAddClass(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
81 void
82 cupsdAddPrinterToClass(
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
130 void
131 cupsdDeletePrinterFromClass(
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
195 void
196 cupsdDeletePrinterFromClasses(
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
232 void
233 cupsdDeleteAllClasses(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
250 cupsd_printer_t * /* O - Available printer or NULL */
251 cupsdFindAvailablePrinter(
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
302 cupsd_printer_t * /* O - Matching class or NULL */
303 cupsdFindClass(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
320 void
321 cupsdLoadAllClasses(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 {
339 if (errno != ENOENT)
340 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", line,
341 strerror(errno));
342 return;
343 }
344
345 /*
346 * Read class configurations until we hit EOF...
347 */
348
349 linenum = 0;
350 p = NULL;
351
352 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
353 {
354 /*
355 * Decode the directive...
356 */
357
358 if (!strcasecmp(line, "<Class") ||
359 !strcasecmp(line, "<DefaultClass"))
360 {
361 /*
362 * <Class name> or <DefaultClass name>
363 */
364
365 if (p == NULL && value)
366 {
367 cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading class %s...", value);
368
369 /*
370 * Since prior classes may have implicitly defined this class,
371 * see if it already exists...
372 */
373
374 if ((p = cupsdFindDest(value)) != NULL)
375 {
376 p->type = CUPS_PRINTER_CLASS;
377 cupsdSetStringf(&p->uri, "ipp://%s:%d/classes/%s", ServerName,
378 LocalPort, value);
379 cupsdSetString(&p->error_policy, "retry-job");
380 }
381 else
382 p = cupsdAddClass(value);
383
384 p->accepting = 1;
385 p->state = IPP_PRINTER_IDLE;
386
387 if (!strcasecmp(line, "<DefaultClass"))
388 DefaultPrinter = p;
389 }
390 else
391 {
392 cupsdLogMessage(CUPSD_LOG_ERROR,
393 "Syntax error on line %d of classes.conf.", linenum);
394 return;
395 }
396 }
397 else if (!strcasecmp(line, "</Class>"))
398 {
399 if (p != NULL)
400 {
401 cupsdSetPrinterAttrs(p);
402 p = NULL;
403 }
404 else
405 {
406 cupsdLogMessage(CUPSD_LOG_ERROR,
407 "Syntax error on line %d of classes.conf.", linenum);
408 return;
409 }
410 }
411 else if (!p)
412 {
413 cupsdLogMessage(CUPSD_LOG_ERROR,
414 "Syntax error on line %d of classes.conf.", linenum);
415 return;
416 }
417 else if (!strcasecmp(line, "AuthInfoRequired"))
418 {
419 if (!cupsdSetAuthInfoRequired(p, value, NULL))
420 cupsdLogMessage(CUPSD_LOG_ERROR,
421 "Bad AuthInfoRequired on line %d of classes.conf.",
422 linenum);
423 }
424 else if (!strcasecmp(line, "Info"))
425 {
426 if (value)
427 cupsdSetString(&p->info, value);
428 }
429 else if (!strcasecmp(line, "Location"))
430 {
431 if (value)
432 cupsdSetString(&p->location, value);
433 }
434 else if (!strcasecmp(line, "Option") && value)
435 {
436 /*
437 * Option name value
438 */
439
440 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
441
442 if (!*valueptr)
443 cupsdLogMessage(CUPSD_LOG_ERROR,
444 "Syntax error on line %d of classes.conf.", linenum);
445 else
446 {
447 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
448
449 p->num_options = cupsAddOption(value, valueptr, p->num_options,
450 &(p->options));
451 }
452 }
453 else if (!strcasecmp(line, "Printer"))
454 {
455 if (!value)
456 {
457 cupsdLogMessage(CUPSD_LOG_ERROR,
458 "Syntax error on line %d of classes.conf.", linenum);
459 return;
460 }
461 else if ((temp = cupsdFindPrinter(value)) == NULL)
462 {
463 cupsdLogMessage(CUPSD_LOG_WARN,
464 "Unknown printer %s on line %d of classes.conf.",
465 value, linenum);
466
467 /*
468 * Add the missing remote printer...
469 */
470
471 if ((temp = cupsdAddPrinter(value)) != NULL)
472 {
473 cupsdSetString(&temp->make_model, "Remote Printer on unknown");
474
475 temp->state = IPP_PRINTER_STOPPED;
476 temp->type |= CUPS_PRINTER_REMOTE;
477 temp->browse_time = 2147483647;
478
479 cupsdSetString(&temp->location, "Location Unknown");
480 cupsdSetString(&temp->info, "No Information Available");
481 temp->hostname[0] = '\0';
482
483 cupsdSetPrinterAttrs(temp);
484 }
485 }
486
487 if (temp)
488 cupsdAddPrinterToClass(p, temp);
489 }
490 else if (!strcasecmp(line, "State"))
491 {
492 /*
493 * Set the initial queue state...
494 */
495
496 if (!strcasecmp(value, "idle"))
497 p->state = IPP_PRINTER_IDLE;
498 else if (!strcasecmp(value, "stopped"))
499 p->state = IPP_PRINTER_STOPPED;
500 else
501 {
502 cupsdLogMessage(CUPSD_LOG_ERROR,
503 "Syntax error on line %d of classes.conf.",
504 linenum);
505 return;
506 }
507 }
508 else if (!strcasecmp(line, "StateMessage"))
509 {
510 /*
511 * Set the initial queue state message...
512 */
513
514 if (value)
515 strlcpy(p->state_message, value, sizeof(p->state_message));
516 }
517 else if (!strcasecmp(line, "StateTime"))
518 {
519 /*
520 * Set the state time...
521 */
522
523 if (value)
524 p->state_time = atoi(value);
525 }
526 else if (!strcasecmp(line, "Accepting"))
527 {
528 /*
529 * Set the initial accepting state...
530 */
531
532 if (value &&
533 (!strcasecmp(value, "yes") ||
534 !strcasecmp(value, "on") ||
535 !strcasecmp(value, "true")))
536 p->accepting = 1;
537 else if (value &&
538 (!strcasecmp(value, "no") ||
539 !strcasecmp(value, "off") ||
540 !strcasecmp(value, "false")))
541 p->accepting = 0;
542 else
543 {
544 cupsdLogMessage(CUPSD_LOG_ERROR,
545 "Syntax error on line %d of classes.conf.",
546 linenum);
547 return;
548 }
549 }
550 else if (!strcasecmp(line, "Shared"))
551 {
552 /*
553 * Set the initial shared state...
554 */
555
556 if (value &&
557 (!strcasecmp(value, "yes") ||
558 !strcasecmp(value, "on") ||
559 !strcasecmp(value, "true")))
560 p->shared = 1;
561 else if (value &&
562 (!strcasecmp(value, "no") ||
563 !strcasecmp(value, "off") ||
564 !strcasecmp(value, "false")))
565 p->shared = 0;
566 else
567 {
568 cupsdLogMessage(CUPSD_LOG_ERROR,
569 "Syntax error on line %d of printers.conf.",
570 linenum);
571 return;
572 }
573 }
574 else if (!strcasecmp(line, "JobSheets"))
575 {
576 /*
577 * Set the initial job sheets...
578 */
579
580 if (value)
581 {
582 for (valueptr = value;
583 *valueptr && !isspace(*valueptr & 255);
584 valueptr ++);
585
586 if (*valueptr)
587 *valueptr++ = '\0';
588
589 cupsdSetString(&p->job_sheets[0], value);
590
591 while (isspace(*valueptr & 255))
592 valueptr ++;
593
594 if (*valueptr)
595 {
596 for (value = valueptr;
597 *valueptr && !isspace(*valueptr & 255);
598 valueptr ++);
599
600 if (*valueptr)
601 *valueptr++ = '\0';
602
603 cupsdSetString(&p->job_sheets[1], value);
604 }
605 }
606 else
607 {
608 cupsdLogMessage(CUPSD_LOG_ERROR,
609 "Syntax error on line %d of classes.conf.", linenum);
610 return;
611 }
612 }
613 else if (!strcasecmp(line, "AllowUser"))
614 {
615 if (value)
616 {
617 p->deny_users = 0;
618 cupsdAddPrinterUser(p, value);
619 }
620 else
621 {
622 cupsdLogMessage(CUPSD_LOG_ERROR,
623 "Syntax error on line %d of classes.conf.", linenum);
624 return;
625 }
626 }
627 else if (!strcasecmp(line, "DenyUser"))
628 {
629 if (value)
630 {
631 p->deny_users = 1;
632 cupsdAddPrinterUser(p, value);
633 }
634 else
635 {
636 cupsdLogMessage(CUPSD_LOG_ERROR,
637 "Syntax error on line %d of classes.conf.", linenum);
638 return;
639 }
640 }
641 else if (!strcasecmp(line, "QuotaPeriod"))
642 {
643 if (value)
644 p->quota_period = atoi(value);
645 else
646 {
647 cupsdLogMessage(CUPSD_LOG_ERROR,
648 "Syntax error on line %d of classes.conf.", linenum);
649 return;
650 }
651 }
652 else if (!strcasecmp(line, "PageLimit"))
653 {
654 if (value)
655 p->page_limit = atoi(value);
656 else
657 {
658 cupsdLogMessage(CUPSD_LOG_ERROR,
659 "Syntax error on line %d of classes.conf.", linenum);
660 return;
661 }
662 }
663 else if (!strcasecmp(line, "KLimit"))
664 {
665 if (value)
666 p->k_limit = atoi(value);
667 else
668 {
669 cupsdLogMessage(CUPSD_LOG_ERROR,
670 "Syntax error on line %d of classes.conf.", linenum);
671 return;
672 }
673 }
674 else if (!strcasecmp(line, "OpPolicy"))
675 {
676 if (value)
677 cupsdSetString(&p->op_policy, value);
678 else
679 {
680 cupsdLogMessage(CUPSD_LOG_ERROR,
681 "Syntax error on line %d of classes.conf.", linenum);
682 return;
683 }
684 }
685 else if (!strcasecmp(line, "ErrorPolicy"))
686 {
687 if (value)
688 cupsdSetString(&p->error_policy, value);
689 else
690 {
691 cupsdLogMessage(CUPSD_LOG_ERROR,
692 "Syntax error on line %d of classes.conf.", linenum);
693 return;
694 }
695 }
696 else
697 {
698 /*
699 * Something else we don't understand...
700 */
701
702 cupsdLogMessage(CUPSD_LOG_ERROR,
703 "Unknown configuration directive %s on line %d of classes.conf.",
704 line, linenum);
705 }
706 }
707
708 cupsFileClose(fp);
709 }
710
711
712 /*
713 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
714 */
715
716 void
717 cupsdSaveAllClasses(void)
718 {
719 cups_file_t *fp; /* classes.conf file */
720 char temp[1024]; /* Temporary string */
721 char backup[1024]; /* classes.conf.O file */
722 cupsd_printer_t *pclass; /* Current printer class */
723 int i; /* Looping var */
724 time_t curtime; /* Current time */
725 struct tm *curdate; /* Current date */
726 cups_option_t *option; /* Current option */
727 const char *ptr; /* Pointer into info/location */
728
729
730 /*
731 * Create the classes.conf file...
732 */
733
734 snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot);
735 snprintf(backup, sizeof(backup), "%s/classes.conf.O", ServerRoot);
736
737 if (rename(temp, backup))
738 {
739 if (errno != ENOENT)
740 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup classes.conf - %s",
741 strerror(errno));
742 }
743
744 if ((fp = cupsFileOpen(temp, "w")) == NULL)
745 {
746 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to save classes.conf - %s",
747 strerror(errno));
748
749 if (rename(backup, temp))
750 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to restore classes.conf - %s",
751 strerror(errno));
752 return;
753 }
754 else
755 cupsdLogMessage(CUPSD_LOG_INFO, "Saving classes.conf...");
756
757 /*
758 * Restrict access to the file...
759 */
760
761 fchown(cupsFileNumber(fp), RunUser, Group);
762 fchmod(cupsFileNumber(fp), 0600);
763
764 /*
765 * Write a small header to the file...
766 */
767
768 curtime = time(NULL);
769 curdate = localtime(&curtime);
770 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
771
772 cupsFilePuts(fp, "# Class configuration file for " CUPS_SVERSION "\n");
773 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
774
775 /*
776 * Write each local class known to the system...
777 */
778
779 for (pclass = (cupsd_printer_t *)cupsArrayFirst(Printers);
780 pclass;
781 pclass = (cupsd_printer_t *)cupsArrayNext(Printers))
782 {
783 /*
784 * Skip remote destinations and regular printers...
785 */
786
787 if ((pclass->type & CUPS_PRINTER_REMOTE) ||
788 (pclass->type & CUPS_PRINTER_IMPLICIT) ||
789 !(pclass->type & CUPS_PRINTER_CLASS))
790 continue;
791
792 /*
793 * Write printers as needed...
794 */
795
796 if (pclass == DefaultPrinter)
797 cupsFilePrintf(fp, "<DefaultClass %s>\n", pclass->name);
798 else
799 cupsFilePrintf(fp, "<Class %s>\n", pclass->name);
800
801 if (pclass->num_auth_info_required > 0)
802 {
803 cupsFilePrintf(fp, "AuthInfoRequired %s", pclass->auth_info_required[0]);
804 for (i = 1; i < pclass->num_auth_info_required; i ++)
805 cupsFilePrintf(fp, ",%s", pclass->auth_info_required[i]);
806 cupsFilePutChar(fp, '\n');
807 }
808
809 if (pclass->info)
810 {
811 if ((ptr = strchr(pclass->info, '#')) != NULL)
812 {
813 /*
814 * Need to quote the first # in the info string...
815 */
816
817 cupsFilePuts(fp, "Info ");
818 cupsFileWrite(fp, pclass->info, ptr - pclass->info);
819 cupsFilePutChar(fp, '\\');
820 cupsFilePuts(fp, ptr);
821 cupsFilePutChar(fp, '\n');
822 }
823 else
824 cupsFilePrintf(fp, "Info %s\n", pclass->info);
825 }
826
827 if (pclass->location)
828 {
829 if ((ptr = strchr(pclass->info, '#')) != NULL)
830 {
831 /*
832 * Need to quote the first # in the location string...
833 */
834
835 cupsFilePuts(fp, "Location ");
836 cupsFileWrite(fp, pclass->location, ptr - pclass->location);
837 cupsFilePutChar(fp, '\\');
838 cupsFilePuts(fp, ptr);
839 cupsFilePutChar(fp, '\n');
840 }
841 else
842 cupsFilePrintf(fp, "Location %s\n", pclass->location);
843 }
844
845 if (pclass->state == IPP_PRINTER_STOPPED)
846 {
847 cupsFilePuts(fp, "State Stopped\n");
848 cupsFilePrintf(fp, "StateMessage %s\n", pclass->state_message);
849 }
850 else
851 cupsFilePuts(fp, "State Idle\n");
852
853 cupsFilePrintf(fp, "StateTime %d\n", (int)pclass->state_time);
854
855 if (pclass->accepting)
856 cupsFilePuts(fp, "Accepting Yes\n");
857 else
858 cupsFilePuts(fp, "Accepting No\n");
859
860 if (pclass->shared)
861 cupsFilePuts(fp, "Shared Yes\n");
862 else
863 cupsFilePuts(fp, "Shared No\n");
864
865 cupsFilePrintf(fp, "JobSheets %s %s\n", pclass->job_sheets[0],
866 pclass->job_sheets[1]);
867
868 for (i = 0; i < pclass->num_printers; i ++)
869 cupsFilePrintf(fp, "Printer %s\n", pclass->printers[i]->name);
870
871 cupsFilePrintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
872 cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit);
873 cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit);
874
875 for (i = 0; i < pclass->num_users; i ++)
876 cupsFilePrintf(fp, "%sUser %s\n", pclass->deny_users ? "Deny" : "Allow",
877 pclass->users[i]);
878
879 if (pclass->op_policy)
880 cupsFilePrintf(fp, "OpPolicy %s\n", pclass->op_policy);
881 if (pclass->error_policy)
882 cupsFilePrintf(fp, "ErrorPolicy %s\n", pclass->error_policy);
883
884 for (i = pclass->num_options, option = pclass->options;
885 i > 0;
886 i --, option ++)
887 cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value);
888
889 cupsFilePuts(fp, "</Class>\n");
890 }
891
892 cupsFileClose(fp);
893 }
894
895
896 /*
897 * 'cupsdUpdateImplicitClasses()' - Update the accepting state of implicit
898 * classes.
899 */
900
901 void
902 cupsdUpdateImplicitClasses(void)
903 {
904 int i; /* Looping var */
905 cupsd_printer_t *pclass; /* Current class */
906 int accepting; /* printer-is-accepting-jobs value */
907
908
909 for (pclass = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters);
910 pclass;
911 pclass = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters))
912 {
913 /*
914 * Loop through the printers to come up with a composite state...
915 */
916
917 for (i = 0, accepting = 0; i < pclass->num_printers; i ++)
918 if ((accepting = pclass->printers[i]->accepting) != 0)
919 break;
920
921 pclass->accepting = accepting;
922 }
923 }
924
925
926 /*
927 * End of "$Id: classes.c 6318 2007-03-06 04:36:55Z mike $".
928 */