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