]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/printers.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / scheduler / printers.c
CommitLineData
ef416fc2 1/*
c07d5b2d 2 * "$Id: printers.c 181 2006-06-22 20:01:18Z jlovell $"
ef416fc2 3 *
4 * Printer routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 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 * cupsdAddPrinter() - Add a printer to the system.
ef416fc2 27 * cupsdAddPrinterHistory() - Add the current printer state to the history.
28 * cupsdAddPrinterUser() - Add a user to the ACL.
29 * cupsdDeleteAllPrinters() - Delete all printers from the system.
30 * cupsdDeletePrinter() - Delete a printer from the system.
ef416fc2 31 * cupsdFindPrinter() - Find a printer in the list.
32 * cupsdFreePrinterUsers() - Free allow/deny users.
33 * cupsdLoadAllPrinters() - Load printers from the printers.conf file.
b423cd4c 34 * cupsdRenamePrinter() - Rename a printer.
fa73b229 35 * cupsdSaveAllPrinters() - Save all printer definitions to the
36 * printers.conf file.
37 * cupsdSetPrinterAttrs() - Set printer attributes based upon the PPD
38 * file.
ef416fc2 39 * cupsdSetPrinterReasons() - Set/update the reasons strings.
40 * cupsdSetPrinterState() - Update the current state of a printer.
41 * cupsdStopPrinter() - Stop a printer from printing any jobs...
42 * cupsdUpdatePrinters() - Update printers after a partial reload.
43 * cupsdValidateDest() - Validate a printer/class destination.
44 * cupsdWritePrintcap() - Write a pseudo-printcap file for older
45 * applications that need it...
46 * cupsdSanitizeURI() - Sanitize a device URI...
b423cd4c 47 * add_printer_defaults() - Add name-default attributes to the printer
48 * attributes.
bd7854cb 49 * add_printer_filter() - Add a MIME filter for a printer.
50 * add_printer_formats() - Add document-format-supported values for
51 * a printer.
ef416fc2 52 * compare_printers() - Compare two printers.
e1d6a774 53 * delete_printer_filters() - Delete all MIME filters for a printer.
ef416fc2 54 * write_irix_config() - Update the config files used by the IRIX
55 * desktop tools.
fa73b229 56 * write_irix_state() - Update the status files used by IRIX
57 * printing desktop tools.
ef416fc2 58 */
59
60/*
61 * Include necessary headers...
62 */
63
64#include "cupsd.h"
ed486911 65#include <cups/dir.h>
ef416fc2 66
67
68/*
69 * Local functions...
70 */
71
b423cd4c 72static void add_printer_defaults(cupsd_printer_t *p);
bd7854cb 73static void add_printer_filter(cupsd_printer_t *p, const char *filter);
74static void add_printer_formats(cupsd_printer_t *p);
ef416fc2 75static int compare_printers(void *first, void *second, void *data);
e1d6a774 76static void delete_printer_filters(cupsd_printer_t *p);
ef416fc2 77#ifdef __sgi
78static void write_irix_config(cupsd_printer_t *p);
79static void write_irix_state(cupsd_printer_t *p);
80#endif /* __sgi */
81
82
83/*
84 * 'cupsdAddPrinter()' - Add a printer to the system.
85 */
86
87cupsd_printer_t * /* O - New printer */
88cupsdAddPrinter(const char *name) /* I - Name of printer */
89{
90 cupsd_printer_t *p; /* New printer */
91
92
93 /*
94 * Range check input...
95 */
96
97 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPrinter(\"%s\")", name);
98
99 /*
100 * Create a new printer entity...
101 */
102
103 if ((p = calloc(1, sizeof(cupsd_printer_t))) == NULL)
104 {
105 cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for printer - %s",
106 strerror(errno));
107 return (NULL);
108 }
109
110 cupsdSetString(&p->name, name);
111 cupsdSetString(&p->info, name);
112 cupsdSetString(&p->hostname, ServerName);
113
114 cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, LocalPort, name);
115 cupsdSetStringf(&p->device_uri, "file:/dev/null");
116
117 p->state = IPP_PRINTER_STOPPED;
118 p->state_time = time(NULL);
119 p->accepting = 0;
fa73b229 120 p->shared = DefaultShared;
ef416fc2 121 p->filetype = mimeAddType(MimeDatabase, "printer", name);
122
123 cupsdSetString(&p->job_sheets[0], "none");
124 cupsdSetString(&p->job_sheets[1], "none");
125
126 cupsdSetString(&p->error_policy, "stop-printer");
127 cupsdSetString(&p->op_policy, DefaultPolicy);
128
129 p->op_policy_ptr = DefaultPolicyPtr;
130
131 if (MaxPrinterHistory)
132 p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *));
133
134 /*
135 * Insert the printer in the printer list alphabetically...
136 */
137
138 if (!Printers)
139 Printers = cupsArrayNew(compare_printers, NULL);
140
141 cupsArrayAdd(Printers, p);
142
143 if (!ImplicitPrinters)
144 ImplicitPrinters = cupsArrayNew(compare_printers, NULL);
145
146 /*
147 * Return the new printer...
148 */
149
150 return (p);
151}
152
153
ef416fc2 154/*
155 * 'cupsdAddPrinterHistory()' - Add the current printer state to the history.
156 */
157
158void
159cupsdAddPrinterHistory(
160 cupsd_printer_t *p) /* I - Printer */
161{
162 ipp_t *history; /* History collection */
163
164
165 /*
166 * Stop early if we aren't keeping history data...
167 */
168
169 if (MaxPrinterHistory <= 0)
170 return;
171
172 /*
173 * Retire old history data as needed...
174 */
175
176 p->sequence_number ++;
177
178 if (p->num_history >= MaxPrinterHistory)
179 {
180 p->num_history --;
181 ippDelete(p->history[0]);
182 memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *));
183 }
184
185 /*
186 * Create a collection containing the current printer-state, printer-up-time,
187 * printer-state-message, and printer-state-reasons attributes.
188 */
189
190 history = ippNew();
191 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
192 p->state);
193 ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
194 p->accepting);
fa73b229 195 ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared);
ef416fc2 196 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
197 NULL, p->state_message);
e00b005a 198#ifdef __APPLE__
199 if (p->recoverable)
200 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT,
201 "com.apple.print.recoverable-message", NULL, p->recoverable);
202#endif /* __APPLE__ */
ef416fc2 203 if (p->num_reasons == 0)
204 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
205 "printer-state-reasons", NULL,
206 p->state == IPP_PRINTER_STOPPED ? "paused" : "none");
207 else
208 ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
209 "printer-state-reasons", p->num_reasons, NULL,
210 (const char * const *)p->reasons);
211 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
212 "printer-state-change-time", p->state_time);
213 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
214 "printer-state-sequence-number", p->sequence_number);
215
216 p->history[p->num_history] = history;
217 p->num_history ++;
218}
219
220
221/*
222 * 'cupsdAddPrinterUser()' - Add a user to the ACL.
223 */
224
225void
226cupsdAddPrinterUser(
227 cupsd_printer_t *p, /* I - Printer */
228 const char *username) /* I - User */
229{
230 const char **temp; /* Temporary array pointer */
231
232
233 if (!p || !username)
234 return;
235
236 if (p->num_users == 0)
237 temp = malloc(sizeof(char **));
238 else
239 temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
240
241 if (!temp)
242 return;
243
244 p->users = temp;
245 temp += p->num_users;
246
247 if ((*temp = strdup(username)) != NULL)
248 p->num_users ++;
249}
250
251
252/*
253 * 'cupsdCreateCommonData()' - Create the common printer data.
254 */
255
256void
257cupsdCreateCommonData(void)
258{
259 int i; /* Looping var */
260 ipp_attribute_t *attr; /* Attribute data */
ed486911 261 cups_dir_t *dir; /* Notifier directory */
262 cups_dentry_t *dent; /* Notifier directory entry */
263 cups_array_t *notifiers; /* Notifier array */
264 char filename[1024], /* Filename */
265 *notifier; /* Current notifier */
ef416fc2 266 static const int nups[] = /* number-up-supported values */
267 { 1, 2, 4, 6, 9, 16 };
268 static const ipp_orient_t orients[4] =/* orientation-requested-supported values */
269 {
270 IPP_PORTRAIT,
271 IPP_LANDSCAPE,
272 IPP_REVERSE_LANDSCAPE,
273 IPP_REVERSE_PORTRAIT
274 };
275 static const char * const holds[] = /* job-hold-until-supported values */
276 {
277 "no-hold",
278 "indefinite",
279 "day-time",
280 "evening",
281 "night",
282 "second-shift",
283 "third-shift",
284 "weekend"
285 };
286 static const char * const versions[] =/* ipp-versions-supported values */
287 {
288 "1.0",
289 "1.1"
290 };
291 static const ipp_op_t ops[] = /* operations-supported values */
292 {
293 IPP_PRINT_JOB,
294 IPP_VALIDATE_JOB,
295 IPP_CREATE_JOB,
296 IPP_SEND_DOCUMENT,
297 IPP_CANCEL_JOB,
298 IPP_GET_JOB_ATTRIBUTES,
299 IPP_GET_JOBS,
300 IPP_GET_PRINTER_ATTRIBUTES,
301 IPP_HOLD_JOB,
302 IPP_RELEASE_JOB,
303 IPP_PAUSE_PRINTER,
304 IPP_RESUME_PRINTER,
305 IPP_PURGE_JOBS,
306 IPP_SET_JOB_ATTRIBUTES,
307 IPP_CREATE_PRINTER_SUBSCRIPTION,
308 IPP_CREATE_JOB_SUBSCRIPTION,
309 IPP_GET_SUBSCRIPTION_ATTRIBUTES,
310 IPP_GET_SUBSCRIPTIONS,
311 IPP_RENEW_SUBSCRIPTION,
312 IPP_CANCEL_SUBSCRIPTION,
313 IPP_GET_NOTIFICATIONS,
314 IPP_ENABLE_PRINTER,
315 IPP_DISABLE_PRINTER,
316 CUPS_GET_DEFAULT,
317 CUPS_GET_PRINTERS,
318 CUPS_ADD_PRINTER,
319 CUPS_DELETE_PRINTER,
320 CUPS_GET_CLASSES,
321 CUPS_ADD_CLASS,
322 CUPS_DELETE_CLASS,
323 CUPS_ACCEPT_JOBS,
324 CUPS_REJECT_JOBS,
325 CUPS_SET_DEFAULT,
326 CUPS_GET_DEVICES,
327 CUPS_GET_PPDS,
328 CUPS_MOVE_JOB,
329 CUPS_AUTHENTICATE_JOB,
330 IPP_RESTART_JOB
331 };
332 static const char * const charsets[] =/* charset-supported values */
333 {
334 "us-ascii",
335 "utf-8"
336 };
337 static const char * const compressions[] =
338 { /* document-compression-supported values */
339 "none"
340#ifdef HAVE_LIBZ
341 ,"gzip"
342#endif /* HAVE_LIBZ */
343 };
344 static const char * const multiple_document_handling[] =
345 { /* multiple-document-handling-supported values */
346 "separate-documents-uncollated-copies",
347 "separate-documents-collated-copies"
348 };
349 static const char * const errors[] = /* printer-error-policy-supported values */
350 {
351 "abort-job",
352 "retry-job",
353 "stop-printer"
354 };
355 static const char * const notify_attrs[] =
356 { /* notify-attributes-supported values */
357 "printer-state-change-time",
358 "notify-lease-expiration-time",
359 "notify-subscriber-user-name"
360 };
361 static const char * const notify_events[] =
362 { /* notify-events-supported values */
363 "job-completed",
364 "job-config-changed",
365 "job-created",
366 "job-progress",
367 "job-state-changed",
368 "job-stopped",
369 "printer-added",
370 "printer-changed",
371 "printer-config-changed",
372 "printer-deleted",
373 "printer-finishings-changed",
374 "printer-media-changed",
375 "printer-modified",
376 "printer-restarted",
377 "printer-shutdown",
378 "printer-state-changed",
379 "printer-stopped",
380 "server-audit",
381 "server-restarted",
382 "server-started",
383 "server-stopped"
384 };
385
386
387 if (CommonData)
388 ippDelete(CommonData);
389
390 CommonData = ippNew();
391
392 /*
393 * This list of attributes is sorted to improve performance when the
394 * client provides a requested-attributes attribute...
395 */
396
397 /* charset-configured */
398 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET,
399 "charset-configured", NULL, DefaultCharset);
400
401 /* charset-supported */
402 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET,
403 "charset-supported", sizeof(charsets) / sizeof(charsets[0]),
404 NULL, charsets);
405
406 /* compression-supported */
407 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
408 "compression-supported",
409 sizeof(compressions) / sizeof(compressions[0]),
410 NULL, compressions);
411
ef416fc2 412 /* copies-supported */
413 ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
414
ef416fc2 415 /* generated-natural-language-supported */
416 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
417 "generated-natural-language-supported", NULL, DefaultLanguage);
418
419 /* ipp-versions-supported */
420 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
421 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
422 NULL, versions);
423
ef416fc2 424 /* job-hold-until-supported */
425 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
426 "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]),
427 NULL, holds);
428
ef416fc2 429 /* job-priority-supported */
430 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
431 "job-priority-supported", 100);
432
433 /* job-sheets-supported */
fa73b229 434 if (cupsArrayCount(Banners) > 0)
ef416fc2 435 {
436 /*
437 * Setup the job-sheets-supported attribute...
438 */
439
440 if (Classification && !ClassifyOverride)
441 attr = ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
442 "job-sheets-supported", NULL, Classification);
443 else
444 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
fa73b229 445 "job-sheets-supported", cupsArrayCount(Banners) + 1,
446 NULL, NULL);
ef416fc2 447
448 if (attr == NULL)
449 cupsdLogMessage(CUPSD_LOG_EMERG,
bd7854cb 450 "Unable to allocate memory for "
ef416fc2 451 "job-sheets-supported attribute: %s!", strerror(errno));
452 else if (!Classification || ClassifyOverride)
453 {
fa73b229 454 cupsd_banner_t *banner; /* Current banner */
455
456
757d2cad 457 attr->values[0].string.text = _cupsStrAlloc("none");
ef416fc2 458
fa73b229 459 for (i = 1, banner = (cupsd_banner_t *)cupsArrayFirst(Banners);
460 banner;
461 i ++, banner = (cupsd_banner_t *)cupsArrayNext(Banners))
757d2cad 462 attr->values[i].string.text = _cupsStrAlloc(banner->name);
ef416fc2 463 }
464 }
465 else
466 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
467 "job-sheets-supported", NULL, "none");
468
469 /* multiple-document-handling-supported */
470 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
471 "multiple-document-handling-supported",
472 sizeof(multiple_document_handling) /
473 sizeof(multiple_document_handling[0]), NULL,
474 multiple_document_handling);
475
476 /* multiple-document-jobs-supported */
477 ippAddBoolean(CommonData, IPP_TAG_PRINTER,
478 "multiple-document-jobs-supported", 1);
479
480 /* multiple-operation-time-out */
481 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
482 "multiple-operation-time-out", 60);
483
484 /* natural-language-configured */
485 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
486 "natural-language-configured", NULL, DefaultLanguage);
487
488 /* notify-attributes-supported */
489 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
490 "notify-attributes-supported",
491 (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])),
492 NULL, notify_attrs);
493
ef416fc2 494 /* notify-lease-duration-default */
495 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
496 "notify-lease-duration-default", DefaultLeaseDuration);
497
498 /* notify-lease-duration-supported */
499 ippAddRange(CommonData, IPP_TAG_PRINTER,
500 "notify-lease-duration-supported", 0,
501 MaxLeaseDuration ? MaxLeaseDuration : 2147483647);
502
503 /* notify-max-events-supported */
504 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
505 "notify-max-events-supported", MaxEvents);
506
ed486911 507 /* notify-events-default */
ef416fc2 508 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
509 "notify-events-default", NULL, "job-completed");
510
ed486911 511 /* notify-events-supported */
ef416fc2 512 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
513 "notify-events-supported",
514 (int)(sizeof(notify_events) / sizeof(notify_events[0])),
515 NULL, notify_events);
516
517 /* notify-pull-method-supported */
518 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
519 "notify-pull-method-supported", NULL, "ippget");
520
ef416fc2 521 /* notify-schemes-supported */
ed486911 522 snprintf(filename, sizeof(filename), "%s/notifier", ServerBin);
523 if ((dir = cupsDirOpen(filename)) != NULL)
524 {
525 notifiers = cupsArrayNew((cups_array_func_t)strcmp, NULL);
526
527 while ((dent = cupsDirRead(dir)) != NULL)
528 if (S_ISREG(dent->fileinfo.st_mode) &&
529 (dent->fileinfo.st_mode & S_IXOTH) != 0)
530 cupsArrayAdd(notifiers, _cupsStrAlloc(dent->filename));
531
532 if (cupsArrayCount(notifiers) > 0)
533 {
534 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
535 "notify-schemes-supported",
536 cupsArrayCount(notifiers), NULL, NULL);
537
538 for (i = 0, notifier = (char *)cupsArrayFirst(notifiers);
539 notifier;
540 i ++, notifier = (char *)cupsArrayNext(notifiers))
541 attr->values[i].string.text = notifier;
542 }
543
544 cupsArrayDelete(notifiers);
545 }
ef416fc2 546
ef416fc2 547 /* number-up-supported */
548 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
549 "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
550
551 /* operations-supported */
552 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
553 "operations-supported",
554 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
555
ef416fc2 556 /* orientation-requested-supported */
557 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
558 "orientation-requested-supported", 4, (int *)orients);
559
560 /* page-ranges-supported */
561 ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
562
563 /* pdf-override-supported */
564 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
565 "pdl-override-supported", NULL, "not-attempted");
566
567 /* printer-error-policy-supported */
568 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
569 "printer-error-policy-supported",
570 sizeof(errors) / sizeof(errors[0]), NULL, errors);
571
572 /* printer-op-policy-supported */
573 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME,
574 "printer-op-policy-supported", NumPolicies, NULL, NULL);
575 for (i = 0; i < NumPolicies; i ++)
757d2cad 576 attr->values[i].string.text = _cupsStrAlloc(Policies[i]->name);
ef416fc2 577}
578
579
580/*
581 * 'cupsdDeleteAllPrinters()' - Delete all printers from the system.
582 */
583
584void
585cupsdDeleteAllPrinters(void)
586{
587 cupsd_printer_t *p; /* Pointer to current printer/class */
588
589
590 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
591 p;
592 p = (cupsd_printer_t *)cupsArrayNext(Printers))
593 if (!(p->type & CUPS_PRINTER_CLASS))
594 cupsdDeletePrinter(p, 0);
595}
596
597
598/*
599 * 'cupsdDeletePrinter()' - Delete a printer from the system.
600 */
601
602void
603cupsdDeletePrinter(
604 cupsd_printer_t *p, /* I - Printer to delete */
605 int update) /* I - Update printers.conf? */
606{
607 int i; /* Looping var */
608#ifdef __sgi
609 char filename[1024]; /* Interface script filename */
610#endif /* __sgi */
611
612
613 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)",
614 p, p->name, update);
615
616 /*
617 * Save the current position in the Printers array...
618 */
619
620 cupsArraySave(Printers);
621
622 /*
623 * Stop printing on this printer...
624 */
625
626 cupsdStopPrinter(p, update);
627
628 /*
629 * If this printer is the next for browsing, point to the next one...
630 */
631
632 if (p == BrowseNext)
633 {
634 cupsArrayFind(Printers, p);
635 BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers);
636 }
637
638 /*
639 * Remove the printer from the list...
640 */
641
642 cupsArrayRemove(Printers, p);
643
644 /*
645 * Remove the dummy interface/icon/option files under IRIX...
646 */
647
648#ifdef __sgi
649 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
650 unlink(filename);
651
652 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
653 p->name);
654 unlink(filename);
655
656 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
657 unlink(filename);
658
659 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
660 unlink(filename);
661
662 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
663 unlink(filename);
664
665 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
666 unlink(filename);
667#endif /* __sgi */
668
669 /*
e00b005a 670 * If p is the default printer, assign a different one...
ef416fc2 671 */
672
673 if (p == DefaultPrinter)
e00b005a 674 {
675 DefaultPrinter = NULL;
676
677 if (UseNetworkDefault)
678 {
679 /*
680 * Find the first network default printer and use it...
681 */
682
683 cupsd_printer_t *dp; /* New default printer */
684
685
686 for (dp = (cupsd_printer_t *)cupsArrayFirst(Printers);
687 dp;
688 dp = (cupsd_printer_t *)cupsArrayNext(Printers))
689 if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT))
690 {
ed486911 691 DefaultPrinter = dp;
e00b005a 692 break;
693 }
694 }
695 }
ef416fc2 696
697 /*
698 * Remove this printer from any classes and send a browse delete message...
699 */
700
701 if (!(p->type & CUPS_PRINTER_IMPLICIT))
702 {
703 cupsdDeletePrinterFromClasses(p);
704 cupsdSendBrowseDelete(p);
705 }
706
707 /*
708 * Free all memory used by the printer...
709 */
710
711 if (p->printers != NULL)
712 free(p->printers);
713
714 if (MaxPrinterHistory)
715 {
716 for (i = 0; i < p->num_history; i ++)
717 ippDelete(p->history[i]);
718
719 free(p->history);
720 }
721
722 for (i = 0; i < p->num_reasons; i ++)
723 free(p->reasons[i]);
724
725 ippDelete(p->attrs);
726
e1d6a774 727 delete_printer_filters(p);
ef416fc2 728
fa73b229 729 mimeDeleteType(MimeDatabase, p->filetype);
730
ef416fc2 731 cupsdFreePrinterUsers(p);
732 cupsdFreeQuotas(p);
733
734 cupsdClearString(&p->uri);
735 cupsdClearString(&p->hostname);
736 cupsdClearString(&p->name);
737 cupsdClearString(&p->location);
738 cupsdClearString(&p->make_model);
739 cupsdClearString(&p->info);
740 cupsdClearString(&p->job_sheets[0]);
741 cupsdClearString(&p->job_sheets[1]);
742 cupsdClearString(&p->device_uri);
743 cupsdClearString(&p->port_monitor);
744 cupsdClearString(&p->op_policy);
745 cupsdClearString(&p->error_policy);
746
80ca4592 747 cupsArrayDelete(p->filetypes);
748
b423cd4c 749 if (p->browse_attrs)
750 free(p->browse_attrs);
751
e00b005a 752#ifdef __APPLE__
753 cupsdClearString(&p->recoverable);
754#endif /* __APPLE__ */
755
b423cd4c 756 cupsFreeOptions(p->num_options, p->options);
757
ef416fc2 758 free(p);
759
760 /*
761 * Restore the previous position in the Printers array...
762 */
763
764 cupsArrayRestore(Printers);
765}
766
767
ef416fc2 768/*
769 * 'cupsdFindDest()' - Find a destination in the list.
770 */
771
772cupsd_printer_t * /* O - Destination in list */
773cupsdFindDest(const char *name) /* I - Name of printer or class to find */
774{
775 cupsd_printer_t key; /* Search key */
776
777
778 key.name = (char *)name;
779 return ((cupsd_printer_t *)cupsArrayFind(Printers, &key));
780}
781
782
783/*
784 * 'cupsdFindPrinter()' - Find a printer in the list.
785 */
786
787cupsd_printer_t * /* O - Printer in list */
788cupsdFindPrinter(const char *name) /* I - Name of printer to find */
789{
790 cupsd_printer_t *p; /* Printer in list */
791
792
793 if ((p = cupsdFindDest(name)) != NULL && (p->type & CUPS_PRINTER_CLASS))
794 return (NULL);
795 else
796 return (p);
797}
798
799
800/*
801 * 'cupsdFreePrinterUsers()' - Free allow/deny users.
802 */
803
804void
805cupsdFreePrinterUsers(
806 cupsd_printer_t *p) /* I - Printer */
807{
808 int i; /* Looping var */
809
810
811 if (!p || !p->num_users)
812 return;
813
814 for (i = 0; i < p->num_users; i ++)
815 free((void *)p->users[i]);
816
817 free(p->users);
818
819 p->num_users = 0;
820 p->users = NULL;
821}
822
823
824/*
825 * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file.
826 */
827
828void
829cupsdLoadAllPrinters(void)
830{
831 cups_file_t *fp; /* printers.conf file */
832 int linenum; /* Current line number */
833 char line[1024], /* Line from file */
834 *value, /* Pointer to value */
835 *valueptr; /* Pointer into value */
836 cupsd_printer_t *p; /* Current printer */
837
838
839 /*
840 * Open the printers.conf file...
841 */
842
843 snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
844 if ((fp = cupsFileOpen(line, "r")) == NULL)
845 {
fa73b229 846 if (errno != ENOENT)
bd7854cb 847 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", line,
fa73b229 848 strerror(errno));
ef416fc2 849 return;
850 }
851
852 /*
853 * Read printer configurations until we hit EOF...
854 */
855
856 linenum = 0;
857 p = NULL;
858
859 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
860 {
861 /*
862 * Decode the directive...
863 */
864
865 if (!strcasecmp(line, "<Printer") ||
866 !strcasecmp(line, "<DefaultPrinter"))
867 {
868 /*
869 * <Printer name> or <DefaultPrinter name>
870 */
871
872 if (p == NULL && value)
873 {
874 /*
875 * Add the printer and a base file type...
876 */
877
bd7854cb 878 cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading printer %s...", value);
ef416fc2 879
880 p = cupsdAddPrinter(value);
881 p->accepting = 1;
882 p->state = IPP_PRINTER_IDLE;
883
884 /*
885 * Set the default printer as needed...
886 */
887
888 if (!strcasecmp(line, "<DefaultPrinter"))
889 DefaultPrinter = p;
890 }
891 else
892 {
893 cupsdLogMessage(CUPSD_LOG_ERROR,
894 "Syntax error on line %d of printers.conf.", linenum);
895 return;
896 }
897 }
898 else if (!strcasecmp(line, "</Printer>"))
899 {
900 if (p != NULL)
901 {
902 /*
903 * Close out the current printer...
904 */
905
906 cupsdSetPrinterAttrs(p);
907 cupsdAddPrinterHistory(p);
908
909 if (p->device_uri && strncmp(p->device_uri, "file:", 5) &&
910 p->state != IPP_PRINTER_STOPPED)
911 {
912 /*
913 * See if the backend exists...
914 */
915
916 snprintf(line, sizeof(line), "%s/backend/%s", ServerBin,
917 p->device_uri);
918
919 if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
920 *valueptr = '\0'; /* Chop everything but URI scheme */
921
922 if (access(line, 0))
923 {
924 /*
925 * Backend does not exist, stop printer...
926 */
927
928 p->state = IPP_PRINTER_STOPPED;
929 snprintf(p->state_message, sizeof(p->state_message),
930 "Backend %s does not exist!", line);
931 }
932 }
933
934 p = NULL;
935 }
936 else
937 {
938 cupsdLogMessage(CUPSD_LOG_ERROR,
939 "Syntax error on line %d of printers.conf.", linenum);
940 return;
941 }
942 }
943 else if (!p)
944 {
945 cupsdLogMessage(CUPSD_LOG_ERROR,
946 "Syntax error on line %d of printers.conf.", linenum);
947 return;
948 }
949 else if (!strcasecmp(line, "Info"))
950 {
951 if (value)
952 cupsdSetString(&p->info, value);
953 }
954 else if (!strcasecmp(line, "Location"))
955 {
956 if (value)
957 cupsdSetString(&p->location, value);
958 }
959 else if (!strcasecmp(line, "DeviceURI"))
960 {
961 if (value)
962 cupsdSetString(&p->device_uri, value);
963 else
964 {
965 cupsdLogMessage(CUPSD_LOG_ERROR,
966 "Syntax error on line %d of printers.conf.", linenum);
967 return;
968 }
969 }
b423cd4c 970 else if (!strcasecmp(line, "Option") && value)
971 {
972 /*
973 * Option name value
974 */
975
976 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
977
978 if (!*valueptr)
979 cupsdLogMessage(CUPSD_LOG_ERROR,
980 "Syntax error on line %d of printers.conf.", linenum);
981 else
982 {
983 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
984
985 p->num_options = cupsAddOption(value, valueptr, p->num_options,
986 &(p->options));
987 }
988 }
ef416fc2 989 else if (!strcasecmp(line, "PortMonitor"))
990 {
991 if (value && strcmp(value, "none"))
992 cupsdSetString(&p->port_monitor, value);
993 else if (value)
994 cupsdClearString(&p->port_monitor);
995 else
996 {
997 cupsdLogMessage(CUPSD_LOG_ERROR,
998 "Syntax error on line %d of printers.conf.", linenum);
999 return;
1000 }
1001 }
1002 else if (!strcasecmp(line, "State"))
1003 {
1004 /*
1005 * Set the initial queue state...
1006 */
1007
1008 if (value && !strcasecmp(value, "idle"))
1009 p->state = IPP_PRINTER_IDLE;
1010 else if (value && !strcasecmp(value, "stopped"))
1011 p->state = IPP_PRINTER_STOPPED;
1012 else
1013 {
1014 cupsdLogMessage(CUPSD_LOG_ERROR,
1015 "Syntax error on line %d of printers.conf.", linenum);
1016 return;
1017 }
1018 }
1019 else if (!strcasecmp(line, "StateMessage"))
1020 {
1021 /*
1022 * Set the initial queue state message...
1023 */
1024
1025 if (value)
1026 strlcpy(p->state_message, value, sizeof(p->state_message));
1027 }
1028 else if (!strcasecmp(line, "StateTime"))
1029 {
1030 /*
1031 * Set the state time...
1032 */
1033
1034 if (value)
1035 p->state_time = atoi(value);
1036 }
1037 else if (!strcasecmp(line, "Accepting"))
1038 {
1039 /*
1040 * Set the initial accepting state...
1041 */
1042
1043 if (value &&
1044 (!strcasecmp(value, "yes") ||
1045 !strcasecmp(value, "on") ||
1046 !strcasecmp(value, "true")))
1047 p->accepting = 1;
1048 else if (value &&
1049 (!strcasecmp(value, "no") ||
1050 !strcasecmp(value, "off") ||
1051 !strcasecmp(value, "false")))
1052 p->accepting = 0;
1053 else
1054 {
1055 cupsdLogMessage(CUPSD_LOG_ERROR,
1056 "Syntax error on line %d of printers.conf.", linenum);
1057 return;
1058 }
1059 }
1060 else if (!strcasecmp(line, "Shared"))
1061 {
1062 /*
1063 * Set the initial shared state...
1064 */
1065
1066 if (value &&
1067 (!strcasecmp(value, "yes") ||
1068 !strcasecmp(value, "on") ||
1069 !strcasecmp(value, "true")))
1070 p->shared = 1;
1071 else if (value &&
1072 (!strcasecmp(value, "no") ||
1073 !strcasecmp(value, "off") ||
1074 !strcasecmp(value, "false")))
1075 p->shared = 0;
1076 else
1077 {
1078 cupsdLogMessage(CUPSD_LOG_ERROR,
1079 "Syntax error on line %d of printers.conf.", linenum);
1080 return;
1081 }
1082 }
1083 else if (!strcasecmp(line, "JobSheets"))
1084 {
1085 /*
1086 * Set the initial job sheets...
1087 */
1088
1089 if (value)
1090 {
1091 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1092
1093 if (*valueptr)
1094 *valueptr++ = '\0';
1095
1096 cupsdSetString(&p->job_sheets[0], value);
1097
1098 while (isspace(*valueptr & 255))
1099 valueptr ++;
1100
1101 if (*valueptr)
1102 {
1103 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1104
1105 if (*valueptr)
1106 *valueptr++ = '\0';
1107
1108 cupsdSetString(&p->job_sheets[1], value);
1109 }
1110 }
1111 else
1112 {
1113 cupsdLogMessage(CUPSD_LOG_ERROR,
1114 "Syntax error on line %d of printers.conf.", linenum);
1115 return;
1116 }
1117 }
1118 else if (!strcasecmp(line, "AllowUser"))
1119 {
1120 if (value)
1121 {
1122 p->deny_users = 0;
1123 cupsdAddPrinterUser(p, value);
1124 }
1125 else
1126 {
1127 cupsdLogMessage(CUPSD_LOG_ERROR,
1128 "Syntax error on line %d of printers.conf.", linenum);
1129 return;
1130 }
1131 }
1132 else if (!strcasecmp(line, "DenyUser"))
1133 {
1134 if (value)
1135 {
1136 p->deny_users = 1;
1137 cupsdAddPrinterUser(p, value);
1138 }
1139 else
1140 {
1141 cupsdLogMessage(CUPSD_LOG_ERROR,
1142 "Syntax error on line %d of printers.conf.", linenum);
1143 return;
1144 }
1145 }
1146 else if (!strcasecmp(line, "QuotaPeriod"))
1147 {
1148 if (value)
1149 p->quota_period = atoi(value);
1150 else
1151 {
1152 cupsdLogMessage(CUPSD_LOG_ERROR,
1153 "Syntax error on line %d of printers.conf.", linenum);
1154 return;
1155 }
1156 }
1157 else if (!strcasecmp(line, "PageLimit"))
1158 {
1159 if (value)
1160 p->page_limit = atoi(value);
1161 else
1162 {
1163 cupsdLogMessage(CUPSD_LOG_ERROR,
1164 "Syntax error on line %d of printers.conf.", linenum);
1165 return;
1166 }
1167 }
1168 else if (!strcasecmp(line, "KLimit"))
1169 {
1170 if (value)
1171 p->k_limit = atoi(value);
1172 else
1173 {
1174 cupsdLogMessage(CUPSD_LOG_ERROR,
1175 "Syntax error on line %d of printers.conf.", linenum);
1176 return;
1177 }
1178 }
1179 else if (!strcasecmp(line, "OpPolicy"))
1180 {
1181 if (value)
1182 cupsdSetString(&p->op_policy, value);
1183 else
1184 {
1185 cupsdLogMessage(CUPSD_LOG_ERROR,
1186 "Syntax error on line %d of printers.conf.", linenum);
1187 return;
1188 }
1189 }
1190 else if (!strcasecmp(line, "ErrorPolicy"))
1191 {
1192 if (value)
1193 cupsdSetString(&p->error_policy, value);
1194 else
1195 {
1196 cupsdLogMessage(CUPSD_LOG_ERROR,
1197 "Syntax error on line %d of printers.conf.", linenum);
1198 return;
1199 }
1200 }
1201 else
1202 {
1203 /*
1204 * Something else we don't understand...
1205 */
1206
1207 cupsdLogMessage(CUPSD_LOG_ERROR,
1208 "Unknown configuration directive %s on line %d of printers.conf.",
1209 line, linenum);
1210 }
1211 }
1212
1213 cupsFileClose(fp);
1214}
1215
1216
b423cd4c 1217/*
1218 * 'cupsdRenamePrinter()' - Rename a printer.
1219 */
1220
1221void
1222cupsdRenamePrinter(
1223 cupsd_printer_t *p, /* I - Printer */
1224 const char *name) /* I - New name */
1225{
1226 /*
1227 * Remove the printer from the array(s) first...
1228 */
1229
1230 cupsArrayRemove(Printers, p);
1231
1232 if (p->type & CUPS_PRINTER_IMPLICIT)
1233 cupsArrayRemove(ImplicitPrinters, p);
1234
1235 /*
1236 * Rename the printer type...
1237 */
1238
1239 mimeDeleteType(MimeDatabase, p->filetype);
1240 p->filetype = mimeAddType(MimeDatabase, "printer", name);
1241
1242 /*
1243 * Rename the printer...
1244 */
1245
a74454a7 1246 cupsdSetString(&p->name, name);
b423cd4c 1247
1248 /*
1249 * Reset printer attributes...
1250 */
1251
1252 cupsdSetPrinterAttrs(p);
1253
1254 /*
1255 * Add the printer back to the printer array(s)...
1256 */
1257
1258 cupsArrayAdd(Printers, p);
1259 if (p->type & CUPS_PRINTER_IMPLICIT)
1260 cupsArrayAdd(ImplicitPrinters, p);
1261}
1262
1263
ef416fc2 1264/*
1265 * 'cupsdSaveAllPrinters()' - Save all printer definitions to the printers.conf
1266 * file.
1267 */
1268
1269void
1270cupsdSaveAllPrinters(void)
1271{
1272 int i; /* Looping var */
1273 cups_file_t *fp; /* printers.conf file */
1274 char temp[1024]; /* Temporary string */
1275 char backup[1024]; /* printers.conf.O file */
1276 cupsd_printer_t *printer; /* Current printer class */
1277 time_t curtime; /* Current time */
1278 struct tm *curdate; /* Current date */
b423cd4c 1279 cups_option_t *option; /* Current option */
ef416fc2 1280
1281
1282 /*
1283 * Create the printers.conf file...
1284 */
1285
1286 snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
1287 snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
1288
1289 if (rename(temp, backup))
1290 {
1291 if (errno != ENOENT)
1292 cupsdLogMessage(CUPSD_LOG_ERROR,
1293 "Unable to backup printers.conf - %s", strerror(errno));
1294 }
1295
1296 if ((fp = cupsFileOpen(temp, "w")) == NULL)
1297 {
1298 cupsdLogMessage(CUPSD_LOG_ERROR,
1299 "Unable to save printers.conf - %s", strerror(errno));
1300
1301 if (rename(backup, temp))
1302 cupsdLogMessage(CUPSD_LOG_ERROR,
1303 "Unable to restore printers.conf - %s", strerror(errno));
1304 return;
1305 }
1306 else
1307 cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf...");
1308
1309 /*
1310 * Restrict access to the file...
1311 */
1312
1313 fchown(cupsFileNumber(fp), getuid(), Group);
fa73b229 1314 fchmod(cupsFileNumber(fp), 0600);
ef416fc2 1315
1316 /*
1317 * Write a small header to the file...
1318 */
1319
1320 curtime = time(NULL);
1321 curdate = localtime(&curtime);
1322 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
1323
1324 cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
1325 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
1326
1327 /*
1328 * Write each local printer known to the system...
1329 */
1330
1331 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
1332 printer;
1333 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
1334 {
1335 /*
1336 * Skip remote destinations and printer classes...
1337 */
1338
1339 if ((printer->type & CUPS_PRINTER_REMOTE) ||
1340 (printer->type & CUPS_PRINTER_CLASS) ||
1341 (printer->type & CUPS_PRINTER_IMPLICIT))
1342 continue;
1343
1344 /*
1345 * Write printers as needed...
1346 */
1347
1348 if (printer == DefaultPrinter)
1349 cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name);
1350 else
1351 cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
1352
1353 if (printer->info)
1354 cupsFilePrintf(fp, "Info %s\n", printer->info);
1355
1356 if (printer->location)
1357 cupsFilePrintf(fp, "Location %s\n", printer->location);
1358
1359 if (printer->device_uri)
1360 cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
1361
1362 if (printer->port_monitor)
1363 cupsFilePrintf(fp, "PortMonitor %s\n", printer->port_monitor);
1364
1365 if (printer->state == IPP_PRINTER_STOPPED)
1366 {
1367 cupsFilePuts(fp, "State Stopped\n");
1368 cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
1369 }
1370 else
1371 cupsFilePuts(fp, "State Idle\n");
1372
1373 cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
1374
1375 if (printer->accepting)
1376 cupsFilePuts(fp, "Accepting Yes\n");
1377 else
1378 cupsFilePuts(fp, "Accepting No\n");
1379
1380 if (printer->shared)
1381 cupsFilePuts(fp, "Shared Yes\n");
1382 else
1383 cupsFilePuts(fp, "Shared No\n");
1384
1385 cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
1386 printer->job_sheets[1]);
1387
1388 cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period);
1389 cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
1390 cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
1391
1392 for (i = 0; i < printer->num_users; i ++)
1393 cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
1394 printer->users[i]);
1395
1396 if (printer->op_policy)
1397 cupsFilePrintf(fp, "OpPolicy %s\n", printer->op_policy);
1398 if (printer->error_policy)
1399 cupsFilePrintf(fp, "ErrorPolicy %s\n", printer->error_policy);
1400
b423cd4c 1401 for (i = printer->num_options, option = printer->options;
1402 i > 0;
1403 i --, option ++)
1404 cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value);
1405
ef416fc2 1406 cupsFilePuts(fp, "</Printer>\n");
1407
1408#ifdef __sgi
1409 /*
1410 * Make IRIX desktop & printer status happy
1411 */
1412
1413 write_irix_state(printer);
1414#endif /* __sgi */
1415 }
1416
1417 cupsFileClose(fp);
1418}
1419
1420
1421/*
1422 * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file.
1423 */
1424
1425void
1426cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
1427{
b423cd4c 1428 int i, /* Looping var */
1429 length; /* Length of browse attributes */
1430 char uri[HTTP_MAX_URI]; /* URI for printer */
1431 char resource[HTTP_MAX_URI]; /* Resource portion of URI */
1432 char filename[1024]; /* Name of PPD file */
1433 int num_media; /* Number of media options */
1434 cupsd_location_t *auth; /* Pointer to authentication element */
1435 const char *auth_supported; /* Authentication supported */
1436 cups_ptype_t printer_type; /* Printer type data */
1437 ppd_file_t *ppd; /* PPD file data */
1438 ppd_option_t *input_slot, /* InputSlot options */
1439 *media_type, /* MediaType options */
1440 *page_size, /* PageSize options */
1441 *output_bin, /* OutputBin options */
1442 *media_quality, /* EFMediaQualityMode options */
1443 *duplex; /* Duplex options */
1444 ppd_attr_t *ppdattr; /* PPD attribute */
1445 ipp_attribute_t *attr; /* Attribute data */
1446 ipp_value_t *val; /* Attribute value */
1447 int num_finishings; /* Number of finishings */
1448 ipp_finish_t finishings[5]; /* finishings-supported values */
1449 cups_option_t *option; /* Current printer option */
ef416fc2 1450 static const char * const sides[3] = /* sides-supported values */
1451 {
b423cd4c 1452 "one-sided",
1453 "two-sided-long-edge",
1454 "two-sided-short-edge"
ef416fc2 1455 };
1456
1457
1458 DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
1459 p->type));
1460
1461 /*
1462 * Make sure that we have the common attributes defined...
1463 */
1464
1465 if (!CommonData)
1466 cupsdCreateCommonData();
1467
1468 /*
1469 * Clear out old filters, if any...
1470 */
1471
e1d6a774 1472 delete_printer_filters(p);
ef416fc2 1473
1474 /*
1475 * Figure out the authentication that is required for the printer.
1476 */
1477
1478 auth_supported = "requesting-user-name";
1479 if (!(p->type & CUPS_PRINTER_REMOTE))
1480 {
1481 if (p->type & CUPS_PRINTER_CLASS)
1482 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
1483 else
1484 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
1485
1486 if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL)
1487 auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
1488
1489 if (auth)
1490 {
1491 if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST)
1492 auth_supported = "basic";
1493 else if (auth->type == AUTH_DIGEST)
1494 auth_supported = "digest";
1495
1496 if (auth->type != AUTH_NONE)
1497 p->type |= CUPS_PRINTER_AUTHENTICATED;
1498 else
1499 p->type &= ~CUPS_PRINTER_AUTHENTICATED;
1500 }
1501 else
1502 p->type &= ~CUPS_PRINTER_AUTHENTICATED;
1503 }
1504
1505 /*
1506 * Create the required IPP attributes for a printer...
1507 */
1508
1509 if (p->attrs)
1510 ippDelete(p->attrs);
1511
1512 p->attrs = ippNew();
1513
1514 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1515 "uri-authentication-supported", NULL, auth_supported);
1516 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1517 "uri-security-supported", NULL, "none");
1518 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
1519 p->name);
1520 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
1521 NULL, p->location ? p->location : "");
1522 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
1523 NULL, p->info ? p->info : "");
1524 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
1525 NULL, p->uri);
1526
1527 if (p->num_users)
1528 {
1529 if (p->deny_users)
1530 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1531 "requesting-user-name-denied", p->num_users, NULL,
1532 p->users);
1533 else
1534 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1535 "requesting-user-name-allowed", p->num_users, NULL,
1536 p->users);
1537 }
1538
1539 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1540 "job-quota-period", p->quota_period);
1541 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1542 "job-k-limit", p->k_limit);
1543 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1544 "job-page-limit", p->page_limit);
1545
fa73b229 1546 if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_REMOTE))
ef416fc2 1547 {
1548 /*
1549 * Setup the job-sheets-default attribute...
1550 */
1551
1552 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1553 "job-sheets-default", 2, NULL, NULL);
1554
1555 if (attr != NULL)
1556 {
757d2cad 1557 attr->values[0].string.text = _cupsStrAlloc(Classification ?
ef416fc2 1558 Classification : p->job_sheets[0]);
757d2cad 1559 attr->values[1].string.text = _cupsStrAlloc(Classification ?
ef416fc2 1560 Classification : p->job_sheets[1]);
1561 }
1562 }
1563
e00b005a 1564 printer_type = p->type;
ef416fc2 1565
1566 p->raw = 0;
1567
1568 if (p->type & CUPS_PRINTER_REMOTE)
1569 {
1570 /*
1571 * Tell the client this is a remote printer of some type...
1572 */
1573
1574 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
1575 "printer-uri-supported", NULL, p->uri);
1576
1577 if (p->make_model)
1578 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1579 "printer-make-and-model", NULL, p->make_model);
1580
fa73b229 1581 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1582 p->uri);
1583
ef416fc2 1584 p->raw = 1;
1585 }
1586 else
1587 {
1588 /*
1589 * Assign additional attributes depending on whether this is a printer
1590 * or class...
1591 */
1592
1593 p->type &= ~CUPS_PRINTER_OPTIONS;
1594
1595 if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
1596 {
1597 p->raw = 1;
1598
1599 /*
1600 * Add class-specific attributes...
1601 */
1602
1603 if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 &&
1604 p->printers[0]->make_model)
1605 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1606 "printer-make-and-model", NULL, p->printers[0]->make_model);
1607 else
1608 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1609 "printer-make-and-model", NULL, "Local Printer Class");
1610
fa73b229 1611 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1612 "file:///dev/null");
1613
ef416fc2 1614 if (p->num_printers > 0)
1615 {
1616 /*
1617 * Add a list of member URIs and names...
1618 */
1619
1620 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
1621 "member-uris", p->num_printers, NULL, NULL);
1622 p->type |= CUPS_PRINTER_OPTIONS;
1623
1624 for (i = 0; i < p->num_printers; i ++)
1625 {
1626 if (attr != NULL)
757d2cad 1627 attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->uri);
ef416fc2 1628
1629 p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
1630 }
1631
1632 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
1633 "member-names", p->num_printers, NULL, NULL);
1634
1635 if (attr != NULL)
1636 {
1637 for (i = 0; i < p->num_printers; i ++)
757d2cad 1638 attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name);
ef416fc2 1639 }
1640 }
1641 }
1642 else
1643 {
1644 /*
1645 * Add printer-specific attributes... Start by sanitizing the device
1646 * URI so it doesn't have a username or password in it...
1647 */
1648
1649 if (!p->device_uri)
1650 strcpy(uri, "file:/dev/null");
1651 else if (strstr(p->device_uri, "://") != NULL)
1652 {
1653 /*
1654 * http://..., ipp://..., etc.
1655 */
1656
1657 cupsdSanitizeURI(p->device_uri, uri, sizeof(uri));
1658 }
1659 else
1660 {
1661 /*
1662 * file:..., serial:..., etc.
1663 */
1664
1665 strlcpy(uri, p->device_uri, sizeof(uri));
1666 }
1667
1668 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
1669 uri);
1670
1671 /*
1672 * Assign additional attributes from the PPD file (if any)...
1673 */
1674
1675 p->type |= CUPS_PRINTER_BW;
1676 finishings[0] = IPP_FINISHINGS_NONE;
1677 num_finishings = 1;
1678
1679 snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
1680 p->name);
1681
1682 if ((ppd = ppdOpenFile(filename)) != NULL)
1683 {
1684 /*
1685 * Add make/model and other various attributes...
1686 */
1687
1688 if (ppd->color_device)
1689 p->type |= CUPS_PRINTER_COLOR;
1690 if (ppd->variable_sizes)
1691 p->type |= CUPS_PRINTER_VARIABLE;
1692 if (!ppd->manual_copies)
1693 p->type |= CUPS_PRINTER_COPIES;
1694 if ((ppdattr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
1695 if (ppdattr->value && !strcasecmp(ppdattr->value, "true"))
1696 p->type |= CUPS_PRINTER_FAX;
1697
1698 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
1699 ppd->color_device);
1700 if (ppd->throughput)
1701 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
1702 "pages-per-minute", ppd->throughput);
1703
1704 if (ppd->nickname)
bd7854cb 1705 {
1706 /*
1707 * The NickName can be localized in the character set specified
e1d6a774 1708 * by the LanugageEncoding attribute. However, ppdOpen2() has
1709 * already converted the ppd->nickname member to UTF-8 for us
1710 * (the original attribute value is available separately)
bd7854cb 1711 */
1712
e1d6a774 1713 cupsdSetString(&p->make_model, ppd->nickname);
bd7854cb 1714 }
ef416fc2 1715 else if (ppd->modelname)
e1d6a774 1716 {
1717 /*
1718 * Model name can only contain specific characters...
1719 */
1720
ef416fc2 1721 cupsdSetString(&p->make_model, ppd->modelname);
e1d6a774 1722 }
ef416fc2 1723 else
1724 cupsdSetString(&p->make_model, "Bad PPD File");
1725
bd7854cb 1726 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1727 "printer-make-and-model", NULL, p->make_model);
ef416fc2 1728
1729 /*
1730 * Add media options from the PPD file...
1731 */
1732
1733 if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
1734 num_media = input_slot->num_choices;
1735 else
1736 num_media = 0;
1737
1738 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
1739 num_media += media_type->num_choices;
1740
1741 if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
1742 num_media += page_size->num_choices;
1743
1744 if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL)
1745 num_media += media_quality->num_choices;
1746
1747 if (num_media == 0)
1748 {
bd7854cb 1749 cupsdLogMessage(CUPSD_LOG_CRIT,
b423cd4c 1750 "The PPD file for printer %s contains no media "
1751 "options and is therefore invalid!", p->name);
ef416fc2 1752 }
1753 else
1754 {
1755 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1756 "media-supported", num_media, NULL, NULL);
1757 if (attr != NULL)
1758 {
1759 val = attr->values;
1760
1761 if (input_slot != NULL)
1762 for (i = 0; i < input_slot->num_choices; i ++, val ++)
757d2cad 1763 val->string.text = _cupsStrAlloc(input_slot->choices[i].choice);
ef416fc2 1764
1765 if (media_type != NULL)
1766 for (i = 0; i < media_type->num_choices; i ++, val ++)
757d2cad 1767 val->string.text = _cupsStrAlloc(media_type->choices[i].choice);
ef416fc2 1768
1769 if (media_quality != NULL)
1770 for (i = 0; i < media_quality->num_choices; i ++, val ++)
757d2cad 1771 val->string.text = _cupsStrAlloc(media_quality->choices[i].choice);
ef416fc2 1772
1773 if (page_size != NULL)
1774 {
1775 for (i = 0; i < page_size->num_choices; i ++, val ++)
757d2cad 1776 val->string.text = _cupsStrAlloc(page_size->choices[i].choice);
ef416fc2 1777
b423cd4c 1778 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1779 "media-default", NULL, page_size->defchoice);
ef416fc2 1780 }
1781 else if (input_slot != NULL)
b423cd4c 1782 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1783 "media-default", NULL, input_slot->defchoice);
ef416fc2 1784 else if (media_type != NULL)
b423cd4c 1785 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1786 "media-default", NULL, media_type->defchoice);
ef416fc2 1787 else if (media_quality != NULL)
b423cd4c 1788 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1789 "media-default", NULL, media_quality->defchoice);
ef416fc2 1790 else
b423cd4c 1791 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1792 "media-default", NULL, "none");
ef416fc2 1793 }
1794 }
1795
1796 /*
1797 * Output bin...
1798 */
1799
1800 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
1801 {
1802 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1803 "output-bin-supported", output_bin->num_choices,
1804 NULL, NULL);
1805
1806 if (attr != NULL)
1807 {
1808 for (i = 0, val = attr->values;
1809 i < output_bin->num_choices;
1810 i ++, val ++)
757d2cad 1811 val->string.text = _cupsStrAlloc(output_bin->choices[i].choice);
ef416fc2 1812 }
1813 }
1814
1815 /*
1816 * Duplexing, etc...
1817 */
1818
b423cd4c 1819 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
1820 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
1821 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
1822 if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
1823 duplex = ppdFindOption(ppd, "JCLDuplex");
1824
1825 if (duplex && duplex->num_choices > 1)
ef416fc2 1826 {
1827 p->type |= CUPS_PRINTER_DUPLEX;
1828
b423cd4c 1829 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1830 "sides-supported", 3, NULL, sides);
1831
1832 if (!strcasecmp(duplex->defchoice, "DuplexTumble"))
1833 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1834 "sides-default", NULL, "two-sided-short-edge");
1835 else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble"))
1836 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1837 "sides-default", NULL, "two-sided-long-edge");
1838 else
1839 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1840 "sides-default", NULL, "one-sided");
ef416fc2 1841 }
1842
1843 if (ppdFindOption(ppd, "Collate") != NULL)
1844 p->type |= CUPS_PRINTER_COLLATE;
1845
1846 if (ppdFindOption(ppd, "StapleLocation") != NULL)
1847 {
1848 p->type |= CUPS_PRINTER_STAPLE;
1849 finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
1850 }
1851
1852 if (ppdFindOption(ppd, "BindEdge") != NULL)
1853 {
1854 p->type |= CUPS_PRINTER_BIND;
1855 finishings[num_finishings++] = IPP_FINISHINGS_BIND;
1856 }
1857
1858 for (i = 0; i < ppd->num_sizes; i ++)
1859 if (ppd->sizes[i].length > 1728)
1860 p->type |= CUPS_PRINTER_LARGE;
1861 else if (ppd->sizes[i].length > 1008)
1862 p->type |= CUPS_PRINTER_MEDIUM;
1863 else
1864 p->type |= CUPS_PRINTER_SMALL;
1865
1866 /*
1867 * Add a filter from application/vnd.cups-raw to printer/name to
1868 * handle "raw" printing by users.
1869 */
1870
bd7854cb 1871 add_printer_filter(p, "application/vnd.cups-raw 0 -");
ef416fc2 1872
1873 /*
1874 * Add any filters in the PPD file...
1875 */
1876
1877 DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
1878 for (i = 0; i < ppd->num_filters; i ++)
1879 {
1880 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
bd7854cb 1881 add_printer_filter(p, ppd->filters[i]);
ef416fc2 1882 }
1883
1884 if (ppd->num_filters == 0)
1885 {
1886 /*
1887 * If there are no filters, add a PostScript printing filter.
1888 */
1889
bd7854cb 1890 add_printer_filter(p, "application/vnd.cups-postscript 0 -");
ef416fc2 1891 }
1892
1893 /*
1894 * Show current and available port monitors for this printer...
1895 */
1896
1897 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "port-monitor",
1898 NULL, p->port_monitor ? p->port_monitor : "none");
1899
1900
1901 for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
1902 ppdattr;
1903 i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
1904
1905 if (ppd->protocols)
1906 {
1907 if (strstr(ppd->protocols, "TBCP"))
1908 i ++;
1909 else if (strstr(ppd->protocols, "BCP"))
1910 i ++;
1911 }
1912
1913 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
1914 "port-monitor-supported", i, NULL, NULL);
1915
757d2cad 1916 attr->values[0].string.text = _cupsStrAlloc("none");
ef416fc2 1917
1918 for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
1919 ppdattr;
1920 i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
757d2cad 1921 attr->values[i].string.text = _cupsStrAlloc(ppdattr->value);
ef416fc2 1922
1923 if (ppd->protocols)
1924 {
1925 if (strstr(ppd->protocols, "TBCP"))
757d2cad 1926 attr->values[i].string.text = _cupsStrAlloc("tbcp");
ef416fc2 1927 else if (strstr(ppd->protocols, "BCP"))
757d2cad 1928 attr->values[i].string.text = _cupsStrAlloc("bcp");
ef416fc2 1929 }
1930
1931 /*
1932 * Close the PPD and set the type...
1933 */
1934
1935 ppdClose(ppd);
1936
e00b005a 1937 printer_type = p->type;
ef416fc2 1938 }
1939 else if (!access(filename, 0))
1940 {
1941 int pline; /* PPD line number */
1942 ppd_status_t pstatus; /* PPD load status */
1943
1944
1945 pstatus = ppdLastError(&pline);
1946
b423cd4c 1947 cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
1948 p->name);
ef416fc2 1949
1950 if (pstatus <= PPD_ALLOC_ERROR)
1951 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
1952 else
b423cd4c 1953 cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
1954 ppdErrorString(pstatus), pline);
ef416fc2 1955
b423cd4c 1956 cupsdLogMessage(CUPSD_LOG_INFO,
1957 "Hint: Run \"cupstestppd %s\" and fix any errors.",
1958 filename);
ef416fc2 1959
1960 /*
1961 * Add a filter from application/vnd.cups-raw to printer/name to
1962 * handle "raw" printing by users.
1963 */
1964
bd7854cb 1965 add_printer_filter(p, "application/vnd.cups-raw 0 -");
ef416fc2 1966
1967 /*
1968 * Add a PostScript filter, since this is still possibly PS printer.
1969 */
1970
bd7854cb 1971 add_printer_filter(p, "application/vnd.cups-postscript 0 -");
ef416fc2 1972 }
1973 else
1974 {
1975 /*
1976 * If we have an interface script, add a filter entry for it...
1977 */
1978
1979 snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
1980 p->name);
b423cd4c 1981 if (!access(filename, X_OK))
ef416fc2 1982 {
1983 /*
1984 * Yes, we have a System V style interface script; use it!
1985 */
1986
1987 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
1988 "printer-make-and-model", NULL, "Local System V Printer");
1989
1990 snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
1991 ServerRoot, p->name);
bd7854cb 1992 add_printer_filter(p, filename);
ef416fc2 1993 }
1994 else if (p->device_uri &&
1995 !strncmp(p->device_uri, "ipp://", 6) &&
1996 (strstr(p->device_uri, "/printers/") != NULL ||
1997 strstr(p->device_uri, "/classes/") != NULL))
1998 {
1999 /*
2000 * Tell the client this is really a hard-wired remote printer.
2001 */
2002
e00b005a 2003 printer_type |= CUPS_PRINTER_REMOTE;
ef416fc2 2004
2005 /*
2006 * Point the printer-uri-supported attribute to the
2007 * remote printer...
2008 */
2009
2010 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
2011 "printer-uri-supported", NULL, p->device_uri);
2012
2013 /*
2014 * Then set the make-and-model accordingly...
2015 */
2016
2017 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2018 "printer-make-and-model", NULL, "Remote Printer");
2019
2020 /*
2021 * Print all files directly...
2022 */
2023
2024 p->raw = 1;
2025 }
2026 else
2027 {
2028 /*
2029 * Otherwise we have neither - treat this as a "dumb" printer
2030 * with no PPD file...
2031 */
2032
2033 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2034 "printer-make-and-model", NULL, "Local Raw Printer");
2035
2036 p->raw = 1;
2037 }
2038 }
2039
2040 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
2041 "finishings-supported", num_finishings, (int *)finishings);
2042 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
2043 "finishings-default", IPP_FINISHINGS_NONE);
2044 }
2045 }
2046
b423cd4c 2047 /*
2048 * Copy the printer options into a browse attributes string we can re-use.
2049 */
2050
2051 if (!(p->type & CUPS_PRINTER_REMOTE))
2052 {
2053 const char *valptr; /* Pointer into value */
2054 char *attrptr; /* Pointer into attribute string */
2055
2056
2057 /*
2058 * Free the old browse attributes as needed...
2059 */
2060
2061 if (p->browse_attrs)
2062 free(p->browse_attrs);
2063
2064 /*
2065 * Compute the length of all attributes + job-sheets, lease-duration,
2066 * and BrowseLocalOptions.
2067 */
2068
2069 for (length = 1, i = p->num_options, option = p->options;
2070 i > 0;
2071 i --, option ++)
2072 {
2073 length += strlen(option->name) + 2;
2074
2075 if (option->value)
2076 {
2077 for (valptr = option->value; *valptr; valptr ++)
2078 if (strchr(" \"\'\\", *valptr))
2079 length += 2;
2080 else
2081 length ++;
2082 }
2083 }
2084
2085 length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]);
2086 length += 32;
2087 if (BrowseLocalOptions)
2088 length += 12 + strlen(BrowseLocalOptions);
2089
2090 /*
2091 * Allocate the new string...
2092 */
2093
2094 if ((p->browse_attrs = calloc(1, length)) == NULL)
2095 cupsdLogMessage(CUPSD_LOG_ERROR,
2096 "Unable to allocate %d bytes for browse data!",
2097 length);
2098 else
2099 {
2100 /*
2101 * Got the allocated string, now copy the options and attributes over...
2102 */
2103
2104 sprintf(p->browse_attrs, "job-sheets=%s,%s lease-duration=%d",
2105 p->job_sheets[0], p->job_sheets[1], BrowseTimeout);
2106 attrptr = p->browse_attrs + strlen(p->browse_attrs);
2107
2108 if (BrowseLocalOptions)
2109 {
2110 sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions);
2111 attrptr += strlen(attrptr);
2112 }
2113
2114 for (i = p->num_options, option = p->options;
2115 i > 0;
2116 i --, option ++)
2117 {
2118 *attrptr++ = ' ';
2119 strcpy(attrptr, option->name);
2120 attrptr += strlen(attrptr);
2121
2122 if (option->value)
2123 {
2124 *attrptr++ = '=';
2125
2126 for (valptr = option->value; *valptr; valptr ++)
2127 {
2128 if (strchr(" \"\'\\", *valptr))
2129 *attrptr++ = '\\';
2130
2131 *attrptr++ = *valptr;
2132 }
2133 }
2134 }
2135
2136 *attrptr = '\0';
2137 }
2138 }
2139
bd7854cb 2140 /*
2141 * Populate the document-format-supported attribute...
2142 */
2143
2144 add_printer_formats(p);
2145
ef416fc2 2146 DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
2147 p->type));
2148
b423cd4c 2149 /*
2150 * Add name-default attributes...
2151 */
2152
2153 add_printer_defaults(p);
2154
ef416fc2 2155#ifdef __sgi
2156 /*
2157 * Write the IRIX printer config and status files...
2158 */
2159
2160 write_irix_config(p);
2161 write_irix_state(p);
2162#endif /* __sgi */
2163}
2164
2165
2166/*
2167 * 'cupsdSetPrinterReasons()' - Set/update the reasons strings.
2168 */
2169
2170void
2171cupsdSetPrinterReasons(
2172 cupsd_printer_t *p, /* I - Printer */
2173 const char *s) /* I - Reasons strings */
2174{
2175 int i; /* Looping var */
2176 const char *sptr; /* Pointer into reasons */
2177 char reason[255], /* Reason string */
2178 *rptr; /* Pointer into reason */
2179
2180
2181 if (s[0] == '-' || s[0] == '+')
2182 {
2183 /*
2184 * Add/remove reasons...
2185 */
2186
2187 sptr = s + 1;
2188 }
2189 else
2190 {
2191 /*
2192 * Replace reasons...
2193 */
2194
2195 sptr = s;
2196
2197 for (i = 0; i < p->num_reasons; i ++)
2198 free(p->reasons[i]);
2199
2200 p->num_reasons = 0;
2201 }
2202
2203 /*
2204 * Loop through all of the reasons...
2205 */
2206
2207 while (*sptr)
2208 {
2209 /*
2210 * Skip leading whitespace and commas...
2211 */
2212
2213 while (isspace(*sptr & 255) || *sptr == ',')
2214 sptr ++;
2215
2216 for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++)
2217 if (rptr < (reason + sizeof(reason) - 1))
2218 *rptr++ = *sptr;
2219
2220 if (rptr == reason)
2221 break;
2222
2223 *rptr = '\0';
2224
2225 if (s[0] == '-')
2226 {
2227 /*
2228 * Remove reason...
2229 */
2230
2231 for (i = 0; i < p->num_reasons; i ++)
2232 if (!strcasecmp(reason, p->reasons[i]))
2233 {
2234 /*
2235 * Found a match, so remove it...
2236 */
2237
2238 p->num_reasons --;
2239 free(p->reasons[i]);
2240
2241 if (i < p->num_reasons)
2242 memmove(p->reasons + i, p->reasons + i + 1,
2243 (p->num_reasons - i) * sizeof(char *));
2244
2245 i --;
2246 }
2247 }
2248 else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
2249 {
2250 /*
2251 * Add reason...
2252 */
2253
2254 for (i = 0; i < p->num_reasons; i ++)
2255 if (!strcasecmp(reason, p->reasons[i]))
2256 break;
2257
2258 if (i >= p->num_reasons)
2259 {
2260 p->reasons[i] = strdup(reason);
2261 p->num_reasons ++;
2262 }
2263 }
2264 }
2265}
2266
2267
2268/*
2269 * 'cupsdSetPrinterState()' - Update the current state of a printer.
2270 */
2271
2272void
2273cupsdSetPrinterState(
2274 cupsd_printer_t *p, /* I - Printer to change */
2275 ipp_pstate_t s, /* I - New state */
2276 int update) /* I - Update printers.conf? */
2277{
2278 ipp_pstate_t old_state; /* Old printer state */
2279
2280
2281 /*
2282 * Can't set status of remote printers...
2283 */
2284
2285 if (p->type & CUPS_PRINTER_REMOTE)
2286 return;
2287
2288 /*
2289 * Set the new state...
2290 */
2291
2292 old_state = p->state;
2293 p->state = s;
2294
2295 if (old_state != s)
2296 {
e53920b9 2297 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE_CHANGED, p, NULL,
2298 "%s \"%s\" state changed.",
2299 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
2300 p->name);
2301
ef416fc2 2302 /*
2303 * Let the browse code know this needs to be updated...
2304 */
2305
2306 BrowseNext = p;
2307 p->state_time = time(NULL);
2308 p->browse_time = 0;
2309
2310#ifdef __sgi
2311 write_irix_state(p);
2312#endif /* __sgi */
2313 }
2314
2315 cupsdAddPrinterHistory(p);
2316
2317 /*
2318 * Save the printer configuration if a printer goes from idle or processing
2319 * to stopped (or visa-versa)...
2320 */
2321
2322 if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED) &&
2323 update)
2324 {
2325 if (p->type & CUPS_PRINTER_CLASS)
2326 cupsdSaveAllClasses();
2327 else
2328 cupsdSaveAllPrinters();
2329 }
2330}
2331
2332
2333/*
2334 * 'cupsdStopPrinter()' - Stop a printer from printing any jobs...
2335 */
2336
2337void
2338cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */
2339 int update)/* I - Update printers.conf? */
2340{
2341 cupsd_job_t *job; /* Active print job */
2342
2343
2344 /*
2345 * Set the printer state...
2346 */
2347
2348 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
2349
2350 /*
2351 * See if we have a job printing on this printer...
2352 */
2353
2354 if (p->job)
2355 {
2356 /*
2357 * Get pointer to job...
2358 */
2359
2360 job = (cupsd_job_t *)p->job;
2361
2362 /*
2363 * Stop it...
2364 */
2365
2366 cupsdStopJob(job, 0);
2367
2368 /*
2369 * Reset the state to pending...
2370 */
2371
2372 job->state->values[0].integer = IPP_JOB_PENDING;
bd7854cb 2373 job->state_value = IPP_JOB_PENDING;
ef416fc2 2374
2375 cupsdSaveJob(job);
2376 }
2377}
2378
2379
2380/*
2381 * 'cupsdUpdatePrinters()' - Update printers after a partial reload.
2382 */
2383
2384void
2385cupsdUpdatePrinters(void)
2386{
2387 cupsd_printer_t *p; /* Current printer */
2388
2389
2390 /*
2391 * Loop through the printers and recreate the printer attributes
2392 * for any local printers since the policy and/or access control
2393 * stuff may have changed. Also, if browsing is disabled, remove
2394 * any remote printers...
2395 */
2396
2397 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2398 p;
2399 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2400 {
2401 if (!Browsing && (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_REMOTE)))
2402 {
2403 if (p->type & CUPS_PRINTER_IMPLICIT)
2404 cupsArrayRemove(ImplicitPrinters, p);
2405
2406 cupsArraySave(Printers);
2407 cupsdDeletePrinter(p, 0);
2408 cupsArrayRestore(Printers);
2409 continue;
2410 }
2411 else if (!(p->type & CUPS_PRINTER_REMOTE))
2412 cupsdSetPrinterAttrs(p);
2413
2414 /*
2415 * Update the operation policy pointer...
2416 */
2417
2418 if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
2419 p->op_policy_ptr = DefaultPolicyPtr;
2420 }
2421}
2422
2423
2424/*
2425 * 'cupsdValidateDest()' - Validate a printer/class destination.
2426 */
2427
2428const char * /* O - Printer or class name */
2429cupsdValidateDest(
ed486911 2430 const char *uri, /* I - Printer URI */
ef416fc2 2431 cups_ptype_t *dtype, /* O - Type (printer or class) */
2432 cupsd_printer_t **printer) /* O - Printer pointer */
2433{
2434 cupsd_printer_t *p; /* Current printer */
2435 char localname[1024],/* Localized hostname */
2436 *lptr, /* Pointer into localized hostname */
ed486911 2437 *sptr, /* Pointer into server name */
2438 *rptr, /* Pointer into resource */
2439 scheme[32], /* Scheme portion of URI */
2440 username[64], /* Username portion of URI */
2441 hostname[HTTP_MAX_HOST],
2442 /* Host portion of URI */
2443 resource[HTTP_MAX_URI];
2444 /* Resource portion of URI */
2445 int port; /* Port portion of URI */
2446
2447
2448 DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
ef416fc2 2449 dtype, printer));
2450
2451 /*
2452 * Initialize return values...
2453 */
2454
2455 if (printer)
2456 *printer = NULL;
2457
ed486911 2458 if (dtype)
2459 *dtype = (cups_ptype_t)0;
2460
2461 /*
2462 * Pull the hostname and resource from the URI...
2463 */
2464
2465 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
2466 username, sizeof(username), hostname, sizeof(hostname),
2467 &port, resource, sizeof(resource));
ef416fc2 2468
2469 /*
2470 * See if the resource is a class or printer...
2471 */
2472
2473 if (!strncmp(resource, "/classes/", 9))
2474 {
2475 /*
2476 * Class...
2477 */
2478
ed486911 2479 rptr = resource + 9;
ef416fc2 2480 }
2481 else if (!strncmp(resource, "/printers/", 10))
2482 {
2483 /*
2484 * Printer...
2485 */
2486
ed486911 2487 rptr = resource + 10;
ef416fc2 2488 }
2489 else
2490 {
2491 /*
2492 * Bad resource name...
2493 */
2494
2495 return (NULL);
2496 }
2497
2498 /*
2499 * See if the printer or class name exists...
2500 */
2501
ed486911 2502 p = cupsdFindDest(rptr);
ef416fc2 2503
ed486911 2504 if (p == NULL && strchr(rptr, '@') == NULL)
ef416fc2 2505 return (NULL);
2506 else if (p != NULL)
2507 {
2508 if (printer)
2509 *printer = p;
2510
ed486911 2511 if (dtype)
2512 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
2513 CUPS_PRINTER_REMOTE);
2514
ef416fc2 2515 return (p->name);
2516 }
2517
2518 /*
2519 * Change localhost to the server name...
2520 */
2521
2522 if (!strcasecmp(hostname, "localhost"))
ed486911 2523 strlcpy(hostname, ServerName, sizeof(hostname));
ef416fc2 2524
2525 strlcpy(localname, hostname, sizeof(localname));
2526
2527 if (!strcasecmp(hostname, ServerName))
2528 {
2529 /*
2530 * Localize the hostname...
2531 */
2532
2533 lptr = strchr(localname, '.');
2534 sptr = strchr(ServerName, '.');
2535
2536 if (sptr != NULL && lptr != NULL)
2537 {
2538 /*
2539 * Strip the common domain name components...
2540 */
2541
2542 while (lptr != NULL)
2543 {
2544 if (!strcasecmp(lptr, sptr))
2545 {
2546 *lptr = '\0';
2547 break;
2548 }
2549 else
2550 lptr = strchr(lptr + 1, '.');
2551 }
2552 }
2553 }
2554
2555 DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
2556
2557 /*
2558 * Find a matching printer or class...
2559 */
2560
2561 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2562 p;
2563 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2564 if (!strcasecmp(p->hostname, localname) &&
ed486911 2565 !strcasecmp(p->name, rptr))
ef416fc2 2566 {
2567 if (printer)
2568 *printer = p;
2569
ed486911 2570 if (dtype)
2571 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
2572 CUPS_PRINTER_REMOTE);
2573
ef416fc2 2574 return (p->name);
2575 }
2576
2577 return (NULL);
2578}
2579
2580
2581/*
2582 * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications
2583 * that need it...
2584 */
2585
2586void
2587cupsdWritePrintcap(void)
2588{
2589 cups_file_t *fp; /* printcap file */
2590 cupsd_printer_t *p; /* Current printer */
2591
2592
2593#ifdef __sgi
2594 /*
2595 * Update the IRIX printer state for the default printer; if
2596 * no printers remain, then the default printer file will be
2597 * removed...
2598 */
2599
2600 write_irix_state(DefaultPrinter);
2601#endif /* __sgi */
2602
2603 /*
2604 * See if we have a printcap file; if not, don't bother writing it.
2605 */
2606
2607 if (!Printcap || !*Printcap)
2608 return;
2609
2610 /*
2611 * Open the printcap file...
2612 */
2613
2614 if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
2615 return;
2616
2617 /*
2618 * Put a comment header at the top so that users will know where the
2619 * data has come from...
2620 */
2621
2622 cupsFilePuts(fp, "# This file was automatically generated by cupsd(8) from the\n");
2623 cupsFilePrintf(fp, "# %s/printers.conf file. All changes to this file\n",
2624 ServerRoot);
2625 cupsFilePuts(fp, "# will be lost.\n");
2626
2627 if (Printers)
2628 {
2629 /*
2630 * Write a new printcap with the current list of printers.
2631 */
2632
2633 switch (PrintcapFormat)
2634 {
2635 case PRINTCAP_BSD:
2636 /*
2637 * Each printer is put in the file as:
2638 *
2639 * Printer1:
2640 * Printer2:
2641 * Printer3:
2642 * ...
2643 * PrinterN:
2644 */
2645
2646 if (DefaultPrinter)
2647 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
2648 DefaultPrinter->info, ServerName, DefaultPrinter->name);
2649
2650 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2651 p;
2652 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2653 if (p != DefaultPrinter)
2654 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
2655 ServerName, p->name);
2656 break;
2657
2658 case PRINTCAP_SOLARIS:
2659 /*
2660 * Each printer is put in the file as:
2661 *
2662 * _all:all=Printer1,Printer2,Printer3,...,PrinterN
2663 * _default:use=DefaultPrinter
2664 * Printer1:\
2665 * :bsdaddr=ServerName,Printer1:\
2666 * :description=Description:
2667 * Printer2:
2668 * :bsdaddr=ServerName,Printer2:\
2669 * :description=Description:
2670 * Printer3:
2671 * :bsdaddr=ServerName,Printer3:\
2672 * :description=Description:
2673 * ...
2674 * PrinterN:
2675 * :bsdaddr=ServerName,PrinterN:\
2676 * :description=Description:
2677 */
2678
2679 cupsFilePuts(fp, "_all:all=");
2680 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2681 p;
2682 p = (cupsd_printer_t *)cupsArrayCurrent(Printers))
2683 cupsFilePrintf(fp, "%s%c", p->name,
2684 cupsArrayNext(Printers) ? ',' : '\n');
2685
2686 if (DefaultPrinter)
2687 cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
2688
2689 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2690 p;
2691 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2692 cupsFilePrintf(fp, "%s:\\\n"
2693 "\t:bsdaddr=%s,%s:\\\n"
2694 "\t:description=%s:\n",
2695 p->name, ServerName, p->name, p->info ? p->info : "");
2696 break;
2697 }
2698 }
2699
2700 /*
2701 * Close the file...
2702 */
2703
2704 cupsFileClose(fp);
2705}
2706
2707
2708/*
2709 * 'cupsdSanitizeURI()' - Sanitize a device URI...
2710 */
2711
2712char * /* O - New device URI */
2713cupsdSanitizeURI(const char *uri, /* I - Original device URI */
2714 char *buffer, /* O - New device URI */
2715 int buflen) /* I - Size of new device URI buffer */
2716{
2717 char *start, /* Start of data after scheme */
2718 *slash, /* First slash after scheme:// */
2719 *ptr; /* Pointer into user@host:port part */
2720
2721
2722 /*
2723 * Range check input...
2724 */
2725
2726 if (!uri || !buffer || buflen < 2)
2727 return (NULL);
2728
2729 /*
2730 * Copy the device URI to the new buffer...
2731 */
2732
2733 strlcpy(buffer, uri, buflen);
2734
2735 /*
2736 * Find the end of the scheme:// part...
2737 */
2738
2739 if ((ptr = strchr(buffer, ':')) == NULL)
2740 return (buffer); /* No scheme: part... */
2741
2742 for (start = ptr + 1; *start; start ++)
2743 if (*start != '/')
2744 break;
2745
2746 /*
2747 * Find the next slash (/) in the URI...
2748 */
2749
2750 if ((slash = strchr(start, '/')) == NULL)
2751 slash = start + strlen(start); /* No slash, point to the end */
2752
2753 /*
2754 * Check for an @ sign before the slash...
2755 */
2756
2757 if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
2758 {
2759 /*
2760 * Found an @ sign and it is before the resource part, so we have
2761 * an authentication string. Copy the remaining URI over the
2762 * authentication string...
2763 */
2764
2765 _cups_strcpy(start, ptr + 1);
2766 }
2767
2768 /*
2769 * Return the new device URI...
2770 */
2771
2772 return (buffer);
2773}
2774
2775
b423cd4c 2776/*
2777 * 'add_printer_defaults()' - Add name-default attributes to the printer attributes.
2778 */
2779
2780static void
2781add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
2782{
2783 int i; /* Looping var */
2784 int num_options; /* Number of default options */
2785 cups_option_t *options, /* Default options */
2786 *option; /* Current option */
2787 char name[256]; /* name-default */
2788
2789
2790 /*
2791 * Add all of the default options from the .conf files...
2792 */
2793
2794 for (num_options = 0, i = p->num_options, option = p->options;
2795 i > 0;
2796 i --, option ++)
2797 {
2798 if (strcmp(option->name, "ipp-options") &&
2799 strcmp(option->name, "job-sheets") &&
2800 strcmp(option->name, "lease-duration"))
2801 {
2802 snprintf(name, sizeof(name), "%s-default", option->name);
2803 num_options = cupsAddOption(name, option->value, num_options, &options);
2804 }
2805 }
2806
2807 /*
2808 * Convert options to IPP attributes...
2809 */
2810
2811 cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER);
2812 cupsFreeOptions(num_options, options);
2813
2814 /*
2815 * Add standard -default attributes as needed...
2816 */
2817
2818 if (!cupsGetOption("copies", p->num_options, p->options))
2819 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default",
2820 1);
2821
ed486911 2822 if (!cupsGetOption("document-format", p->num_options, p->options))
2823 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
2824 "document-format-default", NULL, "application/octet-stream");
2825
b423cd4c 2826 if (!cupsGetOption("job-hold-until", p->num_options, p->options))
2827 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2828 "job-hold-until-default", NULL, "no-hold");
2829
2830 if (!cupsGetOption("job-priority", p->num_options, p->options))
2831 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2832 "job-priority-default", 50);
2833
2834 if (!cupsGetOption("number-up", p->num_options, p->options))
2835 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2836 "number-up-default", 1);
2837
2838 if (!cupsGetOption("orientation-requested", p->num_options, p->options))
2839 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
2840 "orientation-requested-default", IPP_PORTRAIT);
2841}
2842
2843
bd7854cb 2844/*
2845 * 'add_printer_filter()' - Add a MIME filter for a printer.
2846 */
2847
2848static void
2849add_printer_filter(
2850 cupsd_printer_t *p, /* I - Printer to add to */
2851 const char *filter) /* I - Filter to add */
2852{
2853 char super[MIME_MAX_SUPER], /* Super-type for filter */
2854 type[MIME_MAX_TYPE], /* Type for filter */
2855 program[1024]; /* Program/filter name */
2856 int cost; /* Cost of filter */
2857 mime_type_t *temptype; /* MIME type looping var */
2858 char filename[1024]; /* Full filter filename */
2859
2860
2861 /*
2862 * Parse the filter string; it should be in the following format:
2863 *
2864 * super/type cost program
2865 */
2866
2867 if (sscanf(filter, "%15[^/]/%31s%d%1023s", super, type, &cost, program) != 4)
2868 {
2869 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
2870 p->name, filter);
2871 return;
2872 }
2873
2874 /*
2875 * See if the filter program exists; if not, stop the printer and flag
2876 * the error!
2877 */
2878
ecdc0628 2879 if (strcmp(program, "-"))
bd7854cb 2880 {
ecdc0628 2881 if (program[0] == '/')
2882 strlcpy(filename, program, sizeof(filename));
2883 else
2884 snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
2885
2886 if (access(filename, X_OK))
2887 {
2888 snprintf(p->state_message, sizeof(p->state_message),
2889 "Filter \"%s\" for printer \"%s\" not available: %s",
2890 program, p->name, strerror(errno));
2891 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 0);
2892 cupsdSetPrinterReasons(p, "+cups-missing-filter-error");
2893 cupsdAddPrinterHistory(p);
2894
2895 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
2896 }
bd7854cb 2897 }
2898
b423cd4c 2899 /*
2900 * Mark the CUPS_PRINTER_COMMANDS bit if we have a filter for
2901 * application/vnd.cups-command...
2902 */
2903
2904 if (!strcasecmp(super, "application") &&
2905 !strcasecmp(type, "vnd.cups-command"))
2906 p->type |= CUPS_PRINTER_COMMANDS;
2907
bd7854cb 2908 /*
2909 * Add the filter to the MIME database, supporting wildcards as needed...
2910 */
2911
2912 for (temptype = mimeFirstType(MimeDatabase);
2913 temptype;
2914 temptype = mimeNextType(MimeDatabase))
2915 if (((super[0] == '*' && strcasecmp(temptype->super, "printer")) ||
2916 !strcasecmp(temptype->super, super)) &&
2917 (type[0] == '*' || !strcasecmp(temptype->type, type)))
2918 {
2919 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2920 "add_printer_filter: %s: adding filter %s/%s %s/%s %d %s",
2921 p->name, temptype->super, temptype->type,
2922 p->filetype->super, p->filetype->type,
2923 cost, program);
2924 mimeAddFilter(MimeDatabase, temptype, p->filetype, cost, program);
2925 }
2926}
2927
2928
2929/*
2930 * 'add_printer_formats()' - Add document-format-supported values for a printer.
2931 */
2932
2933static void
2934add_printer_formats(cupsd_printer_t *p) /* I - Printer */
2935{
2936 int i; /* Looping var */
2937 mime_type_t *type; /* Current MIME type */
2938 cups_array_t *filters; /* Filters */
80ca4592 2939 ipp_attribute_t *attr; /* document-format-supported attribute */
bd7854cb 2940 char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
2941 /* MIME type name */
2942
2943
2944 /*
2945 * Raw (and remote) queues advertise all of the supported MIME
2946 * types...
2947 */
2948
80ca4592 2949 cupsArrayDelete(p->filetypes);
2950 p->filetypes = NULL;
2951
bd7854cb 2952 if (p->raw)
2953 {
2954 ippAddStrings(p->attrs, IPP_TAG_PRINTER,
2955 (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
2956 "document-format-supported", NumMimeTypes, NULL, MimeTypes);
2957 return;
2958 }
2959
2960 /*
2961 * Otherwise, loop through the supported MIME types and see if there
2962 * are filters for them...
2963 */
2964
bd7854cb 2965 cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters",
2966 mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
2967
80ca4592 2968 p->filetypes = cupsArrayNew(NULL, NULL);
bd7854cb 2969
80ca4592 2970 for (type = mimeFirstType(MimeDatabase);
bd7854cb 2971 type;
2972 type = mimeNextType(MimeDatabase))
2973 {
bd7854cb 2974 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
2975
2976 if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
2977 {
2978 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2979 "add_printer_formats: %s: %s needs %d filters",
2980 p->name, mimetype, cupsArrayCount(filters));
2981
2982 cupsArrayDelete(filters);
80ca4592 2983 cupsArrayAdd(p->filetypes, type);
bd7854cb 2984 }
2985 else
2986 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2987 "add_printer_formats: %s: %s not supported",
2988 p->name, mimetype);
2989 }
2990
2991 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2992 "add_printer_formats: %s: %d supported types",
80ca4592 2993 p->name, cupsArrayCount(p->filetypes) + 1);
bd7854cb 2994
2995 /*
2996 * Add the file formats that can be filtered...
2997 */
2998
f301802f 2999 if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL ||
3000 !cupsArrayFind(p->filetypes, type))
3001 i = 1;
3002 else
3003 i = 0;
bd7854cb 3004
80ca4592 3005 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
3006 "document-format-supported",
3007 cupsArrayCount(p->filetypes) + 1, NULL, NULL);
3008
f301802f 3009 if (i)
3010 attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
bd7854cb 3011
f301802f 3012 for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
80ca4592 3013 type;
3014 i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes))
3015 {
3016 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
bd7854cb 3017
80ca4592 3018 attr->values[i].string.text = _cupsStrAlloc(mimetype);
3019 }
bd7854cb 3020}
3021
3022
ef416fc2 3023/*
3024 * 'compare_printers()' - Compare two printers.
3025 */
3026
3027static int /* O - Result of comparison */
3028compare_printers(void *first, /* I - First printer */
3029 void *second, /* I - Second printer */
3030 void *data) /* I - App data (not used) */
3031{
3032 return (strcasecmp(((cupsd_printer_t *)first)->name,
3033 ((cupsd_printer_t *)second)->name));
3034}
3035
3036
bd7854cb 3037/*
e1d6a774 3038 * 'delete_printer_filters()' - Delete all MIME filters for a printer.
bd7854cb 3039 */
3040
3041static void
e1d6a774 3042delete_printer_filters(
3043 cupsd_printer_t *p) /* I - Printer to remove from */
bd7854cb 3044{
e1d6a774 3045 mime_filter_t *filter; /* MIME filter looping var */
bd7854cb 3046
bd7854cb 3047
3048 /*
e1d6a774 3049 * Range check input...
bd7854cb 3050 */
3051
e1d6a774 3052 if (p == NULL)
3053 return;
bd7854cb 3054
3055 /*
e1d6a774 3056 * Remove all filters from the MIME database that have a destination
3057 * type == printer...
bd7854cb 3058 */
3059
e1d6a774 3060 for (filter = mimeFirstFilter(MimeDatabase);
3061 filter;
3062 filter = mimeNextFilter(MimeDatabase))
3063 if (filter->dst == p->filetype)
3064 {
3065 /*
3066 * Delete the current filter...
3067 */
bd7854cb 3068
e1d6a774 3069 mimeDeleteFilter(MimeDatabase, filter);
3070 }
bd7854cb 3071}
3072
3073
ef416fc2 3074#ifdef __sgi
3075/*
3076 * 'write_irix_config()' - Update the config files used by the IRIX
3077 * desktop tools.
3078 */
3079
3080static void
3081write_irix_config(cupsd_printer_t *p) /* I - Printer to update */
3082{
3083 char filename[1024]; /* Interface script filename */
3084 cups_file_t *fp; /* Interface script file */
f301802f 3085 ipp_attribute_t *attr; /* Attribute data */
ef416fc2 3086
3087
3088 /*
3089 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
3090 * tools. First the interface script that tells the tools what kind of
3091 * printer we have...
3092 */
3093
3094 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
3095
3096 if (p->type & CUPS_PRINTER_CLASS)
3097 unlink(filename);
3098 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3099 {
3100 cupsFilePuts(fp, "#!/bin/sh\n");
3101
3102 if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
3103 IPP_TAG_TEXT)) != NULL)
3104 cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
3105 else if (p->type & CUPS_PRINTER_CLASS)
3106 cupsFilePuts(fp, "NAME=\"Printer Class\"\n");
3107 else
3108 cupsFilePuts(fp, "NAME=\"Remote Destination\"\n");
3109
3110 if (p->type & CUPS_PRINTER_COLOR)
3111 cupsFilePuts(fp, "TYPE=ColorPostScript\n");
3112 else
3113 cupsFilePuts(fp, "TYPE=MonoPostScript\n");
3114
3115 cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName);
3116 cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name);
3117
3118 cupsFileClose(fp);
3119
3120 chmod(filename, 0755);
3121 chown(filename, User, Group);
3122 }
3123
3124 /*
3125 * Then the member file that tells which device file the queue is connected
3126 * to... Networked printers use "/dev/null" in this file, so that's what
3127 * we use (the actual device URI can confuse some apps...)
3128 */
3129
3130 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
3131
3132 if (p->type & CUPS_PRINTER_CLASS)
3133 unlink(filename);
3134 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3135 {
3136 cupsFilePuts(fp, "/dev/null\n");
3137
3138 cupsFileClose(fp);
3139
3140 chmod(filename, 0644);
3141 chown(filename, User, Group);
3142 }
3143
3144 /*
3145 * The gui_interface file is a script or program that launches a GUI
3146 * option panel for the printer, using options specified on the
3147 * command-line in the third argument. The option panel must send
3148 * any printing options to stdout on a single line when the user
3149 * accepts them, or nothing if the user cancels the dialog.
3150 *
3151 * The default options panel program is /usr/bin/glpoptions, from
3152 * the ESP Print Pro software. You can select another using the
3153 * PrintcapGUI option.
3154 */
3155
3156 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
3157
3158 if (p->type & CUPS_PRINTER_CLASS)
3159 unlink(filename);
3160 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3161 {
3162 cupsFilePuts(fp, "#!/bin/sh\n");
3163 cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
3164
3165 cupsFileClose(fp);
3166
3167 chmod(filename, 0755);
3168 chown(filename, User, Group);
3169 }
3170
3171 /*
3172 * The POD config file is needed by the printstatus command to show
3173 * the printer location and device.
3174 */
3175
3176 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
3177
3178 if (p->type & CUPS_PRINTER_CLASS)
3179 unlink(filename);
3180 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3181 {
3182 cupsFilePrintf(fp, "Printer Class | %s\n",
3183 (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
3184 cupsFilePrintf(fp, "Printer Model | %s\n", p->make_model ? p->make_model : "");
3185 cupsFilePrintf(fp, "Location Code | %s\n", p->location ? p->location : "");
3186 cupsFilePrintf(fp, "Physical Location | %s\n", p->info ? p->info : "");
3187 cupsFilePrintf(fp, "Port Path | %s\n", p->device_uri ? p->device_uri : "");
3188 cupsFilePrintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
3189 cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
3190 cupsFilePuts(fp, "Status Update Wait | 10 seconds\n");
3191
3192 cupsFileClose(fp);
3193
3194 chmod(filename, 0664);
3195 chown(filename, User, Group);
3196 }
3197}
3198
3199
3200/*
3201 * 'write_irix_state()' - Update the status files used by IRIX printing
3202 * desktop tools.
3203 */
3204
3205static void
3206write_irix_state(cupsd_printer_t *p) /* I - Printer to update */
3207{
3208 char filename[1024]; /* Interface script filename */
3209 cups_file_t *fp; /* Interface script file */
3210 int tag; /* Status tag value */
3211
3212
3213 if (p)
3214 {
3215 /*
3216 * The POD status file is needed for the printstatus window to
3217 * provide the current status of the printer.
3218 */
3219
3220 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
3221
3222 if (p->type & CUPS_PRINTER_CLASS)
3223 unlink(filename);
3224 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3225 {
3226 cupsFilePrintf(fp, "Operational Status | %s\n",
3227 (p->state == IPP_PRINTER_IDLE) ? "Idle" :
3228 (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
3229 "Faulted");
3230 cupsFilePrintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
3231 cupsFilePrintf(fp, "Information | 02 00 00 | Device URI: %s\n",
3232 p->device_uri ? p->device_uri : "");
3233 cupsFilePrintf(fp, "Information | 03 00 00 | %s jobs\n",
3234 p->accepting ? "Accepting" : "Not accepting");
3235 cupsFilePrintf(fp, "Information | 04 00 00 | %s\n", p->state_message);
3236
3237 cupsFileClose(fp);
3238
3239 chmod(filename, 0664);
3240 chown(filename, User, Group);
3241 }
3242
3243 /*
3244 * The activeicons file is needed to provide desktop icons for printers:
3245 *
3246 * [ quoted from /usr/lib/print/tagit ]
3247 *
3248 * --- Type of printer tags (base values)
3249 *
3250 * Dumb=66048 # 0x10200
3251 * DumbColor=66080 # 0x10220
3252 * Raster=66112 # 0x10240
3253 * ColorRaster=66144 # 0x10260
3254 * Plotter=66176 # 0x10280
3255 * PostScript=66208 # 0x102A0
3256 * ColorPostScript=66240 # 0x102C0
3257 * MonoPostScript=66272 # 0x102E0
3258 *
3259 * --- Printer state modifiers for local printers
3260 *
3261 * Idle=0 # 0x0
3262 * Busy=1 # 0x1
3263 * Faulted=2 # 0x2
3264 * Unknown=3 # 0x3 (Faulted due to unknown reason)
3265 *
3266 * --- Printer state modifiers for network printers
3267 *
3268 * NetIdle=8 # 0x8
3269 * NetBusy=9 # 0x9
3270 * NetFaulted=10 # 0xA
3271 * NetUnknown=11 # 0xB (Faulted due to unknown reason)
3272 */
3273
3274 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
3275
3276 if (p->type & CUPS_PRINTER_CLASS)
3277 unlink(filename);
3278 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
3279 {
3280 if (p->type & CUPS_PRINTER_COLOR)
3281 tag = 66240;
3282 else
3283 tag = 66272;
3284
3285 if (p->type & CUPS_PRINTER_REMOTE)
3286 tag |= 8;
3287
3288 if (p->state == IPP_PRINTER_PROCESSING)
3289 tag |= 1;
3290
3291 else if (p->state == IPP_PRINTER_STOPPED)
3292 tag |= 2;
3293
3294 cupsFilePuts(fp, "#!/bin/sh\n");
3295 cupsFilePrintf(fp, "#Tag %d\n", tag);
3296
3297 cupsFileClose(fp);
3298
3299 chmod(filename, 0755);
3300 chown(filename, User, Group);
3301 }
3302 }
3303
3304 /*
3305 * The default file is needed by the printers window to show
3306 * the default printer.
3307 */
3308
3309 snprintf(filename, sizeof(filename), "/var/spool/lp/default");
3310
3311 if (DefaultPrinter != NULL)
3312 {
3313 if ((fp = cupsFileOpen(filename, "w")) != NULL)
3314 {
3315 cupsFilePrintf(fp, "%s\n", DefaultPrinter->name);
3316
3317 cupsFileClose(fp);
3318
3319 chmod(filename, 0644);
3320 chown(filename, User, Group);
3321 }
3322 }
3323 else
3324 unlink(filename);
3325}
3326#endif /* __sgi */
3327
3328
3329/*
c07d5b2d 3330 * End of "$Id: printers.c 181 2006-06-22 20:01:18Z jlovell $".
ef416fc2 3331 */