]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/printers.c
Add missing image.
[thirdparty/cups.git] / scheduler / printers.c
CommitLineData
ef416fc2 1/*
0af14961 2 * "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $"
ef416fc2 3 *
4 * Printer routines for the Common UNIX Printing System (CUPS).
5 *
91c84a35 6 * Copyright 2007-2008 by Apple Inc.
f7deaa1a 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 *
15 * Contents:
16 *
17 * cupsdAddPrinter() - Add a printer to the system.
ef416fc2 18 * cupsdAddPrinterHistory() - Add the current printer state to the history.
19 * cupsdAddPrinterUser() - Add a user to the ACL.
b94498cf 20 * cupsdCreateCommonData() - Create the common printer data.
ef416fc2 21 * cupsdDeleteAllPrinters() - Delete all printers from the system.
22 * cupsdDeletePrinter() - Delete a printer from the system.
ef416fc2 23 * cupsdFindPrinter() - Find a printer in the list.
24 * cupsdFreePrinterUsers() - Free allow/deny users.
25 * cupsdLoadAllPrinters() - Load printers from the printers.conf file.
b423cd4c 26 * cupsdRenamePrinter() - Rename a printer.
fa73b229 27 * cupsdSaveAllPrinters() - Save all printer definitions to the
28 * printers.conf file.
09a101d6 29 * cupsdSetAuthInfoRequired() - Set the required authentication info.
0af14961 30 * cupsdSetDeviceURI() - Set the device URI for a printer.
5a738aea 31 * cupsdSetPrinterAttr() - Set a printer attribute.
fa73b229 32 * cupsdSetPrinterAttrs() - Set printer attributes based upon the PPD
33 * file.
ef416fc2 34 * cupsdSetPrinterReasons() - Set/update the reasons strings.
35 * cupsdSetPrinterState() - Update the current state of a printer.
36 * cupsdStopPrinter() - Stop a printer from printing any jobs...
37 * cupsdUpdatePrinters() - Update printers after a partial reload.
38 * cupsdValidateDest() - Validate a printer/class destination.
39 * cupsdWritePrintcap() - Write a pseudo-printcap file for older
40 * applications that need it...
b423cd4c 41 * add_printer_defaults() - Add name-default attributes to the printer
42 * attributes.
bd7854cb 43 * add_printer_filter() - Add a MIME filter for a printer.
44 * add_printer_formats() - Add document-format-supported values for
45 * a printer.
ef416fc2 46 * compare_printers() - Compare two printers.
e1d6a774 47 * delete_printer_filters() - Delete all MIME filters for a printer.
ef416fc2 48 * write_irix_config() - Update the config files used by the IRIX
49 * desktop tools.
fa73b229 50 * write_irix_state() - Update the status files used by IRIX
51 * printing desktop tools.
0af14961 52 * write_xml_string() - Write a string with XML escaping.
ef416fc2 53 */
54
55/*
56 * Include necessary headers...
57 */
58
59#include "cupsd.h"
ed486911 60#include <cups/dir.h>
ef416fc2 61
62
63/*
64 * Local functions...
65 */
66
b423cd4c 67static void add_printer_defaults(cupsd_printer_t *p);
f7deaa1a 68static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
69 const char *filter);
bd7854cb 70static void add_printer_formats(cupsd_printer_t *p);
ef416fc2 71static int compare_printers(void *first, void *second, void *data);
e1d6a774 72static void delete_printer_filters(cupsd_printer_t *p);
ef416fc2 73#ifdef __sgi
74static void write_irix_config(cupsd_printer_t *p);
75static void write_irix_state(cupsd_printer_t *p);
76#endif /* __sgi */
0af14961 77static void write_xml_string(cups_file_t *fp, const char *s);
ef416fc2 78
79
80/*
81 * 'cupsdAddPrinter()' - Add a printer to the system.
82 */
83
84cupsd_printer_t * /* O - New printer */
85cupsdAddPrinter(const char *name) /* I - Name of printer */
86{
87 cupsd_printer_t *p; /* New printer */
88
89
90 /*
91 * Range check input...
92 */
93
94 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPrinter(\"%s\")", name);
95
96 /*
97 * Create a new printer entity...
98 */
99
100 if ((p = calloc(1, sizeof(cupsd_printer_t))) == NULL)
101 {
102 cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for printer - %s",
103 strerror(errno));
104 return (NULL);
105 }
106
107 cupsdSetString(&p->name, name);
108 cupsdSetString(&p->info, name);
109 cupsdSetString(&p->hostname, ServerName);
110
111 cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, LocalPort, name);
0af14961 112 cupsdSetDeviceURI(p, "file:/dev/null");
ef416fc2 113
114 p->state = IPP_PRINTER_STOPPED;
115 p->state_time = time(NULL);
116 p->accepting = 0;
fa73b229 117 p->shared = DefaultShared;
ef416fc2 118 p->filetype = mimeAddType(MimeDatabase, "printer", name);
119
120 cupsdSetString(&p->job_sheets[0], "none");
121 cupsdSetString(&p->job_sheets[1], "none");
122
323c5de1 123 cupsdSetString(&p->error_policy, ErrorPolicy);
ef416fc2 124 cupsdSetString(&p->op_policy, DefaultPolicy);
125
126 p->op_policy_ptr = DefaultPolicyPtr;
127
128 if (MaxPrinterHistory)
129 p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *));
130
131 /*
132 * Insert the printer in the printer list alphabetically...
133 */
134
135 if (!Printers)
136 Printers = cupsArrayNew(compare_printers, NULL);
137
1f0275e3
MS
138 cupsdLogMessage(CUPSD_LOG_DEBUG2,
139 "cupsdAddPrinter: Adding %s to Printers", p->name);
ef416fc2 140 cupsArrayAdd(Printers, p);
141
142 if (!ImplicitPrinters)
143 ImplicitPrinters = cupsArrayNew(compare_printers, NULL);
144
145 /*
146 * Return the new printer...
147 */
148
149 return (p);
150}
151
152
ef416fc2 153/*
154 * 'cupsdAddPrinterHistory()' - Add the current printer state to the history.
155 */
156
157void
158cupsdAddPrinterHistory(
159 cupsd_printer_t *p) /* I - Printer */
160{
161 ipp_t *history; /* History collection */
162
163
164 /*
165 * Stop early if we aren't keeping history data...
166 */
167
168 if (MaxPrinterHistory <= 0)
169 return;
170
171 /*
172 * Retire old history data as needed...
173 */
174
175 p->sequence_number ++;
176
177 if (p->num_history >= MaxPrinterHistory)
178 {
179 p->num_history --;
180 ippDelete(p->history[0]);
181 memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *));
182 }
183
184 /*
185 * Create a collection containing the current printer-state, printer-up-time,
186 * printer-state-message, and printer-state-reasons attributes.
187 */
188
189 history = ippNew();
190 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
191 p->state);
192 ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
193 p->accepting);
fa73b229 194 ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared);
ef416fc2 195 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
196 NULL, p->state_message);
e00b005a 197#ifdef __APPLE__
198 if (p->recoverable)
199 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT,
200 "com.apple.print.recoverable-message", NULL, p->recoverable);
201#endif /* __APPLE__ */
ef416fc2 202 if (p->num_reasons == 0)
203 ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
204 "printer-state-reasons", NULL,
205 p->state == IPP_PRINTER_STOPPED ? "paused" : "none");
206 else
207 ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
208 "printer-state-reasons", p->num_reasons, NULL,
209 (const char * const *)p->reasons);
210 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
211 "printer-state-change-time", p->state_time);
212 ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
213 "printer-state-sequence-number", p->sequence_number);
214
215 p->history[p->num_history] = history;
216 p->num_history ++;
217}
218
219
220/*
221 * 'cupsdAddPrinterUser()' - Add a user to the ACL.
222 */
223
224void
225cupsdAddPrinterUser(
226 cupsd_printer_t *p, /* I - Printer */
227 const char *username) /* I - User */
228{
229 const char **temp; /* Temporary array pointer */
230
231
232 if (!p || !username)
233 return;
234
235 if (p->num_users == 0)
236 temp = malloc(sizeof(char **));
237 else
238 temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
239
240 if (!temp)
241 return;
242
243 p->users = temp;
244 temp += p->num_users;
245
246 if ((*temp = strdup(username)) != NULL)
247 p->num_users ++;
248}
249
250
251/*
252 * 'cupsdCreateCommonData()' - Create the common printer data.
253 */
254
255void
256cupsdCreateCommonData(void)
257{
258 int i; /* Looping var */
259 ipp_attribute_t *attr; /* Attribute data */
ed486911 260 cups_dir_t *dir; /* Notifier directory */
261 cups_dentry_t *dent; /* Notifier directory entry */
262 cups_array_t *notifiers; /* Notifier array */
263 char filename[1024], /* Filename */
264 *notifier; /* Current notifier */
2e4ff8af 265 cupsd_policy_t *p; /* Current policy */
ef416fc2 266 static const int nups[] = /* number-up-supported values */
267 { 1, 2, 4, 6, 9, 16 };
b94498cf 268 static const int orients[4] =/* orientation-requested-supported values */
ef416fc2 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 };
b94498cf 291 static const int ops[] = /* operations-supported values */
ef416fc2 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,
2e4ff8af
MS
330 CUPS_GET_PPD,
331 CUPS_GET_DOCUMENT,
ef416fc2 332 IPP_RESTART_JOB
333 };
334 static const char * const charsets[] =/* charset-supported values */
335 {
336 "us-ascii",
337 "utf-8"
338 };
339 static const char * const compressions[] =
340 { /* document-compression-supported values */
341 "none"
342#ifdef HAVE_LIBZ
343 ,"gzip"
344#endif /* HAVE_LIBZ */
345 };
346 static const char * const multiple_document_handling[] =
347 { /* multiple-document-handling-supported values */
348 "separate-documents-uncollated-copies",
349 "separate-documents-collated-copies"
350 };
351 static const char * const errors[] = /* printer-error-policy-supported values */
352 {
353 "abort-job",
ee571f26 354 "retry-current-job",
ef416fc2 355 "retry-job",
356 "stop-printer"
357 };
358 static const char * const notify_attrs[] =
359 { /* notify-attributes-supported values */
360 "printer-state-change-time",
361 "notify-lease-expiration-time",
362 "notify-subscriber-user-name"
363 };
364 static const char * const notify_events[] =
365 { /* notify-events-supported values */
366 "job-completed",
367 "job-config-changed",
368 "job-created",
369 "job-progress",
370 "job-state-changed",
371 "job-stopped",
372 "printer-added",
373 "printer-changed",
374 "printer-config-changed",
375 "printer-deleted",
376 "printer-finishings-changed",
377 "printer-media-changed",
378 "printer-modified",
379 "printer-restarted",
380 "printer-shutdown",
381 "printer-state-changed",
382 "printer-stopped",
383 "server-audit",
384 "server-restarted",
385 "server-started",
386 "server-stopped"
387 };
1f6f3dbc
MS
388 static const char * const job_settable[] =
389 { /* job-settable-attributes-supported */
390 "copies",
391 "finishings",
392 "job-hold-until",
393 "job-priority",
394 "media",
395 "multiple-document-handling",
396 "number-up",
397 "orientation-requested",
398 "page-ranges",
399 "print-quality",
400 "printer-resolution",
401 "sides"
402 };
ef416fc2 403
404
405 if (CommonData)
406 ippDelete(CommonData);
407
408 CommonData = ippNew();
409
410 /*
411 * This list of attributes is sorted to improve performance when the
412 * client provides a requested-attributes attribute...
413 */
414
415 /* charset-configured */
1f6f3dbc 416 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
ef416fc2 417 "charset-configured", NULL, DefaultCharset);
418
419 /* charset-supported */
1f6f3dbc 420 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
ef416fc2 421 "charset-supported", sizeof(charsets) / sizeof(charsets[0]),
422 NULL, charsets);
423
424 /* compression-supported */
1f6f3dbc 425 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
ef416fc2 426 "compression-supported",
427 sizeof(compressions) / sizeof(compressions[0]),
428 NULL, compressions);
429
ef416fc2 430 /* copies-supported */
431 ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
432
b94498cf 433 /* cups-version */
1f6f3dbc
MS
434 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY,
435 "cups-version", NULL, CUPS_SVERSION + 6);
b94498cf 436
ef416fc2 437 /* generated-natural-language-supported */
1f6f3dbc 438 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
ef416fc2 439 "generated-natural-language-supported", NULL, DefaultLanguage);
440
441 /* ipp-versions-supported */
1f6f3dbc 442 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
ef416fc2 443 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
444 NULL, versions);
445
ef416fc2 446 /* job-hold-until-supported */
1f6f3dbc 447 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
ef416fc2 448 "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]),
449 NULL, holds);
450
ef416fc2 451 /* job-priority-supported */
452 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
453 "job-priority-supported", 100);
454
1f6f3dbc
MS
455 /* job-settable-attributes-supported */
456 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
457 "job-settable-attributes-supported",
458 sizeof(job_settable) / sizeof(job_settable[0]),
459 NULL, job_settable);
460
ef416fc2 461 /* job-sheets-supported */
fa73b229 462 if (cupsArrayCount(Banners) > 0)
ef416fc2 463 {
464 /*
465 * Setup the job-sheets-supported attribute...
466 */
467
468 if (Classification && !ClassifyOverride)
1f6f3dbc
MS
469 attr = ippAddString(CommonData, IPP_TAG_PRINTER,
470 IPP_TAG_NAME | IPP_TAG_COPY,
ef416fc2 471 "job-sheets-supported", NULL, Classification);
472 else
1f6f3dbc
MS
473 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER,
474 IPP_TAG_NAME | IPP_TAG_COPY,
fa73b229 475 "job-sheets-supported", cupsArrayCount(Banners) + 1,
476 NULL, NULL);
ef416fc2 477
478 if (attr == NULL)
479 cupsdLogMessage(CUPSD_LOG_EMERG,
bd7854cb 480 "Unable to allocate memory for "
ef416fc2 481 "job-sheets-supported attribute: %s!", strerror(errno));
482 else if (!Classification || ClassifyOverride)
483 {
fa73b229 484 cupsd_banner_t *banner; /* Current banner */
485
486
757d2cad 487 attr->values[0].string.text = _cupsStrAlloc("none");
ef416fc2 488
fa73b229 489 for (i = 1, banner = (cupsd_banner_t *)cupsArrayFirst(Banners);
490 banner;
491 i ++, banner = (cupsd_banner_t *)cupsArrayNext(Banners))
1f6f3dbc 492 attr->values[i].string.text = banner->name;
ef416fc2 493 }
494 }
495 else
1f6f3dbc 496 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
ef416fc2 497 "job-sheets-supported", NULL, "none");
498
499 /* multiple-document-handling-supported */
1f6f3dbc 500 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
ef416fc2 501 "multiple-document-handling-supported",
502 sizeof(multiple_document_handling) /
503 sizeof(multiple_document_handling[0]), NULL,
504 multiple_document_handling);
505
506 /* multiple-document-jobs-supported */
507 ippAddBoolean(CommonData, IPP_TAG_PRINTER,
508 "multiple-document-jobs-supported", 1);
509
510 /* multiple-operation-time-out */
511 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
512 "multiple-operation-time-out", 60);
513
514 /* natural-language-configured */
1f6f3dbc 515 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
ef416fc2 516 "natural-language-configured", NULL, DefaultLanguage);
517
518 /* notify-attributes-supported */
1f6f3dbc 519 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
ef416fc2 520 "notify-attributes-supported",
521 (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])),
522 NULL, notify_attrs);
523
ef416fc2 524 /* notify-lease-duration-supported */
525 ippAddRange(CommonData, IPP_TAG_PRINTER,
526 "notify-lease-duration-supported", 0,
527 MaxLeaseDuration ? MaxLeaseDuration : 2147483647);
528
529 /* notify-max-events-supported */
530 ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
531 "notify-max-events-supported", MaxEvents);
532
ed486911 533 /* notify-events-supported */
1f6f3dbc 534 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
ef416fc2 535 "notify-events-supported",
536 (int)(sizeof(notify_events) / sizeof(notify_events[0])),
537 NULL, notify_events);
538
539 /* notify-pull-method-supported */
1f6f3dbc 540 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
ef416fc2 541 "notify-pull-method-supported", NULL, "ippget");
542
ef416fc2 543 /* notify-schemes-supported */
ed486911 544 snprintf(filename, sizeof(filename), "%s/notifier", ServerBin);
545 if ((dir = cupsDirOpen(filename)) != NULL)
546 {
547 notifiers = cupsArrayNew((cups_array_func_t)strcmp, NULL);
548
549 while ((dent = cupsDirRead(dir)) != NULL)
550 if (S_ISREG(dent->fileinfo.st_mode) &&
551 (dent->fileinfo.st_mode & S_IXOTH) != 0)
552 cupsArrayAdd(notifiers, _cupsStrAlloc(dent->filename));
553
554 if (cupsArrayCount(notifiers) > 0)
555 {
556 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
557 "notify-schemes-supported",
558 cupsArrayCount(notifiers), NULL, NULL);
559
560 for (i = 0, notifier = (char *)cupsArrayFirst(notifiers);
561 notifier;
562 i ++, notifier = (char *)cupsArrayNext(notifiers))
563 attr->values[i].string.text = notifier;
564 }
565
566 cupsArrayDelete(notifiers);
8ca02f3c 567 cupsDirClose(dir);
ed486911 568 }
ef416fc2 569
ef416fc2 570 /* number-up-supported */
571 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
572 "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
573
574 /* operations-supported */
575 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
576 "operations-supported",
b94498cf 577 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, ops);
ef416fc2 578
ef416fc2 579 /* orientation-requested-supported */
580 ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
b94498cf 581 "orientation-requested-supported", 4, orients);
ef416fc2 582
583 /* page-ranges-supported */
584 ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
585
586 /* pdf-override-supported */
1f6f3dbc 587 ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
ef416fc2 588 "pdl-override-supported", NULL, "not-attempted");
589
590 /* printer-error-policy-supported */
1f6f3dbc 591 ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
ef416fc2 592 "printer-error-policy-supported",
593 sizeof(errors) / sizeof(errors[0]), NULL, errors);
594
595 /* printer-op-policy-supported */
1f6f3dbc 596 attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
2e4ff8af
MS
597 "printer-op-policy-supported", cupsArrayCount(Policies),
598 NULL, NULL);
599 for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies);
600 p;
601 i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies))
1f6f3dbc 602 attr->values[i].string.text = p->name;
2e4ff8af 603
1f6f3dbc 604 /* server-is-sharing-printers */
2e4ff8af
MS
605 ippAddBoolean(CommonData, IPP_TAG_PRINTER, "server-is-sharing-printers",
606 BrowseLocalProtocols != 0 && Browsing);
ef416fc2 607}
608
609
610/*
611 * 'cupsdDeleteAllPrinters()' - Delete all printers from the system.
612 */
613
614void
615cupsdDeleteAllPrinters(void)
616{
617 cupsd_printer_t *p; /* Pointer to current printer/class */
618
619
620 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
621 p;
622 p = (cupsd_printer_t *)cupsArrayNext(Printers))
0af14961 623 cupsdDeletePrinter(p, 0);
ef416fc2 624}
625
626
627/*
628 * 'cupsdDeletePrinter()' - Delete a printer from the system.
629 */
630
631void
632cupsdDeletePrinter(
633 cupsd_printer_t *p, /* I - Printer to delete */
634 int update) /* I - Update printers.conf? */
635{
636 int i; /* Looping var */
637#ifdef __sgi
638 char filename[1024]; /* Interface script filename */
639#endif /* __sgi */
640
641
642 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)",
643 p, p->name, update);
644
645 /*
646 * Save the current position in the Printers array...
647 */
648
649 cupsArraySave(Printers);
650
651 /*
652 * Stop printing on this printer...
653 */
654
655 cupsdStopPrinter(p, update);
656
657 /*
658 * If this printer is the next for browsing, point to the next one...
659 */
660
661 if (p == BrowseNext)
662 {
663 cupsArrayFind(Printers, p);
664 BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers);
665 }
666
667 /*
668 * Remove the printer from the list...
669 */
670
1f0275e3
MS
671 cupsdLogMessage(CUPSD_LOG_DEBUG2,
672 "cupsdDeletePrinter: Removing %s from Printers", p->name);
ef416fc2 673 cupsArrayRemove(Printers, p);
674
8ca02f3c 675 if (p->type & CUPS_PRINTER_IMPLICIT)
1f0275e3
MS
676 {
677 cupsdLogMessage(CUPSD_LOG_DEBUG2,
678 "cupsdDeletePrinter: Removing %s from ImplicitPrinters",
679 p->name);
8ca02f3c 680 cupsArrayRemove(ImplicitPrinters, p);
1f0275e3 681 }
8ca02f3c 682
ef416fc2 683 /*
684 * Remove the dummy interface/icon/option files under IRIX...
685 */
686
687#ifdef __sgi
688 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
689 unlink(filename);
690
691 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
692 p->name);
693 unlink(filename);
694
695 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
696 unlink(filename);
697
698 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
699 unlink(filename);
700
701 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
702 unlink(filename);
703
704 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
705 unlink(filename);
706#endif /* __sgi */
707
708 /*
e00b005a 709 * If p is the default printer, assign a different one...
ef416fc2 710 */
711
712 if (p == DefaultPrinter)
e00b005a 713 {
714 DefaultPrinter = NULL;
715
716 if (UseNetworkDefault)
717 {
718 /*
719 * Find the first network default printer and use it...
720 */
721
722 cupsd_printer_t *dp; /* New default printer */
723
724
725 for (dp = (cupsd_printer_t *)cupsArrayFirst(Printers);
726 dp;
727 dp = (cupsd_printer_t *)cupsArrayNext(Printers))
728 if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT))
729 {
ed486911 730 DefaultPrinter = dp;
e00b005a 731 break;
732 }
733 }
734 }
ef416fc2 735
736 /*
f7deaa1a 737 * Remove this printer from any classes...
ef416fc2 738 */
739
740 if (!(p->type & CUPS_PRINTER_IMPLICIT))
741 {
742 cupsdDeletePrinterFromClasses(p);
f7deaa1a 743
744 /*
745 * Deregister from any browse protocols...
746 */
747
748 cupsdDeregisterPrinter(p, 1);
ef416fc2 749 }
750
751 /*
752 * Free all memory used by the printer...
753 */
754
755 if (p->printers != NULL)
756 free(p->printers);
757
758 if (MaxPrinterHistory)
759 {
760 for (i = 0; i < p->num_history; i ++)
761 ippDelete(p->history[i]);
762
763 free(p->history);
764 }
765
766 for (i = 0; i < p->num_reasons; i ++)
1f6f3dbc 767 _cupsStrFree(p->reasons[i]);
ef416fc2 768
769 ippDelete(p->attrs);
770
e1d6a774 771 delete_printer_filters(p);
ef416fc2 772
fa73b229 773 mimeDeleteType(MimeDatabase, p->filetype);
f7deaa1a 774 mimeDeleteType(MimeDatabase, p->prefiltertype);
fa73b229 775
ef416fc2 776 cupsdFreePrinterUsers(p);
777 cupsdFreeQuotas(p);
778
779 cupsdClearString(&p->uri);
780 cupsdClearString(&p->hostname);
781 cupsdClearString(&p->name);
782 cupsdClearString(&p->location);
783 cupsdClearString(&p->make_model);
784 cupsdClearString(&p->info);
785 cupsdClearString(&p->job_sheets[0]);
786 cupsdClearString(&p->job_sheets[1]);
787 cupsdClearString(&p->device_uri);
0af14961 788 cupsdClearString(&p->sanitized_device_uri);
ef416fc2 789 cupsdClearString(&p->port_monitor);
790 cupsdClearString(&p->op_policy);
791 cupsdClearString(&p->error_policy);
792
323c5de1 793 cupsdClearString(&p->alert);
794 cupsdClearString(&p->alert_description);
795
f7deaa1a 796#ifdef HAVE_DNSSD
797 cupsdClearString(&p->product);
798 cupsdClearString(&p->pdl);
799#endif /* HAVE_DNSSD */
800
80ca4592 801 cupsArrayDelete(p->filetypes);
802
b423cd4c 803 if (p->browse_attrs)
804 free(p->browse_attrs);
805
e00b005a 806#ifdef __APPLE__
807 cupsdClearString(&p->recoverable);
808#endif /* __APPLE__ */
809
b423cd4c 810 cupsFreeOptions(p->num_options, p->options);
811
ef416fc2 812 free(p);
813
814 /*
815 * Restore the previous position in the Printers array...
816 */
817
818 cupsArrayRestore(Printers);
819}
820
821
ef416fc2 822/*
823 * 'cupsdFindDest()' - Find a destination in the list.
824 */
825
826cupsd_printer_t * /* O - Destination in list */
827cupsdFindDest(const char *name) /* I - Name of printer or class to find */
828{
829 cupsd_printer_t key; /* Search key */
830
831
832 key.name = (char *)name;
833 return ((cupsd_printer_t *)cupsArrayFind(Printers, &key));
834}
835
836
837/*
838 * 'cupsdFindPrinter()' - Find a printer in the list.
839 */
840
841cupsd_printer_t * /* O - Printer in list */
842cupsdFindPrinter(const char *name) /* I - Name of printer to find */
843{
844 cupsd_printer_t *p; /* Printer in list */
845
846
847 if ((p = cupsdFindDest(name)) != NULL && (p->type & CUPS_PRINTER_CLASS))
848 return (NULL);
849 else
850 return (p);
851}
852
853
854/*
855 * 'cupsdFreePrinterUsers()' - Free allow/deny users.
856 */
857
858void
859cupsdFreePrinterUsers(
860 cupsd_printer_t *p) /* I - Printer */
861{
862 int i; /* Looping var */
863
864
865 if (!p || !p->num_users)
866 return;
867
868 for (i = 0; i < p->num_users; i ++)
869 free((void *)p->users[i]);
870
871 free(p->users);
872
873 p->num_users = 0;
874 p->users = NULL;
875}
876
877
878/*
879 * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file.
880 */
881
882void
883cupsdLoadAllPrinters(void)
884{
885 cups_file_t *fp; /* printers.conf file */
886 int linenum; /* Current line number */
887 char line[1024], /* Line from file */
888 *value, /* Pointer to value */
889 *valueptr; /* Pointer into value */
890 cupsd_printer_t *p; /* Current printer */
891
892
893 /*
894 * Open the printers.conf file...
895 */
896
897 snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
898 if ((fp = cupsFileOpen(line, "r")) == NULL)
899 {
fa73b229 900 if (errno != ENOENT)
bd7854cb 901 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", line,
fa73b229 902 strerror(errno));
ef416fc2 903 return;
904 }
905
906 /*
907 * Read printer configurations until we hit EOF...
908 */
909
910 linenum = 0;
911 p = NULL;
912
913 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
914 {
915 /*
916 * Decode the directive...
917 */
918
919 if (!strcasecmp(line, "<Printer") ||
920 !strcasecmp(line, "<DefaultPrinter"))
921 {
922 /*
923 * <Printer name> or <DefaultPrinter name>
924 */
925
926 if (p == NULL && value)
927 {
928 /*
929 * Add the printer and a base file type...
930 */
931
bd7854cb 932 cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading printer %s...", value);
ef416fc2 933
934 p = cupsdAddPrinter(value);
935 p->accepting = 1;
936 p->state = IPP_PRINTER_IDLE;
937
938 /*
939 * Set the default printer as needed...
940 */
941
942 if (!strcasecmp(line, "<DefaultPrinter"))
943 DefaultPrinter = p;
944 }
945 else
ef416fc2 946 cupsdLogMessage(CUPSD_LOG_ERROR,
947 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 948 }
949 else if (!strcasecmp(line, "</Printer>"))
950 {
951 if (p != NULL)
952 {
953 /*
954 * Close out the current printer...
955 */
956
957 cupsdSetPrinterAttrs(p);
958 cupsdAddPrinterHistory(p);
959
0af14961 960 if (strncmp(p->device_uri, "file:", 5) &&
ef416fc2 961 p->state != IPP_PRINTER_STOPPED)
962 {
963 /*
964 * See if the backend exists...
965 */
966
967 snprintf(line, sizeof(line), "%s/backend/%s", ServerBin,
968 p->device_uri);
969
970 if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
971 *valueptr = '\0'; /* Chop everything but URI scheme */
972
973 if (access(line, 0))
974 {
975 /*
976 * Backend does not exist, stop printer...
977 */
978
979 p->state = IPP_PRINTER_STOPPED;
980 snprintf(p->state_message, sizeof(p->state_message),
981 "Backend %s does not exist!", line);
982 }
983 }
984
985 p = NULL;
986 }
987 else
ef416fc2 988 cupsdLogMessage(CUPSD_LOG_ERROR,
989 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 990 }
991 else if (!p)
992 {
993 cupsdLogMessage(CUPSD_LOG_ERROR,
994 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 995 }
f7deaa1a 996 else if (!strcasecmp(line, "AuthInfoRequired"))
997 {
998 if (!cupsdSetAuthInfoRequired(p, value, NULL))
999 cupsdLogMessage(CUPSD_LOG_ERROR,
1000 "Bad AuthInfoRequired on line %d of printers.conf.",
1001 linenum);
1002 }
ef416fc2 1003 else if (!strcasecmp(line, "Info"))
1004 {
1005 if (value)
1006 cupsdSetString(&p->info, value);
1007 }
1008 else if (!strcasecmp(line, "Location"))
1009 {
1010 if (value)
1011 cupsdSetString(&p->location, value);
1012 }
1013 else if (!strcasecmp(line, "DeviceURI"))
1014 {
1015 if (value)
0af14961 1016 cupsdSetDeviceURI(p, value);
ef416fc2 1017 else
ef416fc2 1018 cupsdLogMessage(CUPSD_LOG_ERROR,
1019 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1020 }
b423cd4c 1021 else if (!strcasecmp(line, "Option") && value)
1022 {
1023 /*
1024 * Option name value
1025 */
1026
1027 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1028
1029 if (!*valueptr)
1030 cupsdLogMessage(CUPSD_LOG_ERROR,
1031 "Syntax error on line %d of printers.conf.", linenum);
1032 else
1033 {
1034 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
1035
1036 p->num_options = cupsAddOption(value, valueptr, p->num_options,
1037 &(p->options));
1038 }
1039 }
ef416fc2 1040 else if (!strcasecmp(line, "PortMonitor"))
1041 {
1042 if (value && strcmp(value, "none"))
1043 cupsdSetString(&p->port_monitor, value);
1044 else if (value)
1045 cupsdClearString(&p->port_monitor);
1046 else
ef416fc2 1047 cupsdLogMessage(CUPSD_LOG_ERROR,
1048 "Syntax error on line %d of printers.conf.", linenum);
0af14961
MS
1049 }
1050 else if (!strcasecmp(line, "Reason"))
1051 {
1052 if (value &&
1053 p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
1054 {
1055 p->reasons[p->num_reasons] = _cupsStrAlloc(value);
1056 p->num_reasons ++;
ef416fc2 1057 }
0af14961
MS
1058 else
1059 cupsdLogMessage(CUPSD_LOG_ERROR,
1060 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1061 }
1062 else if (!strcasecmp(line, "State"))
1063 {
1064 /*
1065 * Set the initial queue state...
1066 */
1067
1068 if (value && !strcasecmp(value, "idle"))
1069 p->state = IPP_PRINTER_IDLE;
1070 else if (value && !strcasecmp(value, "stopped"))
1071 p->state = IPP_PRINTER_STOPPED;
1072 else
ef416fc2 1073 cupsdLogMessage(CUPSD_LOG_ERROR,
1074 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1075 }
1076 else if (!strcasecmp(line, "StateMessage"))
1077 {
1078 /*
1079 * Set the initial queue state message...
1080 */
1081
1082 if (value)
1083 strlcpy(p->state_message, value, sizeof(p->state_message));
1084 }
1085 else if (!strcasecmp(line, "StateTime"))
1086 {
1087 /*
1088 * Set the state time...
1089 */
1090
1091 if (value)
1092 p->state_time = atoi(value);
1093 }
1094 else if (!strcasecmp(line, "Accepting"))
1095 {
1096 /*
1097 * Set the initial accepting state...
1098 */
1099
1100 if (value &&
1101 (!strcasecmp(value, "yes") ||
1102 !strcasecmp(value, "on") ||
1103 !strcasecmp(value, "true")))
1104 p->accepting = 1;
1105 else if (value &&
1106 (!strcasecmp(value, "no") ||
1107 !strcasecmp(value, "off") ||
1108 !strcasecmp(value, "false")))
1109 p->accepting = 0;
1110 else
ef416fc2 1111 cupsdLogMessage(CUPSD_LOG_ERROR,
1112 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1113 }
1114 else if (!strcasecmp(line, "Shared"))
1115 {
1116 /*
1117 * Set the initial shared state...
1118 */
1119
1120 if (value &&
1121 (!strcasecmp(value, "yes") ||
1122 !strcasecmp(value, "on") ||
1123 !strcasecmp(value, "true")))
1124 p->shared = 1;
1125 else if (value &&
1126 (!strcasecmp(value, "no") ||
1127 !strcasecmp(value, "off") ||
1128 !strcasecmp(value, "false")))
1129 p->shared = 0;
1130 else
ef416fc2 1131 cupsdLogMessage(CUPSD_LOG_ERROR,
1132 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1133 }
1134 else if (!strcasecmp(line, "JobSheets"))
1135 {
1136 /*
1137 * Set the initial job sheets...
1138 */
1139
1140 if (value)
1141 {
1142 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1143
1144 if (*valueptr)
1145 *valueptr++ = '\0';
1146
1147 cupsdSetString(&p->job_sheets[0], value);
1148
1149 while (isspace(*valueptr & 255))
1150 valueptr ++;
1151
1152 if (*valueptr)
1153 {
1154 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1155
1156 if (*valueptr)
1f0275e3 1157 *valueptr = '\0';
ef416fc2 1158
1159 cupsdSetString(&p->job_sheets[1], value);
1160 }
1161 }
1162 else
ef416fc2 1163 cupsdLogMessage(CUPSD_LOG_ERROR,
1164 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1165 }
1166 else if (!strcasecmp(line, "AllowUser"))
1167 {
1168 if (value)
1169 {
1170 p->deny_users = 0;
1171 cupsdAddPrinterUser(p, value);
1172 }
1173 else
ef416fc2 1174 cupsdLogMessage(CUPSD_LOG_ERROR,
1175 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1176 }
1177 else if (!strcasecmp(line, "DenyUser"))
1178 {
1179 if (value)
1180 {
1181 p->deny_users = 1;
1182 cupsdAddPrinterUser(p, value);
1183 }
1184 else
ef416fc2 1185 cupsdLogMessage(CUPSD_LOG_ERROR,
1186 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1187 }
1188 else if (!strcasecmp(line, "QuotaPeriod"))
1189 {
1190 if (value)
1191 p->quota_period = atoi(value);
1192 else
ef416fc2 1193 cupsdLogMessage(CUPSD_LOG_ERROR,
1194 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1195 }
1196 else if (!strcasecmp(line, "PageLimit"))
1197 {
1198 if (value)
1199 p->page_limit = atoi(value);
1200 else
ef416fc2 1201 cupsdLogMessage(CUPSD_LOG_ERROR,
1202 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1203 }
1204 else if (!strcasecmp(line, "KLimit"))
1205 {
1206 if (value)
1207 p->k_limit = atoi(value);
1208 else
ef416fc2 1209 cupsdLogMessage(CUPSD_LOG_ERROR,
1210 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1211 }
1212 else if (!strcasecmp(line, "OpPolicy"))
1213 {
1214 if (value)
c0e1af83 1215 {
1216 cupsd_policy_t *pol; /* Policy */
1217
1218
1219 if ((pol = cupsdFindPolicy(value)) != NULL)
1220 {
1221 cupsdSetString(&p->op_policy, value);
1222 p->op_policy_ptr = pol;
1223 }
1224 else
1225 cupsdLogMessage(CUPSD_LOG_ERROR,
1226 "Bad policy \"%s\" on line %d of printers.conf",
1227 value, linenum);
1228 }
ef416fc2 1229 else
ef416fc2 1230 cupsdLogMessage(CUPSD_LOG_ERROR,
1231 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1232 }
1233 else if (!strcasecmp(line, "ErrorPolicy"))
1234 {
1235 if (value)
1236 cupsdSetString(&p->error_policy, value);
1237 else
ef416fc2 1238 cupsdLogMessage(CUPSD_LOG_ERROR,
1239 "Syntax error on line %d of printers.conf.", linenum);
ef416fc2 1240 }
20fbc903
MS
1241 else if (!strcasecmp(line, "Attribute") && value)
1242 {
1243 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
1244
1245 if (!*valueptr)
1246 cupsdLogMessage(CUPSD_LOG_ERROR,
1247 "Syntax error on line %d of printers.conf.", linenum);
1248 else
1249 {
1250 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
1251
8922323b
MS
1252 if (!p->attrs)
1253 cupsdSetPrinterAttrs(p);
1254
20fbc903
MS
1255 cupsdSetPrinterAttr(p, value, valueptr);
1256
1257 if (!strncmp(value, "marker-", 7))
1258 p->marker_time = time(NULL);
1259 }
1260 }
ef416fc2 1261 else
1262 {
1263 /*
1264 * Something else we don't understand...
1265 */
1266
1267 cupsdLogMessage(CUPSD_LOG_ERROR,
1268 "Unknown configuration directive %s on line %d of printers.conf.",
1269 line, linenum);
1270 }
1271 }
1272
1273 cupsFileClose(fp);
1274}
1275
1276
b423cd4c 1277/*
1278 * 'cupsdRenamePrinter()' - Rename a printer.
1279 */
1280
1281void
1282cupsdRenamePrinter(
1283 cupsd_printer_t *p, /* I - Printer */
1284 const char *name) /* I - New name */
1285{
1286 /*
1287 * Remove the printer from the array(s) first...
1288 */
1289
1f0275e3
MS
1290 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1291 "cupsdRenamePrinter: Removing %s from Printers", p->name);
b423cd4c 1292 cupsArrayRemove(Printers, p);
1293
1294 if (p->type & CUPS_PRINTER_IMPLICIT)
1f0275e3
MS
1295 {
1296 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1297 "cupsdRenamePrinter: Removing %s from ImplicitPrinters",
1298 p->name);
b423cd4c 1299 cupsArrayRemove(ImplicitPrinters, p);
1f0275e3 1300 }
b423cd4c 1301
1302 /*
1303 * Rename the printer type...
1304 */
1305
1306 mimeDeleteType(MimeDatabase, p->filetype);
1307 p->filetype = mimeAddType(MimeDatabase, "printer", name);
1308
f7deaa1a 1309 mimeDeleteType(MimeDatabase, p->prefiltertype);
1310 p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);
1311
b423cd4c 1312 /*
1313 * Rename the printer...
1314 */
1315
a74454a7 1316 cupsdSetString(&p->name, name);
b423cd4c 1317
1318 /*
1319 * Reset printer attributes...
1320 */
1321
1322 cupsdSetPrinterAttrs(p);
1323
1324 /*
1325 * Add the printer back to the printer array(s)...
1326 */
1327
1f0275e3
MS
1328 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1329 "cupsdRenamePrinter: Adding %s to Printers", p->name);
b423cd4c 1330 cupsArrayAdd(Printers, p);
8ca02f3c 1331
b423cd4c 1332 if (p->type & CUPS_PRINTER_IMPLICIT)
1f0275e3
MS
1333 {
1334 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1335 "cupsdRenamePrinter: Adding %s to ImplicitPrinters",
1336 p->name);
b423cd4c 1337 cupsArrayAdd(ImplicitPrinters, p);
1f0275e3 1338 }
b423cd4c 1339}
1340
1341
ef416fc2 1342/*
1343 * 'cupsdSaveAllPrinters()' - Save all printer definitions to the printers.conf
1344 * file.
1345 */
1346
1347void
1348cupsdSaveAllPrinters(void)
1349{
1350 int i; /* Looping var */
1351 cups_file_t *fp; /* printers.conf file */
1352 char temp[1024]; /* Temporary string */
1353 char backup[1024]; /* printers.conf.O file */
1354 cupsd_printer_t *printer; /* Current printer class */
1355 time_t curtime; /* Current time */
1356 struct tm *curdate; /* Current date */
b423cd4c 1357 cups_option_t *option; /* Current option */
f7deaa1a 1358 const char *ptr; /* Pointer into info/location */
20fbc903 1359 ipp_attribute_t *marker; /* Current marker attribute */
ef416fc2 1360
1361
1362 /*
1363 * Create the printers.conf file...
1364 */
1365
1366 snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
1367 snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
1368
1369 if (rename(temp, backup))
1370 {
1371 if (errno != ENOENT)
1372 cupsdLogMessage(CUPSD_LOG_ERROR,
1373 "Unable to backup printers.conf - %s", strerror(errno));
1374 }
1375
1376 if ((fp = cupsFileOpen(temp, "w")) == NULL)
1377 {
1378 cupsdLogMessage(CUPSD_LOG_ERROR,
1379 "Unable to save printers.conf - %s", strerror(errno));
1380
1381 if (rename(backup, temp))
1382 cupsdLogMessage(CUPSD_LOG_ERROR,
1383 "Unable to restore printers.conf - %s", strerror(errno));
1384 return;
1385 }
1386 else
1387 cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf...");
1388
1389 /*
1390 * Restrict access to the file...
1391 */
1392
1393 fchown(cupsFileNumber(fp), getuid(), Group);
fa73b229 1394 fchmod(cupsFileNumber(fp), 0600);
ef416fc2 1395
1396 /*
1397 * Write a small header to the file...
1398 */
1399
1400 curtime = time(NULL);
1401 curdate = localtime(&curtime);
1402 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
1403
1404 cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
1405 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
1406
1407 /*
1408 * Write each local printer known to the system...
1409 */
1410
1411 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
1412 printer;
1413 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
1414 {
1415 /*
1416 * Skip remote destinations and printer classes...
1417 */
1418
09a101d6 1419 if ((printer->type & CUPS_PRINTER_DISCOVERED) ||
ef416fc2 1420 (printer->type & CUPS_PRINTER_CLASS) ||
1421 (printer->type & CUPS_PRINTER_IMPLICIT))
1422 continue;
1423
1424 /*
1425 * Write printers as needed...
1426 */
1427
1428 if (printer == DefaultPrinter)
1429 cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name);
1430 else
1431 cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
1432
f7deaa1a 1433 if (printer->num_auth_info_required > 0)
1434 {
1435 cupsFilePrintf(fp, "AuthInfoRequired %s", printer->auth_info_required[0]);
1436 for (i = 1; i < printer->num_auth_info_required; i ++)
1437 cupsFilePrintf(fp, ",%s", printer->auth_info_required[i]);
1438 cupsFilePutChar(fp, '\n');
1439 }
1440
ef416fc2 1441 if (printer->info)
f7deaa1a 1442 {
1443 if ((ptr = strchr(printer->info, '#')) != NULL)
1444 {
1445 /*
1446 * Need to quote the first # in the info string...
1447 */
1448
1449 cupsFilePuts(fp, "Info ");
1450 cupsFileWrite(fp, printer->info, ptr - printer->info);
1451 cupsFilePutChar(fp, '\\');
1452 cupsFilePuts(fp, ptr);
1453 cupsFilePutChar(fp, '\n');
1454 }
1455 else
1456 cupsFilePrintf(fp, "Info %s\n", printer->info);
1457 }
ef416fc2 1458
1459 if (printer->location)
f7deaa1a 1460 {
1461 if ((ptr = strchr(printer->info, '#')) != NULL)
1462 {
1463 /*
1464 * Need to quote the first # in the location string...
1465 */
ef416fc2 1466
f7deaa1a 1467 cupsFilePuts(fp, "Location ");
1468 cupsFileWrite(fp, printer->location, ptr - printer->location);
1469 cupsFilePutChar(fp, '\\');
1470 cupsFilePuts(fp, ptr);
1471 cupsFilePutChar(fp, '\n');
1472 }
1473 else
1474 cupsFilePrintf(fp, "Location %s\n", printer->location);
1475 }
0af14961 1476 cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
ef416fc2 1477
1478 if (printer->port_monitor)
1479 cupsFilePrintf(fp, "PortMonitor %s\n", printer->port_monitor);
1480
1481 if (printer->state == IPP_PRINTER_STOPPED)
1482 {
1483 cupsFilePuts(fp, "State Stopped\n");
1484 cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
1485 }
1486 else
1487 cupsFilePuts(fp, "State Idle\n");
1488
1489 cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
1490
0af14961
MS
1491 for (i = 0; i < printer->num_reasons; i ++)
1492 cupsFilePrintf(fp, "Reason %s\n", printer->reasons[i]);
1493
ef416fc2 1494 if (printer->accepting)
1495 cupsFilePuts(fp, "Accepting Yes\n");
1496 else
1497 cupsFilePuts(fp, "Accepting No\n");
1498
1499 if (printer->shared)
1500 cupsFilePuts(fp, "Shared Yes\n");
1501 else
1502 cupsFilePuts(fp, "Shared No\n");
1503
1504 cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
1505 printer->job_sheets[1]);
1506
1507 cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period);
1508 cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
1509 cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
1510
1511 for (i = 0; i < printer->num_users; i ++)
8922323b
MS
1512 {
1513 if ((ptr = strchr(printer->users[i], '#')) != NULL)
1514 {
1515 /*
1516 * Need to quote the first # in the user string...
1517 */
1518
1519 cupsFilePrintf(fp, "%sUser ", printer->deny_users ? "Deny" : "Allow");
1520 cupsFileWrite(fp, printer->users[i], ptr - printer->users[i]);
1521 cupsFilePutChar(fp, '\\');
1522 cupsFilePuts(fp, ptr);
1523 cupsFilePutChar(fp, '\n');
1524 }
1525 else
1526 cupsFilePrintf(fp, "%sUser %s\n",
1527 printer->deny_users ? "Deny" : "Allow",
1528 printer->users[i]);
1529 }
ef416fc2 1530
1531 if (printer->op_policy)
1532 cupsFilePrintf(fp, "OpPolicy %s\n", printer->op_policy);
1533 if (printer->error_policy)
1534 cupsFilePrintf(fp, "ErrorPolicy %s\n", printer->error_policy);
1535
b423cd4c 1536 for (i = printer->num_options, option = printer->options;
1537 i > 0;
1538 i --, option ++)
8922323b
MS
1539 {
1540 if ((ptr = strchr(option->value, '#')) != NULL)
1541 {
1542 /*
1543 * Need to quote the first # in the option string...
1544 */
1545
1546 cupsFilePrintf(fp, "Option %s ", option->name);
1547 cupsFileWrite(fp, option->value, ptr - option->value);
1548 cupsFilePutChar(fp, '\\');
1549 cupsFilePuts(fp, ptr);
1550 cupsFilePutChar(fp, '\n');
1551 }
1552 else
1553 cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value);
1554 }
b423cd4c 1555
20fbc903
MS
1556 if ((marker = ippFindAttribute(printer->attrs, "marker-colors",
1557 IPP_TAG_NAME)) != NULL)
1558 {
8922323b
MS
1559 cupsFilePrintf(fp, "Attribute %s ", marker->name);
1560
1561 for (i = 0, ptr = NULL; i < marker->num_values; i ++)
1562 {
1563 if (i)
1564 cupsFilePutChar(fp, ',');
1565
1566 if (!ptr && (ptr = strchr(marker->values[i].string.text, '#')) != NULL)
1567 {
1568 cupsFileWrite(fp, marker->values[i].string.text,
1569 ptr - marker->values[i].string.text);
1570 cupsFilePutChar(fp, '\\');
1571 cupsFilePuts(fp, ptr);
1572 }
1573 else
1574 cupsFilePuts(fp, marker->values[i].string.text);
1575 }
1576
20fbc903
MS
1577 cupsFilePuts(fp, "\n");
1578 }
1579
1580 if ((marker = ippFindAttribute(printer->attrs, "marker-levels",
1581 IPP_TAG_INTEGER)) != NULL)
1582 {
1583 cupsFilePrintf(fp, "Attribute %s %d", marker->name,
1584 marker->values[0].integer);
1585 for (i = 1; i < marker->num_values; i ++)
1586 cupsFilePrintf(fp, ",%d", marker->values[i].integer);
1587 cupsFilePuts(fp, "\n");
1588 }
1589
75bd9771
MS
1590 if ((marker = ippFindAttribute(printer->attrs, "marker-message",
1591 IPP_TAG_TEXT)) != NULL)
1592 {
1593 cupsFilePrintf(fp, "Attribute %s ", marker->name);
1594
1f0275e3 1595 if ((ptr = strchr(marker->values[0].string.text, '#')) != NULL)
75bd9771
MS
1596 {
1597 cupsFileWrite(fp, marker->values[0].string.text,
1598 ptr - marker->values[0].string.text);
1599 cupsFilePutChar(fp, '\\');
1600 cupsFilePuts(fp, ptr);
1601 }
1602 else
1603 cupsFilePuts(fp, marker->values[0].string.text);
1604
1605 cupsFilePuts(fp, "\n");
1606 }
1607
20fbc903
MS
1608 if ((marker = ippFindAttribute(printer->attrs, "marker-names",
1609 IPP_TAG_NAME)) != NULL)
1610 {
8922323b
MS
1611 cupsFilePrintf(fp, "Attribute %s ", marker->name);
1612
1613 for (i = 0, ptr = NULL; i < marker->num_values; i ++)
1614 {
1615 if (i)
1616 cupsFilePutChar(fp, ',');
1617
1618 if (!ptr && (ptr = strchr(marker->values[i].string.text, '#')) != NULL)
1619 {
1620 cupsFileWrite(fp, marker->values[i].string.text,
1621 ptr - marker->values[i].string.text);
1622 cupsFilePutChar(fp, '\\');
1623 cupsFilePuts(fp, ptr);
1624 }
1625 else
1626 cupsFilePuts(fp, marker->values[i].string.text);
1627 }
1628
20fbc903
MS
1629 cupsFilePuts(fp, "\n");
1630 }
1631
1632 if ((marker = ippFindAttribute(printer->attrs, "marker-types",
1633 IPP_TAG_KEYWORD)) != NULL)
1634 {
8922323b
MS
1635 cupsFilePrintf(fp, "Attribute %s ", marker->name);
1636
1637 for (i = 0, ptr = NULL; i < marker->num_values; i ++)
1638 {
1639 if (i)
1640 cupsFilePutChar(fp, ',');
1641
1642 if (!ptr && (ptr = strchr(marker->values[i].string.text, '#')) != NULL)
1643 {
1644 cupsFileWrite(fp, marker->values[i].string.text,
1645 ptr - marker->values[i].string.text);
1646 cupsFilePutChar(fp, '\\');
1647 cupsFilePuts(fp, ptr);
1648 }
1649 else
1650 cupsFilePuts(fp, marker->values[i].string.text);
1651 }
1652
20fbc903
MS
1653 cupsFilePuts(fp, "\n");
1654 }
1655
ef416fc2 1656 cupsFilePuts(fp, "</Printer>\n");
1657
1658#ifdef __sgi
1659 /*
1660 * Make IRIX desktop & printer status happy
1661 */
1662
1663 write_irix_state(printer);
1664#endif /* __sgi */
1665 }
1666
1667 cupsFileClose(fp);
1668}
1669
1670
f7deaa1a 1671/*
1672 * 'cupsdSetAuthInfoRequired()' - Set the required authentication info.
1673 */
1674
1675int /* O - 1 if value OK, 0 otherwise */
1676cupsdSetAuthInfoRequired(
1677 cupsd_printer_t *p, /* I - Printer */
1678 const char *values, /* I - Plain text value (or NULL) */
1679 ipp_attribute_t *attr) /* I - IPP attribute value (or NULL) */
1680{
1681 int i; /* Looping var */
1682
1683
1684 p->num_auth_info_required = 0;
1685
1686 /*
1687 * Do we have a plain text value?
1688 */
1689
1690 if (values)
1691 {
1692 /*
1693 * Yes, grab the keywords...
1694 */
1695
1696 const char *end; /* End of current value */
1697
1698
1699 while (*values && p->num_auth_info_required < 4)
1700 {
1701 if ((end = strchr(values, ',')) == NULL)
1702 end = values + strlen(values);
1703
f899b121 1704 if ((end - values) == 4 && !strncmp(values, "none", 4))
f7deaa1a 1705 {
1706 if (p->num_auth_info_required != 0 || *end)
1707 return (0);
1708
1709 p->auth_info_required[p->num_auth_info_required] = "none";
1710 p->num_auth_info_required ++;
1711
1712 return (1);
1713 }
f899b121 1714 else if ((end - values) == 9 && !strncmp(values, "negotiate", 9))
1715 {
1716 if (p->num_auth_info_required != 0 || *end)
1717 return (0);
1718
1719 p->auth_info_required[p->num_auth_info_required] = "negotiate";
1720 p->num_auth_info_required ++;
f899b121 1721 }
1722 else if ((end - values) == 6 && !strncmp(values, "domain", 6))
f7deaa1a 1723 {
1724 p->auth_info_required[p->num_auth_info_required] = "domain";
1725 p->num_auth_info_required ++;
1726 }
f899b121 1727 else if ((end - values) == 8 && !strncmp(values, "password", 8))
f7deaa1a 1728 {
1729 p->auth_info_required[p->num_auth_info_required] = "password";
1730 p->num_auth_info_required ++;
1731 }
f899b121 1732 else if ((end - values) == 8 && !strncmp(values, "username", 8))
f7deaa1a 1733 {
1734 p->auth_info_required[p->num_auth_info_required] = "username";
1735 p->num_auth_info_required ++;
1736 }
1737 else
1738 return (0);
09a101d6 1739
1740 values = (*end) ? end + 1 : end;
f7deaa1a 1741 }
1742
1743 if (p->num_auth_info_required == 0)
1744 {
1745 p->auth_info_required[0] = "none";
1746 p->num_auth_info_required = 1;
1747 }
1748
09a101d6 1749 /*
1750 * Update the printer-type value as needed...
1751 */
1752
1753 if (p->num_auth_info_required > 1 ||
1754 strcmp(p->auth_info_required[0], "none"))
1755 p->type |= CUPS_PRINTER_AUTHENTICATED;
1756 else
1757 p->type &= ~CUPS_PRINTER_AUTHENTICATED;
1758
f7deaa1a 1759 return (1);
1760 }
1761
1762 /*
1763 * Grab values from an attribute instead...
1764 */
1765
1766 if (!attr || attr->num_values > 4)
1767 return (0);
1768
09a101d6 1769 /*
1770 * Update the printer-type value as needed...
1771 */
1772
1773 if (attr->num_values > 1 ||
1774 strcmp(attr->values[0].string.text, "none"))
1775 p->type |= CUPS_PRINTER_AUTHENTICATED;
1776 else
1777 p->type &= ~CUPS_PRINTER_AUTHENTICATED;
1778
f7deaa1a 1779 for (i = 0; i < attr->num_values; i ++)
1780 {
1781 if (!strcmp(attr->values[i].string.text, "none"))
1782 {
1783 if (p->num_auth_info_required != 0 || attr->num_values != 1)
1784 return (0);
1785
1786 p->auth_info_required[p->num_auth_info_required] = "none";
1787 p->num_auth_info_required ++;
1788
1789 return (1);
1790 }
f899b121 1791 else if (!strcmp(attr->values[i].string.text, "negotiate"))
1792 {
1793 if (p->num_auth_info_required != 0 || attr->num_values != 1)
1794 return (0);
1795
1796 p->auth_info_required[p->num_auth_info_required] = "negotiate";
1797 p->num_auth_info_required ++;
1798
1799 return (1);
1800 }
f7deaa1a 1801 else if (!strcmp(attr->values[i].string.text, "domain"))
1802 {
1803 p->auth_info_required[p->num_auth_info_required] = "domain";
1804 p->num_auth_info_required ++;
1805 }
1806 else if (!strcmp(attr->values[i].string.text, "password"))
1807 {
1808 p->auth_info_required[p->num_auth_info_required] = "password";
1809 p->num_auth_info_required ++;
1810 }
1811 else if (!strcmp(attr->values[i].string.text, "username"))
1812 {
1813 p->auth_info_required[p->num_auth_info_required] = "username";
1814 p->num_auth_info_required ++;
1815 }
1816 else
1817 return (0);
1818 }
1819
1820 return (1);
1821}
1822
1823
0af14961
MS
1824/*
1825 * 'cupsdSetDeviceURI()' - Set the device URI for a printer.
1826 */
1827
1828void
1829cupsdSetDeviceURI(cupsd_printer_t *p, /* I - Printer */
1830 const char *uri) /* I - Device URI */
1831{
1832 char buffer[1024], /* URI buffer */
1833 *start, /* Start of data after scheme */
1834 *slash, /* First slash after scheme:// */
1835 *ptr; /* Pointer into user@host:port part */
1836
1837
1838 /*
1839 * Set the full device URI..
1840 */
1841
1842 cupsdSetString(&(p->device_uri), uri);
1843
1844 /*
1845 * Copy the device URI to a temporary buffer so we can sanitize any auth
1846 * info in it...
1847 */
1848
1849 strlcpy(buffer, uri, sizeof(buffer));
1850
1851 /*
1852 * Find the end of the scheme:// part...
1853 */
1854
1855 if ((ptr = strchr(buffer, ':')) != NULL)
1856 {
1857 for (start = ptr + 1; *start; start ++)
1858 if (*start != '/')
1859 break;
1860
1861 /*
1862 * Find the next slash (/) in the URI...
1863 */
1864
1865 if ((slash = strchr(start, '/')) == NULL)
1866 slash = start + strlen(start); /* No slash, point to the end */
1867
1868 /*
1869 * Check for an @ sign before the slash...
1870 */
1871
1872 if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
1873 {
1874 /*
1875 * Found an @ sign and it is before the resource part, so we have
1876 * an authentication string. Copy the remaining URI over the
1877 * authentication string...
1878 */
1879
1880 _cups_strcpy(start, ptr + 1);
1881 }
1882 }
1883
1884 /*
1885 * Save the sanitized URI...
1886 */
1887
1888 cupsdSetString(&(p->sanitized_device_uri), buffer);
1889}
1890
1891
5a738aea
MS
1892/*
1893 * 'cupsdSetPrinterAttr()' - Set a printer attribute.
1894 */
1895
1896void
1897cupsdSetPrinterAttr(
1898 cupsd_printer_t *p, /* I - Printer */
1899 const char *name, /* I - Attribute name */
1900 char *value) /* I - Attribute value string */
1901{
1902 ipp_attribute_t *attr; /* Attribute */
1903 int i, /* Looping var */
1904 count; /* Number of values */
1905 char *ptr; /* Pointer into value */
1906 ipp_tag_t value_tag; /* Value tag for this attribute */
1907
1908
1909 /*
1910 * Count the number of values...
1911 */
1912
1913 for (count = 1, ptr = value;
1914 (ptr = strchr(ptr, ',')) != NULL;
1915 ptr ++, count ++);
1916
1917 /*
1918 * Then add or update the attribute as needed...
1919 */
1920
1921 if (!strcmp(name, "marker-levels"))
1922 {
1923 /*
1924 * Integer values...
1925 */
1926
1927 if ((attr = ippFindAttribute(p->attrs, name, IPP_TAG_INTEGER)) != NULL &&
1928 attr->num_values < count)
1929 {
1930 ippDeleteAttribute(p->attrs, attr);
1931 attr = NULL;
1932 }
1933
1934 if (attr)
1935 attr->num_values = count;
1936 else
1937 attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, name,
1938 count, NULL);
1939
1940 if (!attr)
1941 {
1942 cupsdLogMessage(CUPSD_LOG_ERROR,
1943 "Unable to allocate memory for printer attribute "
1944 "(%d values)", count);
1945 return;
1946 }
1947
1948 for (i = 0; i < count; i ++)
1949 {
1950 if ((ptr = strchr(value, ',')) != NULL)
1951 *ptr++ = '\0';
1952
1953 attr->values[i].integer = strtol(value, NULL, 10);
1954
1955 if (ptr)
1956 value = ptr;
1957 }
1958 }
1959 else
1960 {
1961 /*
1962 * Name or keyword values...
1963 */
1964
1965 if (!strcmp(name, "marker-types"))
1966 value_tag = IPP_TAG_KEYWORD;
75bd9771
MS
1967 else if (!strcmp(name, "marker-message"))
1968 value_tag = IPP_TAG_TEXT;
5a738aea
MS
1969 else
1970 value_tag = IPP_TAG_NAME;
1971
1972 if ((attr = ippFindAttribute(p->attrs, name, value_tag)) != NULL &&
1973 attr->num_values < count)
1974 {
1975 ippDeleteAttribute(p->attrs, attr);
1976 attr = NULL;
1977 }
1978
1979 if (attr)
75bd9771
MS
1980 {
1981 for (i = 0; i < attr->num_values; i ++)
1982 _cupsStrFree(attr->values[i].string.text);
1983
5a738aea 1984 attr->num_values = count;
75bd9771 1985 }
5a738aea
MS
1986 else
1987 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, value_tag, name,
1988 count, NULL, NULL);
1989
1990 if (!attr)
1991 {
1992 cupsdLogMessage(CUPSD_LOG_ERROR,
1993 "Unable to allocate memory for printer attribute "
1994 "(%d values)", count);
1995 return;
1996 }
1997
1998 for (i = 0; i < count; i ++)
1999 {
2000 if ((ptr = strchr(value, ',')) != NULL)
2001 *ptr++ = '\0';
2002
5a738aea
MS
2003 attr->values[i].string.text = _cupsStrAlloc(value);
2004
2005 if (ptr)
2006 value = ptr;
2007 }
2008 }
20fbc903
MS
2009
2010 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5a738aea
MS
2011}
2012
2013
ef416fc2 2014/*
2015 * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file.
2016 */
2017
2018void
2019cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
2020{
b423cd4c 2021 int i, /* Looping var */
2022 length; /* Length of browse attributes */
b423cd4c 2023 char resource[HTTP_MAX_URI]; /* Resource portion of URI */
2024 char filename[1024]; /* Name of PPD file */
bc44d920 2025 int num_air; /* Number of auth-info-required values */
2026 const char * const *air; /* auth-info-required values */
b423cd4c 2027 int num_media; /* Number of media options */
2028 cupsd_location_t *auth; /* Pointer to authentication element */
2029 const char *auth_supported; /* Authentication supported */
b423cd4c 2030 ppd_file_t *ppd; /* PPD file data */
2031 ppd_option_t *input_slot, /* InputSlot options */
2032 *media_type, /* MediaType options */
2033 *page_size, /* PageSize options */
2034 *output_bin, /* OutputBin options */
2035 *media_quality, /* EFMediaQualityMode options */
2036 *duplex; /* Duplex options */
2037 ppd_attr_t *ppdattr; /* PPD attribute */
8922323b 2038 ipp_t *oldattrs; /* Old printer attributes */
b423cd4c 2039 ipp_attribute_t *attr; /* Attribute data */
2040 ipp_value_t *val; /* Attribute value */
2041 int num_finishings; /* Number of finishings */
b94498cf 2042 int finishings[5]; /* finishings-supported values */
b423cd4c 2043 cups_option_t *option; /* Current printer option */
ef416fc2 2044 static const char * const sides[3] = /* sides-supported values */
2045 {
b423cd4c 2046 "one-sided",
2047 "two-sided-long-edge",
2048 "two-sided-short-edge"
ef416fc2 2049 };
bc44d920 2050 static const char * const air_userpass[] =
2051 { /* Basic/Digest authentication */
2052 "username",
2053 "password"
2054 };
a4924f6c 2055#ifdef HAVE_GSSAPI
bc44d920 2056 static const char * const air_negotiate[] =
2057 { /* Kerberos authentication */
2058 "negotiate"
2059 };
a4924f6c 2060#endif /* HAVE_GSSAPI */
bc44d920 2061 static const char * const air_none[] =
2062 { /* No authentication */
2063 "none"
2064 };
01ce6322
MS
2065 static const char * const standard_commands[] =
2066 { /* Standard CUPS commands */
2067 "AutoConfigure",
2068 "Clean",
2069 "PrintSelfTestPage",
2070 "ReportLevels"
2071 };
ef416fc2 2072
2073
2074 DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
2075 p->type));
2076
2077 /*
2078 * Make sure that we have the common attributes defined...
2079 */
2080
2081 if (!CommonData)
2082 cupsdCreateCommonData();
2083
2084 /*
2085 * Clear out old filters, if any...
2086 */
2087
e1d6a774 2088 delete_printer_filters(p);
ef416fc2 2089
2090 /*
2091 * Figure out the authentication that is required for the printer.
2092 */
2093
2094 auth_supported = "requesting-user-name";
bc44d920 2095 num_air = 1;
2096 air = air_none;
2097
2098 if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
2099 {
2100 num_air = p->num_auth_info_required;
2101 air = p->auth_info_required;
2102
2103 if (!strcmp(air[0], "username"))
2104 auth_supported = "basic";
2105 else
2106 auth_supported = "negotiate";
2107 }
2108 else if (!(p->type & CUPS_PRINTER_DISCOVERED))
ef416fc2 2109 {
2110 if (p->type & CUPS_PRINTER_CLASS)
2111 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
2112 else
2113 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
2114
d09495fa 2115 if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
5bd77a73 2116 auth->type == CUPSD_AUTH_NONE)
ef416fc2 2117 auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
2118
2119 if (auth)
2120 {
9a4f8274
MS
2121 int auth_type; /* Authentication type */
2122
2123
2124 if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
2125 auth_type = DefaultAuthType;
2126
2127 if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
f899b121 2128 {
ef416fc2 2129 auth_supported = "basic";
bc44d920 2130 num_air = 2;
2131 air = air_userpass;
f899b121 2132 }
9a4f8274 2133 else if (auth_type == CUPSD_AUTH_DIGEST)
f899b121 2134 {
ef416fc2 2135 auth_supported = "digest";
bc44d920 2136 num_air = 2;
2137 air = air_userpass;
f899b121 2138 }
2139#ifdef HAVE_GSSAPI
9a4f8274 2140 else if (auth_type == CUPSD_AUTH_NEGOTIATE)
f899b121 2141 {
2142 auth_supported = "negotiate";
bc44d920 2143 num_air = 1;
2144 air = air_negotiate;
f899b121 2145 }
2146#endif /* HAVE_GSSAPI */
ef416fc2 2147
9a4f8274 2148 if (auth_type != CUPSD_AUTH_NONE)
ef416fc2 2149 p->type |= CUPS_PRINTER_AUTHENTICATED;
2150 else
2151 p->type &= ~CUPS_PRINTER_AUTHENTICATED;
2152 }
2153 else
2154 p->type &= ~CUPS_PRINTER_AUTHENTICATED;
2155 }
bc44d920 2156 else if (p->type & CUPS_PRINTER_AUTHENTICATED)
2157 {
2158 num_air = 2;
2159 air = air_userpass;
2160 }
ef416fc2 2161
2162 /*
2163 * Create the required IPP attributes for a printer...
2164 */
2165
8922323b 2166 oldattrs = p->attrs;
ef416fc2 2167 p->attrs = ippNew();
2168
2169 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2170 "uri-authentication-supported", NULL, auth_supported);
2171 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2172 "uri-security-supported", NULL, "none");
2173 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
2174 p->name);
2175 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
2176 NULL, p->location ? p->location : "");
2177 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
2178 NULL, p->info ? p->info : "");
2179 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
2180 NULL, p->uri);
2181
2182 if (p->num_users)
2183 {
2184 if (p->deny_users)
2185 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2186 "requesting-user-name-denied", p->num_users, NULL,
2187 p->users);
2188 else
2189 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2190 "requesting-user-name-allowed", p->num_users, NULL,
2191 p->users);
2192 }
2193
2194 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2195 "job-quota-period", p->quota_period);
2196 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2197 "job-k-limit", p->k_limit);
2198 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2199 "job-page-limit", p->page_limit);
bc44d920 2200 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2201 "auth-info-required", num_air, NULL, air);
ef416fc2 2202
09a101d6 2203 if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_DISCOVERED))
ef416fc2 2204 {
2205 /*
2206 * Setup the job-sheets-default attribute...
2207 */
2208
2209 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2210 "job-sheets-default", 2, NULL, NULL);
2211
2212 if (attr != NULL)
2213 {
757d2cad 2214 attr->values[0].string.text = _cupsStrAlloc(Classification ?
ef416fc2 2215 Classification : p->job_sheets[0]);
757d2cad 2216 attr->values[1].string.text = _cupsStrAlloc(Classification ?
ef416fc2 2217 Classification : p->job_sheets[1]);
2218 }
2219 }
2220
d09495fa 2221 p->raw = 0;
2222 p->remote = 0;
ef416fc2 2223
09a101d6 2224 if (p->type & CUPS_PRINTER_DISCOVERED)
ef416fc2 2225 {
2226 /*
2227 * Tell the client this is a remote printer of some type...
2228 */
2229
2230 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
2231 "printer-uri-supported", NULL, p->uri);
2232
2233 if (p->make_model)
2234 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2235 "printer-make-and-model", NULL, p->make_model);
2236
fa73b229 2237 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
2238 p->uri);
2239
d09495fa 2240 p->raw = 1;
2241 p->remote = 1;
ef416fc2 2242 }
2243 else
2244 {
2245 /*
2246 * Assign additional attributes depending on whether this is a printer
2247 * or class...
2248 */
2249
2250 p->type &= ~CUPS_PRINTER_OPTIONS;
2251
2252 if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
2253 {
2254 p->raw = 1;
2255
2256 /*
2257 * Add class-specific attributes...
2258 */
2259
2260 if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 &&
2261 p->printers[0]->make_model)
2262 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2263 "printer-make-and-model", NULL, p->printers[0]->make_model);
2264 else
2265 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2266 "printer-make-and-model", NULL, "Local Printer Class");
2267
fa73b229 2268 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
2269 "file:///dev/null");
2270
ef416fc2 2271 if (p->num_printers > 0)
2272 {
2273 /*
dd1abb6b 2274 * Add a list of member names; URIs are added in copy_printer_attrs...
ef416fc2 2275 */
2276
dd1abb6b
MS
2277 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2278 "member-names", p->num_printers, NULL, NULL);
ef416fc2 2279 p->type |= CUPS_PRINTER_OPTIONS;
2280
2281 for (i = 0; i < p->num_printers; i ++)
2282 {
2283 if (attr != NULL)
dd1abb6b 2284 attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name);
ef416fc2 2285
2286 p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
2287 }
ef416fc2 2288 }
2289 }
2290 else
2291 {
2292 /*
0af14961 2293 * Add printer-specific attributes...
ef416fc2 2294 */
2295
ef416fc2 2296 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
0af14961 2297 p->sanitized_device_uri);
ef416fc2 2298
2299 /*
2300 * Assign additional attributes from the PPD file (if any)...
2301 */
2302
2303 p->type |= CUPS_PRINTER_BW;
2304 finishings[0] = IPP_FINISHINGS_NONE;
2305 num_finishings = 1;
2306
2307 snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
2308 p->name);
2309
2310 if ((ppd = ppdOpenFile(filename)) != NULL)
2311 {
2312 /*
2313 * Add make/model and other various attributes...
2314 */
2315
2316 if (ppd->color_device)
2317 p->type |= CUPS_PRINTER_COLOR;
2318 if (ppd->variable_sizes)
2319 p->type |= CUPS_PRINTER_VARIABLE;
2320 if (!ppd->manual_copies)
2321 p->type |= CUPS_PRINTER_COPIES;
2322 if ((ppdattr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
2323 if (ppdattr->value && !strcasecmp(ppdattr->value, "true"))
2324 p->type |= CUPS_PRINTER_FAX;
2325
2326 ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
2327 ppd->color_device);
2328 if (ppd->throughput)
2329 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2330 "pages-per-minute", ppd->throughput);
2331
2332 if (ppd->nickname)
bd7854cb 2333 {
2334 /*
2335 * The NickName can be localized in the character set specified
e1d6a774 2336 * by the LanugageEncoding attribute. However, ppdOpen2() has
2337 * already converted the ppd->nickname member to UTF-8 for us
2338 * (the original attribute value is available separately)
bd7854cb 2339 */
2340
e1d6a774 2341 cupsdSetString(&p->make_model, ppd->nickname);
bd7854cb 2342 }
ef416fc2 2343 else if (ppd->modelname)
e1d6a774 2344 {
2345 /*
2346 * Model name can only contain specific characters...
2347 */
2348
ef416fc2 2349 cupsdSetString(&p->make_model, ppd->modelname);
e1d6a774 2350 }
ef416fc2 2351 else
2352 cupsdSetString(&p->make_model, "Bad PPD File");
2353
bd7854cb 2354 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2355 "printer-make-and-model", NULL, p->make_model);
ef416fc2 2356
2357 /*
2358 * Add media options from the PPD file...
2359 */
2360
2361 if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
2362 num_media = input_slot->num_choices;
2363 else
2364 num_media = 0;
2365
2366 if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
2367 num_media += media_type->num_choices;
2368
2369 if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
2370 num_media += page_size->num_choices;
2371
2372 if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL)
2373 num_media += media_quality->num_choices;
2374
2375 if (num_media == 0)
2376 {
bd7854cb 2377 cupsdLogMessage(CUPSD_LOG_CRIT,
b423cd4c 2378 "The PPD file for printer %s contains no media "
2379 "options and is therefore invalid!", p->name);
ef416fc2 2380 }
2381 else
2382 {
2383 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2384 "media-supported", num_media, NULL, NULL);
2385 if (attr != NULL)
2386 {
2387 val = attr->values;
2388
2389 if (input_slot != NULL)
2390 for (i = 0; i < input_slot->num_choices; i ++, val ++)
757d2cad 2391 val->string.text = _cupsStrAlloc(input_slot->choices[i].choice);
ef416fc2 2392
2393 if (media_type != NULL)
2394 for (i = 0; i < media_type->num_choices; i ++, val ++)
757d2cad 2395 val->string.text = _cupsStrAlloc(media_type->choices[i].choice);
ef416fc2 2396
2397 if (media_quality != NULL)
2398 for (i = 0; i < media_quality->num_choices; i ++, val ++)
757d2cad 2399 val->string.text = _cupsStrAlloc(media_quality->choices[i].choice);
ef416fc2 2400
2401 if (page_size != NULL)
2402 {
2403 for (i = 0; i < page_size->num_choices; i ++, val ++)
757d2cad 2404 val->string.text = _cupsStrAlloc(page_size->choices[i].choice);
ef416fc2 2405
b423cd4c 2406 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2407 "media-default", NULL, page_size->defchoice);
ef416fc2 2408 }
2409 else if (input_slot != NULL)
b423cd4c 2410 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2411 "media-default", NULL, input_slot->defchoice);
ef416fc2 2412 else if (media_type != NULL)
b423cd4c 2413 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2414 "media-default", NULL, media_type->defchoice);
ef416fc2 2415 else if (media_quality != NULL)
b423cd4c 2416 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2417 "media-default", NULL, media_quality->defchoice);
ef416fc2 2418 else
b423cd4c 2419 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2420 "media-default", NULL, "none");
ef416fc2 2421 }
2422 }
2423
2424 /*
2425 * Output bin...
2426 */
2427
2428 if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
2429 {
2430 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2431 "output-bin-supported", output_bin->num_choices,
2432 NULL, NULL);
2433
2434 if (attr != NULL)
2435 {
2436 for (i = 0, val = attr->values;
2437 i < output_bin->num_choices;
2438 i ++, val ++)
757d2cad 2439 val->string.text = _cupsStrAlloc(output_bin->choices[i].choice);
ef416fc2 2440 }
2441 }
2442
2443 /*
2444 * Duplexing, etc...
2445 */
2446
b423cd4c 2447 if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
2448 if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
2449 if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
2450 if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
2451 duplex = ppdFindOption(ppd, "JCLDuplex");
2452
005dd1eb
MS
2453 if (duplex && duplex->num_choices > 1 &&
2454 !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
ef416fc2 2455 {
2456 p->type |= CUPS_PRINTER_DUPLEX;
2457
b423cd4c 2458 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2459 "sides-supported", 3, NULL, sides);
2460
2461 if (!strcasecmp(duplex->defchoice, "DuplexTumble"))
2462 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2463 "sides-default", NULL, "two-sided-short-edge");
2464 else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble"))
2465 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2466 "sides-default", NULL, "two-sided-long-edge");
2467 else
2468 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2469 "sides-default", NULL, "one-sided");
ef416fc2 2470 }
2471
2472 if (ppdFindOption(ppd, "Collate") != NULL)
2473 p->type |= CUPS_PRINTER_COLLATE;
2474
2475 if (ppdFindOption(ppd, "StapleLocation") != NULL)
2476 {
2477 p->type |= CUPS_PRINTER_STAPLE;
2478 finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
2479 }
2480
2481 if (ppdFindOption(ppd, "BindEdge") != NULL)
2482 {
2483 p->type |= CUPS_PRINTER_BIND;
2484 finishings[num_finishings++] = IPP_FINISHINGS_BIND;
2485 }
2486
2487 for (i = 0; i < ppd->num_sizes; i ++)
2488 if (ppd->sizes[i].length > 1728)
2489 p->type |= CUPS_PRINTER_LARGE;
2490 else if (ppd->sizes[i].length > 1008)
2491 p->type |= CUPS_PRINTER_MEDIUM;
2492 else
2493 p->type |= CUPS_PRINTER_SMALL;
2494
2495 /*
2496 * Add a filter from application/vnd.cups-raw to printer/name to
2497 * handle "raw" printing by users.
2498 */
2499
f7deaa1a 2500 add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
2501
2502 /*
2503 * Add any pre-filters in the PPD file...
2504 */
2505
2506 if ((ppdattr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
2507 {
2508 p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
2509
2510 for (; ppdattr; ppdattr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
2511 if (ppdattr->value)
2512 add_printer_filter(p, p->prefiltertype, ppdattr->value);
2513 }
ef416fc2 2514
2515 /*
2516 * Add any filters in the PPD file...
2517 */
2518
2519 DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
2520 for (i = 0; i < ppd->num_filters; i ++)
2521 {
2522 DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
f7deaa1a 2523 add_printer_filter(p, p->filetype, ppd->filters[i]);
ef416fc2 2524 }
2525
2526 if (ppd->num_filters == 0)
2527 {
2528 /*
7a14d768 2529 * If there are no filters, add PostScript printing filters.
ef416fc2 2530 */
2531
7a14d768
MS
2532 add_printer_filter(p, p->filetype,
2533 "application/vnd.cups-command 0 commandtops");
f7deaa1a 2534 add_printer_filter(p, p->filetype,
2535 "application/vnd.cups-postscript 0 -");
7a14d768
MS
2536
2537 p->type |= CUPS_PRINTER_COMMANDS;
ef416fc2 2538 }
20fbc903
MS
2539 else if (!(p->type & CUPS_PRINTER_COMMANDS))
2540 {
2541 /*
2542 * See if this is a PostScript device without a command filter...
2543 */
2544
2545 for (i = 0; i < ppd->num_filters; i ++)
2546 if (!strncasecmp(ppd->filters[i],
2547 "application/vnd.cups-postscript", 31))
2548 break;
2549
2550 if (i < ppd->num_filters)
2551 {
2552 /*
2553 * Add the generic PostScript command filter...
2554 */
2555
2556 add_printer_filter(p, p->filetype,
2557 "application/vnd.cups-command 0 commandtops");
2558 p->type |= CUPS_PRINTER_COMMANDS;
2559 }
2560 }
ef416fc2 2561
01ce6322
MS
2562 if (p->type & CUPS_PRINTER_COMMANDS)
2563 {
2564 char *commands, /* Copy of commands */
2565 *start, /* Start of name */
2566 *end; /* End of name */
2567 int count; /* Number of commands */
2568
2569
2570 if ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
2571 ppdattr->value && ppdattr->value[0])
2572 {
2573 for (count = 0, start = ppdattr->value; *start; count ++)
2574 {
2575 while (isspace(*start & 255))
2576 start ++;
2577
2578 if (!*start)
2579 break;
2580
2581 while (*start && !isspace(*start & 255))
2582 start ++;
2583 }
2584 }
2585 else
2586 count = 0;
2587
2588 if (count > 0)
2589 {
2590 /*
2591 * Make a copy of the commands string and count how many ...
2592 */
2593
2594 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2595 "printer-commands", count, NULL, NULL);
2596
2597 commands = strdup(ppdattr->value);
2598
2599 for (count = 0, start = commands; *start; count ++)
2600 {
2601 while (isspace(*start & 255))
2602 start ++;
2603
2604 if (!*start)
2605 break;
2606
2607 end = start;
2608 while (*end && !isspace(*end & 255))
2609 end ++;
2610
2611 if (*end)
2612 *end++ = '\0';
2613
2614 attr->values[count].string.text = _cupsStrAlloc(start);
2615
2616 start = end;
2617 }
2618
2619 free(commands);
2620 }
2621 else
2622 {
2623 /*
2624 * Add the standard list of commands...
2625 */
2626
2627 ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2628 "printer-commands",
2629 (int)(sizeof(standard_commands) /
2630 sizeof(standard_commands[0])), NULL,
2631 standard_commands);
2632 }
2633 }
2634 else
2635 {
2636 /*
2637 * No commands supported...
2638 */
2639
2640 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2641 "printer-commands", NULL, "none");
2642 }
2643
ef416fc2 2644 /*
2645 * Show current and available port monitors for this printer...
2646 */
2647
09a101d6 2648 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
ef416fc2 2649 NULL, p->port_monitor ? p->port_monitor : "none");
2650
ef416fc2 2651 for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
2652 ppdattr;
2653 i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
2654
2655 if (ppd->protocols)
2656 {
2657 if (strstr(ppd->protocols, "TBCP"))
2658 i ++;
2659 else if (strstr(ppd->protocols, "BCP"))
2660 i ++;
2661 }
2662
09a101d6 2663 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
ef416fc2 2664 "port-monitor-supported", i, NULL, NULL);
2665
757d2cad 2666 attr->values[0].string.text = _cupsStrAlloc("none");
ef416fc2 2667
2668 for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
2669 ppdattr;
2670 i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
757d2cad 2671 attr->values[i].string.text = _cupsStrAlloc(ppdattr->value);
ef416fc2 2672
2673 if (ppd->protocols)
2674 {
2675 if (strstr(ppd->protocols, "TBCP"))
757d2cad 2676 attr->values[i].string.text = _cupsStrAlloc("tbcp");
ef416fc2 2677 else if (strstr(ppd->protocols, "BCP"))
757d2cad 2678 attr->values[i].string.text = _cupsStrAlloc("bcp");
ef416fc2 2679 }
2680
f7deaa1a 2681#ifdef HAVE_DNSSD
2682 cupsdSetString(&p->product, ppd->product);
2683#endif /* HAVE_DNSSD */
2684
09a101d6 2685 if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
2686 p->type |= CUPS_PRINTER_REMOTE;
3d8365b8 2687
ef416fc2 2688 /*
2689 * Close the PPD and set the type...
2690 */
2691
2692 ppdClose(ppd);
ef416fc2 2693 }
2694 else if (!access(filename, 0))
2695 {
2696 int pline; /* PPD line number */
2697 ppd_status_t pstatus; /* PPD load status */
2698
2699
2700 pstatus = ppdLastError(&pline);
2701
b423cd4c 2702 cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
2703 p->name);
ef416fc2 2704
2705 if (pstatus <= PPD_ALLOC_ERROR)
2706 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
2707 else
b423cd4c 2708 cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
2709 ppdErrorString(pstatus), pline);
ef416fc2 2710
b423cd4c 2711 cupsdLogMessage(CUPSD_LOG_INFO,
2712 "Hint: Run \"cupstestppd %s\" and fix any errors.",
2713 filename);
ef416fc2 2714
2715 /*
2716 * Add a filter from application/vnd.cups-raw to printer/name to
2717 * handle "raw" printing by users.
2718 */
2719
f7deaa1a 2720 add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
ef416fc2 2721
2722 /*
2723 * Add a PostScript filter, since this is still possibly PS printer.
2724 */
2725
f7deaa1a 2726 add_printer_filter(p, p->filetype,
2727 "application/vnd.cups-postscript 0 -");
ef416fc2 2728 }
2729 else
2730 {
2731 /*
2732 * If we have an interface script, add a filter entry for it...
2733 */
2734
2735 snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
2736 p->name);
b423cd4c 2737 if (!access(filename, X_OK))
ef416fc2 2738 {
2739 /*
2740 * Yes, we have a System V style interface script; use it!
2741 */
2742
2743 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
f7deaa1a 2744 "printer-make-and-model", NULL,
2745 "Local System V Printer");
ef416fc2 2746
2747 snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
2748 ServerRoot, p->name);
f7deaa1a 2749 add_printer_filter(p, p->filetype, filename);
ef416fc2 2750 }
0af14961 2751 else if (!strncmp(p->device_uri, "ipp://", 6) &&
ef416fc2 2752 (strstr(p->device_uri, "/printers/") != NULL ||
2753 strstr(p->device_uri, "/classes/") != NULL))
2754 {
2755 /*
2756 * Tell the client this is really a hard-wired remote printer.
2757 */
2758
09a101d6 2759 p->type |= CUPS_PRINTER_REMOTE;
ef416fc2 2760
2761 /*
2762 * Point the printer-uri-supported attribute to the
2763 * remote printer...
2764 */
2765
2766 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
2767 "printer-uri-supported", NULL, p->device_uri);
2768
2769 /*
2770 * Then set the make-and-model accordingly...
2771 */
2772
2773 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2774 "printer-make-and-model", NULL, "Remote Printer");
2775
2776 /*
2777 * Print all files directly...
2778 */
2779
d09495fa 2780 p->raw = 1;
2781 p->remote = 1;
ef416fc2 2782 }
2783 else
2784 {
2785 /*
2786 * Otherwise we have neither - treat this as a "dumb" printer
2787 * with no PPD file...
2788 */
2789
2790 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
2791 "printer-make-and-model", NULL, "Local Raw Printer");
2792
2793 p->raw = 1;
2794 }
2795 }
2796
2797 ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
b94498cf 2798 "finishings-supported", num_finishings, finishings);
ef416fc2 2799 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
2800 "finishings-default", IPP_FINISHINGS_NONE);
2801 }
2802 }
2803
8922323b
MS
2804 /*
2805 * Copy marker attributes as needed...
2806 */
2807
2808 if (oldattrs)
2809 {
2810 ipp_attribute_t *oldattr; /* Old attribute */
2811
2812
2813 if ((oldattr = ippFindAttribute(oldattrs, "marker-colors",
2814 IPP_TAG_NAME)) != NULL)
2815 {
2816 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2817 "marker-colors", oldattr->num_values, NULL,
2818 NULL)) != NULL)
2819 {
2820 for (i = 0; i < oldattr->num_values; i ++)
2821 attr->values[i].string.text =
2822 _cupsStrAlloc(oldattr->values[i].string.text);
2823 }
2824 }
2825
2826 if ((oldattr = ippFindAttribute(oldattrs, "marker-levels",
2827 IPP_TAG_INTEGER)) != NULL)
2828 {
2829 if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
2830 "marker-levels", oldattr->num_values,
2831 NULL)) != NULL)
2832 {
2833 for (i = 0; i < oldattr->num_values; i ++)
2834 attr->values[i].integer = oldattr->values[i].integer;
2835 }
2836 }
2837
2838 if ((oldattr = ippFindAttribute(oldattrs, "marker-names",
2839 IPP_TAG_NAME)) != NULL)
2840 {
2841 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
2842 "marker-names", oldattr->num_values, NULL,
2843 NULL)) != NULL)
2844 {
2845 for (i = 0; i < oldattr->num_values; i ++)
2846 attr->values[i].string.text =
2847 _cupsStrAlloc(oldattr->values[i].string.text);
2848 }
2849 }
2850
2851 if ((oldattr = ippFindAttribute(oldattrs, "marker-types",
2852 IPP_TAG_KEYWORD)) != NULL)
2853 {
2854 if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
2855 "marker-types", oldattr->num_values, NULL,
2856 NULL)) != NULL)
2857 {
2858 for (i = 0; i < oldattr->num_values; i ++)
2859 attr->values[i].string.text =
2860 _cupsStrAlloc(oldattr->values[i].string.text);
2861 }
2862 }
2863
2864 ippDelete(oldattrs);
2865 }
2866
b423cd4c 2867 /*
bc44d920 2868 * Force sharing off for remote queues...
b423cd4c 2869 */
2870
bc44d920 2871 if (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
2872 p->shared = 0;
2873 else
b423cd4c 2874 {
bc44d920 2875 /*
2876 * Copy the printer options into a browse attributes string we can re-use.
2877 */
2878
b423cd4c 2879 const char *valptr; /* Pointer into value */
2880 char *attrptr; /* Pointer into attribute string */
2881
2882
2883 /*
2884 * Free the old browse attributes as needed...
2885 */
2886
2887 if (p->browse_attrs)
2888 free(p->browse_attrs);
2889
2890 /*
2891 * Compute the length of all attributes + job-sheets, lease-duration,
2892 * and BrowseLocalOptions.
2893 */
2894
2895 for (length = 1, i = p->num_options, option = p->options;
2896 i > 0;
2897 i --, option ++)
2898 {
2899 length += strlen(option->name) + 2;
2900
2901 if (option->value)
2902 {
2903 for (valptr = option->value; *valptr; valptr ++)
2904 if (strchr(" \"\'\\", *valptr))
2905 length += 2;
2906 else
2907 length ++;
2908 }
2909 }
2910
2911 length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]);
2912 length += 32;
2913 if (BrowseLocalOptions)
f7deaa1a 2914 length += 12 + strlen(BrowseLocalOptions);
b423cd4c 2915
7594b224 2916 if (p->num_auth_info_required > 0)
2917 {
2918 length += 18; /* auth-info-required */
2919
2920 for (i = 0; i < p->num_auth_info_required; i ++)
2921 length += strlen(p->auth_info_required[i]) + 1;
2922 }
2923
b423cd4c 2924 /*
2925 * Allocate the new string...
2926 */
f7deaa1a 2927
b423cd4c 2928 if ((p->browse_attrs = calloc(1, length)) == NULL)
2929 cupsdLogMessage(CUPSD_LOG_ERROR,
2930 "Unable to allocate %d bytes for browse data!",
2931 length);
2932 else
2933 {
2934 /*
2935 * Got the allocated string, now copy the options and attributes over...
2936 */
2937
2938 sprintf(p->browse_attrs, "job-sheets=%s,%s lease-duration=%d",
2939 p->job_sheets[0], p->job_sheets[1], BrowseTimeout);
2940 attrptr = p->browse_attrs + strlen(p->browse_attrs);
2941
2942 if (BrowseLocalOptions)
2943 {
2944 sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions);
2945 attrptr += strlen(attrptr);
2946 }
2947
2948 for (i = p->num_options, option = p->options;
2949 i > 0;
2950 i --, option ++)
2951 {
2952 *attrptr++ = ' ';
2953 strcpy(attrptr, option->name);
2954 attrptr += strlen(attrptr);
2955
2956 if (option->value)
2957 {
2958 *attrptr++ = '=';
2959
2960 for (valptr = option->value; *valptr; valptr ++)
2961 {
2962 if (strchr(" \"\'\\", *valptr))
2963 *attrptr++ = '\\';
2964
2965 *attrptr++ = *valptr;
2966 }
2967 }
2968 }
2969
7594b224 2970 if (p->num_auth_info_required > 0)
2971 {
2972 strcpy(attrptr, "auth-info-required");
2973 attrptr += 18;
2974
2975 for (i = 0; i < p->num_auth_info_required; i ++)
2976 {
2977 *attrptr++ = i ? ',' : '=';
2978 strcpy(attrptr, p->auth_info_required[i]);
2979 attrptr += strlen(attrptr);
2980 }
2981 }
2982 else
2983 *attrptr = '\0';
b423cd4c 2984 }
2985 }
2986
bd7854cb 2987 /*
2988 * Populate the document-format-supported attribute...
2989 */
2990
2991 add_printer_formats(p);
2992
ef416fc2 2993 DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
2994 p->type));
2995
b423cd4c 2996 /*
2997 * Add name-default attributes...
2998 */
2999
3000 add_printer_defaults(p);
3001
ef416fc2 3002#ifdef __sgi
3003 /*
3004 * Write the IRIX printer config and status files...
3005 */
3006
3007 write_irix_config(p);
3008 write_irix_state(p);
3009#endif /* __sgi */
f7deaa1a 3010
3011 /*
3012 * Let the browse protocols reflect the change
3013 */
3014
3015 cupsdRegisterPrinter(p);
ef416fc2 3016}
3017
3018
3019/*
3020 * 'cupsdSetPrinterReasons()' - Set/update the reasons strings.
3021 */
3022
3023void
3024cupsdSetPrinterReasons(
3025 cupsd_printer_t *p, /* I - Printer */
3026 const char *s) /* I - Reasons strings */
3027{
3028 int i; /* Looping var */
3029 const char *sptr; /* Pointer into reasons */
3030 char reason[255], /* Reason string */
3031 *rptr; /* Pointer into reason */
3032
3033
3034 if (s[0] == '-' || s[0] == '+')
3035 {
3036 /*
3037 * Add/remove reasons...
3038 */
3039
3040 sptr = s + 1;
3041 }
3042 else
3043 {
3044 /*
3045 * Replace reasons...
3046 */
3047
3048 sptr = s;
3049
3050 for (i = 0; i < p->num_reasons; i ++)
0af14961 3051 _cupsStrFree(p->reasons[i]);
ef416fc2 3052
3053 p->num_reasons = 0;
0af14961
MS
3054
3055 if (PrintcapFormat == PRINTCAP_PLIST)
3056 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
ef416fc2 3057 }
3058
bc44d920 3059 if (!strcmp(s, "none"))
3060 return;
3061
ef416fc2 3062 /*
3063 * Loop through all of the reasons...
3064 */
3065
3066 while (*sptr)
3067 {
3068 /*
3069 * Skip leading whitespace and commas...
3070 */
3071
3072 while (isspace(*sptr & 255) || *sptr == ',')
3073 sptr ++;
3074
3075 for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++)
3076 if (rptr < (reason + sizeof(reason) - 1))
3077 *rptr++ = *sptr;
3078
3079 if (rptr == reason)
3080 break;
3081
3082 *rptr = '\0';
3083
3084 if (s[0] == '-')
3085 {
3086 /*
3087 * Remove reason...
3088 */
3089
3090 for (i = 0; i < p->num_reasons; i ++)
3091 if (!strcasecmp(reason, p->reasons[i]))
3092 {
3093 /*
3094 * Found a match, so remove it...
3095 */
3096
3097 p->num_reasons --;
1f6f3dbc 3098 _cupsStrFree(p->reasons[i]);
ef416fc2 3099
3100 if (i < p->num_reasons)
3101 memmove(p->reasons + i, p->reasons + i + 1,
3102 (p->num_reasons - i) * sizeof(char *));
3103
3104 i --;
c0e1af83 3105
3106 if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED)
3107 cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
0af14961
MS
3108
3109 if (PrintcapFormat == PRINTCAP_PLIST)
3110 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
ef416fc2 3111 }
3112 }
3113 else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
3114 {
3115 /*
3116 * Add reason...
3117 */
3118
3119 for (i = 0; i < p->num_reasons; i ++)
3120 if (!strcasecmp(reason, p->reasons[i]))
3121 break;
3122
3123 if (i >= p->num_reasons)
3124 {
0af14961 3125 p->reasons[i] = _cupsStrAlloc(reason);
ef416fc2 3126 p->num_reasons ++;
c0e1af83 3127
3128 if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED)
3129 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
0af14961
MS
3130
3131 if (PrintcapFormat == PRINTCAP_PLIST)
3132 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
ef416fc2 3133 }
3134 }
3135 }
3136}
3137
3138
3139/*
3140 * 'cupsdSetPrinterState()' - Update the current state of a printer.
3141 */
3142
3143void
3144cupsdSetPrinterState(
3145 cupsd_printer_t *p, /* I - Printer to change */
3146 ipp_pstate_t s, /* I - New state */
3147 int update) /* I - Update printers.conf? */
3148{
3149 ipp_pstate_t old_state; /* Old printer state */
3150
3151
3152 /*
3153 * Can't set status of remote printers...
3154 */
3155
09a101d6 3156 if (p->type & CUPS_PRINTER_DISCOVERED)
ef416fc2 3157 return;
3158
3159 /*
3160 * Set the new state...
3161 */
3162
0af14961
MS
3163 if (PrintcapFormat == PRINTCAP_PLIST)
3164 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
3165
ef416fc2 3166 old_state = p->state;
3167 p->state = s;
3168
3169 if (old_state != s)
3170 {
0a682745 3171 cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED :
d9bca400 3172 CUPSD_EVENT_PRINTER_STATE, p, NULL,
e53920b9 3173 "%s \"%s\" state changed.",
3174 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
3175 p->name);
3176
ef416fc2 3177 /*
3178 * Let the browse code know this needs to be updated...
3179 */
3180
3181 BrowseNext = p;
3182 p->state_time = time(NULL);
3183 p->browse_time = 0;
3184
3185#ifdef __sgi
3186 write_irix_state(p);
3187#endif /* __sgi */
3188 }
3189
3190 cupsdAddPrinterHistory(p);
3191
f7deaa1a 3192 /*
3193 * Let the browse protocols reflect the change...
3194 */
3195
7a14d768
MS
3196 if (update)
3197 cupsdRegisterPrinter(p);
f7deaa1a 3198
ef416fc2 3199 /*
3200 * Save the printer configuration if a printer goes from idle or processing
3201 * to stopped (or visa-versa)...
3202 */
3203
3204 if ((old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED) &&
3205 update)
3206 {
3207 if (p->type & CUPS_PRINTER_CLASS)
3dfe78b3 3208 cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
ef416fc2 3209 else
3dfe78b3 3210 cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
ef416fc2 3211 }
3212}
3213
3214
3215/*
3216 * 'cupsdStopPrinter()' - Stop a printer from printing any jobs...
3217 */
3218
3219void
3220cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */
3221 int update)/* I - Update printers.conf? */
3222{
3223 cupsd_job_t *job; /* Active print job */
3224
3225
3226 /*
3227 * Set the printer state...
3228 */
3229
3230 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
3231
3232 /*
3233 * See if we have a job printing on this printer...
3234 */
3235
3236 if (p->job)
3237 {
3238 /*
3239 * Get pointer to job...
3240 */
3241
3242 job = (cupsd_job_t *)p->job;
3243
3244 /*
3245 * Stop it...
3246 */
3247
3248 cupsdStopJob(job, 0);
3249
3250 /*
3251 * Reset the state to pending...
3252 */
3253
3254 job->state->values[0].integer = IPP_JOB_PENDING;
bd7854cb 3255 job->state_value = IPP_JOB_PENDING;
3dfe78b3 3256 job->dirty = 1;
ef416fc2 3257
3dfe78b3 3258 cupsdMarkDirty(CUPSD_DIRTY_JOBS);
07725fee 3259
3260 cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
3261 "Job stopped due to printer being paused");
ef416fc2 3262 }
3263}
3264
3265
c9fc04c6
MS
3266/*
3267 * 'cupsdUpdatePrinterPPD()' - Update keywords in a printer's PPD file.
3268 */
3269
3270int /* O - 1 if successful, 0 otherwise */
3271cupsdUpdatePrinterPPD(
3272 cupsd_printer_t *p, /* I - Printer */
3273 int num_keywords, /* I - Number of keywords */
3274 cups_option_t *keywords) /* I - Keywords */
3275{
3276 int i; /* Looping var */
3277 cups_file_t *src, /* Original file */
3278 *dst; /* New file */
3279 char srcfile[1024], /* Original filename */
3280 dstfile[1024], /* New filename */
3281 line[1024], /* Line from file */
3282 keystring[41]; /* Keyword from line */
3283 cups_option_t *keyword; /* Current keyword */
3284
3285
3286 cupsdLogMessage(CUPSD_LOG_INFO, "Updating keywords in PPD file for %s...",
3287 p->name);
3288
3289 /*
3290 * Get the old and new PPD filenames...
3291 */
3292
3293 snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd.O", ServerRoot, p->name);
3294 snprintf(dstfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
3295
3296 /*
3297 * Rename the old file and open the old and new...
3298 */
3299
3300 if (rename(dstfile, srcfile))
3301 {
3302 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup PPD file for %s: %s",
3303 p->name, strerror(errno));
3304 return (0);
3305 }
3306
3307 if ((src = cupsFileOpen(srcfile, "r")) == NULL)
3308 {
3309 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open PPD file \"%s\": %s",
3310 srcfile, strerror(errno));
3311 rename(srcfile, dstfile);
3312 return (0);
3313 }
3314
3315 if ((dst = cupsFileOpen(dstfile, "w")) == NULL)
3316 {
3317 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create PPD file \"%s\": %s",
3318 dstfile, strerror(errno));
3319 cupsFileClose(src);
3320 rename(srcfile, dstfile);
3321 return (0);
3322 }
3323
3324 /*
3325 * Copy the first line and then write out all of the keywords...
3326 */
3327
3328 if (!cupsFileGets(src, line, sizeof(line)))
3329 {
3330 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read PPD file \"%s\": %s",
3331 srcfile, strerror(errno));
3332 cupsFileClose(src);
3333 cupsFileClose(dst);
3334 rename(srcfile, dstfile);
3335 return (0);
3336 }
3337
3338 cupsFilePrintf(dst, "%s\n", line);
3339
3340 for (i = num_keywords, keyword = keywords; i > 0; i --, keyword ++)
3341 {
3342 cupsdLogMessage(CUPSD_LOG_DEBUG, "*%s: %s", keyword->name, keyword->value);
3343 cupsFilePrintf(dst, "*%s: %s\n", keyword->name, keyword->value);
3344 }
3345
3346 /*
3347 * Then copy the rest of the PPD file, dropping any keywords we changed.
3348 */
3349
3350 while (cupsFileGets(src, line, sizeof(line)))
3351 {
3352 /*
3353 * Skip keywords we've already set...
3354 */
3355
3356 if (sscanf(line, "*%40[^:]:", keystring) == 1 &&
3357 cupsGetOption(keystring, num_keywords, keywords))
3358 continue;
3359
3360 /*
3361 * Otherwise write the line...
3362 */
3363
3364 cupsFilePrintf(dst, "%s\n", line);
3365 }
3366
3367 /*
3368 * Close files and return...
3369 */
3370
3371 cupsFileClose(src);
3372 cupsFileClose(dst);
3373
3374 return (1);
3375}
3376
3377
ef416fc2 3378/*
3379 * 'cupsdUpdatePrinters()' - Update printers after a partial reload.
3380 */
3381
3382void
3383cupsdUpdatePrinters(void)
3384{
3385 cupsd_printer_t *p; /* Current printer */
3386
3387
3388 /*
3389 * Loop through the printers and recreate the printer attributes
3390 * for any local printers since the policy and/or access control
3391 * stuff may have changed. Also, if browsing is disabled, remove
3392 * any remote printers...
3393 */
3394
3395 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3396 p;
3397 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3398 {
07725fee 3399 /*
3400 * Remove remote printers if we are no longer browsing...
3401 */
3402
09a101d6 3403 if (!Browsing &&
3404 (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_DISCOVERED)))
ef416fc2 3405 {
3406 if (p->type & CUPS_PRINTER_IMPLICIT)
3407 cupsArrayRemove(ImplicitPrinters, p);
3408
3409 cupsArraySave(Printers);
3410 cupsdDeletePrinter(p, 0);
3411 cupsArrayRestore(Printers);
3412 continue;
3413 }
ef416fc2 3414
3415 /*
3416 * Update the operation policy pointer...
3417 */
3418
3419 if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
3420 p->op_policy_ptr = DefaultPolicyPtr;
07725fee 3421
3422 /*
3423 * Update printer attributes as needed...
3424 */
3425
09a101d6 3426 if (!(p->type & CUPS_PRINTER_DISCOVERED))
07725fee 3427 cupsdSetPrinterAttrs(p);
ef416fc2 3428 }
3429}
3430
3431
3432/*
3433 * 'cupsdValidateDest()' - Validate a printer/class destination.
3434 */
3435
3436const char * /* O - Printer or class name */
3437cupsdValidateDest(
f7deaa1a 3438 const char *uri, /* I - Printer URI */
ef416fc2 3439 cups_ptype_t *dtype, /* O - Type (printer or class) */
3440 cupsd_printer_t **printer) /* O - Printer pointer */
3441{
3442 cupsd_printer_t *p; /* Current printer */
3443 char localname[1024],/* Localized hostname */
3444 *lptr, /* Pointer into localized hostname */
f7deaa1a 3445 *sptr, /* Pointer into server name */
3446 *rptr, /* Pointer into resource */
3447 scheme[32], /* Scheme portion of URI */
3448 username[64], /* Username portion of URI */
3449 hostname[HTTP_MAX_HOST],
3450 /* Host portion of URI */
3451 resource[HTTP_MAX_URI];
3452 /* Resource portion of URI */
3453 int port; /* Port portion of URI */
3454
3455
3456 DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
ef416fc2 3457 dtype, printer));
3458
3459 /*
3460 * Initialize return values...
3461 */
3462
3463 if (printer)
3464 *printer = NULL;
3465
f7deaa1a 3466 if (dtype)
3467 *dtype = (cups_ptype_t)0;
3468
3469 /*
3470 * Pull the hostname and resource from the URI...
3471 */
3472
3473 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
3474 username, sizeof(username), hostname, sizeof(hostname),
3475 &port, resource, sizeof(resource));
ef416fc2 3476
3477 /*
3478 * See if the resource is a class or printer...
3479 */
3480
3481 if (!strncmp(resource, "/classes/", 9))
3482 {
3483 /*
3484 * Class...
3485 */
3486
f7deaa1a 3487 rptr = resource + 9;
ef416fc2 3488 }
3489 else if (!strncmp(resource, "/printers/", 10))
3490 {
3491 /*
3492 * Printer...
3493 */
3494
f7deaa1a 3495 rptr = resource + 10;
ef416fc2 3496 }
3497 else
3498 {
3499 /*
3500 * Bad resource name...
3501 */
3502
3503 return (NULL);
3504 }
3505
3506 /*
3507 * See if the printer or class name exists...
3508 */
3509
f7deaa1a 3510 p = cupsdFindDest(rptr);
ef416fc2 3511
f7deaa1a 3512 if (p == NULL && strchr(rptr, '@') == NULL)
ef416fc2 3513 return (NULL);
3514 else if (p != NULL)
3515 {
3516 if (printer)
3517 *printer = p;
3518
f7deaa1a 3519 if (dtype)
3520 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
09a101d6 3521 CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED);
f7deaa1a 3522
ef416fc2 3523 return (p->name);
3524 }
3525
3526 /*
3527 * Change localhost to the server name...
3528 */
3529
3530 if (!strcasecmp(hostname, "localhost"))
f7deaa1a 3531 strlcpy(hostname, ServerName, sizeof(hostname));
ef416fc2 3532
3533 strlcpy(localname, hostname, sizeof(localname));
3534
3535 if (!strcasecmp(hostname, ServerName))
3536 {
3537 /*
3538 * Localize the hostname...
3539 */
3540
3541 lptr = strchr(localname, '.');
3542 sptr = strchr(ServerName, '.');
3543
3544 if (sptr != NULL && lptr != NULL)
3545 {
3546 /*
3547 * Strip the common domain name components...
3548 */
3549
3550 while (lptr != NULL)
3551 {
3552 if (!strcasecmp(lptr, sptr))
3553 {
3554 *lptr = '\0';
3555 break;
3556 }
3557 else
3558 lptr = strchr(lptr + 1, '.');
3559 }
3560 }
3561 }
3562
3563 DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
3564
3565 /*
3566 * Find a matching printer or class...
3567 */
3568
3569 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3570 p;
3571 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3572 if (!strcasecmp(p->hostname, localname) &&
f7deaa1a 3573 !strcasecmp(p->name, rptr))
ef416fc2 3574 {
3575 if (printer)
3576 *printer = p;
3577
f7deaa1a 3578 if (dtype)
3579 *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
09a101d6 3580 CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED);
f7deaa1a 3581
ef416fc2 3582 return (p->name);
3583 }
3584
3585 return (NULL);
3586}
3587
3588
3589/*
3590 * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications
3591 * that need it...
3592 */
3593
3594void
3595cupsdWritePrintcap(void)
3596{
0af14961
MS
3597 int i; /* Looping var */
3598 cups_file_t *fp; /* Printcap file */
ef416fc2 3599 cupsd_printer_t *p; /* Current printer */
3600
3601
3602#ifdef __sgi
3603 /*
3604 * Update the IRIX printer state for the default printer; if
3605 * no printers remain, then the default printer file will be
3606 * removed...
3607 */
3608
3609 write_irix_state(DefaultPrinter);
3610#endif /* __sgi */
3611
3612 /*
3613 * See if we have a printcap file; if not, don't bother writing it.
3614 */
3615
3616 if (!Printcap || !*Printcap)
3617 return;
3618
3619 /*
3620 * Open the printcap file...
3621 */
3622
3623 if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
3624 return;
3625
3626 /*
3627 * Put a comment header at the top so that users will know where the
3628 * data has come from...
3629 */
3630
0af14961
MS
3631 if (PrintcapFormat != PRINTCAP_PLIST)
3632 cupsFilePrintf(fp, "# This file was automatically generated by cupsd(8) "
3633 "from the\n"
3634 "# %s/printers.conf file. All changes to this file\n"
3635 "# will be lost.\n", ServerRoot);
ef416fc2 3636
3637 if (Printers)
3638 {
3639 /*
3640 * Write a new printcap with the current list of printers.
3641 */
3642
3643 switch (PrintcapFormat)
3644 {
0af14961 3645 case PRINTCAP_BSD :
ef416fc2 3646 /*
3647 * Each printer is put in the file as:
3648 *
3649 * Printer1:
3650 * Printer2:
3651 * Printer3:
3652 * ...
3653 * PrinterN:
3654 */
3655
3656 if (DefaultPrinter)
3657 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
c277e2f8
MS
3658 DefaultPrinter->info, ServerName,
3659 DefaultPrinter->name);
ef416fc2 3660
3661 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3662 p;
3663 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3664 if (p != DefaultPrinter)
3665 cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
c277e2f8 3666 ServerName, p->name);
ef416fc2 3667 break;
3668
0af14961
MS
3669 case PRINTCAP_PLIST :
3670 /*
3671 * Each printer is written as a dictionary in a plist file.
3672 * Currently the printer-name, printer-info, printer-is-accepting-jobs,
3673 * printer-location, printer-make-and-model, printer-state,
3674 * printer-state-reasons, printer-type, and (sanitized) device-uri.
3675 */
3676
3677 cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
3678 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD "
3679 "PLIST 1.0//EN\" \"http://www.apple.com/DTDs/"
3680 "PropertyList-1.0.dtd\">\n"
3681 "<plist version=\"1.0\">\n"
3682 "<array>\n");
3683
3684 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3685 p;
3686 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3687 {
3688 cupsFilePuts(fp, "\t<dict>\n"
3689 "\t\t<key>printer-name</key>\n"
3690 "\t\t<string>");
3691 write_xml_string(fp, p->name);
3692 cupsFilePuts(fp, "</string>\n"
3693 "\t\t<key>printer-info</key>\n"
3694 "\t\t<string>");
3695 write_xml_string(fp, p->info);
3696 cupsFilePrintf(fp, "</string>\n"
3697 "\t\t<key>printer-is-accepting-jobs</key>\n"
3698 "\t\t<%s/>\n"
3699 "\t\t<key>printer-location</key>\n"
3700 "\t\t<string>", p->accepting ? "true" : "false");
3701 write_xml_string(fp, p->location);
3702 cupsFilePuts(fp, "</string>\n"
3703 "\t\t<key>printer-make-and-model</key>\n"
3704 "\t\t<string>");
3705 write_xml_string(fp, p->make_model);
3706 cupsFilePrintf(fp, "</string>\n"
3707 "\t\t<key>printer-state</key>\n"
3708 "\t\t<integer>%d</integer>\n"
3709 "\t\t<key>printer-state-reasons</key>\n"
3710 "\t\t<array>\n", p->state);
3711 for (i = 0; i < p->num_reasons; i ++)
3712 {
3713 cupsFilePuts(fp, "\t\t\t<string>");
3714 write_xml_string(fp, p->reasons[i]);
3715 cupsFilePuts(fp, "</string>\n");
3716 }
3717 cupsFilePrintf(fp, "\t\t</array>\n"
3718 "\t\t<key>printer-type</key>\n"
3719 "\t\t<integer>%d</integer>\n"
3720 "\t\t<key>device-uri</key>\n"
3721 "\t\t<string>", p->type);
3722 write_xml_string(fp, p->sanitized_device_uri);
3723 cupsFilePuts(fp, "</string>\n"
3724 "\t</dict>\n");
3725 }
3726 cupsFilePuts(fp, "</array>\n"
3727 "</plist>\n");
3728 break;
3729
3730 case PRINTCAP_SOLARIS :
ef416fc2 3731 /*
3732 * Each printer is put in the file as:
3733 *
3734 * _all:all=Printer1,Printer2,Printer3,...,PrinterN
3735 * _default:use=DefaultPrinter
3736 * Printer1:\
3737 * :bsdaddr=ServerName,Printer1:\
3738 * :description=Description:
3739 * Printer2:
3740 * :bsdaddr=ServerName,Printer2:\
3741 * :description=Description:
3742 * Printer3:
3743 * :bsdaddr=ServerName,Printer3:\
3744 * :description=Description:
3745 * ...
3746 * PrinterN:
3747 * :bsdaddr=ServerName,PrinterN:\
3748 * :description=Description:
3749 */
3750
3751 cupsFilePuts(fp, "_all:all=");
3752 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3753 p;
3754 p = (cupsd_printer_t *)cupsArrayCurrent(Printers))
3755 cupsFilePrintf(fp, "%s%c", p->name,
3756 cupsArrayNext(Printers) ? ',' : '\n');
3757
3758 if (DefaultPrinter)
3759 cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
3760
3761 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3762 p;
3763 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3764 cupsFilePrintf(fp, "%s:\\\n"
c277e2f8
MS
3765 "\t:bsdaddr=%s,%s:\\\n"
3766 "\t:description=%s:\n",
3767 p->name, ServerName, p->name,
3768 p->info ? p->info : "");
ef416fc2 3769 break;
3770 }
3771 }
3772
3773 /*
3774 * Close the file...
3775 */
3776
3777 cupsFileClose(fp);
3778}
3779
3780
b423cd4c 3781/*
3782 * 'add_printer_defaults()' - Add name-default attributes to the printer attributes.
3783 */
3784
3785static void
3786add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
3787{
3788 int i; /* Looping var */
3789 int num_options; /* Number of default options */
3790 cups_option_t *options, /* Default options */
3791 *option; /* Current option */
3792 char name[256]; /* name-default */
3793
3794
f7deaa1a 3795 /*
3796 * Maintain a common array of default attribute names...
3797 */
3798
3799 if (!CommonDefaults)
3800 {
3801 CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL);
3802
3803 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default"));
3804 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default"));
3805 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default"));
3806 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
3807 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
3808 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
3809 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-default"));
3810 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
3811 cupsArrayAdd(CommonDefaults,
3812 _cupsStrAlloc("orientation-requested-default"));
3813 cupsArrayAdd(CommonDefaults, _cupsStrAlloc("sides-default"));
3814 }
3815
b423cd4c 3816 /*
3817 * Add all of the default options from the .conf files...
3818 */
3819
1f0275e3 3820 for (num_options = 0, options = NULL, i = p->num_options, option = p->options;
b423cd4c 3821 i > 0;
3822 i --, option ++)
3823 {
3824 if (strcmp(option->name, "ipp-options") &&
3825 strcmp(option->name, "job-sheets") &&
3826 strcmp(option->name, "lease-duration"))
3827 {
3828 snprintf(name, sizeof(name), "%s-default", option->name);
3829 num_options = cupsAddOption(name, option->value, num_options, &options);
f7deaa1a 3830
3831 if (!cupsArrayFind(CommonDefaults, name))
3832 cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name));
b423cd4c 3833 }
3834 }
3835
3836 /*
3837 * Convert options to IPP attributes...
3838 */
3839
3840 cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER);
3841 cupsFreeOptions(num_options, options);
3842
3843 /*
3844 * Add standard -default attributes as needed...
3845 */
3846
3847 if (!cupsGetOption("copies", p->num_options, p->options))
3848 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default",
3849 1);
3850
f7deaa1a 3851 if (!cupsGetOption("document-format", p->num_options, p->options))
c934a06c 3852 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
f7deaa1a 3853 "document-format-default", NULL, "application/octet-stream");
3854
b423cd4c 3855 if (!cupsGetOption("job-hold-until", p->num_options, p->options))
3856 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3857 "job-hold-until-default", NULL, "no-hold");
3858
3859 if (!cupsGetOption("job-priority", p->num_options, p->options))
3860 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3861 "job-priority-default", 50);
3862
3863 if (!cupsGetOption("number-up", p->num_options, p->options))
3864 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3865 "number-up-default", 1);
3866
3867 if (!cupsGetOption("orientation-requested", p->num_options, p->options))
c277e2f8
MS
3868 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
3869 "orientation-requested-default", NULL, NULL);
f7deaa1a 3870
3871 if (!cupsGetOption("notify-lease-duration", p->num_options, p->options))
3872 ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
3873 "notify-lease-duration-default", DefaultLeaseDuration);
3874
3875 if (!cupsGetOption("notify-events", p->num_options, p->options))
3876 ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
3877 "notify-events-default", NULL, "job-completed");
b423cd4c 3878}
3879
3880
bd7854cb 3881/*
3882 * 'add_printer_filter()' - Add a MIME filter for a printer.
3883 */
3884
3885static void
3886add_printer_filter(
3887 cupsd_printer_t *p, /* I - Printer to add to */
f7deaa1a 3888 mime_type_t *filtertype, /* I - Filter or prefilter MIME type */
bd7854cb 3889 const char *filter) /* I - Filter to add */
3890{
3891 char super[MIME_MAX_SUPER], /* Super-type for filter */
3892 type[MIME_MAX_TYPE], /* Type for filter */
3893 program[1024]; /* Program/filter name */
3894 int cost; /* Cost of filter */
3895 mime_type_t *temptype; /* MIME type looping var */
3896 char filename[1024]; /* Full filter filename */
3897
3898
3899 /*
3900 * Parse the filter string; it should be in the following format:
3901 *
3902 * super/type cost program
3903 */
3904
1f0275e3
MS
3905 if (sscanf(filter, "%15[^/]/%31s%d%*[ \t]%1023[^\n]", super, type, &cost,
3906 program) != 4)
bd7854cb 3907 {
3908 cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
3909 p->name, filter);
3910 return;
3911 }
3912
3913 /*
3914 * See if the filter program exists; if not, stop the printer and flag
3915 * the error!
3916 */
3917
ecdc0628 3918 if (strcmp(program, "-"))
bd7854cb 3919 {
ecdc0628 3920 if (program[0] == '/')
3921 strlcpy(filename, program, sizeof(filename));
3922 else
3923 snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
3924
3925 if (access(filename, X_OK))
3926 {
3927 snprintf(p->state_message, sizeof(p->state_message),
3928 "Filter \"%s\" for printer \"%s\" not available: %s",
3929 program, p->name, strerror(errno));
ecdc0628 3930 cupsdSetPrinterReasons(p, "+cups-missing-filter-error");
07725fee 3931 cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 0);
ecdc0628 3932
3933 cupsdLogMessage(CUPSD_LOG_ERROR, "%s", p->state_message);
3934 }
bd7854cb 3935 }
3936
b423cd4c 3937 /*
3938 * Mark the CUPS_PRINTER_COMMANDS bit if we have a filter for
3939 * application/vnd.cups-command...
3940 */
3941
3942 if (!strcasecmp(super, "application") &&
3943 !strcasecmp(type, "vnd.cups-command"))
3944 p->type |= CUPS_PRINTER_COMMANDS;
3945
bd7854cb 3946 /*
3947 * Add the filter to the MIME database, supporting wildcards as needed...
3948 */
3949
3950 for (temptype = mimeFirstType(MimeDatabase);
3951 temptype;
3952 temptype = mimeNextType(MimeDatabase))
3953 if (((super[0] == '*' && strcasecmp(temptype->super, "printer")) ||
3954 !strcasecmp(temptype->super, super)) &&
3955 (type[0] == '*' || !strcasecmp(temptype->type, type)))
3956 {
3957 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3958 "add_printer_filter: %s: adding filter %s/%s %s/%s %d %s",
3959 p->name, temptype->super, temptype->type,
f7deaa1a 3960 filtertype->super, filtertype->type,
bd7854cb 3961 cost, program);
f7deaa1a 3962 mimeAddFilter(MimeDatabase, temptype, filtertype, cost, program);
bd7854cb 3963 }
3964}
3965
3966
3967/*
3968 * 'add_printer_formats()' - Add document-format-supported values for a printer.
3969 */
3970
3971static void
3972add_printer_formats(cupsd_printer_t *p) /* I - Printer */
3973{
3974 int i; /* Looping var */
3975 mime_type_t *type; /* Current MIME type */
3976 cups_array_t *filters; /* Filters */
80ca4592 3977 ipp_attribute_t *attr; /* document-format-supported attribute */
bd7854cb 3978 char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
3979 /* MIME type name */
3980
3981
3982 /*
3983 * Raw (and remote) queues advertise all of the supported MIME
3984 * types...
3985 */
3986
80ca4592 3987 cupsArrayDelete(p->filetypes);
3988 p->filetypes = NULL;
3989
bd7854cb 3990 if (p->raw)
3991 {
3992 ippAddStrings(p->attrs, IPP_TAG_PRINTER,
3993 (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
3994 "document-format-supported", NumMimeTypes, NULL, MimeTypes);
3995 return;
3996 }
3997
3998 /*
3999 * Otherwise, loop through the supported MIME types and see if there
4000 * are filters for them...
4001 */
4002
bd7854cb 4003 cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters",
4004 mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
4005
80ca4592 4006 p->filetypes = cupsArrayNew(NULL, NULL);
bd7854cb 4007
80ca4592 4008 for (type = mimeFirstType(MimeDatabase);
bd7854cb 4009 type;
4010 type = mimeNextType(MimeDatabase))
4011 {
bd7854cb 4012 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
4013
4014 if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
4015 {
4016 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4017 "add_printer_formats: %s: %s needs %d filters",
4018 p->name, mimetype, cupsArrayCount(filters));
4019
4020 cupsArrayDelete(filters);
80ca4592 4021 cupsArrayAdd(p->filetypes, type);
bd7854cb 4022 }
4023 else
4024 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4025 "add_printer_formats: %s: %s not supported",
4026 p->name, mimetype);
4027 }
4028
4029 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4030 "add_printer_formats: %s: %d supported types",
80ca4592 4031 p->name, cupsArrayCount(p->filetypes) + 1);
bd7854cb 4032
4033 /*
4034 * Add the file formats that can be filtered...
4035 */
4036
f301802f 4037 if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL ||
4038 !cupsArrayFind(p->filetypes, type))
4039 i = 1;
4040 else
4041 i = 0;
bd7854cb 4042
80ca4592 4043 attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
4044 "document-format-supported",
4045 cupsArrayCount(p->filetypes) + 1, NULL, NULL);
4046
f301802f 4047 if (i)
4048 attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
bd7854cb 4049
f301802f 4050 for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
80ca4592 4051 type;
4052 i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes))
4053 {
4054 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
bd7854cb 4055
80ca4592 4056 attr->values[i].string.text = _cupsStrAlloc(mimetype);
4057 }
f7deaa1a 4058
4059#ifdef HAVE_DNSSD
4060 {
4061 char pdl[1024]; /* Buffer to build pdl list */
4062 mime_filter_t *filter; /* MIME filter looping var */
4063
4064
4065 pdl[0] = '\0';
4066
4067 if (mimeType(MimeDatabase, "application", "pdf"))
4068 strlcat(pdl, "application/pdf,", sizeof(pdl));
4069
4070 if (mimeType(MimeDatabase, "application", "postscript"))
4071 strlcat(pdl, "application/postscript,", sizeof(pdl));
4072
4073 if (mimeType(MimeDatabase, "application", "vnd.cups-raster"))
4074 strlcat(pdl, "application/vnd.cups-raster,", sizeof(pdl));
4075
4076 /*
4077 * Determine if this is a Tioga PrintJobMgr based queue...
4078 */
4079
4080 for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters);
4081 filter;
4082 filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
4083 {
4084 if (filter->dst == p->filetype && filter->filter &&
4085 strstr(filter->filter, "PrintJobMgr"))
4086 break;
4087 }
4088
4089 /*
4090 * We only support raw printing if this is not a Tioga PrintJobMgr based
4091 * queue and if application/octet-stream is a known conversion...
4092 */
4093
4094 if (!filter && mimeType(MimeDatabase, "application", "octet-stream"))
4095 strlcat(pdl, "application/octet-stream,", sizeof(pdl));
4096
4097 if (mimeType(MimeDatabase, "image", "png"))
4098 strlcat(pdl, "image/png,", sizeof(pdl));
4099
4100 if (pdl[0])
4101 pdl[strlen(pdl) - 1] = '\0'; /* Remove trailing comma */
4102
4103 cupsdSetString(&p->pdl, pdl);
4104 }
4105#endif /* HAVE_DNSSD */
bd7854cb 4106}
4107
4108
ef416fc2 4109/*
4110 * 'compare_printers()' - Compare two printers.
4111 */
4112
4113static int /* O - Result of comparison */
4114compare_printers(void *first, /* I - First printer */
4115 void *second, /* I - Second printer */
4116 void *data) /* I - App data (not used) */
4117{
4118 return (strcasecmp(((cupsd_printer_t *)first)->name,
4119 ((cupsd_printer_t *)second)->name));
4120}
4121
4122
bd7854cb 4123/*
e1d6a774 4124 * 'delete_printer_filters()' - Delete all MIME filters for a printer.
bd7854cb 4125 */
4126
4127static void
e1d6a774 4128delete_printer_filters(
4129 cupsd_printer_t *p) /* I - Printer to remove from */
bd7854cb 4130{
e1d6a774 4131 mime_filter_t *filter; /* MIME filter looping var */
bd7854cb 4132
bd7854cb 4133
4134 /*
e1d6a774 4135 * Range check input...
bd7854cb 4136 */
4137
e1d6a774 4138 if (p == NULL)
4139 return;
bd7854cb 4140
4141 /*
e1d6a774 4142 * Remove all filters from the MIME database that have a destination
4143 * type == printer...
bd7854cb 4144 */
4145
e1d6a774 4146 for (filter = mimeFirstFilter(MimeDatabase);
4147 filter;
4148 filter = mimeNextFilter(MimeDatabase))
4149 if (filter->dst == p->filetype)
4150 {
4151 /*
4152 * Delete the current filter...
4153 */
bd7854cb 4154
e1d6a774 4155 mimeDeleteFilter(MimeDatabase, filter);
4156 }
bd7854cb 4157}
4158
4159
ef416fc2 4160#ifdef __sgi
4161/*
4162 * 'write_irix_config()' - Update the config files used by the IRIX
4163 * desktop tools.
4164 */
4165
4166static void
4167write_irix_config(cupsd_printer_t *p) /* I - Printer to update */
4168{
4169 char filename[1024]; /* Interface script filename */
4170 cups_file_t *fp; /* Interface script file */
f301802f 4171 ipp_attribute_t *attr; /* Attribute data */
ef416fc2 4172
4173
4174 /*
4175 * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
4176 * tools. First the interface script that tells the tools what kind of
4177 * printer we have...
4178 */
4179
4180 snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
4181
4182 if (p->type & CUPS_PRINTER_CLASS)
4183 unlink(filename);
4184 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
4185 {
4186 cupsFilePuts(fp, "#!/bin/sh\n");
4187
4188 if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
4189 IPP_TAG_TEXT)) != NULL)
4190 cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
4191 else if (p->type & CUPS_PRINTER_CLASS)
4192 cupsFilePuts(fp, "NAME=\"Printer Class\"\n");
4193 else
4194 cupsFilePuts(fp, "NAME=\"Remote Destination\"\n");
4195
4196 if (p->type & CUPS_PRINTER_COLOR)
4197 cupsFilePuts(fp, "TYPE=ColorPostScript\n");
4198 else
4199 cupsFilePuts(fp, "TYPE=MonoPostScript\n");
4200
4201 cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName);
4202 cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name);
4203
4204 cupsFileClose(fp);
4205
4206 chmod(filename, 0755);
4207 chown(filename, User, Group);
4208 }
4209
4210 /*
4211 * Then the member file that tells which device file the queue is connected
4212 * to... Networked printers use "/dev/null" in this file, so that's what
4213 * we use (the actual device URI can confuse some apps...)
4214 */
4215
4216 snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
4217
4218 if (p->type & CUPS_PRINTER_CLASS)
4219 unlink(filename);
4220 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
4221 {
4222 cupsFilePuts(fp, "/dev/null\n");
4223
4224 cupsFileClose(fp);
4225
4226 chmod(filename, 0644);
4227 chown(filename, User, Group);
4228 }
4229
4230 /*
4231 * The gui_interface file is a script or program that launches a GUI
4232 * option panel for the printer, using options specified on the
4233 * command-line in the third argument. The option panel must send
4234 * any printing options to stdout on a single line when the user
4235 * accepts them, or nothing if the user cancels the dialog.
4236 *
4237 * The default options panel program is /usr/bin/glpoptions, from
4238 * the ESP Print Pro software. You can select another using the
4239 * PrintcapGUI option.
4240 */
4241
4242 snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
4243
4244 if (p->type & CUPS_PRINTER_CLASS)
4245 unlink(filename);
4246 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
4247 {
4248 cupsFilePuts(fp, "#!/bin/sh\n");
4249 cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
4250
4251 cupsFileClose(fp);
4252
4253 chmod(filename, 0755);
4254 chown(filename, User, Group);
4255 }
4256
4257 /*
4258 * The POD config file is needed by the printstatus command to show
4259 * the printer location and device.
4260 */
4261
4262 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
4263
4264 if (p->type & CUPS_PRINTER_CLASS)
4265 unlink(filename);
4266 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
4267 {
4268 cupsFilePrintf(fp, "Printer Class | %s\n",
4269 (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
4270 cupsFilePrintf(fp, "Printer Model | %s\n", p->make_model ? p->make_model : "");
4271 cupsFilePrintf(fp, "Location Code | %s\n", p->location ? p->location : "");
4272 cupsFilePrintf(fp, "Physical Location | %s\n", p->info ? p->info : "");
0af14961 4273 cupsFilePrintf(fp, "Port Path | %s\n", p->device_uri);
ef416fc2 4274 cupsFilePrintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name);
4275 cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
4276 cupsFilePuts(fp, "Status Update Wait | 10 seconds\n");
4277
4278 cupsFileClose(fp);
4279
4280 chmod(filename, 0664);
4281 chown(filename, User, Group);
4282 }
4283}
4284
4285
4286/*
4287 * 'write_irix_state()' - Update the status files used by IRIX printing
4288 * desktop tools.
4289 */
4290
4291static void
4292write_irix_state(cupsd_printer_t *p) /* I - Printer to update */
4293{
4294 char filename[1024]; /* Interface script filename */
4295 cups_file_t *fp; /* Interface script file */
4296 int tag; /* Status tag value */
4297
4298
4299 if (p)
4300 {
4301 /*
4302 * The POD status file is needed for the printstatus window to
4303 * provide the current status of the printer.
4304 */
4305
4306 snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
4307
4308 if (p->type & CUPS_PRINTER_CLASS)
4309 unlink(filename);
4310 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
4311 {
4312 cupsFilePrintf(fp, "Operational Status | %s\n",
4313 (p->state == IPP_PRINTER_IDLE) ? "Idle" :
4314 (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
4315 "Faulted");
4316 cupsFilePrintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION);
4317 cupsFilePrintf(fp, "Information | 02 00 00 | Device URI: %s\n",
0af14961 4318 p->device_uri);
ef416fc2 4319 cupsFilePrintf(fp, "Information | 03 00 00 | %s jobs\n",
4320 p->accepting ? "Accepting" : "Not accepting");
4321 cupsFilePrintf(fp, "Information | 04 00 00 | %s\n", p->state_message);
4322
4323 cupsFileClose(fp);
4324
4325 chmod(filename, 0664);
4326 chown(filename, User, Group);
4327 }
4328
4329 /*
4330 * The activeicons file is needed to provide desktop icons for printers:
4331 *
4332 * [ quoted from /usr/lib/print/tagit ]
4333 *
4334 * --- Type of printer tags (base values)
4335 *
4336 * Dumb=66048 # 0x10200
4337 * DumbColor=66080 # 0x10220
4338 * Raster=66112 # 0x10240
4339 * ColorRaster=66144 # 0x10260
4340 * Plotter=66176 # 0x10280
4341 * PostScript=66208 # 0x102A0
4342 * ColorPostScript=66240 # 0x102C0
4343 * MonoPostScript=66272 # 0x102E0
4344 *
4345 * --- Printer state modifiers for local printers
4346 *
4347 * Idle=0 # 0x0
4348 * Busy=1 # 0x1
4349 * Faulted=2 # 0x2
4350 * Unknown=3 # 0x3 (Faulted due to unknown reason)
4351 *
4352 * --- Printer state modifiers for network printers
4353 *
4354 * NetIdle=8 # 0x8
4355 * NetBusy=9 # 0x9
4356 * NetFaulted=10 # 0xA
4357 * NetUnknown=11 # 0xB (Faulted due to unknown reason)
4358 */
4359
4360 snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
4361
4362 if (p->type & CUPS_PRINTER_CLASS)
4363 unlink(filename);
4364 else if ((fp = cupsFileOpen(filename, "w")) != NULL)
4365 {
4366 if (p->type & CUPS_PRINTER_COLOR)
4367 tag = 66240;
4368 else
4369 tag = 66272;
4370
4371 if (p->type & CUPS_PRINTER_REMOTE)
4372 tag |= 8;
4373
4374 if (p->state == IPP_PRINTER_PROCESSING)
4375 tag |= 1;
4376
4377 else if (p->state == IPP_PRINTER_STOPPED)
4378 tag |= 2;
4379
4380 cupsFilePuts(fp, "#!/bin/sh\n");
4381 cupsFilePrintf(fp, "#Tag %d\n", tag);
4382
4383 cupsFileClose(fp);
4384
4385 chmod(filename, 0755);
4386 chown(filename, User, Group);
4387 }
4388 }
4389
4390 /*
4391 * The default file is needed by the printers window to show
4392 * the default printer.
4393 */
4394
4395 snprintf(filename, sizeof(filename), "/var/spool/lp/default");
4396
4397 if (DefaultPrinter != NULL)
4398 {
4399 if ((fp = cupsFileOpen(filename, "w")) != NULL)
4400 {
4401 cupsFilePrintf(fp, "%s\n", DefaultPrinter->name);
4402
4403 cupsFileClose(fp);
4404
4405 chmod(filename, 0644);
4406 chown(filename, User, Group);
4407 }
4408 }
4409 else
4410 unlink(filename);
4411}
4412#endif /* __sgi */
4413
4414
4415/*
0af14961
MS
4416 * 'write_xml_string()' - Write a string with XML escaping.
4417 */
4418
4419static void
4420write_xml_string(cups_file_t *fp, /* I - File to write to */
4421 const char *s) /* I - String to write */
4422{
4423 const char *start; /* Start of current sequence */
4424
4425
4426 if (!s)
4427 return;
4428
4429 for (start = s; *s; s ++)
4430 {
4431 if (*s == '&')
4432 {
4433 if (s > start)
4434 cupsFileWrite(fp, start, s - start);
4435
4436 cupsFilePuts(fp, "&amp;");
4437 start = s + 1;
4438 }
4439 else if (*s == '<')
4440 {
4441 if (s > start)
4442 cupsFileWrite(fp, start, s - start);
4443
4444 cupsFilePuts(fp, "&lt;");
4445 start = s + 1;
4446 }
4447 }
4448
4449 if (s > start)
4450 cupsFilePuts(fp, start);
4451}
4452
4453
4454/*
4455 * End of "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $".
ef416fc2 4456 */