]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
2 * "$Id: classes.c 10996 2013-05-29 11:51:34Z msweet $"
4 * Printer class routines for the CUPS scheduler.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
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 * cupsdFindAvailablePrinter() - Find an available printer in a class.
22 * cupsdFindClass() - Find the named class.
23 * cupsdLoadAllClasses() - Load classes from the classes.conf file.
24 * cupsdSaveAllClasses() - Save classes to the classes.conf file.
28 * Include necessary headers...
35 * 'cupsdAddClass()' - Add a class to the system.
38 cupsd_printer_t
* /* O - New class */
39 cupsdAddClass(const char *name
) /* I - Name of class */
41 cupsd_printer_t
*c
; /* New class */
42 char uri
[1024]; /* Class URI */
46 * Add the printer and set the type to "class"...
49 if ((c
= cupsdAddPrinter(name
)) != NULL
)
52 * Change from a printer to a class...
55 c
->type
= CUPS_PRINTER_CLASS
;
57 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
58 ServerName
, RemotePort
, "/classes/%s", name
);
59 cupsdSetString(&c
->uri
, uri
);
61 cupsdSetString(&c
->error_policy
, "retry-current-job");
69 * 'cupsdAddPrinterToClass()' - Add a printer to a class...
73 cupsdAddPrinterToClass(
74 cupsd_printer_t
*c
, /* I - Class to add to */
75 cupsd_printer_t
*p
) /* I - Printer to add */
77 int i
; /* Looping var */
78 cupsd_printer_t
**temp
; /* Pointer to printer array */
82 * See if this printer is already a member of the class...
85 for (i
= 0; i
< c
->num_printers
; i
++)
86 if (c
->printers
[i
] == p
)
90 * Allocate memory as needed...
93 if (c
->num_printers
== 0)
94 temp
= malloc(sizeof(cupsd_printer_t
*));
96 temp
= realloc(c
->printers
, sizeof(cupsd_printer_t
*) * (c
->num_printers
+ 1));
100 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to add printer %s to class %s!",
106 * Add the printer to the end of the array and update the number of printers.
110 temp
+= c
->num_printers
;
118 * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
121 int /* O - 1 if class changed, 0 otherwise */
122 cupsdDeletePrinterFromClass(
123 cupsd_printer_t
*c
, /* I - Class to delete from */
124 cupsd_printer_t
*p
) /* I - Printer to delete */
126 int i
; /* Looping var */
130 * See if the printer is in the class...
133 for (i
= 0; i
< c
->num_printers
; i
++)
134 if (p
== c
->printers
[i
])
138 * If it is, remove it from the list...
141 if (i
< c
->num_printers
)
144 * Yes, remove the printer...
148 if (i
< c
->num_printers
)
149 memmove(c
->printers
+ i
, c
->printers
+ i
+ 1,
150 (c
->num_printers
- i
) * sizeof(cupsd_printer_t
*));
156 * Update the IPP attributes (have to do this for member-names)...
159 cupsdSetPrinterAttrs(c
);
166 * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
169 int /* O - 1 if class changed, 0 otherwise */
170 cupsdDeletePrinterFromClasses(
171 cupsd_printer_t
*p
) /* I - Printer to delete */
173 int changed
= 0; /* Any class changed? */
174 cupsd_printer_t
*c
; /* Pointer to current class */
178 * Loop through the printer/class list and remove the printer
179 * from each class listed...
182 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
184 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
185 if (c
->type
& CUPS_PRINTER_CLASS
)
186 changed
|= cupsdDeletePrinterFromClass(c
, p
);
193 * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
196 cupsd_printer_t
* /* O - Available printer or NULL */
197 cupsdFindAvailablePrinter(
198 const char *name
) /* I - Class to check */
200 int i
; /* Looping var */
201 cupsd_printer_t
*c
; /* Printer class */
208 if ((c
= cupsdFindClass(name
)) == NULL
)
210 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to find class \"%s\"!", name
);
214 if (c
->num_printers
== 0)
218 * Make sure that the last printer is also a valid index into the printer
219 * array. If not, reset the last printer to 0...
222 if (c
->last_printer
>= c
->num_printers
)
226 * Loop through the printers in the class and return the first idle
227 * printer... We keep track of the last printer that we used so that
228 * a "round robin" type of scheduling is realized (otherwise the first
229 * server might be saturated with print jobs...)
231 * Thanks to Joel Fredrikson for helping us get this right!
234 for (i
= c
->last_printer
+ 1; ; i
++)
236 if (i
>= c
->num_printers
)
239 if (c
->printers
[i
]->accepting
&&
240 (c
->printers
[i
]->state
== IPP_PRINTER_IDLE
||
241 ((c
->printers
[i
]->type
& CUPS_PRINTER_REMOTE
) && !c
->printers
[i
]->job
)))
244 return (c
->printers
[i
]);
247 if (i
== c
->last_printer
)
256 * 'cupsdFindClass()' - Find the named class.
259 cupsd_printer_t
* /* O - Matching class or NULL */
260 cupsdFindClass(const char *name
) /* I - Name of class */
262 cupsd_printer_t
*c
; /* Current class/printer */
265 if ((c
= cupsdFindDest(name
)) != NULL
&& (c
->type
& CUPS_PRINTER_CLASS
))
273 * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
277 cupsdLoadAllClasses(void)
279 int i
; /* Looping var */
280 cups_file_t
*fp
; /* classes.conf file */
281 int linenum
; /* Current line number */
282 char line
[4096], /* Line from file */
283 *value
, /* Pointer to value */
284 *valueptr
; /* Pointer into value */
285 cupsd_printer_t
*p
, /* Current printer class */
286 *temp
; /* Temporary pointer to printer */
290 * Open the classes.conf file...
293 snprintf(line
, sizeof(line
), "%s/classes.conf", ServerRoot
);
294 if ((fp
= cupsdOpenConfFile(line
)) == NULL
)
298 * Read class configurations until we hit EOF...
304 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
307 * Decode the directive...
310 if (!_cups_strcasecmp(line
, "<Class") ||
311 !_cups_strcasecmp(line
, "<DefaultClass"))
314 * <Class name> or <DefaultClass name>
317 if (p
== NULL
&& value
)
319 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Loading class %s...", value
);
322 * Since prior classes may have implicitly defined this class,
323 * see if it already exists...
326 if ((p
= cupsdFindDest(value
)) != NULL
)
328 p
->type
= CUPS_PRINTER_CLASS
;
329 cupsdSetStringf(&p
->uri
, "ipp://%s:%d/classes/%s", ServerName
,
331 cupsdSetString(&p
->error_policy
, "retry-job");
334 p
= cupsdAddClass(value
);
337 p
->state
= IPP_PRINTER_IDLE
;
339 if (!_cups_strcasecmp(line
, "<DefaultClass"))
343 cupsdLogMessage(CUPSD_LOG_ERROR
,
344 "Syntax error on line %d of classes.conf.", linenum
);
346 else if (!_cups_strcasecmp(line
, "</Class>"))
350 cupsdSetPrinterAttrs(p
);
354 cupsdLogMessage(CUPSD_LOG_ERROR
,
355 "Syntax error on line %d of classes.conf.", linenum
);
359 cupsdLogMessage(CUPSD_LOG_ERROR
,
360 "Syntax error on line %d of classes.conf.", linenum
);
362 else if (!_cups_strcasecmp(line
, "UUID"))
364 if (value
&& !strncmp(value
, "urn:uuid:", 9))
365 cupsdSetString(&(p
->uuid
), value
);
367 cupsdLogMessage(CUPSD_LOG_ERROR
,
368 "Bad UUID on line %d of classes.conf.", linenum
);
370 else if (!_cups_strcasecmp(line
, "AuthInfoRequired"))
372 if (!cupsdSetAuthInfoRequired(p
, value
, NULL
))
373 cupsdLogMessage(CUPSD_LOG_ERROR
,
374 "Bad AuthInfoRequired on line %d of classes.conf.",
377 else if (!_cups_strcasecmp(line
, "Info"))
380 cupsdSetString(&p
->info
, value
);
382 else if (!_cups_strcasecmp(line
, "Location"))
385 cupsdSetString(&p
->location
, value
);
387 else if (!_cups_strcasecmp(line
, "Option") && value
)
393 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
396 cupsdLogMessage(CUPSD_LOG_ERROR
,
397 "Syntax error on line %d of classes.conf.", linenum
);
400 for (; *valueptr
&& isspace(*valueptr
& 255); *valueptr
++ = '\0');
402 p
->num_options
= cupsAddOption(value
, valueptr
, p
->num_options
,
406 else if (!_cups_strcasecmp(line
, "Printer"))
410 cupsdLogMessage(CUPSD_LOG_ERROR
,
411 "Syntax error on line %d of classes.conf.", linenum
);
414 else if ((temp
= cupsdFindPrinter(value
)) == NULL
)
416 cupsdLogMessage(CUPSD_LOG_WARN
,
417 "Unknown printer %s on line %d of classes.conf.",
421 * Add the missing remote printer...
424 if ((temp
= cupsdAddPrinter(value
)) != NULL
)
426 cupsdSetString(&temp
->make_model
, "Remote Printer on unknown");
428 temp
->state
= IPP_PRINTER_STOPPED
;
429 temp
->type
|= CUPS_PRINTER_REMOTE
;
431 cupsdSetString(&temp
->location
, "Location Unknown");
432 cupsdSetString(&temp
->info
, "No Information Available");
433 temp
->hostname
[0] = '\0';
435 cupsdSetPrinterAttrs(temp
);
440 cupsdAddPrinterToClass(p
, temp
);
442 else if (!_cups_strcasecmp(line
, "State"))
445 * Set the initial queue state...
448 if (!_cups_strcasecmp(value
, "idle"))
449 p
->state
= IPP_PRINTER_IDLE
;
450 else if (!_cups_strcasecmp(value
, "stopped"))
452 p
->state
= IPP_PRINTER_STOPPED
;
454 for (i
= 0 ; i
< p
->num_reasons
; i
++)
455 if (!strcmp("paused", p
->reasons
[i
]))
458 if (i
>= p
->num_reasons
&&
459 p
->num_reasons
< (int)(sizeof(p
->reasons
) / sizeof(p
->reasons
[0])))
461 p
->reasons
[p
->num_reasons
] = _cupsStrAlloc("paused");
466 cupsdLogMessage(CUPSD_LOG_ERROR
,
467 "Syntax error on line %d of classes.conf.",
470 else if (!_cups_strcasecmp(line
, "StateMessage"))
473 * Set the initial queue state message...
477 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
479 else if (!_cups_strcasecmp(line
, "StateTime"))
482 * Set the state time...
486 p
->state_time
= atoi(value
);
488 else if (!_cups_strcasecmp(line
, "Accepting"))
491 * Set the initial accepting state...
495 (!_cups_strcasecmp(value
, "yes") ||
496 !_cups_strcasecmp(value
, "on") ||
497 !_cups_strcasecmp(value
, "true")))
500 (!_cups_strcasecmp(value
, "no") ||
501 !_cups_strcasecmp(value
, "off") ||
502 !_cups_strcasecmp(value
, "false")))
505 cupsdLogMessage(CUPSD_LOG_ERROR
,
506 "Syntax error on line %d of classes.conf.",
509 else if (!_cups_strcasecmp(line
, "Shared"))
512 * Set the initial shared state...
516 (!_cups_strcasecmp(value
, "yes") ||
517 !_cups_strcasecmp(value
, "on") ||
518 !_cups_strcasecmp(value
, "true")))
521 (!_cups_strcasecmp(value
, "no") ||
522 !_cups_strcasecmp(value
, "off") ||
523 !_cups_strcasecmp(value
, "false")))
526 cupsdLogMessage(CUPSD_LOG_ERROR
,
527 "Syntax error on line %d of classes.conf.",
530 else if (!_cups_strcasecmp(line
, "JobSheets"))
533 * Set the initial job sheets...
538 for (valueptr
= value
;
539 *valueptr
&& !isspace(*valueptr
& 255);
545 cupsdSetString(&p
->job_sheets
[0], value
);
547 while (isspace(*valueptr
& 255))
552 for (value
= valueptr
;
553 *valueptr
&& !isspace(*valueptr
& 255);
559 cupsdSetString(&p
->job_sheets
[1], value
);
563 cupsdLogMessage(CUPSD_LOG_ERROR
,
564 "Syntax error on line %d of classes.conf.", linenum
);
566 else if (!_cups_strcasecmp(line
, "AllowUser"))
571 cupsdAddString(&(p
->users
), value
);
574 cupsdLogMessage(CUPSD_LOG_ERROR
,
575 "Syntax error on line %d of classes.conf.", linenum
);
577 else if (!_cups_strcasecmp(line
, "DenyUser"))
582 cupsdAddString(&(p
->users
), value
);
585 cupsdLogMessage(CUPSD_LOG_ERROR
,
586 "Syntax error on line %d of classes.conf.", linenum
);
588 else if (!_cups_strcasecmp(line
, "QuotaPeriod"))
591 p
->quota_period
= atoi(value
);
593 cupsdLogMessage(CUPSD_LOG_ERROR
,
594 "Syntax error on line %d of classes.conf.", linenum
);
596 else if (!_cups_strcasecmp(line
, "PageLimit"))
599 p
->page_limit
= atoi(value
);
601 cupsdLogMessage(CUPSD_LOG_ERROR
,
602 "Syntax error on line %d of classes.conf.", linenum
);
604 else if (!_cups_strcasecmp(line
, "KLimit"))
607 p
->k_limit
= atoi(value
);
609 cupsdLogMessage(CUPSD_LOG_ERROR
,
610 "Syntax error on line %d of classes.conf.", linenum
);
612 else if (!_cups_strcasecmp(line
, "OpPolicy"))
616 cupsd_policy_t
*pol
; /* Policy */
619 if ((pol
= cupsdFindPolicy(value
)) != NULL
)
621 cupsdSetString(&p
->op_policy
, value
);
622 p
->op_policy_ptr
= pol
;
625 cupsdLogMessage(CUPSD_LOG_ERROR
,
626 "Bad policy \"%s\" on line %d of classes.conf",
630 cupsdLogMessage(CUPSD_LOG_ERROR
,
631 "Syntax error on line %d of classes.conf.", linenum
);
633 else if (!_cups_strcasecmp(line
, "ErrorPolicy"))
637 if (strcmp(value
, "retry-current-job") && strcmp(value
, "retry-job"))
638 cupsdLogMessage(CUPSD_LOG_WARN
,
639 "ErrorPolicy %s ignored on line %d of classes.conf",
643 cupsdLogMessage(CUPSD_LOG_ERROR
,
644 "Syntax error on line %d of classes.conf.", linenum
);
649 * Something else we don't understand...
652 cupsdLogMessage(CUPSD_LOG_ERROR
,
653 "Unknown configuration directive %s on line %d of classes.conf.",
663 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
667 cupsdSaveAllClasses(void)
669 cups_file_t
*fp
; /* classes.conf file */
670 char filename
[1024], /* classes.conf filename */
671 temp
[1024], /* Temporary string */
672 value
[2048], /* Value string */
673 *name
; /* Current user name */
674 cupsd_printer_t
*pclass
; /* Current printer class */
675 int i
; /* Looping var */
676 time_t curtime
; /* Current time */
677 struct tm
*curdate
; /* Current date */
678 cups_option_t
*option
; /* Current option */
682 * Create the classes.conf file...
685 snprintf(filename
, sizeof(filename
), "%s/classes.conf", ServerRoot
);
687 if ((fp
= cupsdCreateConfFile(filename
, ConfigFilePerm
)) == NULL
)
690 cupsdLogMessage(CUPSD_LOG_INFO
, "Saving classes.conf...");
693 * Write a small header to the file...
696 curtime
= time(NULL
);
697 curdate
= localtime(&curtime
);
698 strftime(temp
, sizeof(temp
) - 1, "%Y-%m-%d %H:%M", curdate
);
700 cupsFilePuts(fp
, "# Class configuration file for " CUPS_SVERSION
"\n");
701 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
702 cupsFilePuts(fp
, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
705 * Write each local class known to the system...
708 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
710 pclass
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
713 * Skip remote destinations and regular printers...
716 if ((pclass
->type
& CUPS_PRINTER_REMOTE
) ||
717 !(pclass
->type
& CUPS_PRINTER_CLASS
))
721 * Write printers as needed...
724 if (pclass
== DefaultPrinter
)
725 cupsFilePrintf(fp
, "<DefaultClass %s>\n", pclass
->name
);
727 cupsFilePrintf(fp
, "<Class %s>\n", pclass
->name
);
729 cupsFilePrintf(fp
, "UUID %s\n", pclass
->uuid
);
731 if (pclass
->num_auth_info_required
> 0)
733 switch (pclass
->num_auth_info_required
)
736 strlcpy(value
, pclass
->auth_info_required
[0], sizeof(value
));
740 snprintf(value
, sizeof(value
), "%s,%s",
741 pclass
->auth_info_required
[0],
742 pclass
->auth_info_required
[1]);
747 snprintf(value
, sizeof(value
), "%s,%s,%s",
748 pclass
->auth_info_required
[0],
749 pclass
->auth_info_required
[1],
750 pclass
->auth_info_required
[2]);
754 cupsFilePutConf(fp
, "AuthInfoRequired", value
);
758 cupsFilePutConf(fp
, "Info", pclass
->info
);
760 if (pclass
->location
)
761 cupsFilePutConf(fp
, "Location", pclass
->location
);
763 if (pclass
->state
== IPP_PRINTER_STOPPED
)
764 cupsFilePuts(fp
, "State Stopped\n");
766 cupsFilePuts(fp
, "State Idle\n");
768 cupsFilePrintf(fp
, "StateTime %d\n", (int)pclass
->state_time
);
770 if (pclass
->accepting
)
771 cupsFilePuts(fp
, "Accepting Yes\n");
773 cupsFilePuts(fp
, "Accepting No\n");
776 cupsFilePuts(fp
, "Shared Yes\n");
778 cupsFilePuts(fp
, "Shared No\n");
780 snprintf(value
, sizeof(value
), "%s %s", pclass
->job_sheets
[0],
781 pclass
->job_sheets
[1]);
782 cupsFilePutConf(fp
, "JobSheets", value
);
784 for (i
= 0; i
< pclass
->num_printers
; i
++)
785 cupsFilePrintf(fp
, "Printer %s\n", pclass
->printers
[i
]->name
);
787 cupsFilePrintf(fp
, "QuotaPeriod %d\n", pclass
->quota_period
);
788 cupsFilePrintf(fp
, "PageLimit %d\n", pclass
->page_limit
);
789 cupsFilePrintf(fp
, "KLimit %d\n", pclass
->k_limit
);
791 for (name
= (char *)cupsArrayFirst(pclass
->users
);
793 name
= (char *)cupsArrayNext(pclass
->users
))
794 cupsFilePutConf(fp
, pclass
->deny_users
? "DenyUser" : "AllowUser", name
);
796 if (pclass
->op_policy
)
797 cupsFilePutConf(fp
, "OpPolicy", pclass
->op_policy
);
798 if (pclass
->error_policy
)
799 cupsFilePutConf(fp
, "ErrorPolicy", pclass
->error_policy
);
801 for (i
= pclass
->num_options
, option
= pclass
->options
;
805 snprintf(value
, sizeof(value
), "%s %s", option
->name
, option
->value
);
806 cupsFilePutConf(fp
, "Option", value
);
809 cupsFilePuts(fp
, "</Class>\n");
812 cupsdCloseCreatedConfFile(fp
, filename
);
817 * End of "$Id: classes.c 10996 2013-05-29 11:51:34Z msweet $".