]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
2 * Printer class routines for the CUPS scheduler.
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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
11 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * Include necessary headers...
22 * 'cupsdAddClass()' - Add a class to the system.
25 cupsd_printer_t
* /* O - New class */
26 cupsdAddClass(const char *name
) /* I - Name of class */
28 cupsd_printer_t
*c
; /* New class */
29 char uri
[1024]; /* Class URI */
33 * Add the printer and set the type to "class"...
36 if ((c
= cupsdAddPrinter(name
)) != NULL
)
39 * Change from a printer to a class...
42 c
->type
= CUPS_PRINTER_CLASS
;
44 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
45 ServerName
, RemotePort
, "/classes/%s", name
);
46 cupsdSetString(&c
->uri
, uri
);
48 cupsdSetString(&c
->error_policy
, "retry-current-job");
56 * 'cupsdAddPrinterToClass()' - Add a printer to a class...
60 cupsdAddPrinterToClass(
61 cupsd_printer_t
*c
, /* I - Class to add to */
62 cupsd_printer_t
*p
) /* I - Printer to add */
64 int i
; /* Looping var */
65 cupsd_printer_t
**temp
; /* Pointer to printer array */
69 * See if this printer is already a member of the class...
72 for (i
= 0; i
< c
->num_printers
; i
++)
73 if (c
->printers
[i
] == p
)
77 * Allocate memory as needed...
80 if (c
->num_printers
== 0)
81 temp
= malloc(sizeof(cupsd_printer_t
*));
83 temp
= realloc(c
->printers
, sizeof(cupsd_printer_t
*) * (size_t)(c
->num_printers
+ 1));
87 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to add printer %s to class %s!",
93 * Add the printer to the end of the array and update the number of printers.
97 temp
+= c
->num_printers
;
105 * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
108 int /* O - 1 if class changed, 0 otherwise */
109 cupsdDeletePrinterFromClass(
110 cupsd_printer_t
*c
, /* I - Class to delete from */
111 cupsd_printer_t
*p
) /* I - Printer to delete */
113 int i
; /* Looping var */
117 * See if the printer is in the class...
120 for (i
= 0; i
< c
->num_printers
; i
++)
121 if (p
== c
->printers
[i
])
125 * If it is, remove it from the list...
128 if (i
< c
->num_printers
)
131 * Yes, remove the printer...
135 if (i
< c
->num_printers
)
136 memmove(c
->printers
+ i
, c
->printers
+ i
+ 1,
137 (size_t)(c
->num_printers
- i
) * sizeof(cupsd_printer_t
*));
143 * Update the IPP attributes (have to do this for member-names)...
146 cupsdSetPrinterAttrs(c
);
153 * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
156 int /* O - 1 if class changed, 0 otherwise */
157 cupsdDeletePrinterFromClasses(
158 cupsd_printer_t
*p
) /* I - Printer to delete */
160 int changed
= 0; /* Any class changed? */
161 cupsd_printer_t
*c
; /* Pointer to current class */
165 * Loop through the printer/class list and remove the printer
166 * from each class listed...
169 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
171 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
172 if (c
->type
& CUPS_PRINTER_CLASS
)
173 changed
|= cupsdDeletePrinterFromClass(c
, p
);
180 * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
183 cupsd_printer_t
* /* O - Available printer or NULL */
184 cupsdFindAvailablePrinter(
185 const char *name
) /* I - Class to check */
187 int i
; /* Looping var */
188 cupsd_printer_t
*c
; /* Printer class */
195 if ((c
= cupsdFindClass(name
)) == NULL
)
197 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to find class \"%s\"!", name
);
201 if (c
->num_printers
== 0)
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...
209 if (c
->last_printer
>= c
->num_printers
)
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...)
218 * Thanks to Joel Fredrikson for helping us get this right!
221 for (i
= c
->last_printer
+ 1; ; i
++)
223 if (i
>= c
->num_printers
)
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
)))
231 return (c
->printers
[i
]);
234 if (i
== c
->last_printer
)
243 * 'cupsdFindClass()' - Find the named class.
246 cupsd_printer_t
* /* O - Matching class or NULL */
247 cupsdFindClass(const char *name
) /* I - Name of class */
249 cupsd_printer_t
*c
; /* Current class/printer */
252 if ((c
= cupsdFindDest(name
)) != NULL
&& (c
->type
& CUPS_PRINTER_CLASS
))
260 * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
264 cupsdLoadAllClasses(void)
266 int i
; /* Looping var */
267 cups_file_t
*fp
; /* classes.conf file */
268 int linenum
; /* Current line number */
269 char line
[4096], /* Line from file */
270 *value
, /* Pointer to value */
271 *valueptr
; /* Pointer into value */
272 cupsd_printer_t
*p
, /* Current printer class */
273 *temp
; /* Temporary pointer to printer */
277 * Open the classes.conf file...
280 snprintf(line
, sizeof(line
), "%s/classes.conf", ServerRoot
);
281 if ((fp
= cupsdOpenConfFile(line
)) == NULL
)
285 * Read class configurations until we hit EOF...
291 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
294 * Decode the directive...
297 if (!_cups_strcasecmp(line
, "<Class") ||
298 !_cups_strcasecmp(line
, "<DefaultClass"))
301 * <Class name> or <DefaultClass name>
304 if (p
== NULL
&& value
)
306 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Loading class %s...", value
);
309 * Since prior classes may have implicitly defined this class,
310 * see if it already exists...
313 if ((p
= cupsdFindDest(value
)) != NULL
)
315 p
->type
= CUPS_PRINTER_CLASS
;
316 cupsdSetStringf(&p
->uri
, "ipp://%s:%d/classes/%s", ServerName
,
318 cupsdSetString(&p
->error_policy
, "retry-job");
321 p
= cupsdAddClass(value
);
324 p
->state
= IPP_PRINTER_IDLE
;
326 if (!_cups_strcasecmp(line
, "<DefaultClass"))
330 cupsdLogMessage(CUPSD_LOG_ERROR
,
331 "Syntax error on line %d of classes.conf.", linenum
);
333 else if (!_cups_strcasecmp(line
, "</Class>") || !_cups_strcasecmp(line
, "</DefaultClass>"))
337 cupsdSetPrinterAttrs(p
);
341 cupsdLogMessage(CUPSD_LOG_ERROR
,
342 "Syntax error on line %d of classes.conf.", linenum
);
346 cupsdLogMessage(CUPSD_LOG_ERROR
,
347 "Syntax error on line %d of classes.conf.", linenum
);
349 else if (!_cups_strcasecmp(line
, "UUID"))
351 if (value
&& !strncmp(value
, "urn:uuid:", 9))
352 cupsdSetString(&(p
->uuid
), value
);
354 cupsdLogMessage(CUPSD_LOG_ERROR
,
355 "Bad UUID on line %d of classes.conf.", linenum
);
357 else if (!_cups_strcasecmp(line
, "AuthInfoRequired"))
359 if (!cupsdSetAuthInfoRequired(p
, value
, NULL
))
360 cupsdLogMessage(CUPSD_LOG_ERROR
,
361 "Bad AuthInfoRequired on line %d of classes.conf.",
364 else if (!_cups_strcasecmp(line
, "Info"))
367 cupsdSetString(&p
->info
, value
);
369 else if (!_cups_strcasecmp(line
, "Location"))
372 cupsdSetString(&p
->location
, value
);
374 else if (!_cups_strcasecmp(line
, "Option") && value
)
380 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
383 cupsdLogMessage(CUPSD_LOG_ERROR
,
384 "Syntax error on line %d of classes.conf.", linenum
);
387 for (; *valueptr
&& isspace(*valueptr
& 255); *valueptr
++ = '\0');
389 p
->num_options
= cupsAddOption(value
, valueptr
, p
->num_options
,
393 else if (!_cups_strcasecmp(line
, "Printer"))
397 cupsdLogMessage(CUPSD_LOG_ERROR
,
398 "Syntax error on line %d of classes.conf.", linenum
);
401 else if ((temp
= cupsdFindPrinter(value
)) == NULL
)
403 cupsdLogMessage(CUPSD_LOG_WARN
,
404 "Unknown printer %s on line %d of classes.conf.",
408 * Add the missing remote printer...
411 if ((temp
= cupsdAddPrinter(value
)) != NULL
)
413 cupsdSetString(&temp
->make_model
, "Remote Printer on unknown");
415 temp
->state
= IPP_PRINTER_STOPPED
;
416 temp
->type
|= CUPS_PRINTER_REMOTE
;
418 cupsdSetString(&temp
->location
, "Location Unknown");
419 cupsdSetString(&temp
->info
, "No Information Available");
420 temp
->hostname
[0] = '\0';
422 cupsdSetPrinterAttrs(temp
);
427 cupsdAddPrinterToClass(p
, temp
);
429 else if (!_cups_strcasecmp(line
, "State"))
432 * Set the initial queue state...
435 if (!_cups_strcasecmp(value
, "idle"))
436 p
->state
= IPP_PRINTER_IDLE
;
437 else if (!_cups_strcasecmp(value
, "stopped"))
439 p
->state
= IPP_PRINTER_STOPPED
;
441 for (i
= 0 ; i
< p
->num_reasons
; i
++)
442 if (!strcmp("paused", p
->reasons
[i
]))
445 if (i
>= p
->num_reasons
&&
446 p
->num_reasons
< (int)(sizeof(p
->reasons
) / sizeof(p
->reasons
[0])))
448 p
->reasons
[p
->num_reasons
] = _cupsStrAlloc("paused");
453 cupsdLogMessage(CUPSD_LOG_ERROR
,
454 "Syntax error on line %d of classes.conf.",
457 else if (!_cups_strcasecmp(line
, "StateMessage"))
460 * Set the initial queue state message...
464 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
466 else if (!_cups_strcasecmp(line
, "StateTime"))
469 * Set the state time...
473 p
->state_time
= atoi(value
);
475 else if (!_cups_strcasecmp(line
, "Accepting"))
478 * Set the initial accepting state...
482 (!_cups_strcasecmp(value
, "yes") ||
483 !_cups_strcasecmp(value
, "on") ||
484 !_cups_strcasecmp(value
, "true")))
487 (!_cups_strcasecmp(value
, "no") ||
488 !_cups_strcasecmp(value
, "off") ||
489 !_cups_strcasecmp(value
, "false")))
492 cupsdLogMessage(CUPSD_LOG_ERROR
,
493 "Syntax error on line %d of classes.conf.",
496 else if (!_cups_strcasecmp(line
, "Shared"))
499 * Set the initial shared state...
503 (!_cups_strcasecmp(value
, "yes") ||
504 !_cups_strcasecmp(value
, "on") ||
505 !_cups_strcasecmp(value
, "true")))
508 (!_cups_strcasecmp(value
, "no") ||
509 !_cups_strcasecmp(value
, "off") ||
510 !_cups_strcasecmp(value
, "false")))
513 cupsdLogMessage(CUPSD_LOG_ERROR
,
514 "Syntax error on line %d of classes.conf.",
517 else if (!_cups_strcasecmp(line
, "JobSheets"))
520 * Set the initial job sheets...
525 for (valueptr
= value
;
526 *valueptr
&& !isspace(*valueptr
& 255);
532 cupsdSetString(&p
->job_sheets
[0], value
);
534 while (isspace(*valueptr
& 255))
539 for (value
= valueptr
;
540 *valueptr
&& !isspace(*valueptr
& 255);
546 cupsdSetString(&p
->job_sheets
[1], value
);
550 cupsdLogMessage(CUPSD_LOG_ERROR
,
551 "Syntax error on line %d of classes.conf.", linenum
);
553 else if (!_cups_strcasecmp(line
, "AllowUser"))
558 cupsdAddString(&(p
->users
), value
);
561 cupsdLogMessage(CUPSD_LOG_ERROR
,
562 "Syntax error on line %d of classes.conf.", linenum
);
564 else if (!_cups_strcasecmp(line
, "DenyUser"))
569 cupsdAddString(&(p
->users
), value
);
572 cupsdLogMessage(CUPSD_LOG_ERROR
,
573 "Syntax error on line %d of classes.conf.", linenum
);
575 else if (!_cups_strcasecmp(line
, "QuotaPeriod"))
578 p
->quota_period
= atoi(value
);
580 cupsdLogMessage(CUPSD_LOG_ERROR
,
581 "Syntax error on line %d of classes.conf.", linenum
);
583 else if (!_cups_strcasecmp(line
, "PageLimit"))
586 p
->page_limit
= atoi(value
);
588 cupsdLogMessage(CUPSD_LOG_ERROR
,
589 "Syntax error on line %d of classes.conf.", linenum
);
591 else if (!_cups_strcasecmp(line
, "KLimit"))
594 p
->k_limit
= atoi(value
);
596 cupsdLogMessage(CUPSD_LOG_ERROR
,
597 "Syntax error on line %d of classes.conf.", linenum
);
599 else if (!_cups_strcasecmp(line
, "OpPolicy"))
603 cupsd_policy_t
*pol
; /* Policy */
606 if ((pol
= cupsdFindPolicy(value
)) != NULL
)
608 cupsdSetString(&p
->op_policy
, value
);
609 p
->op_policy_ptr
= pol
;
612 cupsdLogMessage(CUPSD_LOG_ERROR
,
613 "Bad policy \"%s\" on line %d of classes.conf",
617 cupsdLogMessage(CUPSD_LOG_ERROR
,
618 "Syntax error on line %d of classes.conf.", linenum
);
620 else if (!_cups_strcasecmp(line
, "ErrorPolicy"))
624 if (strcmp(value
, "retry-current-job") && strcmp(value
, "retry-job"))
625 cupsdLogMessage(CUPSD_LOG_WARN
,
626 "ErrorPolicy %s ignored on line %d of classes.conf",
630 cupsdLogMessage(CUPSD_LOG_ERROR
,
631 "Syntax error on line %d of classes.conf.", linenum
);
636 * Something else we don't understand...
639 cupsdLogMessage(CUPSD_LOG_ERROR
,
640 "Unknown configuration directive %s on line %d of classes.conf.",
650 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
654 cupsdSaveAllClasses(void)
656 cups_file_t
*fp
; /* classes.conf file */
657 char filename
[1024], /* classes.conf filename */
658 temp
[1024], /* Temporary string */
659 value
[2048], /* Value string */
660 *name
; /* Current user name */
661 cupsd_printer_t
*pclass
; /* Current printer class */
662 int i
; /* Looping var */
663 time_t curtime
; /* Current time */
664 struct tm
*curdate
; /* Current date */
665 cups_option_t
*option
; /* Current option */
669 * Create the classes.conf file...
672 snprintf(filename
, sizeof(filename
), "%s/classes.conf", ServerRoot
);
674 if ((fp
= cupsdCreateConfFile(filename
, ConfigFilePerm
)) == NULL
)
677 cupsdLogMessage(CUPSD_LOG_INFO
, "Saving classes.conf...");
680 * Write a small header to the file...
683 curtime
= time(NULL
);
684 curdate
= localtime(&curtime
);
685 strftime(temp
, sizeof(temp
) - 1, "%Y-%m-%d %H:%M", curdate
);
687 cupsFilePuts(fp
, "# Class configuration file for " CUPS_SVERSION
"\n");
688 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
689 cupsFilePuts(fp
, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
692 * Write each local class known to the system...
695 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
697 pclass
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
700 * Skip remote destinations and regular printers...
703 if ((pclass
->type
& CUPS_PRINTER_REMOTE
) ||
704 !(pclass
->type
& CUPS_PRINTER_CLASS
))
708 * Write printers as needed...
711 if (pclass
== DefaultPrinter
)
712 cupsFilePrintf(fp
, "<DefaultClass %s>\n", pclass
->name
);
714 cupsFilePrintf(fp
, "<Class %s>\n", pclass
->name
);
716 cupsFilePrintf(fp
, "UUID %s\n", pclass
->uuid
);
718 if (pclass
->num_auth_info_required
> 0)
720 switch (pclass
->num_auth_info_required
)
723 strlcpy(value
, pclass
->auth_info_required
[0], sizeof(value
));
727 snprintf(value
, sizeof(value
), "%s,%s",
728 pclass
->auth_info_required
[0],
729 pclass
->auth_info_required
[1]);
734 snprintf(value
, sizeof(value
), "%s,%s,%s",
735 pclass
->auth_info_required
[0],
736 pclass
->auth_info_required
[1],
737 pclass
->auth_info_required
[2]);
741 cupsFilePutConf(fp
, "AuthInfoRequired", value
);
745 cupsFilePutConf(fp
, "Info", pclass
->info
);
747 if (pclass
->location
)
748 cupsFilePutConf(fp
, "Location", pclass
->location
);
750 if (pclass
->state
== IPP_PRINTER_STOPPED
)
751 cupsFilePuts(fp
, "State Stopped\n");
753 cupsFilePuts(fp
, "State Idle\n");
755 cupsFilePrintf(fp
, "StateTime %d\n", (int)pclass
->state_time
);
757 if (pclass
->accepting
)
758 cupsFilePuts(fp
, "Accepting Yes\n");
760 cupsFilePuts(fp
, "Accepting No\n");
763 cupsFilePuts(fp
, "Shared Yes\n");
765 cupsFilePuts(fp
, "Shared No\n");
767 snprintf(value
, sizeof(value
), "%s %s", pclass
->job_sheets
[0],
768 pclass
->job_sheets
[1]);
769 cupsFilePutConf(fp
, "JobSheets", value
);
771 for (i
= 0; i
< pclass
->num_printers
; i
++)
772 cupsFilePrintf(fp
, "Printer %s\n", pclass
->printers
[i
]->name
);
774 cupsFilePrintf(fp
, "QuotaPeriod %d\n", pclass
->quota_period
);
775 cupsFilePrintf(fp
, "PageLimit %d\n", pclass
->page_limit
);
776 cupsFilePrintf(fp
, "KLimit %d\n", pclass
->k_limit
);
778 for (name
= (char *)cupsArrayFirst(pclass
->users
);
780 name
= (char *)cupsArrayNext(pclass
->users
))
781 cupsFilePutConf(fp
, pclass
->deny_users
? "DenyUser" : "AllowUser", name
);
783 if (pclass
->op_policy
)
784 cupsFilePutConf(fp
, "OpPolicy", pclass
->op_policy
);
785 if (pclass
->error_policy
)
786 cupsFilePutConf(fp
, "ErrorPolicy", pclass
->error_policy
);
788 for (i
= pclass
->num_options
, option
= pclass
->options
;
792 snprintf(value
, sizeof(value
), "%s %s", option
->name
, option
->value
);
793 cupsFilePutConf(fp
, "Option", value
);
796 if (pclass
== DefaultPrinter
)
797 cupsFilePuts(fp
, "</DefaultClass>\n");
799 cupsFilePuts(fp
, "</Class>\n");
802 cupsdCloseCreatedConfFile(fp
, filename
);