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