]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
4 * Printer class routines for the CUPS scheduler.
6 * Copyright 2007-2014 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 * Include necessary headers...
24 * 'cupsdAddClass()' - Add a class to the system.
27 cupsd_printer_t
* /* O - New class */
28 cupsdAddClass(const char *name
) /* I - Name of class */
30 cupsd_printer_t
*c
; /* New class */
31 char uri
[1024]; /* Class URI */
35 * Add the printer and set the type to "class"...
38 if ((c
= cupsdAddPrinter(name
)) != NULL
)
41 * Change from a printer to a class...
44 c
->type
= CUPS_PRINTER_CLASS
;
46 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
47 ServerName
, RemotePort
, "/classes/%s", name
);
48 cupsdSetString(&c
->uri
, uri
);
50 cupsdSetString(&c
->error_policy
, "retry-current-job");
58 * 'cupsdAddPrinterToClass()' - Add a printer to a class...
62 cupsdAddPrinterToClass(
63 cupsd_printer_t
*c
, /* I - Class to add to */
64 cupsd_printer_t
*p
) /* I - Printer to add */
66 int i
; /* Looping var */
67 cupsd_printer_t
**temp
; /* Pointer to printer array */
71 * See if this printer is already a member of the class...
74 for (i
= 0; i
< c
->num_printers
; i
++)
75 if (c
->printers
[i
] == p
)
79 * Allocate memory as needed...
82 if (c
->num_printers
== 0)
83 temp
= malloc(sizeof(cupsd_printer_t
*));
85 temp
= realloc(c
->printers
, sizeof(cupsd_printer_t
*) * (size_t)(c
->num_printers
+ 1));
89 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to add printer %s to class %s!",
95 * Add the printer to the end of the array and update the number of printers.
99 temp
+= c
->num_printers
;
107 * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
110 int /* O - 1 if class changed, 0 otherwise */
111 cupsdDeletePrinterFromClass(
112 cupsd_printer_t
*c
, /* I - Class to delete from */
113 cupsd_printer_t
*p
) /* I - Printer to delete */
115 int i
; /* Looping var */
119 * See if the printer is in the class...
122 for (i
= 0; i
< c
->num_printers
; i
++)
123 if (p
== c
->printers
[i
])
127 * If it is, remove it from the list...
130 if (i
< c
->num_printers
)
133 * Yes, remove the printer...
137 if (i
< c
->num_printers
)
138 memmove(c
->printers
+ i
, c
->printers
+ i
+ 1,
139 (size_t)(c
->num_printers
- i
) * sizeof(cupsd_printer_t
*));
145 * Update the IPP attributes (have to do this for member-names)...
148 cupsdSetPrinterAttrs(c
);
155 * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
158 int /* O - 1 if class changed, 0 otherwise */
159 cupsdDeletePrinterFromClasses(
160 cupsd_printer_t
*p
) /* I - Printer to delete */
162 int changed
= 0; /* Any class changed? */
163 cupsd_printer_t
*c
; /* Pointer to current class */
167 * Loop through the printer/class list and remove the printer
168 * from each class listed...
171 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
173 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
174 if (c
->type
& CUPS_PRINTER_CLASS
)
175 changed
|= cupsdDeletePrinterFromClass(c
, p
);
182 * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
185 cupsd_printer_t
* /* O - Available printer or NULL */
186 cupsdFindAvailablePrinter(
187 const char *name
) /* I - Class to check */
189 int i
; /* Looping var */
190 cupsd_printer_t
*c
; /* Printer class */
197 if ((c
= cupsdFindClass(name
)) == NULL
)
199 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to find class \"%s\"!", name
);
203 if (c
->num_printers
== 0)
207 * Make sure that the last printer is also a valid index into the printer
208 * array. If not, reset the last printer to 0...
211 if (c
->last_printer
>= c
->num_printers
)
215 * Loop through the printers in the class and return the first idle
216 * printer... We keep track of the last printer that we used so that
217 * a "round robin" type of scheduling is realized (otherwise the first
218 * server might be saturated with print jobs...)
220 * Thanks to Joel Fredrikson for helping us get this right!
223 for (i
= c
->last_printer
+ 1; ; i
++)
225 if (i
>= c
->num_printers
)
228 if (c
->printers
[i
]->accepting
&&
229 (c
->printers
[i
]->state
== IPP_PRINTER_IDLE
||
230 ((c
->printers
[i
]->type
& CUPS_PRINTER_REMOTE
) && !c
->printers
[i
]->job
)))
233 return (c
->printers
[i
]);
236 if (i
== c
->last_printer
)
245 * 'cupsdFindClass()' - Find the named class.
248 cupsd_printer_t
* /* O - Matching class or NULL */
249 cupsdFindClass(const char *name
) /* I - Name of class */
251 cupsd_printer_t
*c
; /* Current class/printer */
254 if ((c
= cupsdFindDest(name
)) != NULL
&& (c
->type
& CUPS_PRINTER_CLASS
))
262 * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
266 cupsdLoadAllClasses(void)
268 int i
; /* Looping var */
269 cups_file_t
*fp
; /* classes.conf file */
270 int linenum
; /* Current line number */
271 char line
[4096], /* Line from file */
272 *value
, /* Pointer to value */
273 *valueptr
; /* Pointer into value */
274 cupsd_printer_t
*p
, /* Current printer class */
275 *temp
; /* Temporary pointer to printer */
279 * Open the classes.conf file...
282 snprintf(line
, sizeof(line
), "%s/classes.conf", ServerRoot
);
283 if ((fp
= cupsdOpenConfFile(line
)) == NULL
)
287 * Read class configurations until we hit EOF...
293 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
296 * Decode the directive...
299 if (!_cups_strcasecmp(line
, "<Class") ||
300 !_cups_strcasecmp(line
, "<DefaultClass"))
303 * <Class name> or <DefaultClass name>
306 if (p
== NULL
&& value
)
308 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Loading class %s...", value
);
311 * Since prior classes may have implicitly defined this class,
312 * see if it already exists...
315 if ((p
= cupsdFindDest(value
)) != NULL
)
317 p
->type
= CUPS_PRINTER_CLASS
;
318 cupsdSetStringf(&p
->uri
, "ipp://%s:%d/classes/%s", ServerName
,
320 cupsdSetString(&p
->error_policy
, "retry-job");
323 p
= cupsdAddClass(value
);
326 p
->state
= IPP_PRINTER_IDLE
;
328 if (!_cups_strcasecmp(line
, "<DefaultClass"))
332 cupsdLogMessage(CUPSD_LOG_ERROR
,
333 "Syntax error on line %d of classes.conf.", linenum
);
335 else if (!_cups_strcasecmp(line
, "</Class>") || !_cups_strcasecmp(line
, "</DefaultClass>"))
339 cupsdSetPrinterAttrs(p
);
343 cupsdLogMessage(CUPSD_LOG_ERROR
,
344 "Syntax error on line %d of classes.conf.", linenum
);
348 cupsdLogMessage(CUPSD_LOG_ERROR
,
349 "Syntax error on line %d of classes.conf.", linenum
);
351 else if (!_cups_strcasecmp(line
, "UUID"))
353 if (value
&& !strncmp(value
, "urn:uuid:", 9))
354 cupsdSetString(&(p
->uuid
), value
);
356 cupsdLogMessage(CUPSD_LOG_ERROR
,
357 "Bad UUID on line %d of classes.conf.", linenum
);
359 else if (!_cups_strcasecmp(line
, "AuthInfoRequired"))
361 if (!cupsdSetAuthInfoRequired(p
, value
, NULL
))
362 cupsdLogMessage(CUPSD_LOG_ERROR
,
363 "Bad AuthInfoRequired on line %d of classes.conf.",
366 else if (!_cups_strcasecmp(line
, "Info"))
369 cupsdSetString(&p
->info
, value
);
371 else if (!_cups_strcasecmp(line
, "Location"))
374 cupsdSetString(&p
->location
, value
);
376 else if (!_cups_strcasecmp(line
, "Option") && value
)
382 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
385 cupsdLogMessage(CUPSD_LOG_ERROR
,
386 "Syntax error on line %d of classes.conf.", linenum
);
389 for (; *valueptr
&& isspace(*valueptr
& 255); *valueptr
++ = '\0');
391 p
->num_options
= cupsAddOption(value
, valueptr
, p
->num_options
,
395 else if (!_cups_strcasecmp(line
, "Printer"))
399 cupsdLogMessage(CUPSD_LOG_ERROR
,
400 "Syntax error on line %d of classes.conf.", linenum
);
403 else if ((temp
= cupsdFindPrinter(value
)) == NULL
)
405 cupsdLogMessage(CUPSD_LOG_WARN
,
406 "Unknown printer %s on line %d of classes.conf.",
410 * Add the missing remote printer...
413 if ((temp
= cupsdAddPrinter(value
)) != NULL
)
415 cupsdSetString(&temp
->make_model
, "Remote Printer on unknown");
417 temp
->state
= IPP_PRINTER_STOPPED
;
418 temp
->type
|= CUPS_PRINTER_REMOTE
;
420 cupsdSetString(&temp
->location
, "Location Unknown");
421 cupsdSetString(&temp
->info
, "No Information Available");
422 temp
->hostname
[0] = '\0';
424 cupsdSetPrinterAttrs(temp
);
429 cupsdAddPrinterToClass(p
, temp
);
431 else if (!_cups_strcasecmp(line
, "State"))
434 * Set the initial queue state...
437 if (!_cups_strcasecmp(value
, "idle"))
438 p
->state
= IPP_PRINTER_IDLE
;
439 else if (!_cups_strcasecmp(value
, "stopped"))
441 p
->state
= IPP_PRINTER_STOPPED
;
443 for (i
= 0 ; i
< p
->num_reasons
; i
++)
444 if (!strcmp("paused", p
->reasons
[i
]))
447 if (i
>= p
->num_reasons
&&
448 p
->num_reasons
< (int)(sizeof(p
->reasons
) / sizeof(p
->reasons
[0])))
450 p
->reasons
[p
->num_reasons
] = _cupsStrAlloc("paused");
455 cupsdLogMessage(CUPSD_LOG_ERROR
,
456 "Syntax error on line %d of classes.conf.",
459 else if (!_cups_strcasecmp(line
, "StateMessage"))
462 * Set the initial queue state message...
466 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
468 else if (!_cups_strcasecmp(line
, "StateTime"))
471 * Set the state time...
475 p
->state_time
= atoi(value
);
477 else if (!_cups_strcasecmp(line
, "Accepting"))
480 * Set the initial accepting state...
484 (!_cups_strcasecmp(value
, "yes") ||
485 !_cups_strcasecmp(value
, "on") ||
486 !_cups_strcasecmp(value
, "true")))
489 (!_cups_strcasecmp(value
, "no") ||
490 !_cups_strcasecmp(value
, "off") ||
491 !_cups_strcasecmp(value
, "false")))
494 cupsdLogMessage(CUPSD_LOG_ERROR
,
495 "Syntax error on line %d of classes.conf.",
498 else if (!_cups_strcasecmp(line
, "Shared"))
501 * Set the initial shared state...
505 (!_cups_strcasecmp(value
, "yes") ||
506 !_cups_strcasecmp(value
, "on") ||
507 !_cups_strcasecmp(value
, "true")))
510 (!_cups_strcasecmp(value
, "no") ||
511 !_cups_strcasecmp(value
, "off") ||
512 !_cups_strcasecmp(value
, "false")))
515 cupsdLogMessage(CUPSD_LOG_ERROR
,
516 "Syntax error on line %d of classes.conf.",
519 else if (!_cups_strcasecmp(line
, "JobSheets"))
522 * Set the initial job sheets...
527 for (valueptr
= value
;
528 *valueptr
&& !isspace(*valueptr
& 255);
534 cupsdSetString(&p
->job_sheets
[0], value
);
536 while (isspace(*valueptr
& 255))
541 for (value
= valueptr
;
542 *valueptr
&& !isspace(*valueptr
& 255);
548 cupsdSetString(&p
->job_sheets
[1], value
);
552 cupsdLogMessage(CUPSD_LOG_ERROR
,
553 "Syntax error on line %d of classes.conf.", linenum
);
555 else if (!_cups_strcasecmp(line
, "AllowUser"))
560 cupsdAddString(&(p
->users
), value
);
563 cupsdLogMessage(CUPSD_LOG_ERROR
,
564 "Syntax error on line %d of classes.conf.", linenum
);
566 else if (!_cups_strcasecmp(line
, "DenyUser"))
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
, "QuotaPeriod"))
580 p
->quota_period
= atoi(value
);
582 cupsdLogMessage(CUPSD_LOG_ERROR
,
583 "Syntax error on line %d of classes.conf.", linenum
);
585 else if (!_cups_strcasecmp(line
, "PageLimit"))
588 p
->page_limit
= atoi(value
);
590 cupsdLogMessage(CUPSD_LOG_ERROR
,
591 "Syntax error on line %d of classes.conf.", linenum
);
593 else if (!_cups_strcasecmp(line
, "KLimit"))
596 p
->k_limit
= atoi(value
);
598 cupsdLogMessage(CUPSD_LOG_ERROR
,
599 "Syntax error on line %d of classes.conf.", linenum
);
601 else if (!_cups_strcasecmp(line
, "OpPolicy"))
605 cupsd_policy_t
*pol
; /* Policy */
608 if ((pol
= cupsdFindPolicy(value
)) != NULL
)
610 cupsdSetString(&p
->op_policy
, value
);
611 p
->op_policy_ptr
= pol
;
614 cupsdLogMessage(CUPSD_LOG_ERROR
,
615 "Bad policy \"%s\" on line %d of classes.conf",
619 cupsdLogMessage(CUPSD_LOG_ERROR
,
620 "Syntax error on line %d of classes.conf.", linenum
);
622 else if (!_cups_strcasecmp(line
, "ErrorPolicy"))
626 if (strcmp(value
, "retry-current-job") && strcmp(value
, "retry-job"))
627 cupsdLogMessage(CUPSD_LOG_WARN
,
628 "ErrorPolicy %s ignored on line %d of classes.conf",
632 cupsdLogMessage(CUPSD_LOG_ERROR
,
633 "Syntax error on line %d of classes.conf.", linenum
);
638 * Something else we don't understand...
641 cupsdLogMessage(CUPSD_LOG_ERROR
,
642 "Unknown configuration directive %s on line %d of classes.conf.",
652 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
656 cupsdSaveAllClasses(void)
658 cups_file_t
*fp
; /* classes.conf file */
659 char filename
[1024], /* classes.conf filename */
660 temp
[1024], /* Temporary string */
661 value
[2048], /* Value string */
662 *name
; /* Current user name */
663 cupsd_printer_t
*pclass
; /* Current printer class */
664 int i
; /* Looping var */
665 time_t curtime
; /* Current time */
666 struct tm
*curdate
; /* Current date */
667 cups_option_t
*option
; /* Current option */
671 * Create the classes.conf file...
674 snprintf(filename
, sizeof(filename
), "%s/classes.conf", ServerRoot
);
676 if ((fp
= cupsdCreateConfFile(filename
, ConfigFilePerm
)) == NULL
)
679 cupsdLogMessage(CUPSD_LOG_INFO
, "Saving classes.conf...");
682 * Write a small header to the file...
685 curtime
= time(NULL
);
686 curdate
= localtime(&curtime
);
687 strftime(temp
, sizeof(temp
) - 1, "%Y-%m-%d %H:%M", curdate
);
689 cupsFilePuts(fp
, "# Class configuration file for " CUPS_SVERSION
"\n");
690 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
691 cupsFilePuts(fp
, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
694 * Write each local class known to the system...
697 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
699 pclass
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
702 * Skip remote destinations and regular printers...
705 if ((pclass
->type
& CUPS_PRINTER_REMOTE
) ||
706 !(pclass
->type
& CUPS_PRINTER_CLASS
))
710 * Write printers as needed...
713 if (pclass
== DefaultPrinter
)
714 cupsFilePrintf(fp
, "<DefaultClass %s>\n", pclass
->name
);
716 cupsFilePrintf(fp
, "<Class %s>\n", pclass
->name
);
718 cupsFilePrintf(fp
, "UUID %s\n", pclass
->uuid
);
720 if (pclass
->num_auth_info_required
> 0)
722 switch (pclass
->num_auth_info_required
)
725 strlcpy(value
, pclass
->auth_info_required
[0], sizeof(value
));
729 snprintf(value
, sizeof(value
), "%s,%s",
730 pclass
->auth_info_required
[0],
731 pclass
->auth_info_required
[1]);
736 snprintf(value
, sizeof(value
), "%s,%s,%s",
737 pclass
->auth_info_required
[0],
738 pclass
->auth_info_required
[1],
739 pclass
->auth_info_required
[2]);
743 cupsFilePutConf(fp
, "AuthInfoRequired", value
);
747 cupsFilePutConf(fp
, "Info", pclass
->info
);
749 if (pclass
->location
)
750 cupsFilePutConf(fp
, "Location", pclass
->location
);
752 if (pclass
->state
== IPP_PRINTER_STOPPED
)
753 cupsFilePuts(fp
, "State Stopped\n");
755 cupsFilePuts(fp
, "State Idle\n");
757 cupsFilePrintf(fp
, "StateTime %d\n", (int)pclass
->state_time
);
759 if (pclass
->accepting
)
760 cupsFilePuts(fp
, "Accepting Yes\n");
762 cupsFilePuts(fp
, "Accepting No\n");
765 cupsFilePuts(fp
, "Shared Yes\n");
767 cupsFilePuts(fp
, "Shared No\n");
769 snprintf(value
, sizeof(value
), "%s %s", pclass
->job_sheets
[0],
770 pclass
->job_sheets
[1]);
771 cupsFilePutConf(fp
, "JobSheets", value
);
773 for (i
= 0; i
< pclass
->num_printers
; i
++)
774 cupsFilePrintf(fp
, "Printer %s\n", pclass
->printers
[i
]->name
);
776 cupsFilePrintf(fp
, "QuotaPeriod %d\n", pclass
->quota_period
);
777 cupsFilePrintf(fp
, "PageLimit %d\n", pclass
->page_limit
);
778 cupsFilePrintf(fp
, "KLimit %d\n", pclass
->k_limit
);
780 for (name
= (char *)cupsArrayFirst(pclass
->users
);
782 name
= (char *)cupsArrayNext(pclass
->users
))
783 cupsFilePutConf(fp
, pclass
->deny_users
? "DenyUser" : "AllowUser", name
);
785 if (pclass
->op_policy
)
786 cupsFilePutConf(fp
, "OpPolicy", pclass
->op_policy
);
787 if (pclass
->error_policy
)
788 cupsFilePutConf(fp
, "ErrorPolicy", pclass
->error_policy
);
790 for (i
= pclass
->num_options
, option
= pclass
->options
;
794 snprintf(value
, sizeof(value
), "%s %s", option
->name
, option
->value
);
795 cupsFilePutConf(fp
, "Option", value
);
798 if (pclass
== DefaultPrinter
)
799 cupsFilePuts(fp
, "</DefaultClass>\n");
801 cupsFilePuts(fp
, "</Class>\n");
804 cupsdCloseCreatedConfFile(fp
, filename
);