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