]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/printers.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / scheduler / printers.c
1 /*
2 * "$Id: printers.c,v 1.93.2.8 2002/01/23 17:32:16 mike Exp $"
3 *
4 * Printer 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 * AddPrinter() - Add a printer to the system.
27 * AddPrinterFilter() - Add a MIME filter for a printer.
28 * AddPrinterUser() - Add a user to the ACL.
29 * DeleteAllPrinters() - Delete all printers from the system.
30 * DeletePrinter() - Delete a printer from the system.
31 * DeletePrinterFilters() - Delete all MIME filters for a printer.
32 * FindPrinter() - Find a printer in the list.
33 * FreePrinterUsers() - Free allow/deny users.
34 * LoadAllPrinters() - Load printers from the printers.conf file.
35 * SaveAllPrinters() - Save all printer definitions to the printers.conf
36 * SetPrinterAttrs() - Set printer attributes based upon the PPD file.
37 * SetPrinterState() - Update the current state of a printer.
38 * SortPrinters() - Sort the printer list when a printer name is
39 * changed.
40 * StopPrinter() - Stop a printer from printing any jobs...
41 * ValidateDest() - Validate a printer/class destination.
42 * write_irix_state() - Update the status files used by IRIX printing
43 * desktop tools.
44 * write_printcap() - Write a pseudo-printcap file for older
45 * applications that need it...
46 */
47
48 /*
49 * Include necessary headers...
50 */
51
52 #include "cupsd.h"
53
54
55 /*
56 * Local functions...
57 */
58
59 static void write_printcap(void);
60 #ifdef __sgi
61 static void write_irix_state(printer_t *p);
62 #endif /* __sgi */
63
64
65 /*
66 * 'AddPrinter()' - Add a printer to the system.
67 */
68
69 printer_t * /* O - New printer */
70 AddPrinter(const char *name) /* I - Name of printer */
71 {
72 printer_t *p, /* New printer */
73 *current, /* Current printer in list */
74 *prev; /* Previous printer in list */
75
76
77 DEBUG_printf(("AddPrinter(\"%s\")\n", name));
78
79 /*
80 * Range check input...
81 */
82
83 if (name == NULL)
84 return (NULL);
85
86 /*
87 * Create a new printer entity...
88 */
89
90 if ((p = calloc(1, sizeof(printer_t))) == NULL)
91 return (NULL);
92
93 strncpy(p->name, name, sizeof(p->name) - 1);
94 strncpy(p->hostname, ServerName, sizeof(p->hostname) - 1);
95
96 #ifdef AF_INET6
97 if (Listeners[0].address.addr.sa_family == AF_INET6)
98 snprintf(p->uri, sizeof(p->uri), "ipp://%s:%d/printers/%s", ServerName,
99 ntohs(Listeners[0].address.ipv6.sin6_port), name);
100 else
101 #endif /* AF_INET6 */
102 snprintf(p->uri, sizeof(p->uri), "ipp://%s:%d/printers/%s", ServerName,
103 ntohs(Listeners[0].address.ipv4.sin_port), name);
104
105 p->state = IPP_PRINTER_STOPPED;
106 p->accepting = 0;
107 p->filetype = mimeAddType(MimeDatabase, "printer", name);
108
109 strcpy(p->job_sheets[0], "none");
110 strcpy(p->job_sheets[1], "none");
111
112 /*
113 * Setup required filters and IPP attributes...
114 */
115
116 SetPrinterAttrs(p);
117
118 /*
119 * Insert the printer in the printer list alphabetically...
120 */
121
122 for (prev = NULL, current = Printers;
123 current != NULL;
124 prev = current, current = current->next)
125 if (strcasecmp(p->name, current->name) < 0)
126 break;
127
128 /*
129 * Insert this printer before the current one...
130 */
131
132 if (prev == NULL)
133 Printers = p;
134 else
135 prev->next = p;
136
137 p->next = current;
138
139 /*
140 * Write a new /etc/printcap or /var/spool/lp/pstatus file.
141 */
142
143 write_printcap();
144
145 return (p);
146 }
147
148
149 /*
150 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
151 */
152
153 void
154 AddPrinterFilter(printer_t *p, /* I - Printer to add to */
155 const char *filter) /* I - Filter to add */
156 {
157 int i; /* Looping var */
158 char super[MIME_MAX_SUPER], /* Super-type for filter */
159 type[MIME_MAX_TYPE], /* Type for filter */
160 program[1024]; /* Program/filter name */
161 int cost; /* Cost of filter */
162 mime_type_t **temptype; /* MIME type looping var */
163
164
165 /*
166 * Range check input...
167 */
168
169 if (p == NULL || filter == NULL)
170 return;
171
172 /*
173 * Parse the filter string; it should be in the following format:
174 *
175 * super/type cost program
176 */
177
178 if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4)
179 {
180 LogMessage(L_ERROR, "AddPrinterFilter: Invalid filter string \"%s\"!",
181 filter);
182 return;
183 }
184
185 /*
186 * Add the filter to the MIME database, supporting wildcards as needed...
187 */
188
189 for (temptype = MimeDatabase->types, i = MimeDatabase->num_types;
190 i > 0;
191 i --, temptype ++)
192 if (((super[0] == '*' && strcmp((*temptype)->super, "printer") != 0) ||
193 strcmp((*temptype)->super, super) == 0) &&
194 (type[0] == '*' || strcmp((*temptype)->type, type) == 0))
195 {
196 LogMessage(L_DEBUG2, "Adding filter %s/%s %s/%s %d %s",
197 (*temptype)->super, (*temptype)->type,
198 p->filetype->super, p->filetype->type,
199 cost, program);
200 mimeAddFilter(MimeDatabase, *temptype, p->filetype, cost, program);
201 }
202 }
203
204
205 /*
206 * 'AddPrinterUser()' - Add a user to the ACL.
207 */
208
209 void
210 AddPrinterUser(printer_t *p, /* I - Printer */
211 const char *username) /* I - User */
212 {
213 const char **temp; /* Temporary array pointer */
214
215
216 if (!p || !username)
217 return;
218
219 if (p->num_users == 0)
220 temp = malloc(sizeof(char **));
221 else
222 temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
223
224 if (!temp)
225 return;
226
227 p->users = temp;
228 temp += p->num_users;
229
230 if ((*temp = strdup(username)) != NULL)
231 p->num_users ++;
232 }
233
234
235 /*
236 * 'DeleteAllPrinters()' - Delete all printers from the system.
237 */
238
239 void
240 DeleteAllPrinters(void)
241 {
242 printer_t *p, /* Pointer to current printer/class */
243 *next; /* Pointer to next printer in list */
244
245
246 for (p = Printers; p != NULL; p = next)
247 {
248 next = p->next;
249
250 if (!(p->type & CUPS_PRINTER_CLASS))
251 DeletePrinter(p);
252 }
253 }
254
255
256 /*
257 * 'DeletePrinter()' - Delete a printer from the system.
258 */
259
260 void
261 DeletePrinter(printer_t *p) /* I - Printer to delete */
262 {
263 printer_t *current, /* Current printer in list */
264 *prev; /* Previous printer in list */
265 #ifdef __sgi
266 char filename[1024]; /* Interface script filename */
267 #endif /* __sgi */
268
269
270 DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p, p->name));
271
272 /*
273 * Range check input...
274 */
275
276 if (p == NULL)
277 return;
278
279 /*
280 * Remove the printer from the list...
281 */
282
283 for (prev = NULL, current = Printers;
284 current != NULL;
285 prev = current, current = current->next)
286 if (p == current)
287 break;
288
289 if (current == NULL)
290 {
291 LogMessage(L_ERROR, "Tried to delete a non-existent printer %s!\n",
292 p->name);
293 return;
294 }
295
296 if (prev == NULL)
297 Printers = p->next;
298 else
299 prev->next = p->next;
300
301 /*
302 * Stop printing on this printer...
303 */
304
305 StopPrinter(p);
306
307 /*
308 * Remove the dummy interface/icon/option files under IRIX...
309 */
310
311 #ifdef __sgi
312 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
313 unlink(filename);
314
315 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
316 p->name);
317 unlink(filename);
318
319 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
320 unlink(filename);
321
322 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
323 unlink(filename);
324
325 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
326 unlink(filename);
327 #endif /* __sgi */
328
329 /*
330 * If p is the default printer, assign the next one...
331 */
332
333 if (p == DefaultPrinter)
334 {
335 DefaultPrinter = Printers;
336
337 #ifdef __sgi
338 write_irix_state(DefaultPrinter);
339 #endif /* __sgi */
340 }
341
342 /*
343 * Remove this printer from any classes...
344 */
345
346 if (!(p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)))
347 DeletePrinterFromClasses(p);
348
349 /*
350 * Free all memory used by the printer...
351 */
352
353 if (p->printers != NULL)
354 free(p->printers);
355
356 ippDelete(p->attrs);
357
358 DeletePrinterFilters(p);
359
360 FreePrinterUsers(p);
361 FreeQuotas(p);
362
363 free(p);
364
365 /*
366 * Write a new /etc/printcap file...
367 */
368
369 write_printcap();
370 }
371
372
373 /*
374 * 'DeletePrinterFilters()' - Delete all MIME filters for a printer.
375 */
376
377 void
378 DeletePrinterFilters(printer_t *p) /* I - Printer to remove from */
379 {
380 int i; /* Looping var */
381 mime_filter_t *filter; /* MIME filter looping var */
382
383
384 /*
385 * Range check input...
386 */
387
388 if (p == NULL)
389 return;
390
391 /*
392 * Remove all filters from the MIME database that have a destination
393 * type == printer...
394 */
395
396 for (filter = MimeDatabase->filters, i = MimeDatabase->num_filters;
397 i > 0;
398 i --, filter ++)
399 if (filter->dst == p->filetype)
400 {
401 /*
402 * Delete the current filter...
403 */
404
405 MimeDatabase->num_filters --;
406
407 if (i > 1)
408 memcpy(filter, filter + 1, sizeof(mime_filter_t) * (i - 1));
409
410 filter --;
411 }
412 }
413
414
415 /*
416 * 'FindPrinter()' - Find a printer in the list.
417 */
418
419 printer_t * /* O - Printer in list */
420 FindPrinter(const char *name) /* I - Name of printer to find */
421 {
422 printer_t *p; /* Current printer */
423
424
425 for (p = Printers; p != NULL; p = p->next)
426 switch (strcasecmp(name, p->name))
427 {
428 case 0 : /* name == p->name */
429 if (!(p->type & CUPS_PRINTER_CLASS))
430 return (p);
431 case 1 : /* name > p->name */
432 break;
433 case -1 : /* name < p->name */
434 return (NULL);
435 }
436
437 return (NULL);
438 }
439
440
441 /*
442 * 'FreePrinterUsers()' - Free allow/deny users.
443 */
444
445 void
446 FreePrinterUsers(printer_t *p) /* I - Printer */
447 {
448 int i; /* Looping var */
449
450
451 if (!p || !p->num_users)
452 return;
453
454 for (i = 0; i < p->num_users; i ++)
455 free((void *)p->users[i]);
456
457 free(p->users);
458
459 p->num_users = 0;
460 p->users = NULL;
461 }
462
463
464 /*
465 * 'LoadAllPrinters()' - Load printers from the printers.conf file.
466 */
467
468 void
469 LoadAllPrinters(void)
470 {
471 FILE *fp; /* printers.conf file */
472 int linenum; /* Current line number */
473 int len; /* Length of line */
474 char line[1024], /* Line from file */
475 name[256], /* Parameter name */
476 *nameptr, /* Pointer into name */
477 *value, /* Pointer to value */
478 *valueptr; /* Pointer into value */
479 printer_t *p; /* Current printer */
480
481
482 /*
483 * Open the printers.conf file...
484 */
485
486 snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
487 if ((fp = fopen(line, "r")) == NULL)
488 return;
489
490 /*
491 * Read printer configurations until we hit EOF...
492 */
493
494 linenum = 0;
495 p = NULL;
496
497 while (fgets(line, sizeof(line), fp) != NULL)
498 {
499 linenum ++;
500
501 /*
502 * Skip comment lines...
503 */
504
505 if (line[0] == '#')
506 continue;
507
508 /*
509 * Strip trailing whitespace, if any...
510 */
511
512 len = strlen(line);
513
514 while (len > 0 && isspace(line[len - 1]))
515 {
516 len --;
517 line[len] = '\0';
518 }
519
520 /*
521 * Extract the name from the beginning of the line...
522 */
523
524 for (value = line; isspace(*value); value ++);
525
526 for (nameptr = name; *value != '\0' && !isspace(*value) &&
527 nameptr < (name + sizeof(name) - 1);)
528 *nameptr++ = *value++;
529 *nameptr = '\0';
530
531 while (isspace(*value))
532 value ++;
533
534 if (name[0] == '\0')
535 continue;
536
537 /*
538 * Decode the directive...
539 */
540
541 if (strcmp(name, "<Printer") == 0 ||
542 strcmp(name, "<DefaultPrinter") == 0)
543 {
544 /*
545 * <Printer name> or <DefaultPrinter name>
546 */
547
548 if (line[len - 1] == '>' && p == NULL)
549 {
550 /*
551 * Add the printer and a base file type...
552 */
553
554 line[len - 1] = '\0';
555
556 p = AddPrinter(value);
557 p->accepting = 1;
558 p->state = IPP_PRINTER_IDLE;
559
560 /*
561 * Set the default printer as needed...
562 */
563
564 if (strcmp(name, "<DefaultPrinter") == 0)
565 DefaultPrinter = p;
566 }
567 else
568 {
569 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
570 linenum);
571 return;
572 }
573 }
574 else if (strcmp(name, "</Printer>") == 0)
575 {
576 if (p != NULL)
577 {
578 SetPrinterAttrs(p);
579 p = NULL;
580 }
581 else
582 {
583 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
584 linenum);
585 return;
586 }
587 }
588 else if (p == NULL)
589 {
590 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
591 linenum);
592 return;
593 }
594 else if (strcmp(name, "Info") == 0)
595 strncpy(p->info, value, sizeof(p->info) - 1);
596 else if (strcmp(name, "Location") == 0)
597 strncpy(p->location, value, sizeof(p->location) - 1);
598 else if (strcmp(name, "DeviceURI") == 0)
599 strncpy(p->device_uri, value, sizeof(p->device_uri) - 1);
600 else if (strcmp(name, "State") == 0)
601 {
602 /*
603 * Set the initial queue state...
604 */
605
606 if (strcasecmp(value, "idle") == 0)
607 p->state = IPP_PRINTER_IDLE;
608 else if (strcasecmp(value, "stopped") == 0)
609 p->state = IPP_PRINTER_STOPPED;
610 }
611 else if (strcmp(name, "StateMessage") == 0)
612 {
613 /*
614 * Set the initial queue state message...
615 */
616
617 while (isspace(*value))
618 value ++;
619
620 strncpy(p->state_message, value, sizeof(p->state_message) - 1);
621 }
622 else if (strcmp(name, "Accepting") == 0)
623 {
624 /*
625 * Set the initial accepting state...
626 */
627
628 if (strcasecmp(value, "yes") == 0)
629 p->accepting = 1;
630 else
631 p->accepting = 0;
632 }
633 else if (strcmp(name, "JobSheets") == 0)
634 {
635 /*
636 * Set the initial job sheets...
637 */
638
639 for (valueptr = value; *valueptr && !isspace(*valueptr); valueptr ++);
640
641 if (*valueptr)
642 *valueptr++ = '\0';
643
644 strncpy(p->job_sheets[0], value, sizeof(p->job_sheets[0]) - 1);
645
646 while (isspace(*valueptr))
647 valueptr ++;
648
649 if (*valueptr)
650 {
651 for (value = valueptr; *valueptr && !isspace(*valueptr); valueptr ++);
652
653 if (*valueptr)
654 *valueptr++ = '\0';
655
656 strncpy(p->job_sheets[1], value, sizeof(p->job_sheets[1]) - 1);
657 }
658 }
659 else if (strcmp(name, "AllowUser") == 0)
660 {
661 p->deny_users = 0;
662 AddPrinterUser(p, value);
663 }
664 else if (strcmp(name, "DenyUser") == 0)
665 {
666 p->deny_users = 1;
667 AddPrinterUser(p, value);
668 }
669 else if (strcmp(name, "QuotaPeriod") == 0)
670 p->quota_period = atoi(value);
671 else if (strcmp(name, "PageLimit") == 0)
672 p->page_limit = atoi(value);
673 else if (strcmp(name, "KLimit") == 0)
674 p->k_limit = atoi(value);
675 else
676 {
677 /*
678 * Something else we don't understand...
679 */
680
681 LogMessage(L_ERROR, "Unknown configuration directive %s on line %d of printers.conf.",
682 name, linenum);
683 }
684 }
685
686 fclose(fp);
687 }
688
689
690 /*
691 * 'SaveAllPrinters()' - Save all printer definitions to the printers.conf
692 * file.
693 */
694
695 void
696 SaveAllPrinters(void)
697 {
698 int i; /* Looping var */
699 FILE *fp; /* printers.conf file */
700 char temp[1024]; /* Temporary string */
701 char backup[1024]; /* printers.conf.O file */
702 printer_t *printer; /* Current printer class */
703 time_t curtime; /* Current time */
704 struct tm *curdate; /* Current date */
705
706
707 /*
708 * Create the printers.conf file...
709 */
710
711 snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
712 snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
713
714 if (rename(temp, backup))
715 LogMessage(L_ERROR, "Unable to backup printers.conf - %s", strerror(errno));
716
717 if ((fp = fopen(temp, "w")) == NULL)
718 {
719 LogMessage(L_ERROR, "Unable to save printers.conf - %s", strerror(errno));
720
721 if (rename(backup, temp))
722 LogMessage(L_ERROR, "Unable to restore printers.conf - %s", strerror(errno));
723 return;
724 }
725 else
726 LogMessage(L_INFO, "Saving printers.conf...");
727
728 /*
729 * Restrict access to the file...
730 */
731
732 fchown(fileno(fp), User, Group);
733 fchmod(fileno(fp), 0600);
734
735 /*
736 * Write a small header to the file...
737 */
738
739 curtime = time(NULL);
740 curdate = gmtime(&curtime);
741 strftime(temp, sizeof(temp) - 1, CUPS_STRFTIME_FORMAT, curdate);
742
743 fputs("# Printer configuration file for " CUPS_SVERSION "\n", fp);
744 fprintf(fp, "# Written by cupsd on %s\n", temp);
745
746 /*
747 * Write each local printer known to the system...
748 */
749
750 for (printer = Printers; printer != NULL; printer = printer->next)
751 {
752 /*
753 * Skip remote destinations and printer classes...
754 */
755
756 if ((printer->type & CUPS_PRINTER_REMOTE) ||
757 (printer->type & CUPS_PRINTER_CLASS) ||
758 (printer->type & CUPS_PRINTER_IMPLICIT))
759 continue;
760
761 /*
762 * Write printers as needed...
763 */
764
765 if (printer == DefaultPrinter)
766 fprintf(fp, "<DefaultPrinter %s>\n", printer->name);
767 else
768 fprintf(fp, "<Printer %s>\n", printer->name);
769
770 if (printer->info[0])
771 fprintf(fp, "Info %s\n", printer->info);
772
773 if (printer->location[0])
774 fprintf(fp, "Location %s\n", printer->location);
775
776 if (printer->device_uri[0])
777 fprintf(fp, "DeviceURI %s\n", printer->device_uri);
778
779 if (printer->state == IPP_PRINTER_STOPPED)
780 {
781 fputs("State Stopped\n", fp);
782 fprintf(fp, "StateMessage %s\n", printer->state_message);
783 }
784 else
785 fputs("State Idle\n", fp);
786
787 if (printer->accepting)
788 fputs("Accepting Yes\n", fp);
789 else
790 fputs("Accepting No\n", fp);
791
792 fprintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
793 printer->job_sheets[1]);
794
795 fprintf(fp, "QuotaPeriod %d\n", printer->quota_period);
796 fprintf(fp, "PageLimit %d\n", printer->page_limit);
797 fprintf(fp, "KLimit %d\n", printer->k_limit);
798
799 for (i = 0; i < printer->num_users; i ++)
800 fprintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
801 printer->users[i]);
802
803 fputs("</Printer>\n", fp);
804 #ifdef __sgi
805 /*
806 * Make IRIX desktop & printer status happy
807 */
808
809 write_irix_state(printer);
810
811 #endif /* __sgi */
812 }
813
814 fclose(fp);
815 }
816
817
818 /*
819 * 'SetPrinterAttrs()' - Set printer attributes based upon the PPD file.
820 */
821
822 void
823 SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
824 {
825 char uri[HTTP_MAX_URI]; /* URI for printer */
826 char method[HTTP_MAX_URI], /* Method portion of URI */
827 username[HTTP_MAX_URI], /* Username portion of URI */
828 host[HTTP_MAX_URI], /* Host portion of URI */
829 resource[HTTP_MAX_URI]; /* Resource portion of URI */
830 int port; /* Port portion of URI */
831 int i; /* Looping var */
832 char filename[1024]; /* Name of PPD file */
833 int num_media; /* Number of media options */
834 location_t *auth; /* Pointer to authentication element */
835 const char *auth_supported; /* Authentication supported */
836 cups_ptype_t printer_type; /* Printer type data */
837 ppd_file_t *ppd; /* PPD file data */
838 ppd_option_t *input_slot, /* InputSlot options */
839 *media_type, /* MediaType options */
840 *page_size, /* PageSize options */
841 *output_bin; /* OutputBin options */
842 ipp_attribute_t *attr; /* Attribute data */
843 ipp_value_t *val; /* Attribute value */
844 int nups[3] = /* number-up-supported values */
845 { 1, 2, 4 };
846 ipp_orient_t orients[4] = /* orientation-requested-supported values */
847 {
848 IPP_PORTRAIT,
849 IPP_LANDSCAPE,
850 IPP_REVERSE_LANDSCAPE,
851 IPP_REVERSE_PORTRAIT
852 };
853 const char *sides[3] = /* sides-supported values */
854 {
855 "one",
856 "two-long-edge",
857 "two-short-edge"
858 };
859 const char *versions[] = /* ipp-versions-supported values */
860 {
861 "1.0",
862 "1.1"
863 };
864 ipp_op_t ops[] = /* operations-supported values */
865 {
866 IPP_PRINT_JOB,
867 IPP_VALIDATE_JOB,
868 IPP_CREATE_JOB,
869 IPP_SEND_DOCUMENT,
870 IPP_CANCEL_JOB,
871 IPP_GET_JOB_ATTRIBUTES,
872 IPP_GET_JOBS,
873 IPP_GET_PRINTER_ATTRIBUTES,
874 IPP_HOLD_JOB,
875 IPP_RELEASE_JOB,
876 IPP_PAUSE_PRINTER,
877 IPP_RESUME_PRINTER,
878 IPP_PURGE_JOBS,
879 IPP_SET_JOB_ATTRIBUTES,
880 IPP_ENABLE_PRINTER,
881 IPP_DISABLE_PRINTER,
882 CUPS_GET_DEFAULT,
883 CUPS_GET_PRINTERS,
884 CUPS_ADD_PRINTER,
885 CUPS_DELETE_PRINTER,
886 CUPS_GET_CLASSES,
887 CUPS_ADD_CLASS,
888 CUPS_DELETE_CLASS,
889 CUPS_ACCEPT_JOBS,
890 CUPS_REJECT_JOBS,
891 CUPS_GET_DEVICES,
892 CUPS_GET_PPDS,
893 IPP_RESTART_JOB
894 };
895 const char *charsets[] = /* charset-supported values */
896 {
897 "us-ascii",
898 "iso-8859-1",
899 "iso-8859-2",
900 "iso-8859-3",
901 "iso-8859-4",
902 "iso-8859-5",
903 "iso-8859-6",
904 "iso-8859-7",
905 "iso-8859-8",
906 "iso-8859-9",
907 "iso-8859-10",
908 "iso-8859-13",
909 "iso-8859-14",
910 "iso-8859-15",
911 "utf-8",
912 "windows-874",
913 "windows-1250",
914 "windows-1251",
915 "windows-1252",
916 "windows-1253",
917 "windows-1254",
918 "windows-1255",
919 "windows-1256",
920 "windows-1257",
921 "windows-1258"
922 };
923 int num_finishings;
924 ipp_finish_t finishings[5];
925 const char *multiple_document_handling[] =
926 {
927 "separate-documents-uncollated-copies",
928 "separate-documents-collated-copies"
929 };
930 #ifdef __sgi
931 FILE *fp; /* Interface script file */
932 #endif /* __sgi */
933
934
935 DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p->name,
936 p->type));
937
938 /*
939 * Clear out old filters and add a filter from application/vnd.cups-raw to
940 * printer/name to handle "raw" printing by users.
941 */
942
943 DeletePrinterFilters(p);
944 AddPrinterFilter(p, "application/vnd.cups-raw 0 -");
945
946 /*
947 * Figure out the authentication that is required for the printer.
948 */
949
950 auth_supported = "requesting-user-name";
951 if (!(p->type & CUPS_PRINTER_REMOTE))
952 {
953 if (p->type & CUPS_PRINTER_CLASS)
954 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
955 else
956 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
957
958 if ((auth = FindBest(resource, HTTP_POST)) != NULL)
959 {
960 if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST)
961 auth_supported = "basic";
962 else if (auth->type == AUTH_DIGEST)
963 auth_supported = "digest";
964 }
965 }
966
967 /*
968 * Create the required IPP attributes for a printer...
969 */
970
971 if (p->attrs)
972 ippDelete(p->attrs);
973
974 p->attrs = ippNew();
975
976 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported",
977 NULL, p->uri);
978 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
979 "uri-authentication-supported", NULL, auth_supported);
980 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
981 "uri-security-supported", NULL, "none");
982 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
983 p->name);
984 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
985 NULL, p->location);
986 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
987 NULL, p->info);
988 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
989 NULL, p->uri);
990 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
991 "pdl-override-supported", NULL, "not-attempted");
992 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
993 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
994 NULL, versions);
995 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported",
996 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
997 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "multiple-document-jobs-supported", 1);
998 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
999 "multiple-operation-time-out", 60);
1000 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1001 "multiple-document-handling-supported",
1002 sizeof(multiple_document_handling) /
1003 sizeof(multiple_document_handling[0]), NULL,
1004 multiple_document_handling);
1005 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-configured",
1006 NULL, DefaultCharset);
1007 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET, "charset-supported",
1008 sizeof(charsets) / sizeof(charsets[0]), NULL, charsets);
1009 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
1010 "natural-language-configured", NULL, DefaultLanguage);
1011 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
1012 "generated-natural-language-supported", NULL, DefaultLanguage);
1013 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
1014 "document-format-default", NULL, "application/octet-stream");
1015 ippAddStrings(p->attrs, IPP_TAG_PRINTER,
1016 (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
1017 "document-format-supported", NumMimeTypes, NULL, MimeTypes);
1018 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1019 "compression-supported", NULL, "none");
1020 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1021 "job-priority-supported", 100);
1022 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1023 "job-priority-default", 50);
1024 ippAddRange(p->attrs, IPP_TAG_PRINTER, "copies-supported", 1, 65535);
1025 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1026 "copies-default", 1);
1027 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "page-ranges-supported", 1);
1028 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1029 "number-up-supported", 3, nups);
1030 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1031 "number-up-default", 1);
1032 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
1033 "orientation-requested-supported", 4, (int *)orients);
1034 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
1035 "orientation-requested-default", IPP_PORTRAIT);
1036
1037 if (p->num_users)
1038 {
1039 if (p->deny_users)
1040 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1041 "requesting-user-name-denied", p->num_users, NULL,
1042 p->users);
1043 else
1044 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1045 "requesting-user-name-allowed", p->num_users, NULL,
1046 p->users);
1047 }
1048
1049 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1050 "job-quota-period", p->quota_period);
1051 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1052 "job-k-limit", p->k_limit);
1053 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1054 "job-page-limit", p->page_limit);
1055
1056 if (NumBanners > 0)
1057 {
1058 /*
1059 * Setup the job-sheets-supported and job-sheets-default attributes...
1060 */
1061
1062 if (Classification[0] && !ClassifyOverride)
1063 attr = ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1064 "job-sheets-supported", NULL, Classification);
1065 else
1066 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1067 "job-sheets-supported", NumBanners + 1, NULL, NULL);
1068
1069 if (attr == NULL)
1070 LogMessage(L_EMERG, "SetPrinterAttrs: Unable to allocate memory for "
1071 "job-sheets-supported attribute: %s!",
1072 strerror(errno));
1073 else if (!Classification[0] || ClassifyOverride)
1074 {
1075 attr->values[0].string.text = strdup("none");
1076
1077 for (i = 0; i < NumBanners; i ++)
1078 attr->values[i + 1].string.text = strdup(Banners[i].name);
1079 }
1080
1081 if (!(p->type & CUPS_PRINTER_REMOTE))
1082 {
1083 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1084 "job-sheets-default", 2, NULL, NULL);
1085
1086 if (attr != NULL)
1087 {
1088 attr->values[0].string.text = strdup(Classification[0] ?
1089 Classification : p->job_sheets[0]);
1090 attr->values[1].string.text = strdup(Classification[0] ?
1091 Classification : p->job_sheets[1]);
1092 }
1093 }
1094 }
1095
1096 printer_type = p->type;
1097
1098 if (p->type & CUPS_PRINTER_REMOTE)
1099 {
1100 /*
1101 * Tell the client this is a remote printer of some type...
1102 */
1103
1104 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1105 "printer-make-and-model", NULL, p->make_model);
1106 }
1107 else
1108 {
1109 /*
1110 * Assign additional attributes depending on whether this is a printer
1111 * or class...
1112 */
1113
1114 p->type &= ~CUPS_PRINTER_OPTIONS;
1115
1116 if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
1117 {
1118 /*
1119 * Add class-specific attributes...
1120 */
1121
1122 if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0)
1123 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1124 "printer-make-and-model", NULL, p->printers[0]->make_model);
1125 else
1126 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1127 "printer-make-and-model", NULL, "Local Printer Class");
1128
1129 if (p->num_printers > 0)
1130 {
1131 /*
1132 * Add a list of member URIs and names...
1133 */
1134
1135 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
1136 "member-uris", p->num_printers, NULL, NULL);
1137 p->type |= CUPS_PRINTER_OPTIONS;
1138
1139 for (i = 0; i < p->num_printers; i ++)
1140 {
1141 if (attr != NULL)
1142 attr->values[i].string.text = strdup(p->printers[i]->uri);
1143
1144 p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
1145 }
1146
1147 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1148 "member-names", p->num_printers, NULL, NULL);
1149
1150 if (attr != NULL)
1151 {
1152 for (i = 0; i < p->num_printers; i ++)
1153 attr->values[i].string.text = strdup(p->printers[i]->name);
1154 }
1155 }
1156 }
1157 else
1158 {
1159 /*
1160 * Add printer-specific attributes... Start by sanitizing the device
1161 * URI so it doesn't have a username or password in it...
1162 */
1163
1164 if (strstr(p->device_uri, "://") != NULL)
1165 {
1166 /*
1167 * http://..., ipp://..., etc.
1168 */
1169
1170 httpSeparate(p->device_uri, method, username, host, &port, resource);
1171 if (port)
1172 snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, host, port,
1173 resource);
1174 else
1175 snprintf(uri, sizeof(uri), "%s://%s%s", method, host, resource);
1176 }
1177 else
1178 {
1179 /*
1180 * file:..., serial:..., etc.
1181 */
1182
1183 strcpy(uri, p->device_uri);
1184 }
1185
1186 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1187 uri);
1188
1189 /*
1190 * Assign additional attributes from the PPD file (if any)...
1191 */
1192
1193 p->type |= CUPS_PRINTER_BW;
1194 finishings[0] = IPP_FINISHINGS_NONE;
1195 num_finishings = 1;
1196
1197 snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
1198 p->name);
1199
1200 if ((ppd = ppdOpenFile(filename)) != NULL)
1201 {
1202 /*
1203 * Add make/model and other various attributes...
1204 */
1205
1206 if (ppd->color_device)
1207 p->type |= CUPS_PRINTER_COLOR;
1208 if (ppd->variable_sizes)
1209 p->type |= CUPS_PRINTER_VARIABLE;
1210 if (!ppd->manual_copies)
1211 p->type |= CUPS_PRINTER_COPIES;
1212
1213 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
1214 ppd->color_device);
1215 if (ppd->throughput)
1216 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1217 "pages-per-minute", ppd->throughput);
1218 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1219 "printer-make-and-model", NULL, ppd->nickname);
1220
1221 if (ppd->nickname)
1222 strncpy(p->make_model, ppd->nickname, sizeof(p->make_model) - 1);
1223 else if (ppd->modelname)
1224 strncpy(p->make_model, ppd->modelname, sizeof(p->make_model) - 1);
1225 else
1226 strcpy(p->make_model, "Bad PPD File");
1227
1228 /*
1229 * Add media options from the PPD file...
1230 */
1231
1232 if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
1233 num_media = input_slot->num_choices;
1234 else
1235 num_media = 0;
1236
1237 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
1238 num_media += media_type->num_choices;
1239
1240 if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
1241 num_media += page_size->num_choices;
1242
1243 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1244 "media-supported", num_media, NULL, NULL);
1245 if (attr != NULL)
1246 {
1247 val = attr->values;
1248
1249 if (input_slot != NULL)
1250 for (i = 0; i < input_slot->num_choices; i ++, val ++)
1251 val->string.text = strdup(input_slot->choices[i].choice);
1252
1253 if (media_type != NULL)
1254 for (i = 0; i < media_type->num_choices; i ++, val ++)
1255 val->string.text = strdup(media_type->choices[i].choice);
1256
1257 if (page_size != NULL)
1258 {
1259 for (i = 0; i < page_size->num_choices; i ++, val ++)
1260 val->string.text = strdup(page_size->choices[i].choice);
1261
1262 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1263 NULL, page_size->defchoice);
1264 }
1265 else if (input_slot != NULL)
1266 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1267 NULL, input_slot->defchoice);
1268 else if (media_type != NULL)
1269 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1270 NULL, media_type->defchoice);
1271 else
1272 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1273 NULL, "none");
1274 }
1275
1276 /*
1277 * Output bin...
1278 */
1279
1280 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
1281 {
1282 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1283 "output-bin-supported", output_bin->num_choices,
1284 NULL, NULL);
1285
1286 if (attr != NULL)
1287 {
1288 for (i = 0, val = attr->values;
1289 i < output_bin->num_choices;
1290 i ++, val ++)
1291 val->string.text = strdup(output_bin->choices[i].choice);
1292 }
1293 }
1294
1295 /*
1296 * Duplexing, etc...
1297 */
1298
1299 if (ppdFindOption(ppd, "Duplex") != NULL)
1300 {
1301 p->type |= CUPS_PRINTER_DUPLEX;
1302
1303 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported",
1304 3, NULL, sides);
1305 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-default",
1306 NULL, "one");
1307 }
1308
1309 if (ppdFindOption(ppd, "Collate") != NULL)
1310 p->type |= CUPS_PRINTER_COLLATE;
1311
1312 if (ppdFindOption(ppd, "StapleLocation") != NULL)
1313 {
1314 p->type |= CUPS_PRINTER_STAPLE;
1315 finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
1316 }
1317
1318 if (ppdFindOption(ppd, "BindEdge") != NULL)
1319 {
1320 p->type |= CUPS_PRINTER_BIND;
1321 finishings[num_finishings++] = IPP_FINISHINGS_BIND;
1322 }
1323
1324 for (i = 0; i < ppd->num_sizes; i ++)
1325 if (ppd->sizes[i].length > 1728)
1326 p->type |= CUPS_PRINTER_LARGE;
1327 else if (ppd->sizes[i].length > 1008)
1328 p->type |= CUPS_PRINTER_MEDIUM;
1329 else
1330 p->type |= CUPS_PRINTER_SMALL;
1331
1332 /*
1333 * Add any filters in the PPD file...
1334 */
1335
1336 DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
1337 for (i = 0; i < ppd->num_filters; i ++)
1338 {
1339 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
1340 AddPrinterFilter(p, ppd->filters[i]);
1341 }
1342
1343 if (ppd->num_filters == 0)
1344 AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
1345
1346 ppdClose(ppd);
1347
1348 printer_type = p->type;
1349 }
1350 else if (access(filename, 0) == 0)
1351 {
1352 LogMessage(L_ERROR, "PPD file for %s cannot be loaded!", p->name);
1353
1354 AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
1355 }
1356 else
1357 {
1358 /*
1359 * If we have an interface script, add a filter entry for it...
1360 */
1361
1362 snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
1363 p->name);
1364 if (access(filename, X_OK) == 0)
1365 {
1366 /*
1367 * Yes, we have a System V style interface script; use it!
1368 */
1369
1370 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1371 "printer-make-and-model", NULL, "Local System V Printer");
1372
1373 snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
1374 ServerRoot, p->name);
1375 AddPrinterFilter(p, filename);
1376 }
1377 else if (strncmp(p->device_uri, "ipp://", 6) == 0 &&
1378 (strstr(p->device_uri, "/printers/") != NULL ||
1379 strstr(p->device_uri, "/classes/") != NULL))
1380 {
1381 /*
1382 * Tell the client this is really a hard-wired remote printer.
1383 */
1384
1385 printer_type |= CUPS_PRINTER_REMOTE;
1386
1387 /*
1388 * Reset the printer-uri-supported attribute to point at the
1389 * remote printer...
1390 */
1391
1392 attr = ippFindAttribute(p->attrs, "printer-uri-supported", IPP_TAG_URI);
1393 free(attr->values[0].string.text);
1394 attr->values[0].string.text = strdup(p->device_uri);
1395
1396 /*
1397 * Then set the make-and-model accordingly...
1398 */
1399
1400 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1401 "printer-make-and-model", NULL, "Remote Printer");
1402
1403 /*
1404 * Print all files directly...
1405 */
1406
1407 AddPrinterFilter(p, "*/* 0 -");
1408 }
1409 else
1410 {
1411 /*
1412 * Otherwise we have neither - treat this as a "dumb" printer
1413 * with no PPD file...
1414 */
1415
1416 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1417 "printer-make-and-model", NULL, "Local Raw Printer");
1418
1419 AddPrinterFilter(p, "*/* 0 -");
1420 }
1421 }
1422
1423 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
1424 "finishings-supported", num_finishings, (int *)finishings);
1425 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
1426 "finishings-default", IPP_FINISHINGS_NONE);
1427 }
1428 }
1429
1430 /*
1431 * Add the CUPS-specific printer-type attribute...
1432 */
1433
1434 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type",
1435 printer_type);
1436
1437 DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
1438 p->type));
1439
1440 #ifdef __sgi
1441 /*
1442 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
1443 * tools. First the interface script that tells the tools what kind of
1444 * printer we have...
1445 */
1446
1447 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
1448
1449 if ((fp = fopen(filename, "w")) != NULL)
1450 {
1451 fputs("#!/bin/sh\n", fp);
1452
1453 if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
1454 IPP_TAG_TEXT)) != NULL)
1455 fprintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
1456 else if (p->type & CUPS_PRINTER_CLASS)
1457 fputs("NAME=\"Printer Class\"\n", fp);
1458 else
1459 fputs("NAME=\"Remote Destination\"\n", fp);
1460
1461 if (p->type & CUPS_PRINTER_COLOR)
1462 fputs("TYPE=ColorPostScript\n", fp);
1463 else
1464 fputs("TYPE=PostScript\n", fp);
1465
1466 fclose(fp);
1467
1468 chmod(filename, 0755);
1469 chown(filename, User, Group);
1470 }
1471
1472 /*
1473 * Then the member file that tells which device file the queue is connected
1474 * to... Networked printers use "/dev/null" in this file, so that's what
1475 * we use (the actual device URI can confuse some apps...)
1476 */
1477
1478 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
1479 if ((fp = fopen(filename, "w")) != NULL)
1480 {
1481 fputs("/dev/null\n", fp);
1482
1483 fclose(fp);
1484
1485 chmod(filename, 0644);
1486 chown(filename, User, Group);
1487 }
1488
1489 /*
1490 * The gui_interface file is a script or program that launches a GUI
1491 * option panel for the printer, using options specified on the
1492 * command-line in the third argument. The option panel must send
1493 * any printing options to stdout on a single line when the user
1494 * accepts them, or nothing if the user cancels the dialog.
1495 *
1496 * The default options panel program is /usr/bin/glpoptions, from
1497 * the ESP Print Pro software. You can select another using the
1498 * PrintcapGUI option.
1499 */
1500
1501 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
1502
1503 if ((fp = fopen(filename, "w")) != NULL)
1504 {
1505 fputs("#!/bin/sh\n", fp);
1506 fprintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
1507
1508 fclose(fp);
1509
1510 chmod(filename, 0755);
1511 chown(filename, User, Group);
1512 }
1513
1514 /*
1515 * The POD config file is needed by the printstatus command to show
1516 * the printer location and device.
1517 */
1518
1519 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
1520 if ((fp = fopen(filename, "w")) != NULL)
1521 {
1522 fprintf(fp, "Printer Class | %s\n",
1523 (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "PostScript");
1524 fprintf(fp, "Printer Model | %s\n", p->make_model);
1525 fprintf(fp, "Location Code | %s\n", p->uri);
1526 fprintf(fp, "Physical Location | %s\n", p->location);
1527 fprintf(fp, "Port Path | %s\n", p->device_uri);
1528 fprintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
1529 fprintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
1530 fputs("Status Update Wait | 10 seconds\n", fp);
1531
1532 fclose(fp);
1533
1534 chmod(filename, 0664);
1535 chown(filename, User, Group);
1536 }
1537
1538 /*
1539 * Write the IRIX printer status files...
1540 */
1541
1542 write_irix_state(p);
1543 #endif /* __sgi */
1544 }
1545
1546
1547 /*
1548 * 'SetPrinterState()' - Update the current state of a printer.
1549 */
1550
1551 void
1552 SetPrinterState(printer_t *p, /* I - Printer to change */
1553 ipp_pstate_t s) /* I - New state */
1554 {
1555 ipp_pstate_t old_state; /* Old printer state */
1556
1557
1558 /*
1559 * Can't set status of remote printers...
1560 */
1561
1562 if (p->type & CUPS_PRINTER_REMOTE)
1563 return;
1564
1565 /*
1566 * Set the new state...
1567 */
1568
1569 old_state = p->state;
1570 p->state = s;
1571 p->state_time = time(NULL);
1572
1573 if (old_state != s)
1574 p->browse_time = 0;
1575
1576 /*
1577 * Save the printer configuration if a printer goes from idle or processing
1578 * to stopped (or visa-versa)...
1579 */
1580
1581 if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
1582 SaveAllPrinters();
1583
1584 /*
1585 * Check to see if any pending jobs can now be printed...
1586 */
1587
1588 CheckJobs();
1589 }
1590
1591
1592 /*
1593 * 'SortPrinters()' - Sort the printer list when a printer name is changed.
1594 */
1595
1596 void
1597 SortPrinters(void)
1598 {
1599 printer_t *current, /* Current printer */
1600 *prev, /* Previous printer */
1601 *next; /* Next printer */
1602 int did_swap; /* Non-zero if we did a swap */
1603
1604
1605 do
1606 {
1607 for (did_swap = 0, current = Printers, prev = NULL; current != NULL;)
1608 if (current->next == NULL)
1609 break;
1610 else if (strcasecmp(current->name, current->next->name) > 0)
1611 {
1612 DEBUG_printf(("Swapping %s and %s...\n", current->name,
1613 current->next->name));
1614
1615 /*
1616 * Need to swap these two printers...
1617 */
1618
1619 did_swap = 1;
1620
1621 if (prev == NULL)
1622 Printers = current->next;
1623 else
1624 prev->next = current->next;
1625
1626 /*
1627 * Yes, we can all get a headache from the next bunch of pointer
1628 * swapping...
1629 */
1630
1631 next = current->next;
1632 current->next = next->next;
1633 next->next = current;
1634 prev = next;
1635 }
1636 else
1637 {
1638 prev = current;
1639 current = current->next;
1640 }
1641 }
1642 while (did_swap);
1643 }
1644
1645
1646 /*
1647 * 'StopPrinter()' - Stop a printer from printing any jobs...
1648 */
1649
1650 void
1651 StopPrinter(printer_t *p) /* I - Printer to stop */
1652 {
1653 job_t *job; /* Active print job */
1654
1655
1656 /*
1657 * See if we have a job printing on this printer...
1658 */
1659
1660 if (p->job)
1661 {
1662 /*
1663 * Get pointer to job...
1664 */
1665
1666 job = (job_t *)p->job;
1667
1668 /*
1669 * Stop it...
1670 */
1671
1672 StopJob(job->id);
1673
1674 /*
1675 * Reset the state to pending...
1676 */
1677
1678 job->state->values[0].integer = IPP_JOB_PENDING;
1679
1680 SaveJob(job->id);
1681 }
1682
1683 p->state = IPP_PRINTER_STOPPED;
1684 }
1685
1686
1687 /*
1688 * 'ValidateDest()' - Validate a printer/class destination.
1689 */
1690
1691 const char * /* O - Printer or class name */
1692 ValidateDest(const char *hostname, /* I - Host name */
1693 const char *resource, /* I - Resource name */
1694 cups_ptype_t *dtype) /* O - Type (printer or class) */
1695 {
1696 printer_t *p; /* Current printer */
1697 char localname[1024], /* Localized hostname */
1698 *lptr, /* Pointer into localized hostname */
1699 *sptr; /* Pointer into server name */
1700
1701
1702 DEBUG_printf(("ValidateDest(\"%s\", \"%s\", %p)\n", hostname, resource, dtype));
1703
1704 /*
1705 * See if the resource is a class or printer...
1706 */
1707
1708 if (strncmp(resource, "/classes/", 9) == 0)
1709 {
1710 /*
1711 * Class...
1712 */
1713
1714 resource += 9;
1715 }
1716 else if (strncmp(resource, "/printers/", 10) == 0)
1717 {
1718 /*
1719 * Printer...
1720 */
1721
1722 resource += 10;
1723 }
1724 else
1725 {
1726 /*
1727 * Bad resource name...
1728 */
1729
1730 return (NULL);
1731 }
1732
1733 /*
1734 * See if the printer or class name exists...
1735 */
1736
1737 if ((p = FindPrinter(resource)) == NULL)
1738 p = FindClass(resource);
1739
1740 if (p == NULL && strchr(resource, '@') == NULL)
1741 return (NULL);
1742 else if (p != NULL)
1743 {
1744 *dtype = p->type & CUPS_PRINTER_CLASS;
1745 return (p->name);
1746 }
1747
1748 /*
1749 * Change localhost to the server name...
1750 */
1751
1752 if (strcasecmp(hostname, "localhost") == 0)
1753 hostname = ServerName;
1754
1755 strncpy(localname, hostname, sizeof(localname) - 1);
1756 localname[sizeof(localname) - 1] = '\0';
1757
1758 if (strcasecmp(hostname, ServerName) != 0)
1759 {
1760 /*
1761 * Localize the hostname...
1762 */
1763
1764 lptr = strchr(localname, '.');
1765 sptr = strchr(ServerName, '.');
1766
1767 if (sptr != NULL && lptr != NULL)
1768 {
1769 /*
1770 * Strip the common domain name components...
1771 */
1772
1773 while (lptr != NULL)
1774 {
1775 if (strcasecmp(lptr, sptr) == 0)
1776 {
1777 *lptr = '\0';
1778 break;
1779 }
1780 else
1781 lptr = strchr(lptr + 1, '.');
1782 }
1783 }
1784 }
1785
1786 DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
1787
1788 /*
1789 * Find a matching printer or class...
1790 */
1791
1792 for (p = Printers; p != NULL; p = p->next)
1793 if (strcasecmp(p->hostname, localname) == 0 &&
1794 strcasecmp(p->name, resource) == 0)
1795 {
1796 *dtype = p->type & CUPS_PRINTER_CLASS;
1797 return (p->name);
1798 }
1799
1800 return (NULL);
1801 }
1802
1803
1804 /*
1805 * 'write_printcap()' - Write a pseudo-printcap file for older applications
1806 * that need it...
1807 */
1808
1809 static void
1810 write_printcap(void)
1811 {
1812 FILE *fp; /* printcap file */
1813 printer_t *p; /* Current printer */
1814
1815
1816 /*
1817 * See if we have a printcap file; if not, don't bother writing it.
1818 */
1819
1820 if (!Printcap[0])
1821 return;
1822
1823 /*
1824 * Open the printcap file...
1825 */
1826
1827 if ((fp = fopen(Printcap, "w")) == NULL)
1828 return;
1829
1830 /*
1831 * Write a new printcap with the current list of printers.
1832 */
1833
1834 switch (PrintcapFormat)
1835 {
1836 case PRINTCAP_BSD:
1837 /*
1838 * Each printer is put in the file as:
1839 *
1840 * Printer1:
1841 * Printer2:
1842 * Printer3:
1843 * ...
1844 * PrinterN:
1845 */
1846
1847 for (p = Printers; p != NULL; p = p->next)
1848 fprintf(fp, "%s:\n", p->name);
1849 break;
1850
1851 case PRINTCAP_SOLARIS:
1852 /*
1853 * Each printer is put in the file as:
1854 *
1855 * _all:all=Printer1,Printer2,Printer3,...,PrinterN
1856 * _default:use=DefaultPrinter
1857 * Printer1:
1858 * Printer2:
1859 * Printer3:
1860 * ...
1861 * PrinterN:
1862 */
1863
1864 fputs("_all:all=", fp);
1865 for (p = Printers; p != NULL; p = p->next)
1866 fprintf(fp, "%s%c", p->name, p->next ? ',' : '\n');
1867
1868 if (DefaultPrinter)
1869 fprintf(fp, "_default:use=%s\n", DefaultPrinter->name);
1870
1871 for (p = Printers; p != NULL; p = p->next)
1872 fprintf(fp, "%s:\n", p->name);
1873 break;
1874 }
1875
1876 /*
1877 * Close the file...
1878 */
1879
1880 fclose(fp);
1881 }
1882
1883
1884 #ifdef __sgi
1885 /*
1886 * 'write_irix_state()' - Update the status files used by IRIX printing
1887 * desktop tools.
1888 */
1889
1890 static void
1891 write_irix_state(printer_t *p) /* I - Printer to update */
1892 {
1893 char filename[1024]; /* Interface script filename */
1894 FILE *fp; /* Interface script file */
1895 int tag; /* Status tag value */
1896
1897
1898 /*
1899 * The POD status file is needed for the printstatus window to
1900 * provide the current status of the printer.
1901 */
1902
1903 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
1904
1905 if ((fp = fopen(filename, "w")) != NULL)
1906 {
1907 fprintf(fp, "Operational Status | %s\n",
1908 (p->state == IPP_PRINTER_IDLE) ? "Idle" :
1909 (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
1910 "Faulted");
1911 fprintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
1912 fprintf(fp, "Information | 02 00 00 | %s jobs\n",
1913 p->accepting ? "Accepting" : "Not accepting");
1914 fprintf(fp, "Information | 03 00 00 | %s\n", p->state_message);
1915
1916 fclose(fp);
1917
1918 chmod(filename, 0664);
1919 chown(filename, User, Group);
1920 }
1921
1922 /*
1923 * The activeicons file is needed to provide desktop icons for printers:
1924 *
1925 * [ quoted from /usr/lib/print/tagit ]
1926 *
1927 * --- Type of printer tags (base values)
1928 *
1929 * Dumb=66048 # 0x10200
1930 * DumbColor=66080 # 0x10220
1931 * Raster=66112 # 0x10240
1932 * ColorRaster=66144 # 0x10260
1933 * Plotter=66176 # 0x10280
1934 * PostScript=66208 # 0x102A0
1935 * ColorPostScript=66240 # 0x102C0
1936 * MonoPostScript=66272 # 0x102E0
1937 *
1938 * --- Printer state modifiers for local printers
1939 *
1940 * Idle=0 # 0x0
1941 * Busy=1 # 0x1
1942 * Faulted=2 # 0x2
1943 * Unknown=3 # 0x3 (Faulted due to unknown reason)
1944 *
1945 * --- Printer state modifiers for network printers
1946 *
1947 * NetIdle=8 # 0x8
1948 * NetBusy=9 # 0x9
1949 * NetFaulted=10 # 0xA
1950 * NetUnknown=11 # 0xB (Faulted due to unknown reason)
1951 */
1952
1953 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
1954
1955 if ((fp = fopen(filename, "w")) != NULL)
1956 {
1957 if (p->type & CUPS_PRINTER_COLOR)
1958 tag = 66240;
1959 else
1960 tag = 66208;
1961
1962 if (p->type & CUPS_PRINTER_REMOTE)
1963 tag |= 8;
1964
1965 if (p->state == IPP_PRINTER_PROCESSING)
1966 tag |= 1;
1967
1968 else if (p->state == IPP_PRINTER_STOPPED)
1969 tag |= 2;
1970
1971 fputs("#!/bin/sh\n", fp);
1972 fprintf(fp, "#Tag %d\n", tag);
1973
1974 fclose(fp);
1975
1976 chmod(filename, 0755);
1977 chown(filename, User, Group);
1978 }
1979
1980 /*
1981 * The default file is needed by the printers window to show
1982 * the default printer.
1983 */
1984
1985 snprintf(filename, sizeof(filename), "/var/spool/lp/default");
1986
1987 if (DefaultPrinter != NULL)
1988 {
1989 if ((fp = fopen(filename, "w")) != NULL)
1990 {
1991 fprintf(fp, "%s\n", DefaultPrinter->name);
1992
1993 fclose(fp);
1994
1995 chmod(filename, 0644);
1996 chown(filename, User, Group);
1997 }
1998 }
1999 else
2000 unlink(filename);
2001 }
2002 #endif /* __sgi */
2003
2004
2005 /*
2006 * End of "$Id: printers.c,v 1.93.2.8 2002/01/23 17:32:16 mike Exp $".
2007 */