]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/classes.c
f0c27efd65652416c7e4cdbe0c55da184d3873c2
[thirdparty/cups.git] / scheduler / classes.c
1 /*
2 * "$Id: classes.c,v 1.41 2002/01/02 17:59:14 mike Exp $"
3 *
4 * Printer class routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2002 by Easy Software Products, all rights reserved.
7 *
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
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * AddClass() - Add a class to the system.
27 * AddPrinterToClass() - Add a printer to a class...
28 * DeletePrinterFromClass() - Delete a printer from a class.
29 * DeletePrinterFromClasses() - Delete a printer from all classes.
30 * DeleteAllClasses() - Remove all classes from the system.
31 * FindAvailablePrinter() - Find an available printer in a class.
32 * FindClass() - Find the named class.
33 * LoadAllClasses() - Load classes from the classes.conf file.
34 * SaveAllClasses() - Save classes to the classes.conf file.
35 */
36
37 /*
38 * Include necessary headers...
39 */
40
41 #include "cupsd.h"
42
43
44 /*
45 * 'AddClass()' - Add a class to the system.
46 */
47
48 printer_t * /* O - New class */
49 AddClass(const char *name) /* I - Name of class */
50 {
51 printer_t *c; /* New class */
52
53
54 /*
55 * Add the printer and set the type to "class"...
56 */
57
58 if ((c = AddPrinter(name)) != NULL)
59 {
60 /*
61 * Change from a printer to a class...
62 */
63
64 c->type = CUPS_PRINTER_CLASS;
65 snprintf(c->uri, sizeof(c->uri), "ipp://%s:%d/classes/%s", ServerName,
66 ntohs(Listeners[0].address.sin_port), name);
67
68 /*
69 * Set the printer attributes to make this a class.
70 */
71
72 SetPrinterAttrs(c);
73 }
74
75 return (c);
76 }
77
78
79 /*
80 * 'AddPrinterToClass()' - Add a printer to a class...
81 */
82
83 void
84 AddPrinterToClass(printer_t *c, /* I - Class to add to */
85 printer_t *p) /* I - Printer to add */
86 {
87 int i; /* Looping var */
88 printer_t **temp; /* Pointer to printer array */
89
90
91 /*
92 * See if this printer is already a member of the class...
93 */
94
95 for (i = 0; i < c->num_printers; i ++)
96 if (c->printers[i] == p)
97 return;
98
99 /*
100 * Allocate memory as needed...
101 */
102
103 if (c->num_printers == 0)
104 temp = malloc(sizeof(printer_t *));
105 else
106 temp = realloc(c->printers, sizeof(printer_t *) * (c->num_printers + 1));
107
108 if (temp == NULL)
109 {
110 LogMessage(L_ERROR, "Unable to add printer %s to class %s!",
111 p->name, c->name);
112 return;
113 }
114
115 /*
116 * Add the printer to the end of the array and update the number of printers.
117 */
118
119 c->printers = temp;
120 temp += c->num_printers;
121 c->num_printers ++;
122
123 *temp = p;
124
125 /*
126 * Update the IPP attributes...
127 */
128
129 SetPrinterAttrs(c);
130 }
131
132
133 /*
134 * 'DeletePrinterFromClass()' - Delete a printer from a class.
135 */
136
137 void
138 DeletePrinterFromClass(printer_t *c, /* I - Class to delete from */
139 printer_t *p) /* I - Printer to delete */
140 {
141 int i; /* Looping var */
142 cups_ptype_t type; /* Class type */
143
144
145 /*
146 * See if the printer is in the class...
147 */
148
149 for (i = 0; i < c->num_printers; i ++)
150 if (p == c->printers[i])
151 break;
152
153 /*
154 * If it is, remove it from the list...
155 */
156
157 if (i < c->num_printers)
158 {
159 /*
160 * Yes, remove the printer...
161 */
162
163 c->num_printers --;
164 if (i < c->num_printers)
165 memcpy(c->printers + i, c->printers + i + 1,
166 (c->num_printers - i) * sizeof(printer_t *));
167 }
168
169 /*
170 * Recompute the printer type mask as needed...
171 */
172
173 if (c->num_printers > 0)
174 {
175 type = c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT);
176 c->type = ~CUPS_PRINTER_REMOTE;
177
178 for (i = 0; i < c->num_printers; i ++)
179 c->type &= c->printers[i]->type;
180
181 c->type |= type;
182
183 /*
184 * Update the IPP attributes...
185 */
186
187 SetPrinterAttrs(c);
188 }
189 }
190
191
192 /*
193 * 'DeletePrinterFromClasses()' - Delete a printer from all classes.
194 */
195
196 void
197 DeletePrinterFromClasses(printer_t *p) /* I - Printer to delete */
198 {
199 printer_t *c, /* Pointer to current class */
200 *next; /* Pointer to next class */
201
202
203 /*
204 * Loop through the printer/class list and remove the printer
205 * from each class listed...
206 */
207
208 for (c = Printers; c != NULL; c = next)
209 {
210 next = c->next;
211
212 if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
213 DeletePrinterFromClass(c, p);
214 }
215
216 /*
217 * Then clean out any empty classes...
218 */
219
220 for (c = Printers; c != NULL; c = next)
221 {
222 next = c->next;
223
224 if ((c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) &&
225 c->num_printers == 0)
226 DeletePrinter(c);
227 }
228 }
229
230
231 /*
232 * 'DeleteAllClasses()' - Remove all classes from the system.
233 */
234
235 void
236 DeleteAllClasses(void)
237 {
238 printer_t *c, /* Pointer to current printer/class */
239 *next; /* Pointer to next printer in list */
240
241
242 for (c = Printers; c != NULL; c = next)
243 {
244 next = c->next;
245
246 if (c->type & CUPS_PRINTER_CLASS)
247 DeletePrinter(c);
248 }
249 }
250
251
252 /*
253 * 'FindAvailablePrinter()' - Find an available printer in a class.
254 */
255
256 printer_t * /* O - Available printer or NULL */
257 FindAvailablePrinter(const char *name) /* I - Class to check */
258 {
259 int i; /* Looping var */
260 printer_t *c; /* Printer class */
261
262
263 /*
264 * Find the class...
265 */
266
267 if ((c = FindClass(name)) == NULL)
268 {
269 LogMessage(L_ERROR, "Unable to find class \"%s\"!", name);
270 return (NULL);
271 }
272
273 /*
274 * Loop through the printers in the class and return the first idle
275 * printer... We keep track of the last printer that we used so that
276 * a "round robin" type of scheduling is realized (otherwise the first
277 * server might be saturated with print jobs...)
278 *
279 * Thanks to Joel Fredrikson for helping us get this right!
280 */
281
282 for (i = c->last_printer + 1; ; i ++)
283 {
284 if (i >= c->num_printers)
285 i = 0;
286
287 if (c->printers[i]->state == IPP_PRINTER_IDLE ||
288 ((c->printers[i]->type & CUPS_PRINTER_REMOTE) && !c->printers[i]->job))
289 {
290 c->last_printer = i;
291 return (c->printers[i]);
292 }
293
294 if (i == c->last_printer)
295 break;
296 }
297
298 return (NULL);
299 }
300
301
302 /*
303 * 'FindClass()' - Find the named class.
304 */
305
306 printer_t * /* O - Matching class or NULL */
307 FindClass(const char *name) /* I - Name of class */
308 {
309 printer_t *c; /* Current class/printer */
310
311
312 for (c = Printers; c != NULL; c = c->next)
313 switch (strcasecmp(name, c->name))
314 {
315 case 0 : /* name == c->name */
316 if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
317 return (c);
318 case 1 : /* name > c->name */
319 break;
320 case -1 : /* name < c->name */
321 return (NULL);
322 }
323
324 return (NULL);
325 }
326
327
328 /*
329 * 'LoadAllClasses()' - Load classes from the classes.conf file.
330 */
331
332 void
333 LoadAllClasses(void)
334 {
335 FILE *fp; /* classes.conf file */
336 int linenum; /* Current line number */
337 int len; /* Length of line */
338 char line[1024], /* Line from file */
339 name[256], /* Parameter name */
340 *nameptr, /* Pointer into name */
341 *value, /* Pointer to value */
342 *valueptr; /* Pointer into value */
343 printer_t *p, /* Current printer class */
344 *temp; /* Temporary pointer to printer */
345
346
347 /*
348 * Open the classes.conf file...
349 */
350
351 snprintf(line, sizeof(line), "%s/classes.conf", ServerRoot);
352 if ((fp = fopen(line, "r")) == NULL)
353 return;
354
355 /*
356 * Read class configurations until we hit EOF...
357 */
358
359 linenum = 0;
360 p = NULL;
361
362 while (fgets(line, sizeof(line), fp) != NULL)
363 {
364 linenum ++;
365
366 /*
367 * Skip comment lines...
368 */
369
370 if (line[0] == '#')
371 continue;
372
373 /*
374 * Strip trailing whitespace, if any...
375 */
376
377 len = strlen(line);
378
379 while (len > 0 && isspace(line[len - 1]))
380 {
381 len --;
382 line[len] = '\0';
383 }
384
385 /*
386 * Extract the name from the beginning of the line...
387 */
388
389 for (value = line; isspace(*value); value ++);
390
391 for (nameptr = name; *value != '\0' && !isspace(*value) &&
392 nameptr < (name + sizeof(name) - 1);)
393 *nameptr++ = *value++;
394 *nameptr = '\0';
395
396 while (isspace(*value))
397 value ++;
398
399 if (name[0] == '\0')
400 continue;
401
402 /*
403 * Decode the directive...
404 */
405
406 if (strcmp(name, "<Class") == 0 ||
407 strcmp(name, "<DefaultClass") == 0)
408 {
409 /*
410 * <Class name> or <DefaultClass name>
411 */
412
413 if (line[len - 1] == '>' && p == NULL)
414 {
415 line[len - 1] = '\0';
416
417 p = AddClass(value);
418 p->accepting = 1;
419 p->state = IPP_PRINTER_IDLE;
420
421 if (strcmp(name, "<DefaultClass") == 0)
422 DefaultPrinter = p;
423 }
424 else
425 {
426 LogMessage(L_ERROR, "Syntax error on line %d of classes.conf.",
427 linenum);
428 return;
429 }
430 }
431 else if (strcmp(name, "</Class>") == 0)
432 {
433 if (p != NULL)
434 {
435 SetPrinterAttrs(p);
436 p = NULL;
437 }
438 else
439 {
440 LogMessage(L_ERROR, "Syntax error on line %d of classes.conf.",
441 linenum);
442 return;
443 }
444 }
445 else if (p == NULL)
446 {
447 LogMessage(L_ERROR, "Syntax error on line %d of classes.conf.",
448 linenum);
449 return;
450 }
451
452 else if (strcmp(name, "Info") == 0)
453 strncpy(p->info, value, sizeof(p->info) - 1);
454 else if (strcmp(name, "Location") == 0)
455 strncpy(p->location, value, sizeof(p->location) - 1);
456 else if (strcmp(name, "Printer") == 0)
457 {
458 if ((temp = FindPrinter(value)) == NULL)
459 {
460 LogMessage(L_WARN, "Unknown printer %s on line %d of classes.conf.",
461 value, linenum);
462
463 /*
464 * Add the missing remote printer...
465 */
466
467 temp = AddPrinter(value);
468 strcpy(temp->make_model, "Remote Printer on unknown");
469
470 temp->state = IPP_PRINTER_STOPPED;
471 temp->type |= CUPS_PRINTER_REMOTE;
472 temp->browse_time = 2147483647;
473
474 strcpy(temp->location, "Location Unknown");
475 strcpy(temp->info, "No Information Available");
476 temp->hostname[0] = '\0';
477
478 SetPrinterAttrs(temp);
479 }
480
481 if (temp)
482 AddPrinterToClass(p, temp);
483 }
484 else if (strcmp(name, "State") == 0)
485 {
486 /*
487 * Set the initial queue state...
488 */
489
490 if (strcasecmp(value, "idle") == 0)
491 p->state = IPP_PRINTER_IDLE;
492 else if (strcasecmp(value, "stopped") == 0)
493 p->state = IPP_PRINTER_STOPPED;
494 }
495 else if (strcmp(name, "StateMessage") == 0)
496 {
497 /*
498 * Set the initial queue state message...
499 */
500
501 while (isspace(*value))
502 value ++;
503
504 strncpy(p->state_message, value, sizeof(p->state_message) - 1);
505 }
506 else if (strcmp(name, "Accepting") == 0)
507 {
508 /*
509 * Set the initial accepting state...
510 */
511
512 if (strcasecmp(value, "yes") == 0)
513 p->accepting = 1;
514 else
515 p->accepting = 0;
516 }
517 else if (strcmp(name, "JobSheets") == 0)
518 {
519 /*
520 * Set the initial job sheets...
521 */
522
523 for (valueptr = value; *valueptr && !isspace(*valueptr); valueptr ++);
524
525 if (*valueptr)
526 *valueptr++ = '\0';
527
528 strncpy(p->job_sheets[0], value, sizeof(p->job_sheets[0]) - 1);
529
530 while (isspace(*valueptr))
531 valueptr ++;
532
533 if (*valueptr)
534 {
535 for (value = valueptr; *valueptr && !isspace(*valueptr); valueptr ++);
536
537 if (*valueptr)
538 *valueptr++ = '\0';
539
540 strncpy(p->job_sheets[1], value, sizeof(p->job_sheets[1]) - 1);
541 }
542 }
543 else if (strcmp(name, "AllowUser") == 0)
544 {
545 p->deny_users = 0;
546 AddPrinterUser(p, value);
547 }
548 else if (strcmp(name, "DenyUser") == 0)
549 {
550 p->deny_users = 1;
551 AddPrinterUser(p, value);
552 }
553 else if (strcmp(name, "QuotaPeriod") == 0)
554 p->quota_period = atoi(value);
555 else if (strcmp(name, "PageLimit") == 0)
556 p->page_limit = atoi(value);
557 else if (strcmp(name, "KLimit") == 0)
558 p->k_limit = atoi(value);
559 else
560 {
561 /*
562 * Something else we don't understand...
563 */
564
565 LogMessage(L_ERROR, "Unknown configuration directive %s on line %d of classes.conf.",
566 name, linenum);
567 }
568 }
569
570 fclose(fp);
571 }
572
573
574 /*
575 * 'SaveAllClasses()' - Save classes to the classes.conf file.
576 */
577
578 void
579 SaveAllClasses(void)
580 {
581 FILE *fp; /* classes.conf file */
582 char temp[1024]; /* Temporary string */
583 char backup[1024]; /* classes.conf.O file */
584 printer_t *pclass; /* Current printer class */
585 int i; /* Looping var */
586 time_t curtime; /* Current time */
587 struct tm *curdate; /* Current date */
588
589
590 /*
591 * Create the classes.conf file...
592 */
593
594 snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot);
595 snprintf(backup, sizeof(backup), "%s/classes.conf.O", ServerRoot);
596
597 if (rename(temp, backup))
598 LogMessage(L_ERROR, "Unable to backup classes.conf - %s", strerror(errno));
599
600 if ((fp = fopen(temp, "w")) == NULL)
601 {
602 LogMessage(L_ERROR, "Unable to save classes.conf - %s", strerror(errno));
603
604 if (rename(backup, temp))
605 LogMessage(L_ERROR, "Unable to restore classes.conf - %s", strerror(errno));
606 return;
607 }
608 else
609 LogMessage(L_INFO, "Saving classes.conf...");
610
611 /*
612 * Restrict access to the file...
613 */
614
615 fchown(fileno(fp), User, Group);
616 fchmod(fileno(fp), 0600);
617
618 /*
619 * Write a small header to the file...
620 */
621
622 curtime = time(NULL);
623 curdate = gmtime(&curtime);
624 strftime(temp, sizeof(temp) - 1, CUPS_STRFTIME_FORMAT, curdate);
625
626 fputs("# Class configuration file for " CUPS_SVERSION "\n", fp);
627 fprintf(fp, "# Written by cupsd on %s\n", temp);
628
629 /*
630 * Write each local class known to the system...
631 */
632
633 for (pclass = Printers; pclass != NULL; pclass = pclass->next)
634 {
635 /*
636 * Skip remote destinations and regular printers...
637 */
638
639 if ((pclass->type & CUPS_PRINTER_REMOTE) ||
640 (pclass->type & CUPS_PRINTER_IMPLICIT) ||
641 !(pclass->type & CUPS_PRINTER_CLASS))
642 continue;
643
644 /*
645 * Write printers as needed...
646 */
647
648 if (pclass == DefaultPrinter)
649 fprintf(fp, "<DefaultClass %s>\n", pclass->name);
650 else
651 fprintf(fp, "<Class %s>\n", pclass->name);
652
653 if (pclass->info[0])
654 fprintf(fp, "Info %s\n", pclass->info);
655
656 if (pclass->location[0])
657 fprintf(fp, "Location %s\n", pclass->location);
658
659 if (pclass->state == IPP_PRINTER_STOPPED)
660 {
661 fputs("State Stopped\n", fp);
662 fprintf(fp, "StateMessage %s\n", pclass->state_message);
663 }
664 else
665 fputs("State Idle\n", fp);
666
667 if (pclass->accepting)
668 fputs("Accepting Yes\n", fp);
669 else
670 fputs("Accepting No\n", fp);
671
672 fprintf(fp, "JobSheets %s %s\n", pclass->job_sheets[0],
673 pclass->job_sheets[1]);
674
675 for (i = 0; i < pclass->num_printers; i ++)
676 fprintf(fp, "Printer %s\n", pclass->printers[i]->name);
677
678 fprintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
679 fprintf(fp, "PageLimit %d\n", pclass->page_limit);
680 fprintf(fp, "KLimit %d\n", pclass->k_limit);
681
682 for (i = 0; i < pclass->num_users; i ++)
683 fprintf(fp, "%sUser %s\n", pclass->deny_users ? "Deny" : "Allow",
684 pclass->users[i]);
685
686 fputs("</Class>\n", fp);
687 }
688
689 fclose(fp);
690 }
691
692
693 /*
694 * End of "$Id: classes.c,v 1.41 2002/01/02 17:59:14 mike Exp $".
695 */