]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/printers.c
b4a9027da0c921d3e5a50b1270b5bae3d3cab958
[thirdparty/cups.git] / scheduler / printers.c
1 /*
2 * "$Id$"
3 *
4 * Printer routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2005 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 USA
19 *
20 * Voice: (301) 373-9600
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 * AddPrinterHistory() - Add the current printer state to the history.
29 * AddPrinterUser() - Add a user to the ACL.
30 * DeleteAllPrinters() - Delete all printers from the system.
31 * DeletePrinter() - Delete a printer from the system.
32 * DeletePrinterFilters() - Delete all MIME filters for a printer.
33 * FindPrinter() - Find a printer in the list.
34 * FreePrinterUsers() - Free allow/deny users.
35 * LoadAllPrinters() - Load printers from the printers.conf file.
36 * SaveAllPrinters() - Save all printer definitions to the printers.conf
37 * SetPrinterAttrs() - Set printer attributes based upon the PPD file.
38 * SetPrinterReasons() - Set/update the reasons strings.
39 * SetPrinterState() - Update the current state of a printer.
40 * SortPrinters() - Sort the printer list when a printer name is
41 * changed.
42 * StopPrinter() - Stop a printer from printing any jobs...
43 * ValidateDest() - Validate a printer/class destination.
44 * WritePrintcap() - Write a pseudo-printcap file for older
45 * applications that need it...
46 * cupsdSanitizeURI() - Sanitize a device URI...
47 * write_irix_config() - Update the config files used by the IRIX
48 * desktop tools.
49 * write_irix_state() - Update the status files used by IRIX printing
50 * desktop tools.
51 */
52
53 /*
54 * Include necessary headers...
55 */
56
57 #include "cupsd.h"
58
59
60 /*
61 * Local functions...
62 */
63
64 #ifdef __sgi
65 static void write_irix_config(printer_t *p);
66 static void write_irix_state(printer_t *p);
67 #endif /* __sgi */
68
69
70 /*
71 * 'AddPrinter()' - Add a printer to the system.
72 */
73
74 printer_t * /* O - New printer */
75 AddPrinter(const char *name) /* I - Name of printer */
76 {
77 printer_t *p, /* New printer */
78 *current, /* Current printer in list */
79 *prev; /* Previous printer in list */
80
81
82 /*
83 * Range check input...
84 */
85
86 LogMessage(L_DEBUG2, "AddPrinter(\"%s\")", name ? name : "(null)");
87
88 if (name == NULL)
89 return (NULL);
90
91 /*
92 * Create a new printer entity...
93 */
94
95 if ((p = calloc(1, sizeof(printer_t))) == NULL)
96 {
97 LogMessage(L_CRIT, "Unable to allocate memory for printer - %s",
98 strerror(errno));
99 return (NULL);
100 }
101
102 SetString(&p->name, name);
103 SetString(&p->info, name);
104 SetString(&p->hostname, ServerName);
105
106 SetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, LocalPort, name);
107 SetStringf(&p->device_uri, "file:/dev/null");
108
109 p->state = IPP_PRINTER_STOPPED;
110 p->accepting = 0;
111 p->shared = 1;
112 p->filetype = mimeAddType(MimeDatabase, "printer", name);
113
114 SetString(&p->job_sheets[0], "none");
115 SetString(&p->job_sheets[1], "none");
116
117 SetString(&p->error_policy, "stop-printer");
118 SetString(&p->op_policy, DefaultPolicy);
119
120 p->op_policy_ptr = DefaultPolicyPtr;
121
122 if (MaxPrinterHistory)
123 p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *));
124
125 /*
126 * Insert the printer in the printer list alphabetically...
127 */
128
129 for (prev = NULL, current = Printers;
130 current != NULL;
131 prev = current, current = current->next)
132 if (strcasecmp(p->name, current->name) < 0)
133 break;
134
135 /*
136 * Insert this printer before the current one...
137 */
138
139 if (prev == NULL)
140 Printers = p;
141 else
142 prev->next = p;
143
144 p->next = current;
145
146 /*
147 * Write a new /etc/printcap or /var/spool/lp/pstatus file.
148 */
149
150 WritePrintcap();
151
152 /*
153 * Bump the printer count and return...
154 */
155
156 NumPrinters ++;
157
158 return (p);
159 }
160
161
162 /*
163 * 'AddPrinterFilter()' - Add a MIME filter for a printer.
164 */
165
166 void
167 AddPrinterFilter(printer_t *p, /* I - Printer to add to */
168 const char *filter) /* I - Filter to add */
169 {
170 int i; /* Looping var */
171 char super[MIME_MAX_SUPER], /* Super-type for filter */
172 type[MIME_MAX_TYPE], /* Type for filter */
173 program[1024]; /* Program/filter name */
174 int cost; /* Cost of filter */
175 mime_type_t **temptype; /* MIME type looping var */
176
177
178 /*
179 * Range check input...
180 */
181
182 if (p == NULL || p->filetype == NULL || filter == NULL)
183 return;
184
185 /*
186 * Parse the filter string; it should be in the following format:
187 *
188 * super/type cost program
189 */
190
191 if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4)
192 {
193 LogMessage(L_ERROR, "AddPrinterFilter: Invalid filter string \"%s\"!",
194 filter);
195 return;
196 }
197
198 /*
199 * Add the filter to the MIME database, supporting wildcards as needed...
200 */
201
202 for (temptype = MimeDatabase->types, i = MimeDatabase->num_types;
203 i > 0;
204 i --, temptype ++)
205 if (((super[0] == '*' && strcasecmp((*temptype)->super, "printer") != 0) ||
206 !strcasecmp((*temptype)->super, super)) &&
207 (type[0] == '*' || !strcasecmp((*temptype)->type, type)))
208 {
209 LogMessage(L_DEBUG2, "Adding filter %s/%s %s/%s %d %s",
210 (*temptype)->super, (*temptype)->type,
211 p->filetype->super, p->filetype->type,
212 cost, program);
213 mimeAddFilter(MimeDatabase, *temptype, p->filetype, cost, program);
214 }
215 }
216
217
218 /*
219 * 'AddPrinterHistory()' - Add the current printer state to the history.
220 */
221
222 void
223 AddPrinterHistory(printer_t *p) /* I - Printer */
224 {
225 ipp_t *history; /* History collection */
226
227
228 /*
229 * Stop early if we aren't keeping history data...
230 */
231
232 if (MaxPrinterHistory <= 0)
233 return;
234
235 /*
236 * Retire old history data as needed...
237 */
238
239 p->sequence_number ++;
240
241 if (p->num_history >= MaxPrinterHistory)
242 {
243 p->num_history --;
244 ippDelete(p->history[0]);
245 memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *));
246 }
247
248 /*
249 * Create a collection containing the current printer-state, printer-up-time,
250 * printer-state-message, and printer-state-reasons attributes.
251 */
252
253 history = ippNew();
254 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
255 p->state);
256 ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
257 p->accepting);
258 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
259 NULL, p->state_message);
260 if (p->num_reasons == 0)
261 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
262 "printer-state-reasons", NULL,
263 p->state == IPP_PRINTER_STOPPED ? "paused" : "none");
264 else
265 ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
266 "printer-state-reasons", p->num_reasons, NULL,
267 (const char * const *)p->reasons);
268 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
269 "printer-state-time", p->state_time);
270 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
271 "printer-state-sequence-number", p->sequence_number);
272
273 p->history[p->num_history] = history;
274 p->num_history ++;
275 }
276
277
278 /*
279 * 'AddPrinterUser()' - Add a user to the ACL.
280 */
281
282 void
283 AddPrinterUser(printer_t *p, /* I - Printer */
284 const char *username) /* I - User */
285 {
286 const char **temp; /* Temporary array pointer */
287
288
289 if (!p || !username)
290 return;
291
292 if (p->num_users == 0)
293 temp = malloc(sizeof(char **));
294 else
295 temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
296
297 if (!temp)
298 return;
299
300 p->users = temp;
301 temp += p->num_users;
302
303 if ((*temp = strdup(username)) != NULL)
304 p->num_users ++;
305 }
306
307
308 /*
309 * 'CreateCommonData()' - Create the common printer data.
310 */
311
312 void
313 CreateCommonData(void)
314 {
315 int i; /* Looping var */
316 ipp_attribute_t *attr; /* Attribute data */
317 printer_t *p; /* Current printer */
318 static const int nups[] = /* number-up-supported values */
319 { 1, 2, 4, 6, 9, 16 };
320 static const ipp_orient_t orients[4] =/* orientation-requested-supported values */
321 {
322 IPP_PORTRAIT,
323 IPP_LANDSCAPE,
324 IPP_REVERSE_LANDSCAPE,
325 IPP_REVERSE_PORTRAIT
326 };
327 static const char * const holds[] = /* job-hold-until-supported values */
328 {
329 "no-hold",
330 "indefinite",
331 "day-time",
332 "evening",
333 "night",
334 "second-shift",
335 "third-shift",
336 "weekend"
337 };
338 static const char * const versions[] =/* ipp-versions-supported values */
339 {
340 "1.0",
341 "1.1"
342 };
343 static const ipp_op_t ops[] = /* operations-supported values */
344 {
345 IPP_PRINT_JOB,
346 IPP_VALIDATE_JOB,
347 IPP_CREATE_JOB,
348 IPP_SEND_DOCUMENT,
349 IPP_CANCEL_JOB,
350 IPP_GET_JOB_ATTRIBUTES,
351 IPP_GET_JOBS,
352 IPP_GET_PRINTER_ATTRIBUTES,
353 IPP_HOLD_JOB,
354 IPP_RELEASE_JOB,
355 IPP_PAUSE_PRINTER,
356 IPP_RESUME_PRINTER,
357 IPP_PURGE_JOBS,
358 IPP_SET_JOB_ATTRIBUTES,
359 IPP_CREATE_PRINTER_SUBSCRIPTION,
360 IPP_CREATE_JOB_SUBSCRIPTION,
361 IPP_GET_SUBSCRIPTION_ATTRIBUTES,
362 IPP_GET_SUBSCRIPTIONS,
363 IPP_RENEW_SUBSCRIPTION,
364 IPP_CANCEL_SUBSCRIPTION,
365 IPP_GET_NOTIFICATIONS,
366 IPP_ENABLE_PRINTER,
367 IPP_DISABLE_PRINTER,
368 CUPS_GET_DEFAULT,
369 CUPS_GET_PRINTERS,
370 CUPS_ADD_PRINTER,
371 CUPS_DELETE_PRINTER,
372 CUPS_GET_CLASSES,
373 CUPS_ADD_CLASS,
374 CUPS_DELETE_CLASS,
375 CUPS_ACCEPT_JOBS,
376 CUPS_REJECT_JOBS,
377 CUPS_GET_DEVICES,
378 CUPS_GET_PPDS,
379 IPP_RESTART_JOB
380 };
381 static const char * const charsets[] =/* charset-supported values */
382 {
383 "us-ascii",
384 "utf-8"
385 };
386 static const char * const compressions[] =
387 { /* document-compression-supported values */
388 "none"
389 #ifdef HAVE_LIBZ
390 ,"gzip"
391 #endif /* HAVE_LIBZ */
392 };
393 static const char * const multiple_document_handling[] =
394 { /* multiple-document-handling-supported values */
395 "separate-documents-uncollated-copies",
396 "separate-documents-collated-copies"
397 };
398 static const char * const errors[] = /* printer-error-policy-supported values */
399 {
400 "abort-job",
401 "retry-job",
402 "stop-printer"
403 };
404
405
406 if (CommonData)
407 ippDelete(CommonData);
408
409 CommonData = ippNew();
410
411 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
412 "pdl-override-supported", NULL, "not-attempted");
413 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
414 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
415 NULL, versions);
416 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
417 "operations-supported",
418 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
419 ippAddBoolean(CommonData, IPP_TAG_PRINTER,
420 "multiple-document-jobs-supported", 1);
421 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
422 "multiple-operation-time-out", 60);
423 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
424 "multiple-document-handling-supported",
425 sizeof(multiple_document_handling) /
426 sizeof(multiple_document_handling[0]), NULL,
427 multiple_document_handling);
428 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET,
429 "charset-configured", NULL, DefaultCharset);
430 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET,
431 "charset-supported", sizeof(charsets) / sizeof(charsets[0]),
432 NULL, charsets);
433 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
434 "natural-language-configured", NULL, DefaultLanguage);
435 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
436 "generated-natural-language-supported", NULL, DefaultLanguage);
437 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
438 "document-format-default", NULL, "application/octet-stream");
439 ippAddStrings(CommonData, IPP_TAG_PRINTER,
440 (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
441 "document-format-supported", NumMimeTypes, NULL, MimeTypes);
442 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
443 "compression-supported",
444 sizeof(compressions) / sizeof(compressions[0]),
445 NULL, compressions);
446 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
447 "job-priority-supported", 100);
448 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
449 "job-priority-default", 50);
450 ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
451 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
452 "copies-default", 1);
453 ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
454 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
455 "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
456 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
457 "number-up-default", 1);
458 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
459 "orientation-requested-supported", 4, (int *)orients);
460 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
461 "orientation-requested-default", IPP_PORTRAIT);
462 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
463 "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]),
464 NULL, holds);
465 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
466 "job-hold-until-default", NULL, "no-hold");
467 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
468 "printer-op-policy-supported", NumPolicies, NULL, NULL);
469 for (i = 0; i < NumPolicies; i ++)
470 attr->values[i].string.text = strdup(Policies[i]->name);
471 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
472 "printer-error-policy-supported",
473 sizeof(errors) / sizeof(errors[0]), NULL, errors);
474
475 if (NumBanners > 0)
476 {
477 /*
478 * Setup the job-sheets-supported and job-sheets-default attributes...
479 */
480
481 if (Classification && !ClassifyOverride)
482 attr = ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
483 "job-sheets-supported", NULL, Classification);
484 else
485 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
486 "job-sheets-supported", NumBanners + 1, NULL, NULL);
487
488 if (attr == NULL)
489 LogMessage(L_EMERG, "SetPrinterAttrs: Unable to allocate memory for "
490 "job-sheets-supported attribute: %s!",
491 strerror(errno));
492 else if (!Classification || ClassifyOverride)
493 {
494 attr->values[0].string.text = strdup("none");
495
496 for (i = 0; i < NumBanners; i ++)
497 attr->values[i + 1].string.text = strdup(Banners[i].name);
498 }
499 }
500
501 /*
502 * Loop through the printers and update the op_policy_ptr values...
503 */
504
505 for (p = Printers; p; p = p->next)
506 if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
507 p->op_policy_ptr = DefaultPolicyPtr;
508 }
509
510
511 /*
512 * 'DeleteAllPrinters()' - Delete all printers from the system.
513 */
514
515 void
516 DeleteAllPrinters(void)
517 {
518 printer_t *p, /* Pointer to current printer/class */
519 *next; /* Pointer to next printer in list */
520
521
522 for (p = Printers; p != NULL; p = next)
523 {
524 next = p->next;
525
526 if (!(p->type & CUPS_PRINTER_CLASS))
527 DeletePrinter(p, 0);
528 }
529 }
530
531
532 /*
533 * 'DeletePrinter()' - Delete a printer from the system.
534 */
535
536 void
537 DeletePrinter(printer_t *p, /* I - Printer to delete */
538 int update) /* I - Update printers.conf? */
539 {
540 int i; /* Looping var */
541 printer_t *current, /* Current printer in list */
542 *prev; /* Previous printer in list */
543 #ifdef __sgi
544 char filename[1024]; /* Interface script filename */
545 #endif /* __sgi */
546
547
548 DEBUG_printf(("DeletePrinter(%08x): p->name = \"%s\"...\n", p, p->name));
549
550 /*
551 * Range check input...
552 */
553
554 if (p == NULL)
555 return;
556
557 /*
558 * Find the printer in the list...
559 */
560
561 for (prev = NULL, current = Printers;
562 current != NULL;
563 prev = current, current = current->next)
564 if (p == current)
565 break;
566
567 if (current == NULL)
568 {
569 LogMessage(L_ERROR, "Tried to delete a non-existent printer %s!\n",
570 p->name);
571 return;
572 }
573
574 /*
575 * Remove the printer from the list...
576 */
577
578 if (prev == NULL)
579 Printers = p->next;
580 else
581 prev->next = p->next;
582
583 NumPrinters --;
584
585 /*
586 * Stop printing on this printer...
587 */
588
589 StopPrinter(p, update);
590
591 /*
592 * If this printer is the next for browsing, point to the next one...
593 */
594
595 if (p == BrowseNext)
596 BrowseNext = p->next;
597
598 /*
599 * Remove the dummy interface/icon/option files under IRIX...
600 */
601
602 #ifdef __sgi
603 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
604 unlink(filename);
605
606 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
607 p->name);
608 unlink(filename);
609
610 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
611 unlink(filename);
612
613 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
614 unlink(filename);
615
616 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
617 unlink(filename);
618
619 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
620 unlink(filename);
621 #endif /* __sgi */
622
623 /*
624 * If p is the default printer, assign the next one...
625 */
626
627 if (p == DefaultPrinter)
628 {
629 DefaultPrinter = Printers;
630
631 WritePrintcap();
632 }
633
634 /*
635 * Remove this printer from any classes and send a browse delete message...
636 */
637
638 if (!(p->type & CUPS_PRINTER_IMPLICIT))
639 {
640 DeletePrinterFromClasses(p);
641 SendBrowseDelete(p);
642 }
643
644 /*
645 * Free all memory used by the printer...
646 */
647
648 if (p->printers != NULL)
649 free(p->printers);
650
651 if (MaxPrinterHistory)
652 {
653 for (i = 0; i < p->num_history; i ++)
654 ippDelete(p->history[i]);
655
656 free(p->history);
657 }
658
659 for (i = 0; i < p->num_reasons; i ++)
660 free(p->reasons[i]);
661
662 ippDelete(p->attrs);
663
664 DeletePrinterFilters(p);
665
666 FreePrinterUsers(p);
667 FreeQuotas(p);
668
669 ClearString(&p->uri);
670 ClearString(&p->hostname);
671 ClearString(&p->name);
672 ClearString(&p->location);
673 ClearString(&p->make_model);
674 ClearString(&p->info);
675 ClearString(&p->job_sheets[0]);
676 ClearString(&p->job_sheets[1]);
677 ClearString(&p->device_uri);
678 ClearString(&p->port_monitor);
679 ClearString(&p->op_policy);
680 ClearString(&p->error_policy);
681
682 free(p);
683
684 /*
685 * Write a new /etc/printcap file...
686 */
687
688 WritePrintcap();
689 }
690
691
692 /*
693 * 'DeletePrinterFilters()' - Delete all MIME filters for a printer.
694 */
695
696 void
697 DeletePrinterFilters(printer_t *p) /* I - Printer to remove from */
698 {
699 int i; /* Looping var */
700 mime_filter_t *filter; /* MIME filter looping var */
701
702
703 /*
704 * Range check input...
705 */
706
707 if (p == NULL)
708 return;
709
710 /*
711 * Remove all filters from the MIME database that have a destination
712 * type == printer...
713 */
714
715 for (filter = MimeDatabase->filters, i = MimeDatabase->num_filters;
716 i > 0;
717 i --, filter ++)
718 if (filter->dst == p->filetype)
719 {
720 /*
721 * Delete the current filter...
722 */
723
724 MimeDatabase->num_filters --;
725
726 if (i > 1)
727 memmove(filter, filter + 1, sizeof(mime_filter_t) * (i - 1));
728
729 filter --;
730 }
731 }
732
733
734 /*
735 * 'FindDest()' - Find a destination in the list.
736 */
737
738 printer_t * /* O - Destination in list */
739 FindDest(const char *name) /* I - Name of printer or class to find */
740 {
741 printer_t *p; /* Current destination */
742 int diff; /* Difference */
743
744
745 for (p = Printers; p != NULL; p = p->next)
746 if ((diff = strcasecmp(name, p->name)) == 0)/* name == p->name */
747 return (p);
748 else if (diff < 0) /* name < p->name */
749 return (NULL);
750
751 return (NULL);
752 }
753
754
755 /*
756 * 'FindPrinter()' - Find a printer in the list.
757 */
758
759 printer_t * /* O - Printer in list */
760 FindPrinter(const char *name) /* I - Name of printer to find */
761 {
762 printer_t *p; /* Current printer */
763 int diff; /* Difference */
764
765
766 for (p = Printers; p != NULL; p = p->next)
767 if ((diff = strcasecmp(name, p->name)) == 0 &&
768 !(p->type & CUPS_PRINTER_CLASS)) /* name == p->name */
769 return (p);
770 else if (diff < 0) /* name < p->name */
771 return (NULL);
772
773 return (NULL);
774 }
775
776
777 /*
778 * 'FreePrinterUsers()' - Free allow/deny users.
779 */
780
781 void
782 FreePrinterUsers(printer_t *p) /* I - Printer */
783 {
784 int i; /* Looping var */
785
786
787 if (!p || !p->num_users)
788 return;
789
790 for (i = 0; i < p->num_users; i ++)
791 free((void *)p->users[i]);
792
793 free(p->users);
794
795 p->num_users = 0;
796 p->users = NULL;
797 }
798
799
800 /*
801 * 'LoadAllPrinters()' - Load printers from the printers.conf file.
802 */
803
804 void
805 LoadAllPrinters(void)
806 {
807 cups_file_t *fp; /* printers.conf file */
808 int linenum; /* Current line number */
809 char line[1024], /* Line from file */
810 *value, /* Pointer to value */
811 *valueptr; /* Pointer into value */
812 printer_t *p; /* Current printer */
813
814
815 /*
816 * Open the printers.conf file...
817 */
818
819 snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
820 if ((fp = cupsFileOpen(line, "r")) == NULL)
821 {
822 LogMessage(L_ERROR, "LoadAllPrinters: Unable to open %s - %s", line,
823 strerror(errno));
824 return;
825 }
826
827 /*
828 * Read printer configurations until we hit EOF...
829 */
830
831 linenum = 0;
832 p = NULL;
833
834 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
835 {
836 /*
837 * Decode the directive...
838 */
839
840 if (!strcasecmp(line, "<Printer") ||
841 !strcasecmp(line, "<DefaultPrinter"))
842 {
843 /*
844 * <Printer name> or <DefaultPrinter name>
845 */
846
847 if (p == NULL && value)
848 {
849 /*
850 * Add the printer and a base file type...
851 */
852
853 LogMessage(L_DEBUG, "LoadAllPrinters: Loading printer %s...", value);
854
855 p = AddPrinter(value);
856 p->accepting = 1;
857 p->state = IPP_PRINTER_IDLE;
858
859 /*
860 * Set the default printer as needed...
861 */
862
863 if (!strcasecmp(line, "<DefaultPrinter"))
864 DefaultPrinter = p;
865 }
866 else
867 {
868 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
869 linenum);
870 return;
871 }
872 }
873 else if (!strcasecmp(line, "</Printer>"))
874 {
875 if (p != NULL)
876 {
877 /*
878 * Close out the current printer...
879 */
880
881 SetPrinterAttrs(p);
882 AddPrinterHistory(p);
883
884 if (p->device_uri && strncmp(p->device_uri, "file:", 5) &&
885 p->state != IPP_PRINTER_STOPPED)
886 {
887 /*
888 * See if the backend exists...
889 */
890
891 snprintf(line, sizeof(line), "%s/backends/%s", ServerBin,
892 p->device_uri);
893
894 if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
895 *valueptr = '\0'; /* Chop everything but URI scheme */
896
897 if (access(line, 0))
898 {
899 /*
900 * Backend does not exist, stop printer...
901 */
902
903 p->state = IPP_PRINTER_STOPPED;
904 snprintf(p->state_message, sizeof(p->state_message),
905 "Backend %s does not exist!", line);
906 }
907 }
908
909 p = NULL;
910 }
911 else
912 {
913 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
914 linenum);
915 return;
916 }
917 }
918 else if (!p)
919 {
920 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
921 linenum);
922 return;
923 }
924 else if (!strcasecmp(line, "Info"))
925 {
926 if (value)
927 SetString(&p->info, value);
928 }
929 else if (!strcasecmp(line, "Location"))
930 {
931 if (value)
932 SetString(&p->location, value);
933 }
934 else if (!strcasecmp(line, "DeviceURI"))
935 {
936 if (value)
937 SetString(&p->device_uri, value);
938 else
939 {
940 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
941 linenum);
942 return;
943 }
944 }
945 else if (!strcasecmp(line, "PortMonitor"))
946 {
947 if (value && strcmp(value, "none"))
948 SetString(&p->port_monitor, value);
949 else if (value)
950 ClearString(&p->port_monitor);
951 else
952 {
953 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
954 linenum);
955 return;
956 }
957 }
958 else if (!strcasecmp(line, "State"))
959 {
960 /*
961 * Set the initial queue state...
962 */
963
964 if (value && !strcasecmp(value, "idle"))
965 p->state = IPP_PRINTER_IDLE;
966 else if (value && !strcasecmp(value, "stopped"))
967 p->state = IPP_PRINTER_STOPPED;
968 else
969 {
970 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
971 linenum);
972 return;
973 }
974 }
975 else if (!strcasecmp(line, "StateMessage"))
976 {
977 /*
978 * Set the initial queue state message...
979 */
980
981 if (value)
982 strlcpy(p->state_message, value, sizeof(p->state_message));
983 }
984 else if (!strcasecmp(line, "Accepting"))
985 {
986 /*
987 * Set the initial accepting state...
988 */
989
990 if (value &&
991 (!strcasecmp(value, "yes") ||
992 !strcasecmp(value, "on") ||
993 !strcasecmp(value, "true")))
994 p->accepting = 1;
995 else if (value &&
996 (!strcasecmp(value, "no") ||
997 !strcasecmp(value, "off") ||
998 !strcasecmp(value, "false")))
999 p->accepting = 0;
1000 else
1001 {
1002 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1003 linenum);
1004 return;
1005 }
1006 }
1007 else if (!strcasecmp(line, "Shared"))
1008 {
1009 /*
1010 * Set the initial shared state...
1011 */
1012
1013 if (value &&
1014 (!strcasecmp(value, "yes") ||
1015 !strcasecmp(value, "on") ||
1016 !strcasecmp(value, "true")))
1017 p->shared = 1;
1018 else if (value &&
1019 (!strcasecmp(value, "no") ||
1020 !strcasecmp(value, "off") ||
1021 !strcasecmp(value, "false")))
1022 p->shared = 0;
1023 else
1024 {
1025 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1026 linenum);
1027 return;
1028 }
1029 }
1030 else if (!strcasecmp(line, "JobSheets"))
1031 {
1032 /*
1033 * Set the initial job sheets...
1034 */
1035
1036 if (value)
1037 {
1038 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1039
1040 if (*valueptr)
1041 *valueptr++ = '\0';
1042
1043 SetString(&p->job_sheets[0], value);
1044
1045 while (isspace(*valueptr & 255))
1046 valueptr ++;
1047
1048 if (*valueptr)
1049 {
1050 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1051
1052 if (*valueptr)
1053 *valueptr++ = '\0';
1054
1055 SetString(&p->job_sheets[1], value);
1056 }
1057 }
1058 else
1059 {
1060 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1061 linenum);
1062 return;
1063 }
1064 }
1065 else if (!strcasecmp(line, "AllowUser"))
1066 {
1067 if (value)
1068 {
1069 p->deny_users = 0;
1070 AddPrinterUser(p, value);
1071 }
1072 else
1073 {
1074 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1075 linenum);
1076 return;
1077 }
1078 }
1079 else if (!strcasecmp(line, "DenyUser"))
1080 {
1081 if (value)
1082 {
1083 p->deny_users = 1;
1084 AddPrinterUser(p, value);
1085 }
1086 else
1087 {
1088 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1089 linenum);
1090 return;
1091 }
1092 }
1093 else if (!strcasecmp(line, "QuotaPeriod"))
1094 {
1095 if (value)
1096 p->quota_period = atoi(value);
1097 else
1098 {
1099 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1100 linenum);
1101 return;
1102 }
1103 }
1104 else if (!strcasecmp(line, "PageLimit"))
1105 {
1106 if (value)
1107 p->page_limit = atoi(value);
1108 else
1109 {
1110 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1111 linenum);
1112 return;
1113 }
1114 }
1115 else if (!strcasecmp(line, "KLimit"))
1116 {
1117 if (value)
1118 p->k_limit = atoi(value);
1119 else
1120 {
1121 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1122 linenum);
1123 return;
1124 }
1125 }
1126 else if (!strcasecmp(line, "OpPolicy"))
1127 {
1128 if (value)
1129 SetString(&p->op_policy, value);
1130 else
1131 {
1132 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1133 linenum);
1134 return;
1135 }
1136 }
1137 else if (!strcasecmp(line, "ErrorPolicy"))
1138 {
1139 if (value)
1140 SetString(&p->error_policy, value);
1141 else
1142 {
1143 LogMessage(L_ERROR, "Syntax error on line %d of printers.conf.",
1144 linenum);
1145 return;
1146 }
1147 }
1148 else
1149 {
1150 /*
1151 * Something else we don't understand...
1152 */
1153
1154 LogMessage(L_ERROR, "Unknown configuration directive %s on line %d of printers.conf.",
1155 line, linenum);
1156 }
1157 }
1158
1159 cupsFileClose(fp);
1160 }
1161
1162
1163 /*
1164 * 'SaveAllPrinters()' - Save all printer definitions to the printers.conf
1165 * file.
1166 */
1167
1168 void
1169 SaveAllPrinters(void)
1170 {
1171 int i; /* Looping var */
1172 cups_file_t *fp; /* printers.conf file */
1173 char temp[1024]; /* Temporary string */
1174 char backup[1024]; /* printers.conf.O file */
1175 printer_t *printer; /* Current printer class */
1176 time_t curtime; /* Current time */
1177 struct tm *curdate; /* Current date */
1178
1179
1180 /*
1181 * Create the printers.conf file...
1182 */
1183
1184 snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
1185 snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
1186
1187 if (rename(temp, backup))
1188 LogMessage(L_ERROR, "Unable to backup printers.conf - %s", strerror(errno));
1189
1190 if ((fp = cupsFileOpen(temp, "w")) == NULL)
1191 {
1192 LogMessage(L_ERROR, "Unable to save printers.conf - %s", strerror(errno));
1193
1194 if (rename(backup, temp))
1195 LogMessage(L_ERROR, "Unable to restore printers.conf - %s", strerror(errno));
1196 return;
1197 }
1198 else
1199 LogMessage(L_INFO, "Saving printers.conf...");
1200
1201 /*
1202 * Restrict access to the file...
1203 */
1204
1205 fchown(cupsFileNumber(fp), getuid(), Group);
1206 fchmod(cupsFileNumber(fp), ConfigFilePerm);
1207
1208 /*
1209 * Write a small header to the file...
1210 */
1211
1212 curtime = time(NULL);
1213 curdate = localtime(&curtime);
1214 strftime(temp, sizeof(temp) - 1, CUPS_STRFTIME_FORMAT, curdate);
1215
1216 cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
1217 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
1218
1219 /*
1220 * Write each local printer known to the system...
1221 */
1222
1223 for (printer = Printers; printer != NULL; printer = printer->next)
1224 {
1225 /*
1226 * Skip remote destinations and printer classes...
1227 */
1228
1229 if ((printer->type & CUPS_PRINTER_REMOTE) ||
1230 (printer->type & CUPS_PRINTER_CLASS) ||
1231 (printer->type & CUPS_PRINTER_IMPLICIT))
1232 continue;
1233
1234 /*
1235 * Write printers as needed...
1236 */
1237
1238 if (printer == DefaultPrinter)
1239 cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name);
1240 else
1241 cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
1242
1243 if (printer->info)
1244 cupsFilePrintf(fp, "Info %s\n", printer->info);
1245
1246 if (printer->location)
1247 cupsFilePrintf(fp, "Location %s\n", printer->location);
1248
1249 if (printer->device_uri)
1250 cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
1251
1252 if (printer->port_monitor)
1253 cupsFilePrintf(fp, "PortMonitor %s\n", printer->port_monitor);
1254
1255 if (printer->state == IPP_PRINTER_STOPPED)
1256 {
1257 cupsFilePuts(fp, "State Stopped\n");
1258 cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
1259 }
1260 else
1261 cupsFilePuts(fp, "State Idle\n");
1262
1263 if (printer->accepting)
1264 cupsFilePuts(fp, "Accepting Yes\n");
1265 else
1266 cupsFilePuts(fp, "Accepting No\n");
1267
1268 if (printer->shared)
1269 cupsFilePuts(fp, "Shared Yes\n");
1270 else
1271 cupsFilePuts(fp, "Shared No\n");
1272
1273 cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
1274 printer->job_sheets[1]);
1275
1276 cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period);
1277 cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
1278 cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
1279
1280 for (i = 0; i < printer->num_users; i ++)
1281 cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
1282 printer->users[i]);
1283
1284 if (printer->op_policy)
1285 cupsFilePrintf(fp, "OpPolicy %s\n", printer->op_policy);
1286 if (printer->error_policy)
1287 cupsFilePrintf(fp, "ErrorPolicy %s\n", printer->error_policy);
1288
1289 cupsFilePuts(fp, "</Printer>\n");
1290
1291 #ifdef __sgi
1292 /*
1293 * Make IRIX desktop & printer status happy
1294 */
1295
1296 write_irix_state(printer);
1297 #endif /* __sgi */
1298 }
1299
1300 cupsFileClose(fp);
1301 }
1302
1303
1304 /*
1305 * 'SetPrinterAttrs()' - Set printer attributes based upon the PPD file.
1306 */
1307
1308 void
1309 SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
1310 {
1311 char uri[HTTP_MAX_URI]; /* URI for printer */
1312 char resource[HTTP_MAX_URI]; /* Resource portion of URI */
1313 int i; /* Looping var */
1314 char filename[1024]; /* Name of PPD file */
1315 int num_media; /* Number of media options */
1316 location_t *auth; /* Pointer to authentication element */
1317 const char *auth_supported; /* Authentication supported */
1318 cups_ptype_t printer_type; /* Printer type data */
1319 ppd_file_t *ppd; /* PPD file data */
1320 ppd_option_t *input_slot, /* InputSlot options */
1321 *media_type, /* MediaType options */
1322 *page_size, /* PageSize options */
1323 *output_bin, /* OutputBin options */
1324 *media_quality; /* EFMediaQualityMode options */
1325 ppd_attr_t *ppdattr; /* PPD attribute */
1326 ipp_attribute_t *attr; /* Attribute data */
1327 ipp_value_t *val; /* Attribute value */
1328 int num_finishings;
1329 ipp_finish_t finishings[5]; /* finishings-supported values */
1330 static const char * const sides[3] = /* sides-supported values */
1331 {
1332 "one",
1333 "two-long-edge",
1334 "two-short-edge"
1335 };
1336
1337
1338 DEBUG_printf(("SetPrinterAttrs: entering name = %s, type = %x\n", p->name,
1339 p->type));
1340
1341 /*
1342 * Make sure that we have the common attributes defined...
1343 */
1344
1345 if (!CommonData)
1346 CreateCommonData();
1347
1348 /*
1349 * Clear out old filters, if any...
1350 */
1351
1352 DeletePrinterFilters(p);
1353
1354 /*
1355 * Figure out the authentication that is required for the printer.
1356 */
1357
1358 auth_supported = "requesting-user-name";
1359 if (!(p->type & CUPS_PRINTER_REMOTE))
1360 {
1361 if (p->type & CUPS_PRINTER_CLASS)
1362 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
1363 else
1364 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
1365
1366 if ((auth = FindBest(resource, HTTP_POST)) != NULL)
1367 {
1368 if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST)
1369 auth_supported = "basic";
1370 else if (auth->type == AUTH_DIGEST)
1371 auth_supported = "digest";
1372 }
1373 }
1374
1375 /*
1376 * Create the required IPP attributes for a printer...
1377 */
1378
1379 if (p->attrs)
1380 ippDelete(p->attrs);
1381
1382 p->attrs = ippNew();
1383
1384 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1385 "uri-authentication-supported", NULL, auth_supported);
1386 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1387 "uri-security-supported", NULL, "none");
1388 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
1389 p->name);
1390 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1391 NULL, p->location ? p->location : "");
1392 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1393 NULL, p->info ? p->info : "");
1394 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
1395 NULL, p->uri);
1396
1397 if (p->num_users)
1398 {
1399 if (p->deny_users)
1400 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1401 "requesting-user-name-denied", p->num_users, NULL,
1402 p->users);
1403 else
1404 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1405 "requesting-user-name-allowed", p->num_users, NULL,
1406 p->users);
1407 }
1408
1409 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1410 "job-quota-period", p->quota_period);
1411 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1412 "job-k-limit", p->k_limit);
1413 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1414 "job-page-limit", p->page_limit);
1415
1416 if (NumBanners > 0 && !(p->type & CUPS_PRINTER_REMOTE))
1417 {
1418 /*
1419 * Setup the job-sheets-default attribute...
1420 */
1421
1422 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1423 "job-sheets-default", 2, NULL, NULL);
1424
1425 if (attr != NULL)
1426 {
1427 attr->values[0].string.text = strdup(Classification ?
1428 Classification : p->job_sheets[0]);
1429 attr->values[1].string.text = strdup(Classification ?
1430 Classification : p->job_sheets[1]);
1431 }
1432 }
1433
1434 printer_type = p->type;
1435
1436 p->raw = 0;
1437
1438 if (p->type & CUPS_PRINTER_REMOTE)
1439 {
1440 /*
1441 * Tell the client this is a remote printer of some type...
1442 */
1443
1444 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
1445 "printer-uri-supported", NULL, p->uri);
1446
1447 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1448 "printer-make-and-model", NULL, p->make_model);
1449 p->raw = 1;
1450 }
1451 else
1452 {
1453 /*
1454 * Assign additional attributes depending on whether this is a printer
1455 * or class...
1456 */
1457
1458 p->type &= ~CUPS_PRINTER_OPTIONS;
1459
1460 if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
1461 {
1462 p->raw = 1;
1463
1464 /*
1465 * Add class-specific attributes...
1466 */
1467
1468 if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0)
1469 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1470 "printer-make-and-model", NULL, p->printers[0]->make_model);
1471 else
1472 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1473 "printer-make-and-model", NULL, "Local Printer Class");
1474
1475 if (p->num_printers > 0)
1476 {
1477 /*
1478 * Add a list of member URIs and names...
1479 */
1480
1481 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
1482 "member-uris", p->num_printers, NULL, NULL);
1483 p->type |= CUPS_PRINTER_OPTIONS;
1484
1485 for (i = 0; i < p->num_printers; i ++)
1486 {
1487 if (attr != NULL)
1488 attr->values[i].string.text = strdup(p->printers[i]->uri);
1489
1490 p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
1491 }
1492
1493 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1494 "member-names", p->num_printers, NULL, NULL);
1495
1496 if (attr != NULL)
1497 {
1498 for (i = 0; i < p->num_printers; i ++)
1499 attr->values[i].string.text = strdup(p->printers[i]->name);
1500 }
1501 }
1502 }
1503 else
1504 {
1505 /*
1506 * Add printer-specific attributes... Start by sanitizing the device
1507 * URI so it doesn't have a username or password in it...
1508 */
1509
1510 if (!p->device_uri)
1511 strcpy(uri, "file:/dev/null");
1512 else if (strstr(p->device_uri, "://") != NULL)
1513 {
1514 /*
1515 * http://..., ipp://..., etc.
1516 */
1517
1518 cupsdSanitizeURI(p->device_uri, uri, sizeof(uri));
1519 }
1520 else
1521 {
1522 /*
1523 * file:..., serial:..., etc.
1524 */
1525
1526 strlcpy(uri, p->device_uri, sizeof(uri));
1527 }
1528
1529 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1530 uri);
1531
1532 /*
1533 * Assign additional attributes from the PPD file (if any)...
1534 */
1535
1536 p->type |= CUPS_PRINTER_BW;
1537 finishings[0] = IPP_FINISHINGS_NONE;
1538 num_finishings = 1;
1539
1540 snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
1541 p->name);
1542
1543 if ((ppd = ppdOpenFile(filename)) != NULL)
1544 {
1545 /*
1546 * Add make/model and other various attributes...
1547 */
1548
1549 if (ppd->color_device)
1550 p->type |= CUPS_PRINTER_COLOR;
1551 if (ppd->variable_sizes)
1552 p->type |= CUPS_PRINTER_VARIABLE;
1553 if (!ppd->manual_copies)
1554 p->type |= CUPS_PRINTER_COPIES;
1555 if ((ppdattr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
1556 if (ppdattr->value && !strcasecmp(ppdattr->value, "true"))
1557 p->type |= CUPS_PRINTER_FAX;
1558
1559 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
1560 ppd->color_device);
1561 if (ppd->throughput)
1562 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1563 "pages-per-minute", ppd->throughput);
1564
1565 if (ppd->nickname)
1566 SetString(&p->make_model, ppd->nickname);
1567 else if (ppd->modelname)
1568 SetString(&p->make_model, ppd->modelname);
1569 else
1570 SetString(&p->make_model, "Bad PPD File");
1571
1572 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1573 "printer-make-and-model", NULL, p->make_model);
1574
1575 /*
1576 * Add media options from the PPD file...
1577 */
1578
1579 if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
1580 num_media = input_slot->num_choices;
1581 else
1582 num_media = 0;
1583
1584 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
1585 num_media += media_type->num_choices;
1586
1587 if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
1588 num_media += page_size->num_choices;
1589
1590 if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL)
1591 num_media += media_quality->num_choices;
1592
1593 if (num_media == 0)
1594 {
1595 LogMessage(L_CRIT, "SetPrinterAttrs: The PPD file for printer %s "
1596 "contains no media options and is therefore "
1597 "invalid!", p->name);
1598 }
1599 else
1600 {
1601 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1602 "media-supported", num_media, NULL, NULL);
1603 if (attr != NULL)
1604 {
1605 val = attr->values;
1606
1607 if (input_slot != NULL)
1608 for (i = 0; i < input_slot->num_choices; i ++, val ++)
1609 val->string.text = strdup(input_slot->choices[i].choice);
1610
1611 if (media_type != NULL)
1612 for (i = 0; i < media_type->num_choices; i ++, val ++)
1613 val->string.text = strdup(media_type->choices[i].choice);
1614
1615 if (media_quality != NULL)
1616 for (i = 0; i < media_quality->num_choices; i ++, val ++)
1617 val->string.text = strdup(media_quality->choices[i].choice);
1618
1619 if (page_size != NULL)
1620 {
1621 for (i = 0; i < page_size->num_choices; i ++, val ++)
1622 val->string.text = strdup(page_size->choices[i].choice);
1623
1624 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1625 NULL, page_size->defchoice);
1626 }
1627 else if (input_slot != NULL)
1628 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1629 NULL, input_slot->defchoice);
1630 else if (media_type != NULL)
1631 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1632 NULL, media_type->defchoice);
1633 else if (media_quality != NULL)
1634 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1635 NULL, media_quality->defchoice);
1636 else
1637 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
1638 NULL, "none");
1639 }
1640 }
1641
1642 /*
1643 * Output bin...
1644 */
1645
1646 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
1647 {
1648 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1649 "output-bin-supported", output_bin->num_choices,
1650 NULL, NULL);
1651
1652 if (attr != NULL)
1653 {
1654 for (i = 0, val = attr->values;
1655 i < output_bin->num_choices;
1656 i ++, val ++)
1657 val->string.text = strdup(output_bin->choices[i].choice);
1658 }
1659 }
1660
1661 /*
1662 * Duplexing, etc...
1663 */
1664
1665 if (ppdFindOption(ppd, "Duplex") != NULL)
1666 {
1667 p->type |= CUPS_PRINTER_DUPLEX;
1668
1669 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-supported",
1670 3, NULL, sides);
1671 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "sides-default",
1672 NULL, "one");
1673 }
1674
1675 if (ppdFindOption(ppd, "Collate") != NULL)
1676 p->type |= CUPS_PRINTER_COLLATE;
1677
1678 if (ppdFindOption(ppd, "StapleLocation") != NULL)
1679 {
1680 p->type |= CUPS_PRINTER_STAPLE;
1681 finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
1682 }
1683
1684 if (ppdFindOption(ppd, "BindEdge") != NULL)
1685 {
1686 p->type |= CUPS_PRINTER_BIND;
1687 finishings[num_finishings++] = IPP_FINISHINGS_BIND;
1688 }
1689
1690 for (i = 0; i < ppd->num_sizes; i ++)
1691 if (ppd->sizes[i].length > 1728)
1692 p->type |= CUPS_PRINTER_LARGE;
1693 else if (ppd->sizes[i].length > 1008)
1694 p->type |= CUPS_PRINTER_MEDIUM;
1695 else
1696 p->type |= CUPS_PRINTER_SMALL;
1697
1698 /*
1699 * Add a filter from application/vnd.cups-raw to printer/name to
1700 * handle "raw" printing by users.
1701 */
1702
1703 AddPrinterFilter(p, "application/vnd.cups-raw 0 -");
1704
1705 /*
1706 * Add any filters in the PPD file...
1707 */
1708
1709 DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
1710 for (i = 0; i < ppd->num_filters; i ++)
1711 {
1712 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
1713 AddPrinterFilter(p, ppd->filters[i]);
1714 }
1715
1716 if (ppd->num_filters == 0)
1717 {
1718 /*
1719 * If there are no filters, add a PostScript printing filter.
1720 */
1721
1722 AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
1723 }
1724
1725 /*
1726 * Show current and available port monitors for this printer...
1727 */
1728
1729 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "port-monitor",
1730 NULL, p->port_monitor ? p->port_monitor : "none");
1731
1732
1733 for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
1734 ppdattr;
1735 i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
1736
1737 if (ppd->protocols)
1738 {
1739 if (strstr(ppd->protocols, "TBCP"))
1740 i ++;
1741 else if (strstr(ppd->protocols, "BCP"))
1742 i ++;
1743 }
1744
1745 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1746 "port-monitor-supported", i, NULL, NULL);
1747
1748 attr->values[0].string.text = strdup("none");
1749
1750 for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
1751 ppdattr;
1752 i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
1753 attr->values[i].string.text = strdup(ppdattr->value);
1754
1755 if (ppd->protocols)
1756 {
1757 if (strstr(ppd->protocols, "TBCP"))
1758 attr->values[i].string.text = strdup("tbcp");
1759 else if (strstr(ppd->protocols, "BCP"))
1760 attr->values[i].string.text = strdup("bcp");
1761 }
1762
1763 /*
1764 * Close the PPD and set the type...
1765 */
1766
1767 ppdClose(ppd);
1768
1769 printer_type = p->type;
1770 }
1771 else if (!access(filename, 0))
1772 {
1773 int pline; /* PPD line number */
1774 ppd_status_t pstatus; /* PPD load status */
1775
1776
1777 pstatus = ppdLastError(&pline);
1778
1779 LogMessage(L_ERROR, "PPD file for %s cannot be loaded!", p->name);
1780
1781 if (pstatus <= PPD_ALLOC_ERROR)
1782 LogMessage(L_ERROR, "%s", strerror(errno));
1783 else
1784 LogMessage(L_ERROR, "%s on line %d.", ppdErrorString(pstatus),
1785 pline);
1786
1787 LogMessage(L_INFO, "Hint: Run \"cupstestppd %s\" and fix any errors.",
1788 filename);
1789
1790 /*
1791 * Add a filter from application/vnd.cups-raw to printer/name to
1792 * handle "raw" printing by users.
1793 */
1794
1795 AddPrinterFilter(p, "application/vnd.cups-raw 0 -");
1796
1797 /*
1798 * Add a PostScript filter, since this is still possibly PS printer.
1799 */
1800
1801 AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
1802 }
1803 else
1804 {
1805 /*
1806 * If we have an interface script, add a filter entry for it...
1807 */
1808
1809 snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
1810 p->name);
1811 if (access(filename, X_OK) == 0)
1812 {
1813 /*
1814 * Yes, we have a System V style interface script; use it!
1815 */
1816
1817 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1818 "printer-make-and-model", NULL, "Local System V Printer");
1819
1820 snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
1821 ServerRoot, p->name);
1822 AddPrinterFilter(p, filename);
1823 }
1824 else if (p->device_uri &&
1825 !strncmp(p->device_uri, "ipp://", 6) &&
1826 (strstr(p->device_uri, "/printers/") != NULL ||
1827 strstr(p->device_uri, "/classes/") != NULL))
1828 {
1829 /*
1830 * Tell the client this is really a hard-wired remote printer.
1831 */
1832
1833 printer_type |= CUPS_PRINTER_REMOTE;
1834
1835 /*
1836 * Point the printer-uri-supported attribute to the
1837 * remote printer...
1838 */
1839
1840 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
1841 "printer-uri-supported", NULL, p->device_uri);
1842
1843 /*
1844 * Then set the make-and-model accordingly...
1845 */
1846
1847 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1848 "printer-make-and-model", NULL, "Remote Printer");
1849
1850 /*
1851 * Print all files directly...
1852 */
1853
1854 p->raw = 1;
1855 }
1856 else
1857 {
1858 /*
1859 * Otherwise we have neither - treat this as a "dumb" printer
1860 * with no PPD file...
1861 */
1862
1863 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1864 "printer-make-and-model", NULL, "Local Raw Printer");
1865
1866 p->raw = 1;
1867 }
1868 }
1869
1870 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
1871 "finishings-supported", num_finishings, (int *)finishings);
1872 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
1873 "finishings-default", IPP_FINISHINGS_NONE);
1874 }
1875 }
1876
1877 /*
1878 * Add the CUPS-specific printer-type attribute...
1879 */
1880
1881 if (!p->shared)
1882 p->type |= CUPS_PRINTER_NOT_SHARED;
1883 else
1884 p->type &= ~CUPS_PRINTER_NOT_SHARED;
1885
1886 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type",
1887 printer_type);
1888
1889 DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
1890 p->type));
1891
1892 #ifdef __sgi
1893 /*
1894 * Write the IRIX printer config and status files...
1895 */
1896
1897 write_irix_config(p);
1898 write_irix_state(p);
1899 #endif /* __sgi */
1900 }
1901
1902
1903 /*
1904 * 'SetPrinterReasons()' - Set/update the reasons strings.
1905 */
1906
1907 void
1908 SetPrinterReasons(printer_t *p, /* I - Printer */
1909 const char *s) /* I - Reasons strings */
1910 {
1911 int i; /* Looping var */
1912 const char *sptr; /* Pointer into reasons */
1913 char reason[255], /* Reason string */
1914 *rptr; /* Pointer into reason */
1915
1916
1917 if (s[0] == '-' || s[0] == '+')
1918 {
1919 /*
1920 * Add/remove reasons...
1921 */
1922
1923 sptr = s + 1;
1924 }
1925 else
1926 {
1927 /*
1928 * Replace reasons...
1929 */
1930
1931 sptr = s;
1932
1933 for (i = 0; i < p->num_reasons; i ++)
1934 free(p->reasons[i]);
1935
1936 p->num_reasons = 0;
1937 }
1938
1939 /*
1940 * Loop through all of the reasons...
1941 */
1942
1943 while (*sptr)
1944 {
1945 /*
1946 * Skip leading whitespace and commas...
1947 */
1948
1949 while (isspace(*sptr & 255) || *sptr == ',')
1950 sptr ++;
1951
1952 for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++)
1953 if (rptr < (reason + sizeof(reason) - 1))
1954 *rptr++ = *sptr;
1955
1956 if (rptr == reason)
1957 break;
1958
1959 *rptr = '\0';
1960
1961 if (s[0] == '-')
1962 {
1963 /*
1964 * Remove reason...
1965 */
1966
1967 for (i = 0; i < p->num_reasons; i ++)
1968 if (!strcasecmp(reason, p->reasons[i]))
1969 {
1970 /*
1971 * Found a match, so remove it...
1972 */
1973
1974 p->num_reasons --;
1975 free(p->reasons[i]);
1976
1977 if (i < p->num_reasons)
1978 memmove(p->reasons + i, p->reasons + i + 1,
1979 (p->num_reasons - i) * sizeof(char *));
1980
1981 i --;
1982 }
1983 }
1984 else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
1985 {
1986 /*
1987 * Add reason...
1988 */
1989
1990 for (i = 0; i < p->num_reasons; i ++)
1991 if (!strcasecmp(reason, p->reasons[i]))
1992 break;
1993
1994 if (i >= p->num_reasons)
1995 {
1996 p->reasons[i] = strdup(reason);
1997 p->num_reasons ++;
1998 }
1999 }
2000 }
2001 }
2002
2003
2004 /*
2005 * 'SetPrinterState()' - Update the current state of a printer.
2006 */
2007
2008 void
2009 SetPrinterState(printer_t *p, /* I - Printer to change */
2010 ipp_pstate_t s, /* I - New state */
2011 int update) /* I - Update printers.conf? */
2012 {
2013 ipp_pstate_t old_state; /* Old printer state */
2014
2015
2016 /*
2017 * Can't set status of remote printers...
2018 */
2019
2020 if (p->type & CUPS_PRINTER_REMOTE)
2021 return;
2022
2023 /*
2024 * Set the new state...
2025 */
2026
2027 old_state = p->state;
2028 p->state = s;
2029
2030 if (old_state != s)
2031 {
2032 /*
2033 * Let the browse code know this needs to be updated...
2034 */
2035
2036 BrowseNext = p;
2037 p->state_time = time(NULL);
2038 p->browse_time = 0;
2039
2040 #ifdef __sgi
2041 write_irix_state(p);
2042 #endif /* __sgi */
2043 }
2044
2045 AddPrinterHistory(p);
2046
2047 /*
2048 * Save the printer configuration if a printer goes from idle or processing
2049 * to stopped (or visa-versa)...
2050 */
2051
2052 if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED) &&
2053 update)
2054 {
2055 if (p->type & CUPS_PRINTER_CLASS)
2056 SaveAllClasses();
2057 else
2058 SaveAllPrinters();
2059 }
2060 }
2061
2062
2063 /*
2064 * 'SortPrinters()' - Sort the printer list when a printer name is changed.
2065 */
2066
2067 void
2068 SortPrinters(void)
2069 {
2070 printer_t *current, /* Current printer */
2071 *prev, /* Previous printer */
2072 *next; /* Next printer */
2073 int did_swap; /* Non-zero if we did a swap */
2074
2075
2076 do
2077 {
2078 for (did_swap = 0, current = Printers, prev = NULL; current != NULL;)
2079 if (current->next == NULL)
2080 break;
2081 else if (strcasecmp(current->name, current->next->name) > 0)
2082 {
2083 DEBUG_printf(("Swapping %s and %s...\n", current->name,
2084 current->next->name));
2085
2086 /*
2087 * Need to swap these two printers...
2088 */
2089
2090 did_swap = 1;
2091
2092 if (prev == NULL)
2093 Printers = current->next;
2094 else
2095 prev->next = current->next;
2096
2097 /*
2098 * Yes, we can all get a headache from the next bunch of pointer
2099 * swapping...
2100 */
2101
2102 next = current->next;
2103 current->next = next->next;
2104 next->next = current;
2105 prev = next;
2106 }
2107 else
2108 {
2109 prev = current;
2110 current = current->next;
2111 }
2112 }
2113 while (did_swap);
2114 }
2115
2116
2117 /*
2118 * 'StopPrinter()' - Stop a printer from printing any jobs...
2119 */
2120
2121 void
2122 StopPrinter(printer_t *p, /* I - Printer to stop */
2123 int update) /* I - Update printers.conf? */
2124 {
2125 job_t *job; /* Active print job */
2126
2127
2128 /*
2129 * Set the printer state...
2130 */
2131
2132 SetPrinterState(p, IPP_PRINTER_STOPPED, update);
2133
2134 /*
2135 * See if we have a job printing on this printer...
2136 */
2137
2138 if (p->job)
2139 {
2140 /*
2141 * Get pointer to job...
2142 */
2143
2144 job = (job_t *)p->job;
2145
2146 /*
2147 * Stop it...
2148 */
2149
2150 StopJob(job->id, 0);
2151
2152 /*
2153 * Reset the state to pending...
2154 */
2155
2156 job->state->values[0].integer = IPP_JOB_PENDING;
2157
2158 SaveJob(job->id);
2159 }
2160 }
2161
2162
2163 /*
2164 * 'ValidateDest()' - Validate a printer/class destination.
2165 */
2166
2167 const char * /* O - Printer or class name */
2168 ValidateDest(const char *hostname, /* I - Host name */
2169 const char *resource, /* I - Resource name */
2170 cups_ptype_t *dtype, /* O - Type (printer or class) */
2171 printer_t **printer) /* O - Printer pointer */
2172 {
2173 printer_t *p; /* Current printer */
2174 char localname[1024], /* Localized hostname */
2175 *lptr, /* Pointer into localized hostname */
2176 *sptr; /* Pointer into server name */
2177
2178
2179 DEBUG_printf(("ValidateDest(\"%s\", \"%s\", %p, %p)\n", hostname, resource,
2180 dtype, printer));
2181
2182 /*
2183 * Initialize return values...
2184 */
2185
2186 if (printer)
2187 *printer = NULL;
2188
2189 *dtype = (cups_ptype_t)0;
2190
2191 /*
2192 * See if the resource is a class or printer...
2193 */
2194
2195 if (!strncmp(resource, "/classes/", 9))
2196 {
2197 /*
2198 * Class...
2199 */
2200
2201 resource += 9;
2202 }
2203 else if (!strncmp(resource, "/printers/", 10))
2204 {
2205 /*
2206 * Printer...
2207 */
2208
2209 resource += 10;
2210 }
2211 else
2212 {
2213 /*
2214 * Bad resource name...
2215 */
2216
2217 return (NULL);
2218 }
2219
2220 /*
2221 * See if the printer or class name exists...
2222 */
2223
2224 if ((p = FindPrinter(resource)) == NULL)
2225 p = FindClass(resource);
2226
2227 if (p == NULL && strchr(resource, '@') == NULL)
2228 return (NULL);
2229 else if (p != NULL)
2230 {
2231 if (printer)
2232 *printer = p;
2233
2234 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
2235 CUPS_PRINTER_REMOTE);
2236 return (p->name);
2237 }
2238
2239 /*
2240 * Change localhost to the server name...
2241 */
2242
2243 if (!strcasecmp(hostname, "localhost"))
2244 hostname = ServerName;
2245
2246 strlcpy(localname, hostname, sizeof(localname));
2247
2248 if (!strcasecmp(hostname, ServerName))
2249 {
2250 /*
2251 * Localize the hostname...
2252 */
2253
2254 lptr = strchr(localname, '.');
2255 sptr = strchr(ServerName, '.');
2256
2257 if (sptr != NULL && lptr != NULL)
2258 {
2259 /*
2260 * Strip the common domain name components...
2261 */
2262
2263 while (lptr != NULL)
2264 {
2265 if (!strcasecmp(lptr, sptr))
2266 {
2267 *lptr = '\0';
2268 break;
2269 }
2270 else
2271 lptr = strchr(lptr + 1, '.');
2272 }
2273 }
2274 }
2275
2276 DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
2277
2278 /*
2279 * Find a matching printer or class...
2280 */
2281
2282 for (p = Printers; p != NULL; p = p->next)
2283 if (!strcasecmp(p->hostname, localname) &&
2284 !strcasecmp(p->name, resource))
2285 {
2286 if (printer)
2287 *printer = p;
2288
2289 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
2290 CUPS_PRINTER_REMOTE);
2291 return (p->name);
2292 }
2293
2294 return (NULL);
2295 }
2296
2297
2298 /*
2299 * 'WritePrintcap()' - Write a pseudo-printcap file for older applications
2300 * that need it...
2301 */
2302
2303 void
2304 WritePrintcap(void)
2305 {
2306 cups_file_t *fp; /* printcap file */
2307 printer_t *p; /* Current printer */
2308
2309
2310 #ifdef __sgi
2311 /*
2312 * Update the IRIX printer state for the default printer; if
2313 * no printers remain, then the default printer file will be
2314 * removed...
2315 */
2316
2317 write_irix_state(DefaultPrinter);
2318 #endif /* __sgi */
2319
2320 /*
2321 * See if we have a printcap file; if not, don't bother writing it.
2322 */
2323
2324 if (!Printcap || !*Printcap)
2325 return;
2326
2327 /*
2328 * Open the printcap file...
2329 */
2330
2331 if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
2332 return;
2333
2334 /*
2335 * Put a comment header at the top so that users will know where the
2336 * data has come from...
2337 */
2338
2339 cupsFilePuts(fp, "# This file was automatically generated by cupsd(8) from the\n");
2340 cupsFilePrintf(fp, "# %s/printers.conf file. All changes to this file\n",
2341 ServerRoot);
2342 cupsFilePuts(fp, "# will be lost.\n");
2343
2344 /*
2345 * Write a new printcap with the current list of printers.
2346 */
2347
2348 switch (PrintcapFormat)
2349 {
2350 case PRINTCAP_BSD:
2351 /*
2352 * Each printer is put in the file as:
2353 *
2354 * Printer1:
2355 * Printer2:
2356 * Printer3:
2357 * ...
2358 * PrinterN:
2359 */
2360
2361 if (DefaultPrinter)
2362 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
2363 DefaultPrinter->info, ServerName, DefaultPrinter->name);
2364
2365 for (p = Printers; p != NULL; p = p->next)
2366 if (p != DefaultPrinter)
2367 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
2368 ServerName, p->name);
2369 break;
2370
2371 case PRINTCAP_SOLARIS:
2372 /*
2373 * Each printer is put in the file as:
2374 *
2375 * _all:all=Printer1,Printer2,Printer3,...,PrinterN
2376 * _default:use=DefaultPrinter
2377 * Printer1:\
2378 * :bsdaddr=ServerName,Printer1:\
2379 * :description=Description:
2380 * Printer2:
2381 * :bsdaddr=ServerName,Printer2:\
2382 * :description=Description:
2383 * Printer3:
2384 * :bsdaddr=ServerName,Printer3:\
2385 * :description=Description:
2386 * ...
2387 * PrinterN:
2388 * :bsdaddr=ServerName,PrinterN:\
2389 * :description=Description:
2390 */
2391
2392 cupsFilePuts(fp, "_all:all=");
2393 for (p = Printers; p != NULL; p = p->next)
2394 cupsFilePrintf(fp, "%s%c", p->name, p->next ? ',' : '\n');
2395
2396 if (DefaultPrinter)
2397 cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
2398
2399 for (p = Printers; p != NULL; p = p->next)
2400 cupsFilePrintf(fp, "%s:\\\n"
2401 "\t:bsdaddr=%s,%s:\\\n"
2402 "\t:description=%s:\n",
2403 p->name, ServerName, p->name, p->info ? p->info : "");
2404 break;
2405 }
2406
2407 /*
2408 * Close the file...
2409 */
2410
2411 cupsFileClose(fp);
2412 }
2413
2414
2415 /*
2416 * 'cupsdSanitizeURI()' - Sanitize a device URI...
2417 */
2418
2419 char * /* O - New device URI */
2420 cupsdSanitizeURI(const char *uri, /* I - Original device URI */
2421 char *buffer, /* O - New device URI */
2422 int buflen) /* I - Size of new device URI buffer */
2423 {
2424 char *start, /* Start of data after scheme */
2425 *slash, /* First slash after scheme:// */
2426 *ptr; /* Pointer into user@host:port part */
2427
2428
2429 /*
2430 * Range check input...
2431 */
2432
2433 if (!uri || !buffer || buflen < 2)
2434 return (NULL);
2435
2436 /*
2437 * Copy the device URI to the new buffer...
2438 */
2439
2440 strlcpy(buffer, uri, buflen);
2441
2442 /*
2443 * Find the end of the scheme:// part...
2444 */
2445
2446 if ((ptr = strchr(buffer, ':')) == NULL)
2447 return (buffer); /* No scheme: part... */
2448
2449 for (start = ptr + 1; *start; start ++)
2450 if (*start != '/')
2451 break;
2452
2453 /*
2454 * Find the next slash (/) in the URI...
2455 */
2456
2457 if ((slash = strchr(start, '/')) == NULL)
2458 slash = start + strlen(start); /* No slash, point to the end */
2459
2460 /*
2461 * Check for an @ sign before the slash...
2462 */
2463
2464 if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
2465 {
2466 /*
2467 * Found an @ sign and it is before the resource part, so we have
2468 * an authentication string. Copy the remaining URI over the
2469 * authentication string...
2470 */
2471
2472 cups_strcpy(start, ptr + 1);
2473 }
2474
2475 /*
2476 * Return the new device URI...
2477 */
2478
2479 return (buffer);
2480 }
2481
2482
2483 #ifdef __sgi
2484 /*
2485 * 'write_irix_config()' - Update the config files used by the IRIX
2486 * desktop tools.
2487 */
2488
2489 static void
2490 write_irix_config(printer_t *p) /* I - Printer to update */
2491 {
2492 char filename[1024]; /* Interface script filename */
2493 cups_file_t *fp; /* Interface script file */
2494 int tag; /* Status tag value */
2495
2496
2497
2498 /*
2499 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
2500 * tools. First the interface script that tells the tools what kind of
2501 * printer we have...
2502 */
2503
2504 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
2505
2506 if (p->type & CUPS_PRINTER_CLASS)
2507 unlink(filename);
2508 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
2509 {
2510 cupsFilePuts(fp, "#!/bin/sh\n");
2511
2512 if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
2513 IPP_TAG_TEXT)) != NULL)
2514 cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
2515 else if (p->type & CUPS_PRINTER_CLASS)
2516 cupsFilePuts(fp, "NAME=\"Printer Class\"\n");
2517 else
2518 cupsFilePuts(fp, "NAME=\"Remote Destination\"\n");
2519
2520 if (p->type & CUPS_PRINTER_COLOR)
2521 cupsFilePuts(fp, "TYPE=ColorPostScript\n");
2522 else
2523 cupsFilePuts(fp, "TYPE=MonoPostScript\n");
2524
2525 cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName);
2526 cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name);
2527
2528 cupsFileClose(fp);
2529
2530 chmod(filename, 0755);
2531 chown(filename, User, Group);
2532 }
2533
2534 /*
2535 * Then the member file that tells which device file the queue is connected
2536 * to... Networked printers use "/dev/null" in this file, so that's what
2537 * we use (the actual device URI can confuse some apps...)
2538 */
2539
2540 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
2541
2542 if (p->type & CUPS_PRINTER_CLASS)
2543 unlink(filename);
2544 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
2545 {
2546 cupsFilePuts(fp, "/dev/null\n");
2547
2548 cupsFileClose(fp);
2549
2550 chmod(filename, 0644);
2551 chown(filename, User, Group);
2552 }
2553
2554 /*
2555 * The gui_interface file is a script or program that launches a GUI
2556 * option panel for the printer, using options specified on the
2557 * command-line in the third argument. The option panel must send
2558 * any printing options to stdout on a single line when the user
2559 * accepts them, or nothing if the user cancels the dialog.
2560 *
2561 * The default options panel program is /usr/bin/glpoptions, from
2562 * the ESP Print Pro software. You can select another using the
2563 * PrintcapGUI option.
2564 */
2565
2566 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
2567
2568 if (p->type & CUPS_PRINTER_CLASS)
2569 unlink(filename);
2570 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
2571 {
2572 cupsFilePuts(fp, "#!/bin/sh\n");
2573 cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
2574
2575 cupsFileClose(fp);
2576
2577 chmod(filename, 0755);
2578 chown(filename, User, Group);
2579 }
2580
2581 /*
2582 * The POD config file is needed by the printstatus command to show
2583 * the printer location and device.
2584 */
2585
2586 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
2587
2588 if (p->type & CUPS_PRINTER_CLASS)
2589 unlink(filename);
2590 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
2591 {
2592 cupsFilePrintf(fp, "Printer Class | %s\n",
2593 (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
2594 cupsFilePrintf(fp, "Printer Model | %s\n", p->make_model ? p->make_model : "");
2595 cupsFilePrintf(fp, "Location Code | %s\n", p->location ? p->location : "");
2596 cupsFilePrintf(fp, "Physical Location | %s\n", p->info ? p->info : "");
2597 cupsFilePrintf(fp, "Port Path | %s\n", p->device_uri ? p->device_uri : "");
2598 cupsFilePrintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
2599 cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
2600 cupsFilePuts(fp, "Status Update Wait | 10 seconds\n");
2601
2602 cupsFileClose(fp);
2603
2604 chmod(filename, 0664);
2605 chown(filename, User, Group);
2606 }
2607 }
2608
2609
2610 /*
2611 * 'write_irix_state()' - Update the status files used by IRIX printing
2612 * desktop tools.
2613 */
2614
2615 static void
2616 write_irix_state(printer_t *p) /* I - Printer to update */
2617 {
2618 char filename[1024]; /* Interface script filename */
2619 cups_file_t *fp; /* Interface script file */
2620 int tag; /* Status tag value */
2621
2622
2623 if (p)
2624 {
2625 /*
2626 * The POD status file is needed for the printstatus window to
2627 * provide the current status of the printer.
2628 */
2629
2630 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
2631
2632 if (p->type & CUPS_PRINTER_CLASS)
2633 unlink(filename);
2634 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
2635 {
2636 cupsFilePrintf(fp, "Operational Status | %s\n",
2637 (p->state == IPP_PRINTER_IDLE) ? "Idle" :
2638 (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
2639 "Faulted");
2640 cupsFilePrintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
2641 cupsFilePrintf(fp, "Information | 02 00 00 | Device URI: %s\n",
2642 p->device_uri ? p->device_uri : "");
2643 cupsFilePrintf(fp, "Information | 03 00 00 | %s jobs\n",
2644 p->accepting ? "Accepting" : "Not accepting");
2645 cupsFilePrintf(fp, "Information | 04 00 00 | %s\n", p->state_message);
2646
2647 cupsFileClose(fp);
2648
2649 chmod(filename, 0664);
2650 chown(filename, User, Group);
2651 }
2652
2653 /*
2654 * The activeicons file is needed to provide desktop icons for printers:
2655 *
2656 * [ quoted from /usr/lib/print/tagit ]
2657 *
2658 * --- Type of printer tags (base values)
2659 *
2660 * Dumb=66048 # 0x10200
2661 * DumbColor=66080 # 0x10220
2662 * Raster=66112 # 0x10240
2663 * ColorRaster=66144 # 0x10260
2664 * Plotter=66176 # 0x10280
2665 * PostScript=66208 # 0x102A0
2666 * ColorPostScript=66240 # 0x102C0
2667 * MonoPostScript=66272 # 0x102E0
2668 *
2669 * --- Printer state modifiers for local printers
2670 *
2671 * Idle=0 # 0x0
2672 * Busy=1 # 0x1
2673 * Faulted=2 # 0x2
2674 * Unknown=3 # 0x3 (Faulted due to unknown reason)
2675 *
2676 * --- Printer state modifiers for network printers
2677 *
2678 * NetIdle=8 # 0x8
2679 * NetBusy=9 # 0x9
2680 * NetFaulted=10 # 0xA
2681 * NetUnknown=11 # 0xB (Faulted due to unknown reason)
2682 */
2683
2684 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
2685
2686 if (p->type & CUPS_PRINTER_CLASS)
2687 unlink(filename);
2688 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
2689 {
2690 if (p->type & CUPS_PRINTER_COLOR)
2691 tag = 66240;
2692 else
2693 tag = 66272;
2694
2695 if (p->type & CUPS_PRINTER_REMOTE)
2696 tag |= 8;
2697
2698 if (p->state == IPP_PRINTER_PROCESSING)
2699 tag |= 1;
2700
2701 else if (p->state == IPP_PRINTER_STOPPED)
2702 tag |= 2;
2703
2704 cupsFilePuts(fp, "#!/bin/sh\n");
2705 cupsFilePrintf(fp, "#Tag %d\n", tag);
2706
2707 cupsFileClose(fp);
2708
2709 chmod(filename, 0755);
2710 chown(filename, User, Group);
2711 }
2712 }
2713
2714 /*
2715 * The default file is needed by the printers window to show
2716 * the default printer.
2717 */
2718
2719 snprintf(filename, sizeof(filename), "/var/spool/lp/default");
2720
2721 if (DefaultPrinter != NULL)
2722 {
2723 if ((fp = cupsFileOpen(filename, "w")) != NULL)
2724 {
2725 cupsFilePrintf(fp, "%s\n", DefaultPrinter->name);
2726
2727 cupsFileClose(fp);
2728
2729 chmod(filename, 0644);
2730 chown(filename, User, Group);
2731 }
2732 }
2733 else
2734 unlink(filename);
2735 }
2736 #endif /* __sgi */
2737
2738
2739 /*
2740 * End of "$Id$".
2741 */