]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
2 * Printer class routines for the CUPS scheduler.
4 * Copyright 2007-2017 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
11 * Include necessary headers...
18 * 'cupsdAddClass()' - Add a class to the system.
21 cupsd_printer_t
* /* O - New class */
22 cupsdAddClass(const char *name
) /* I - Name of class */
24 cupsd_printer_t
*c
; /* New class */
25 char uri
[1024]; /* Class URI */
29 * Add the printer and set the type to "class"...
32 if ((c
= cupsdAddPrinter(name
)) != NULL
)
35 * Change from a printer to a class...
38 c
->type
= CUPS_PRINTER_CLASS
;
40 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
41 ServerName
, RemotePort
, "/classes/%s", name
);
42 cupsdSetString(&c
->uri
, uri
);
44 cupsdSetString(&c
->error_policy
, "retry-current-job");
52 * 'cupsdAddPrinterToClass()' - Add a printer to a class...
56 cupsdAddPrinterToClass(
57 cupsd_printer_t
*c
, /* I - Class to add to */
58 cupsd_printer_t
*p
) /* I - Printer to add */
60 int i
; /* Looping var */
61 cupsd_printer_t
**temp
; /* Pointer to printer array */
65 * See if this printer is already a member of the class...
68 for (i
= 0; i
< c
->num_printers
; i
++)
69 if (c
->printers
[i
] == p
)
73 * Allocate memory as needed...
76 if (c
->num_printers
== 0)
77 temp
= malloc(sizeof(cupsd_printer_t
*));
79 temp
= realloc(c
->printers
, sizeof(cupsd_printer_t
*) * (size_t)(c
->num_printers
+ 1));
83 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to add printer %s to class %s!",
89 * Add the printer to the end of the array and update the number of printers.
93 temp
+= c
->num_printers
;
101 * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
104 int /* O - 1 if class changed, 0 otherwise */
105 cupsdDeletePrinterFromClass(
106 cupsd_printer_t
*c
, /* I - Class to delete from */
107 cupsd_printer_t
*p
) /* I - Printer to delete */
109 int i
; /* Looping var */
113 * See if the printer is in the class...
116 for (i
= 0; i
< c
->num_printers
; i
++)
117 if (p
== c
->printers
[i
])
121 * If it is, remove it from the list...
124 if (i
< c
->num_printers
)
127 * Yes, remove the printer...
131 if (i
< c
->num_printers
)
132 memmove(c
->printers
+ i
, c
->printers
+ i
+ 1,
133 (size_t)(c
->num_printers
- i
) * sizeof(cupsd_printer_t
*));
139 * Update the IPP attributes (have to do this for member-names)...
142 cupsdSetPrinterAttrs(c
);
149 * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
152 int /* O - 1 if class changed, 0 otherwise */
153 cupsdDeletePrinterFromClasses(
154 cupsd_printer_t
*p
) /* I - Printer to delete */
156 int changed
= 0; /* Any class changed? */
157 cupsd_printer_t
*c
; /* Pointer to current class */
161 * Loop through the printer/class list and remove the printer
162 * from each class listed...
165 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
167 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
168 if (c
->type
& CUPS_PRINTER_CLASS
)
169 changed
|= cupsdDeletePrinterFromClass(c
, p
);
176 * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
179 cupsd_printer_t
* /* O - Available printer or NULL */
180 cupsdFindAvailablePrinter(
181 const char *name
) /* I - Class to check */
183 int i
; /* Looping var */
184 cupsd_printer_t
*c
; /* Printer class */
191 if ((c
= cupsdFindClass(name
)) == NULL
)
193 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to find class \"%s\"!", name
);
197 if (c
->num_printers
== 0)
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...
205 if (c
->last_printer
>= c
->num_printers
)
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...)
214 * Thanks to Joel Fredrikson for helping us get this right!
217 for (i
= c
->last_printer
+ 1; ; i
++)
219 if (i
>= c
->num_printers
)
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
)))
227 return (c
->printers
[i
]);
230 if (i
== c
->last_printer
)
239 * 'cupsdFindClass()' - Find the named class.
242 cupsd_printer_t
* /* O - Matching class or NULL */
243 cupsdFindClass(const char *name
) /* I - Name of class */
245 cupsd_printer_t
*c
; /* Current class/printer */
248 if ((c
= cupsdFindDest(name
)) != NULL
&& (c
->type
& CUPS_PRINTER_CLASS
))
256 * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
260 cupsdLoadAllClasses(void)
262 int i
; /* Looping var */
263 cups_file_t
*fp
; /* classes.conf file */
264 int linenum
; /* Current line number */
265 char line
[4096], /* Line from file */
266 *value
, /* Pointer to value */
267 *valueptr
; /* Pointer into value */
268 cupsd_printer_t
*p
, /* Current printer class */
269 *temp
; /* Temporary pointer to printer */
273 * Open the classes.conf file...
276 snprintf(line
, sizeof(line
), "%s/classes.conf", ServerRoot
);
277 if ((fp
= cupsdOpenConfFile(line
)) == NULL
)
281 * Read class configurations until we hit EOF...
287 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
290 * Decode the directive...
293 if (!_cups_strcasecmp(line
, "<Class") ||
294 !_cups_strcasecmp(line
, "<DefaultClass"))
297 * <Class name> or <DefaultClass name>
300 if (p
== NULL
&& value
)
302 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Loading class %s...", value
);
305 * Since prior classes may have implicitly defined this class,
306 * see if it already exists...
309 if ((p
= cupsdFindDest(value
)) != NULL
)
311 p
->type
= CUPS_PRINTER_CLASS
;
312 cupsdSetStringf(&p
->uri
, "ipp://%s:%d/classes/%s", ServerName
,
314 cupsdSetString(&p
->error_policy
, "retry-job");
317 p
= cupsdAddClass(value
);
320 p
->state
= IPP_PRINTER_IDLE
;
322 if (!_cups_strcasecmp(line
, "<DefaultClass"))
326 cupsdLogMessage(CUPSD_LOG_ERROR
,
327 "Syntax error on line %d of classes.conf.", linenum
);
329 else if (!_cups_strcasecmp(line
, "</Class>") || !_cups_strcasecmp(line
, "</DefaultClass>"))
333 cupsdSetPrinterAttrs(p
);
337 cupsdLogMessage(CUPSD_LOG_ERROR
,
338 "Syntax error on line %d of classes.conf.", linenum
);
342 cupsdLogMessage(CUPSD_LOG_ERROR
,
343 "Syntax error on line %d of classes.conf.", linenum
);
345 else if (!_cups_strcasecmp(line
, "PrinterId"))
347 if (value
&& (i
= atoi(value
)) > 0)
350 cupsdLogMessage(CUPSD_LOG_ERROR
, "Bad PrinterId on line %d of classes.conf.", linenum
);
352 else if (!_cups_strcasecmp(line
, "UUID"))
354 if (value
&& !strncmp(value
, "urn:uuid:", 9))
355 cupsdSetString(&(p
->uuid
), value
);
357 cupsdLogMessage(CUPSD_LOG_ERROR
,
358 "Bad UUID on line %d of classes.conf.", linenum
);
360 else if (!_cups_strcasecmp(line
, "AuthInfoRequired"))
362 if (!cupsdSetAuthInfoRequired(p
, value
, NULL
))
363 cupsdLogMessage(CUPSD_LOG_ERROR
,
364 "Bad AuthInfoRequired on line %d of classes.conf.",
367 else if (!_cups_strcasecmp(line
, "Info"))
370 cupsdSetString(&p
->info
, value
);
372 else if (!_cups_strcasecmp(line
, "Location"))
375 cupsdSetString(&p
->location
, value
);
377 else if (!_cups_strcasecmp(line
, "Option") && value
)
383 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
386 cupsdLogMessage(CUPSD_LOG_ERROR
,
387 "Syntax error on line %d of classes.conf.", linenum
);
390 for (; *valueptr
&& isspace(*valueptr
& 255); *valueptr
++ = '\0');
392 p
->num_options
= cupsAddOption(value
, valueptr
, p
->num_options
,
396 else if (!_cups_strcasecmp(line
, "Printer"))
400 cupsdLogMessage(CUPSD_LOG_ERROR
,
401 "Syntax error on line %d of classes.conf.", linenum
);
404 else if ((temp
= cupsdFindPrinter(value
)) == NULL
)
406 cupsdLogMessage(CUPSD_LOG_WARN
,
407 "Unknown printer %s on line %d of classes.conf.",
411 * Add the missing remote printer...
414 if ((temp
= cupsdAddPrinter(value
)) != NULL
)
416 cupsdSetString(&temp
->make_model
, "Remote Printer on unknown");
418 temp
->state
= IPP_PRINTER_STOPPED
;
419 temp
->type
|= CUPS_PRINTER_REMOTE
;
421 cupsdSetString(&temp
->location
, "Location Unknown");
422 cupsdSetString(&temp
->info
, "No Information Available");
423 temp
->hostname
[0] = '\0';
425 cupsdSetPrinterAttrs(temp
);
430 cupsdAddPrinterToClass(p
, temp
);
432 else if (!_cups_strcasecmp(line
, "State"))
435 * Set the initial queue state...
438 if (!_cups_strcasecmp(value
, "idle"))
439 p
->state
= IPP_PRINTER_IDLE
;
440 else if (!_cups_strcasecmp(value
, "stopped"))
442 p
->state
= IPP_PRINTER_STOPPED
;
444 for (i
= 0 ; i
< p
->num_reasons
; i
++)
445 if (!strcmp("paused", p
->reasons
[i
]))
448 if (i
>= p
->num_reasons
&&
449 p
->num_reasons
< (int)(sizeof(p
->reasons
) / sizeof(p
->reasons
[0])))
451 p
->reasons
[p
->num_reasons
] = _cupsStrAlloc("paused");
456 cupsdLogMessage(CUPSD_LOG_ERROR
,
457 "Syntax error on line %d of classes.conf.",
460 else if (!_cups_strcasecmp(line
, "StateMessage"))
463 * Set the initial queue state message...
467 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
469 else if (!_cups_strcasecmp(line
, "StateTime"))
472 * Set the state time...
476 p
->state_time
= atoi(value
);
478 else if (!_cups_strcasecmp(line
, "Accepting"))
481 * Set the initial accepting state...
485 (!_cups_strcasecmp(value
, "yes") ||
486 !_cups_strcasecmp(value
, "on") ||
487 !_cups_strcasecmp(value
, "true")))
490 (!_cups_strcasecmp(value
, "no") ||
491 !_cups_strcasecmp(value
, "off") ||
492 !_cups_strcasecmp(value
, "false")))
495 cupsdLogMessage(CUPSD_LOG_ERROR
,
496 "Syntax error on line %d of classes.conf.",
499 else if (!_cups_strcasecmp(line
, "Shared"))
502 * Set the initial shared state...
506 (!_cups_strcasecmp(value
, "yes") ||
507 !_cups_strcasecmp(value
, "on") ||
508 !_cups_strcasecmp(value
, "true")))
511 (!_cups_strcasecmp(value
, "no") ||
512 !_cups_strcasecmp(value
, "off") ||
513 !_cups_strcasecmp(value
, "false")))
516 cupsdLogMessage(CUPSD_LOG_ERROR
,
517 "Syntax error on line %d of classes.conf.",
520 else if (!_cups_strcasecmp(line
, "JobSheets"))
523 * Set the initial job sheets...
528 for (valueptr
= value
;
529 *valueptr
&& !isspace(*valueptr
& 255);
535 cupsdSetString(&p
->job_sheets
[0], value
);
537 while (isspace(*valueptr
& 255))
542 for (value
= valueptr
;
543 *valueptr
&& !isspace(*valueptr
& 255);
549 cupsdSetString(&p
->job_sheets
[1], value
);
553 cupsdLogMessage(CUPSD_LOG_ERROR
,
554 "Syntax error on line %d of classes.conf.", linenum
);
556 else if (!_cups_strcasecmp(line
, "AllowUser"))
561 cupsdAddString(&(p
->users
), value
);
564 cupsdLogMessage(CUPSD_LOG_ERROR
,
565 "Syntax error on line %d of classes.conf.", linenum
);
567 else if (!_cups_strcasecmp(line
, "DenyUser"))
572 cupsdAddString(&(p
->users
), value
);
575 cupsdLogMessage(CUPSD_LOG_ERROR
,
576 "Syntax error on line %d of classes.conf.", linenum
);
578 else if (!_cups_strcasecmp(line
, "QuotaPeriod"))
581 p
->quota_period
= atoi(value
);
583 cupsdLogMessage(CUPSD_LOG_ERROR
,
584 "Syntax error on line %d of classes.conf.", linenum
);
586 else if (!_cups_strcasecmp(line
, "PageLimit"))
589 p
->page_limit
= atoi(value
);
591 cupsdLogMessage(CUPSD_LOG_ERROR
,
592 "Syntax error on line %d of classes.conf.", linenum
);
594 else if (!_cups_strcasecmp(line
, "KLimit"))
597 p
->k_limit
= atoi(value
);
599 cupsdLogMessage(CUPSD_LOG_ERROR
,
600 "Syntax error on line %d of classes.conf.", linenum
);
602 else if (!_cups_strcasecmp(line
, "OpPolicy"))
606 cupsd_policy_t
*pol
; /* Policy */
609 if ((pol
= cupsdFindPolicy(value
)) != NULL
)
611 cupsdSetString(&p
->op_policy
, value
);
612 p
->op_policy_ptr
= pol
;
615 cupsdLogMessage(CUPSD_LOG_ERROR
,
616 "Bad policy \"%s\" on line %d of classes.conf",
620 cupsdLogMessage(CUPSD_LOG_ERROR
,
621 "Syntax error on line %d of classes.conf.", linenum
);
623 else if (!_cups_strcasecmp(line
, "ErrorPolicy"))
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",
633 cupsdLogMessage(CUPSD_LOG_ERROR
,
634 "Syntax error on line %d of classes.conf.", linenum
);
639 * Something else we don't understand...
642 cupsdLogMessage(CUPSD_LOG_ERROR
,
643 "Unknown configuration directive %s on line %d of classes.conf.",
653 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
657 cupsdSaveAllClasses(void)
659 cups_file_t
*fp
; /* classes.conf file */
660 char filename
[1024], /* classes.conf filename */
661 temp
[1024], /* Temporary string */
662 value
[2048], /* Value string */
663 *name
; /* Current user name */
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 */
668 cups_option_t
*option
; /* Current option */
672 * Create the classes.conf file...
675 snprintf(filename
, sizeof(filename
), "%s/classes.conf", ServerRoot
);
677 if ((fp
= cupsdCreateConfFile(filename
, ConfigFilePerm
)) == NULL
)
680 cupsdLogMessage(CUPSD_LOG_INFO
, "Saving classes.conf...");
683 * Write a small header to the file...
686 curtime
= time(NULL
);
687 curdate
= localtime(&curtime
);
688 strftime(temp
, sizeof(temp
) - 1, "%Y-%m-%d %H:%M", curdate
);
690 cupsFilePuts(fp
, "# Class configuration file for " CUPS_SVERSION
"\n");
691 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
692 cupsFilePuts(fp
, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
695 * Write each local class known to the system...
698 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
700 pclass
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
703 * Skip remote destinations and regular printers...
706 if ((pclass
->type
& CUPS_PRINTER_REMOTE
) ||
707 !(pclass
->type
& CUPS_PRINTER_CLASS
))
711 * Write printers as needed...
714 if (pclass
== DefaultPrinter
)
715 cupsFilePrintf(fp
, "<DefaultClass %s>\n", pclass
->name
);
717 cupsFilePrintf(fp
, "<Class %s>\n", pclass
->name
);
719 if (pclass
->printer_id
)
720 cupsFilePrintf(fp
, "PrinterId %d\n", pclass
->printer_id
);
722 cupsFilePrintf(fp
, "UUID %s\n", pclass
->uuid
);
724 if (pclass
->num_auth_info_required
> 0)
726 switch (pclass
->num_auth_info_required
)
729 strlcpy(value
, pclass
->auth_info_required
[0], sizeof(value
));
733 snprintf(value
, sizeof(value
), "%s,%s",
734 pclass
->auth_info_required
[0],
735 pclass
->auth_info_required
[1]);
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]);
747 cupsFilePutConf(fp
, "AuthInfoRequired", value
);
751 cupsFilePutConf(fp
, "Info", pclass
->info
);
753 if (pclass
->location
)
754 cupsFilePutConf(fp
, "Location", pclass
->location
);
756 if (pclass
->state
== IPP_PRINTER_STOPPED
)
757 cupsFilePuts(fp
, "State Stopped\n");
759 cupsFilePuts(fp
, "State Idle\n");
761 cupsFilePrintf(fp
, "StateTime %d\n", (int)pclass
->state_time
);
763 if (pclass
->accepting
)
764 cupsFilePuts(fp
, "Accepting Yes\n");
766 cupsFilePuts(fp
, "Accepting No\n");
769 cupsFilePuts(fp
, "Shared Yes\n");
771 cupsFilePuts(fp
, "Shared No\n");
773 snprintf(value
, sizeof(value
), "%s %s", pclass
->job_sheets
[0],
774 pclass
->job_sheets
[1]);
775 cupsFilePutConf(fp
, "JobSheets", value
);
777 for (i
= 0; i
< pclass
->num_printers
; i
++)
778 cupsFilePrintf(fp
, "Printer %s\n", pclass
->printers
[i
]->name
);
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
);
784 for (name
= (char *)cupsArrayFirst(pclass
->users
);
786 name
= (char *)cupsArrayNext(pclass
->users
))
787 cupsFilePutConf(fp
, pclass
->deny_users
? "DenyUser" : "AllowUser", name
);
789 if (pclass
->op_policy
)
790 cupsFilePutConf(fp
, "OpPolicy", pclass
->op_policy
);
791 if (pclass
->error_policy
)
792 cupsFilePutConf(fp
, "ErrorPolicy", pclass
->error_policy
);
794 for (i
= pclass
->num_options
, option
= pclass
->options
;
798 snprintf(value
, sizeof(value
), "%s %s", option
->name
, option
->value
);
799 cupsFilePutConf(fp
, "Option", value
);
802 if (pclass
== DefaultPrinter
)
803 cupsFilePuts(fp
, "</DefaultClass>\n");
805 cupsFilePuts(fp
, "</Class>\n");
808 cupsdCloseCreatedConfFile(fp
, filename
);