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