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