]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
2 * "$Id: classes.c 6423 2007-04-02 13:05:19Z mike $"
4 * Printer class routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * cupsdAddClass() - Add a class to the system.
27 * cupsdAddPrinterToClass() - Add a printer to a class...
28 * cupsdDeletePrinterFromClass() - Delete a printer from a class.
29 * cupsdDeletePrinterFromClasses() - Delete a printer from all classes.
30 * cupsdDeleteAllClasses() - Remove all classes from the system.
31 * cupsdFindAvailablePrinter() - Find an available printer in a class.
32 * cupsdFindClass() - Find the named class.
33 * cupsdLoadAllClasses() - Load classes from the classes.conf file.
34 * cupsdSaveAllClasses() - Save classes to the classes.conf file.
35 * cupsdUpdateImplicitClasses() - Update the accepting state of implicit
40 * Include necessary headers...
47 * 'cupsdAddClass()' - Add a class to the system.
50 cupsd_printer_t
* /* O - New class */
51 cupsdAddClass(const char *name
) /* I - Name of class */
53 cupsd_printer_t
*c
; /* New class */
57 * Add the printer and set the type to "class"...
60 if ((c
= cupsdAddPrinter(name
)) != NULL
)
63 * Change from a printer to a class...
66 c
->type
= CUPS_PRINTER_CLASS
;
68 cupsdSetStringf(&c
->uri
, "ipp://%s:%d/classes/%s", ServerName
, LocalPort
,
70 cupsdSetString(&c
->error_policy
, "retry-job");
78 * 'cupsdAddPrinterToClass()' - Add a printer to a class...
82 cupsdAddPrinterToClass(
83 cupsd_printer_t
*c
, /* I - Class to add to */
84 cupsd_printer_t
*p
) /* I - Printer to add */
86 int i
; /* Looping var */
87 cupsd_printer_t
**temp
; /* Pointer to printer array */
91 * See if this printer is already a member of the class...
94 for (i
= 0; i
< c
->num_printers
; i
++)
95 if (c
->printers
[i
] == p
)
99 * Allocate memory as needed...
102 if (c
->num_printers
== 0)
103 temp
= malloc(sizeof(cupsd_printer_t
*));
105 temp
= realloc(c
->printers
, sizeof(cupsd_printer_t
*) * (c
->num_printers
+ 1));
109 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to add printer %s to class %s!",
115 * Add the printer to the end of the array and update the number of printers.
119 temp
+= c
->num_printers
;
127 * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class.
131 cupsdDeletePrinterFromClass(
132 cupsd_printer_t
*c
, /* I - Class to delete from */
133 cupsd_printer_t
*p
) /* I - Printer to delete */
135 int i
; /* Looping var */
136 cups_ptype_t type
, /* Class type */
137 oldtype
; /* Old class type */
141 * See if the printer is in the class...
144 for (i
= 0; i
< c
->num_printers
; i
++)
145 if (p
== c
->printers
[i
])
149 * If it is, remove it from the list...
152 if (i
< c
->num_printers
)
155 * Yes, remove the printer...
159 if (i
< c
->num_printers
)
160 memmove(c
->printers
+ i
, c
->printers
+ i
+ 1,
161 (c
->num_printers
- i
) * sizeof(cupsd_printer_t
*));
167 * Recompute the printer type mask as needed...
170 if (c
->num_printers
> 0)
173 type
= c
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
);
174 c
->type
= ~CUPS_PRINTER_REMOTE
;
176 for (i
= 0; i
< c
->num_printers
; i
++)
177 c
->type
&= c
->printers
[i
]->type
;
182 * Update the IPP attributes...
185 if (c
->type
!= oldtype
)
186 cupsdSetPrinterAttrs(c
);
192 * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes.
196 cupsdDeletePrinterFromClasses(
197 cupsd_printer_t
*p
) /* I - Printer to delete */
199 cupsd_printer_t
*c
; /* Pointer to current class */
203 * Loop through the printer/class list and remove the printer
204 * from each class listed...
207 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
209 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
210 if (c
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
))
211 cupsdDeletePrinterFromClass(c
, p
);
214 * Then clean out any empty implicit classes...
217 for (c
= (cupsd_printer_t
*)cupsArrayFirst(ImplicitPrinters
);
219 c
= (cupsd_printer_t
*)cupsArrayNext(ImplicitPrinters
))
220 if (c
->num_printers
== 0)
222 cupsArrayRemove(ImplicitPrinters
, c
);
223 cupsdDeletePrinter(c
, 0);
229 * 'cupsdDeleteAllClasses()' - Remove all classes from the system.
233 cupsdDeleteAllClasses(void)
235 cupsd_printer_t
*c
; /* Pointer to current printer/class */
238 for (c
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
240 c
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
241 if (c
->type
& CUPS_PRINTER_CLASS
)
242 cupsdDeletePrinter(c
, 0);
247 * 'cupsdFindAvailablePrinter()' - Find an available printer in a class.
250 cupsd_printer_t
* /* O - Available printer or NULL */
251 cupsdFindAvailablePrinter(
252 const char *name
) /* I - Class to check */
254 int i
; /* Looping var */
255 cupsd_printer_t
*c
; /* Printer class */
262 if ((c
= cupsdFindClass(name
)) == NULL
)
264 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to find class \"%s\"!", name
);
269 * Make sure that the last printer is also a valid index into the printer
270 * array. If not, reset the last printer to 0...
273 if (c
->last_printer
>= c
->num_printers
)
277 * Loop through the printers in the class and return the first idle
278 * printer... We keep track of the last printer that we used so that
279 * a "round robin" type of scheduling is realized (otherwise the first
280 * server might be saturated with print jobs...)
282 * Thanks to Joel Fredrikson for helping us get this right!
285 for (i
= c
->last_printer
+ 1; ; i
++)
287 if (i
>= c
->num_printers
)
290 if (c
->printers
[i
]->accepting
&&
291 (c
->printers
[i
]->state
== IPP_PRINTER_IDLE
||
292 ((c
->printers
[i
]->type
& CUPS_PRINTER_REMOTE
) && !c
->printers
[i
]->job
)))
295 return (c
->printers
[i
]);
298 if (i
== c
->last_printer
)
307 * 'cupsdFindClass()' - Find the named class.
310 cupsd_printer_t
* /* O - Matching class or NULL */
311 cupsdFindClass(const char *name
) /* I - Name of class */
313 cupsd_printer_t
*c
; /* Current class/printer */
316 if ((c
= cupsdFindDest(name
)) != NULL
&&
317 (c
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_IMPLICIT
)))
325 * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file.
329 cupsdLoadAllClasses(void)
331 cups_file_t
*fp
; /* classes.conf file */
332 int linenum
; /* Current line number */
333 char line
[1024], /* Line from file */
334 *value
, /* Pointer to value */
335 *valueptr
; /* Pointer into value */
336 cupsd_printer_t
*p
, /* Current printer class */
337 *temp
; /* Temporary pointer to printer */
341 * Open the classes.conf file...
344 snprintf(line
, sizeof(line
), "%s/classes.conf", ServerRoot
);
345 if ((fp
= cupsFileOpen(line
, "r")) == NULL
)
348 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to open %s - %s", line
,
354 * Read class configurations until we hit EOF...
360 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
363 * Decode the directive...
366 if (!strcasecmp(line
, "<Class") ||
367 !strcasecmp(line
, "<DefaultClass"))
370 * <Class name> or <DefaultClass name>
373 if (p
== NULL
&& value
)
375 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Loading class %s...", value
);
378 * Since prior classes may have implicitly defined this class,
379 * see if it already exists...
382 if ((p
= cupsdFindDest(value
)) != NULL
)
384 p
->type
= CUPS_PRINTER_CLASS
;
385 cupsdSetStringf(&p
->uri
, "ipp://%s:%d/classes/%s", ServerName
,
387 cupsdSetString(&p
->error_policy
, "retry-job");
390 p
= cupsdAddClass(value
);
393 p
->state
= IPP_PRINTER_IDLE
;
395 if (!strcasecmp(line
, "<DefaultClass"))
400 cupsdLogMessage(CUPSD_LOG_ERROR
,
401 "Syntax error on line %d of classes.conf.", linenum
);
405 else if (!strcasecmp(line
, "</Class>"))
409 cupsdSetPrinterAttrs(p
);
414 cupsdLogMessage(CUPSD_LOG_ERROR
,
415 "Syntax error on line %d of classes.conf.", linenum
);
421 cupsdLogMessage(CUPSD_LOG_ERROR
,
422 "Syntax error on line %d of classes.conf.", linenum
);
425 else if (!strcasecmp(line
, "AuthInfoRequired"))
427 if (!cupsdSetAuthInfoRequired(p
, value
, NULL
))
428 cupsdLogMessage(CUPSD_LOG_ERROR
,
429 "Bad AuthInfoRequired on line %d of classes.conf.",
432 else if (!strcasecmp(line
, "Info"))
435 cupsdSetString(&p
->info
, value
);
437 else if (!strcasecmp(line
, "Location"))
440 cupsdSetString(&p
->location
, value
);
442 else if (!strcasecmp(line
, "Option") && value
)
448 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
451 cupsdLogMessage(CUPSD_LOG_ERROR
,
452 "Syntax error on line %d of classes.conf.", linenum
);
455 for (; *valueptr
&& isspace(*valueptr
& 255); *valueptr
++ = '\0');
457 p
->num_options
= cupsAddOption(value
, valueptr
, p
->num_options
,
461 else if (!strcasecmp(line
, "Printer"))
465 cupsdLogMessage(CUPSD_LOG_ERROR
,
466 "Syntax error on line %d of classes.conf.", linenum
);
469 else if ((temp
= cupsdFindPrinter(value
)) == NULL
)
471 cupsdLogMessage(CUPSD_LOG_WARN
,
472 "Unknown printer %s on line %d of classes.conf.",
476 * Add the missing remote printer...
479 if ((temp
= cupsdAddPrinter(value
)) != NULL
)
481 cupsdSetString(&temp
->make_model
, "Remote Printer on unknown");
483 temp
->state
= IPP_PRINTER_STOPPED
;
484 temp
->type
|= CUPS_PRINTER_REMOTE
;
485 temp
->browse_time
= 2147483647;
487 cupsdSetString(&temp
->location
, "Location Unknown");
488 cupsdSetString(&temp
->info
, "No Information Available");
489 temp
->hostname
[0] = '\0';
491 cupsdSetPrinterAttrs(temp
);
496 cupsdAddPrinterToClass(p
, temp
);
498 else if (!strcasecmp(line
, "State"))
501 * Set the initial queue state...
504 if (!strcasecmp(value
, "idle"))
505 p
->state
= IPP_PRINTER_IDLE
;
506 else if (!strcasecmp(value
, "stopped"))
507 p
->state
= IPP_PRINTER_STOPPED
;
510 cupsdLogMessage(CUPSD_LOG_ERROR
,
511 "Syntax error on line %d of classes.conf.",
516 else if (!strcasecmp(line
, "StateMessage"))
519 * Set the initial queue state message...
523 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
525 else if (!strcasecmp(line
, "StateTime"))
528 * Set the state time...
532 p
->state_time
= atoi(value
);
534 else if (!strcasecmp(line
, "Accepting"))
537 * Set the initial accepting state...
541 (!strcasecmp(value
, "yes") ||
542 !strcasecmp(value
, "on") ||
543 !strcasecmp(value
, "true")))
546 (!strcasecmp(value
, "no") ||
547 !strcasecmp(value
, "off") ||
548 !strcasecmp(value
, "false")))
552 cupsdLogMessage(CUPSD_LOG_ERROR
,
553 "Syntax error on line %d of classes.conf.",
558 else if (!strcasecmp(line
, "Shared"))
561 * Set the initial shared state...
565 (!strcasecmp(value
, "yes") ||
566 !strcasecmp(value
, "on") ||
567 !strcasecmp(value
, "true")))
570 (!strcasecmp(value
, "no") ||
571 !strcasecmp(value
, "off") ||
572 !strcasecmp(value
, "false")))
576 cupsdLogMessage(CUPSD_LOG_ERROR
,
577 "Syntax error on line %d of printers.conf.",
582 else if (!strcasecmp(line
, "JobSheets"))
585 * Set the initial job sheets...
590 for (valueptr
= value
;
591 *valueptr
&& !isspace(*valueptr
& 255);
597 cupsdSetString(&p
->job_sheets
[0], value
);
599 while (isspace(*valueptr
& 255))
604 for (value
= valueptr
;
605 *valueptr
&& !isspace(*valueptr
& 255);
611 cupsdSetString(&p
->job_sheets
[1], value
);
616 cupsdLogMessage(CUPSD_LOG_ERROR
,
617 "Syntax error on line %d of classes.conf.", linenum
);
621 else if (!strcasecmp(line
, "AllowUser"))
626 cupsdAddPrinterUser(p
, value
);
630 cupsdLogMessage(CUPSD_LOG_ERROR
,
631 "Syntax error on line %d of classes.conf.", linenum
);
635 else if (!strcasecmp(line
, "DenyUser"))
640 cupsdAddPrinterUser(p
, value
);
644 cupsdLogMessage(CUPSD_LOG_ERROR
,
645 "Syntax error on line %d of classes.conf.", linenum
);
649 else if (!strcasecmp(line
, "QuotaPeriod"))
652 p
->quota_period
= atoi(value
);
655 cupsdLogMessage(CUPSD_LOG_ERROR
,
656 "Syntax error on line %d of classes.conf.", linenum
);
660 else if (!strcasecmp(line
, "PageLimit"))
663 p
->page_limit
= atoi(value
);
666 cupsdLogMessage(CUPSD_LOG_ERROR
,
667 "Syntax error on line %d of classes.conf.", linenum
);
671 else if (!strcasecmp(line
, "KLimit"))
674 p
->k_limit
= atoi(value
);
677 cupsdLogMessage(CUPSD_LOG_ERROR
,
678 "Syntax error on line %d of classes.conf.", linenum
);
682 else if (!strcasecmp(line
, "OpPolicy"))
686 cupsd_policy_t
*pol
; /* Policy */
689 if ((pol
= cupsdFindPolicy(value
)) != NULL
)
691 cupsdSetString(&p
->op_policy
, value
);
692 p
->op_policy_ptr
= pol
;
695 cupsdLogMessage(CUPSD_LOG_ERROR
,
696 "Bad policy \"%s\" on line %d of classes.conf",
701 cupsdLogMessage(CUPSD_LOG_ERROR
,
702 "Syntax error on line %d of classes.conf.", linenum
);
706 else if (!strcasecmp(line
, "ErrorPolicy"))
709 cupsdSetString(&p
->error_policy
, value
);
712 cupsdLogMessage(CUPSD_LOG_ERROR
,
713 "Syntax error on line %d of classes.conf.", linenum
);
720 * Something else we don't understand...
723 cupsdLogMessage(CUPSD_LOG_ERROR
,
724 "Unknown configuration directive %s on line %d of classes.conf.",
734 * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file.
738 cupsdSaveAllClasses(void)
740 cups_file_t
*fp
; /* classes.conf file */
741 char temp
[1024]; /* Temporary string */
742 char backup
[1024]; /* classes.conf.O file */
743 cupsd_printer_t
*pclass
; /* Current printer class */
744 int i
; /* Looping var */
745 time_t curtime
; /* Current time */
746 struct tm
*curdate
; /* Current date */
747 cups_option_t
*option
; /* Current option */
748 const char *ptr
; /* Pointer into info/location */
752 * Create the classes.conf file...
755 snprintf(temp
, sizeof(temp
), "%s/classes.conf", ServerRoot
);
756 snprintf(backup
, sizeof(backup
), "%s/classes.conf.O", ServerRoot
);
758 if (rename(temp
, backup
))
761 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to backup classes.conf - %s",
765 if ((fp
= cupsFileOpen(temp
, "w")) == NULL
)
767 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to save classes.conf - %s",
770 if (rename(backup
, temp
))
771 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to restore classes.conf - %s",
776 cupsdLogMessage(CUPSD_LOG_INFO
, "Saving classes.conf...");
779 * Restrict access to the file...
782 fchown(cupsFileNumber(fp
), RunUser
, Group
);
783 fchmod(cupsFileNumber(fp
), 0600);
786 * Write a small header to the file...
789 curtime
= time(NULL
);
790 curdate
= localtime(&curtime
);
791 strftime(temp
, sizeof(temp
) - 1, "%Y-%m-%d %H:%M", curdate
);
793 cupsFilePuts(fp
, "# Class configuration file for " CUPS_SVERSION
"\n");
794 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
797 * Write each local class known to the system...
800 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
802 pclass
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
805 * Skip remote destinations and regular printers...
808 if ((pclass
->type
& CUPS_PRINTER_REMOTE
) ||
809 (pclass
->type
& CUPS_PRINTER_IMPLICIT
) ||
810 !(pclass
->type
& CUPS_PRINTER_CLASS
))
814 * Write printers as needed...
817 if (pclass
== DefaultPrinter
)
818 cupsFilePrintf(fp
, "<DefaultClass %s>\n", pclass
->name
);
820 cupsFilePrintf(fp
, "<Class %s>\n", pclass
->name
);
822 if (pclass
->num_auth_info_required
> 0)
824 cupsFilePrintf(fp
, "AuthInfoRequired %s", pclass
->auth_info_required
[0]);
825 for (i
= 1; i
< pclass
->num_auth_info_required
; i
++)
826 cupsFilePrintf(fp
, ",%s", pclass
->auth_info_required
[i
]);
827 cupsFilePutChar(fp
, '\n');
832 if ((ptr
= strchr(pclass
->info
, '#')) != NULL
)
835 * Need to quote the first # in the info string...
838 cupsFilePuts(fp
, "Info ");
839 cupsFileWrite(fp
, pclass
->info
, ptr
- pclass
->info
);
840 cupsFilePutChar(fp
, '\\');
841 cupsFilePuts(fp
, ptr
);
842 cupsFilePutChar(fp
, '\n');
845 cupsFilePrintf(fp
, "Info %s\n", pclass
->info
);
848 if (pclass
->location
)
850 if ((ptr
= strchr(pclass
->info
, '#')) != NULL
)
853 * Need to quote the first # in the location string...
856 cupsFilePuts(fp
, "Location ");
857 cupsFileWrite(fp
, pclass
->location
, ptr
- pclass
->location
);
858 cupsFilePutChar(fp
, '\\');
859 cupsFilePuts(fp
, ptr
);
860 cupsFilePutChar(fp
, '\n');
863 cupsFilePrintf(fp
, "Location %s\n", pclass
->location
);
866 if (pclass
->state
== IPP_PRINTER_STOPPED
)
868 cupsFilePuts(fp
, "State Stopped\n");
869 cupsFilePrintf(fp
, "StateMessage %s\n", pclass
->state_message
);
872 cupsFilePuts(fp
, "State Idle\n");
874 cupsFilePrintf(fp
, "StateTime %d\n", (int)pclass
->state_time
);
876 if (pclass
->accepting
)
877 cupsFilePuts(fp
, "Accepting Yes\n");
879 cupsFilePuts(fp
, "Accepting No\n");
882 cupsFilePuts(fp
, "Shared Yes\n");
884 cupsFilePuts(fp
, "Shared No\n");
886 cupsFilePrintf(fp
, "JobSheets %s %s\n", pclass
->job_sheets
[0],
887 pclass
->job_sheets
[1]);
889 for (i
= 0; i
< pclass
->num_printers
; i
++)
890 cupsFilePrintf(fp
, "Printer %s\n", pclass
->printers
[i
]->name
);
892 cupsFilePrintf(fp
, "QuotaPeriod %d\n", pclass
->quota_period
);
893 cupsFilePrintf(fp
, "PageLimit %d\n", pclass
->page_limit
);
894 cupsFilePrintf(fp
, "KLimit %d\n", pclass
->k_limit
);
896 for (i
= 0; i
< pclass
->num_users
; i
++)
897 cupsFilePrintf(fp
, "%sUser %s\n", pclass
->deny_users
? "Deny" : "Allow",
900 if (pclass
->op_policy
)
901 cupsFilePrintf(fp
, "OpPolicy %s\n", pclass
->op_policy
);
902 if (pclass
->error_policy
)
903 cupsFilePrintf(fp
, "ErrorPolicy %s\n", pclass
->error_policy
);
905 for (i
= pclass
->num_options
, option
= pclass
->options
;
908 cupsFilePrintf(fp
, "Option %s %s\n", option
->name
, option
->value
);
910 cupsFilePuts(fp
, "</Class>\n");
918 * 'cupsdUpdateImplicitClasses()' - Update the accepting state of implicit
923 cupsdUpdateImplicitClasses(void)
925 int i
; /* Looping var */
926 cupsd_printer_t
*pclass
; /* Current class */
927 int accepting
; /* printer-is-accepting-jobs value */
930 for (pclass
= (cupsd_printer_t
*)cupsArrayFirst(ImplicitPrinters
);
932 pclass
= (cupsd_printer_t
*)cupsArrayNext(ImplicitPrinters
))
935 * Loop through the printers to come up with a composite state...
938 for (i
= 0, accepting
= 0; i
< pclass
->num_printers
; i
++)
939 if ((accepting
= pclass
->printers
[i
]->accepting
) != 0)
942 pclass
->accepting
= accepting
;
948 * End of "$Id: classes.c 6423 2007-04-02 13:05:19Z mike $".