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