~ubuntu-branches/ubuntu/utopic/cups/utopic

« back to all changes in this revision

Viewing changes to .pc/fix-stringpool-corruption.patch/scheduler/printers.c

  • Committer: Package Import Robot
  • Author(s): Didier Raboud, Till Kamppeter, Steve Langasek, Didier Raboud
  • Date: 2014-01-03 18:42:39 UTC
  • mfrom: (1.3.2)
  • mto: This revision was merged to the branch mainline in revision 142.
  • Revision ID: package-import@ubuntu.com-20140103184239-juzq32ckr7ra49b3
* New 1.7.0 upstream release

[ Till Kamppeter ]
* Refresh most patches with quilt
* Removed usb-backend-do-not-crash-if-usb-disabled-in-bios and
  cupsd-no-crash-on-avahi-threaded-poll-shutdown patches as they got
  applied upstream
* Removed drop-arch-specifics-from-doc patch as it is not needed
  anymore
* Updated drop_unnecessary_dependencies, manpage-hyphen-minus,
  manpage-translations and ppd-poll-with-client-conf patches manually
  to apply to the new CUPS version
* Added error counting exception from
  usb-backend-do-not-crash-if-usb-disabled-in-bios to
  tests-ignore-warnings
* Install the newly added ippfind utility and its manpage in
  cups-client
* Added pwg.h to libcups2-dev package
* Call dh_auto_clean only if the file Makedefs is present, to avoid a
  FTBFS
* Added color management extensions from Joe Simon's GSoC 2013
  project.
* Patch cups-files.conf to activate CUPS daemon syncing of files when
  closing, so that config files (like printers.conf) do not
  mysteriously disappear (LP: #1157972)
* In the AppArmor profile, allow execution of programs in
  /etc/cups/interfaces/, needed to make CUPS working with queues based
  on System V interface scripts, especially PPD-less queues
  auto-generated by cups-browsed from cups-filters 1.0.41 on.
* Silenced AppArmor noise from udev.conf in syslog (LP: #1229766)

[ Steve Langasek ]
* Add cups-filters (>= 1.0.42) as alternative to foomatic-filters
  (which is deprecated) in package relationships

[ Didier Raboud ]
* Remove Roger Leigh from uploaders on his request with thanks for his
  past work!
* Switch avahi LSB Should-Start dependency to be avahi-daemon; also
  bump package relationship to >= 0.6.31-3~ (Closes: #731608)
* Refresh the manpage translation files
* Move the USB backend quirk rules file to cups-server-common
* Add 38 new 1.7.0 libcups2 symbols
* Mark one C++ libcupsppdc1 symbol as optional as it isn't exported in
  1.7.0 anymore
* Import Fedora patches:
  - to avoid sign-extending CRCs in gz decompression
  - to build with full read-only relocations
  - to fix job history logging (upstream patch)
  - to set the internal default for SyncOnClose to Yes, instead of
    only configuring it to Yes
  - to fix a stringpool corruption issue
  - to prevent USB timeouts causing incorrect print output
* Import Fedora patch updates:
  - to dont-use-dbus-from-two-threads patch so it removes a call to
    avahi_threaded_poll_stop()
  - to avoid_stale_lockfile_in_dbus_notifier patch to call _exit when
    handling SIGTERM
* Move manpage-translations patch at the very end of the patch series
  to have it include all our patches

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * "$Id: printers.c 10996 2013-05-29 11:51:34Z msweet $"
 
3
 *
 
4
 *   Printer routines for the CUPS scheduler.
 
5
 *
 
6
 *   Copyright 2007-2012 by Apple Inc.
 
7
 *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
 
8
 *
 
9
 *   These coded instructions, statements, and computer programs are the
 
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/".
 
14
 *
 
15
 * Contents:
 
16
 *
 
17
 *   cupsdAddPrinter()          - Add a printer to the system.
 
18
 *   cupsdCreateCommonData()    - Create the common printer data.
 
19
 *   cupsdDeleteAllPrinters()   - Delete all printers from the system.
 
20
 *   cupsdDeletePrinter()       - Delete a printer from the system.
 
21
 *   cupsdFindDest()            - Find a destination in the list.
 
22
 *   cupsdFindPrinter()         - Find a printer in the list.
 
23
 *   cupsdLoadAllPrinters()     - Load printers from the printers.conf file.
 
24
 *   cupsdRenamePrinter()       - Rename a printer.
 
25
 *   cupsdSaveAllPrinters()     - Save all printer definitions to the
 
26
 *                                printers.conf file.
 
27
 *   cupsdSetAuthInfoRequired() - Set the required authentication info.
 
28
 *   cupsdSetDeviceURI()        - Set the device URI for a printer.
 
29
 *   cupsdSetPrinterAttr()      - Set a printer attribute.
 
30
 *   cupsdSetPrinterAttrs()     - Set printer attributes based upon the PPD
 
31
 *                                file.
 
32
 *   cupsdSetPrinterReasons()   - Set/update the reasons strings.
 
33
 *   cupsdSetPrinterState()     - Update the current state of a printer.
 
34
 *   cupsdStopPrinter()         - Stop a printer from printing any jobs...
 
35
 *   cupsdUpdatePrinterPPD()    - Update keywords in a printer's PPD file.
 
36
 *   cupsdUpdatePrinters()      - Update printers after a partial reload.
 
37
 *   cupsdValidateDest()        - Validate a printer/class destination.
 
38
 *   cupsdWritePrintcap()       - Write a pseudo-printcap file for older
 
39
 *                                applications that need it...
 
40
 *   add_printer_defaults()     - Add name-default attributes to the printer
 
41
 *                                attributes.
 
42
 *   add_printer_filter()       - Add a MIME filter for a printer.
 
43
 *   add_printer_formats()      - Add document-format-supported values for a
 
44
 *                                printer.
 
45
 *   compare_printers()         - Compare two printers.
 
46
 *   delete_printer_filters()   - Delete all MIME filters for a printer.
 
47
 *   dirty_printer()            - Mark config and state files dirty for the
 
48
 *                                specified printer.
 
49
 *   load_ppd()                 - Load a cached PPD file, updating the cache as
 
50
 *                                needed.
 
51
 *   new_media_col()            - Create a media-col collection value.
 
52
 *   write_xml_string()         - Write a string with XML escaping.
 
53
 */
 
54
 
 
55
/*
 
56
 * Include necessary headers...
 
57
 */
 
58
 
 
59
#include "cupsd.h"
 
60
#include <cups/dir.h>
 
61
#ifdef HAVE_APPLICATIONSERVICES_H
 
62
#  include <ApplicationServices/ApplicationServices.h>
 
63
#endif /* HAVE_APPLICATIONSERVICES_H */
 
64
#ifdef HAVE_SYS_MOUNT_H
 
65
#  include <sys/mount.h>
 
66
#endif /* HAVE_SYS_MOUNT_H */
 
67
#ifdef HAVE_SYS_STATVFS_H
 
68
#  include <sys/statvfs.h>
 
69
#elif defined(HAVE_SYS_STATFS_H)
 
70
#  include <sys/statfs.h>
 
71
#endif /* HAVE_SYS_STATVFS_H */
 
72
#ifdef HAVE_SYS_VFS_H
 
73
#  include <sys/vfs.h>
 
74
#endif /* HAVE_SYS_VFS_H */
 
75
#ifdef __APPLE__
 
76
#  include <asl.h>
 
77
#endif /* __APPLE__ */
 
78
 
 
79
 
 
80
/*
 
81
 * Local functions...
 
82
 */
 
83
 
 
84
static void     add_printer_defaults(cupsd_printer_t *p);
 
85
static void     add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
 
86
                                   const char *filter);
 
87
static void     add_printer_formats(cupsd_printer_t *p);
 
88
static int      compare_printers(void *first, void *second, void *data);
 
89
static void     delete_printer_filters(cupsd_printer_t *p);
 
90
static void     dirty_printer(cupsd_printer_t *p);
 
91
static void     load_ppd(cupsd_printer_t *p);
 
92
static void     log_ipp_conformance(cupsd_printer_t *p, const char *reason);
 
93
static ipp_t    *new_media_col(_pwg_size_t *size, const char *source,
 
94
                               const char *type);
 
95
static void     write_xml_string(cups_file_t *fp, const char *s);
 
96
 
 
97
 
 
98
/*
 
99
 * 'cupsdAddPrinter()' - Add a printer to the system.
 
100
 */
 
101
 
 
102
cupsd_printer_t *                       /* O - New printer */
 
103
cupsdAddPrinter(const char *name)       /* I - Name of printer */
 
104
{
 
105
  cupsd_printer_t       *p;             /* New printer */
 
106
  char                  uri[1024],      /* Printer URI */
 
107
                        uuid[64];       /* Printer UUID */
 
108
 
 
109
 
 
110
 /*
 
111
  * Range check input...
 
112
  */
 
113
 
 
114
  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPrinter(\"%s\")", name);
 
115
 
 
116
 /*
 
117
  * Create a new printer entity...
 
118
  */
 
119
 
 
120
  if ((p = calloc(1, sizeof(cupsd_printer_t))) == NULL)
 
121
  {
 
122
    cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for printer - %s",
 
123
                    strerror(errno));
 
124
    return (NULL);
 
125
  }
 
126
 
 
127
  cupsdSetString(&p->name, name);
 
128
  cupsdSetString(&p->info, name);
 
129
  cupsdSetString(&p->hostname, ServerName);
 
130
 
 
131
  httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
 
132
                   ServerName, RemotePort, "/printers/%s", name);
 
133
  cupsdSetString(&p->uri, uri);
 
134
  cupsdSetString(&p->uuid, _httpAssembleUUID(ServerName, RemotePort, name, 0,
 
135
                                             uuid, sizeof(uuid)));
 
136
  cupsdSetDeviceURI(p, "file:///dev/null");
 
137
  cupsdSetString(&p->ppd_timestamp, "*");
 
138
  p->state         = IPP_PRINTER_STOPPED;
 
139
  p->state_time    = time(NULL);
 
140
  p->accepting     = 0;
 
141
  p->color_managed = 1;
 
142
  p->shared        = DefaultShared;
 
143
  p->filetype      = mimeAddType(MimeDatabase, "printer", name);
 
144
 
 
145
  cupsdSetString(&p->job_sheets[0], "none");
 
146
  cupsdSetString(&p->job_sheets[1], "none");
 
147
 
 
148
  cupsdSetString(&p->error_policy, ErrorPolicy);
 
149
  cupsdSetString(&p->op_policy, DefaultPolicy);
 
150
 
 
151
  p->op_policy_ptr = DefaultPolicyPtr;
 
152
 
 
153
 /*
 
154
  * Insert the printer in the printer list alphabetically...
 
155
  */
 
156
 
 
157
  if (!Printers)
 
158
    Printers = cupsArrayNew(compare_printers, NULL);
 
159
 
 
160
  cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
161
                  "cupsdAddPrinter: Adding %s to Printers", p->name);
 
162
  cupsArrayAdd(Printers, p);
 
163
 
 
164
 /*
 
165
  * Return the new printer...
 
166
  */
 
167
 
 
168
  return (p);
 
169
}
 
170
 
 
171
 
 
172
/*
 
173
 * 'cupsdCreateCommonData()' - Create the common printer data.
 
174
 */
 
175
 
 
176
void
 
177
cupsdCreateCommonData(void)
 
178
{
 
179
  int                   i;              /* Looping var */
 
180
  ipp_attribute_t       *attr;          /* Attribute data */
 
181
  cups_dir_t            *dir;           /* Notifier directory */
 
182
  cups_dentry_t         *dent;          /* Notifier directory entry */
 
183
  cups_array_t          *notifiers;     /* Notifier array */
 
184
  char                  filename[1024], /* Filename */
 
185
                        *notifier;      /* Current notifier */
 
186
  cupsd_policy_t        *p;             /* Current policy */
 
187
  int                   k_supported;    /* Maximum file size supported */
 
188
#ifdef HAVE_STATVFS
 
189
  struct statvfs        spoolinfo;      /* FS info for spool directory */
 
190
  double                spoolsize;      /* FS size */
 
191
#elif defined(HAVE_STATFS)
 
192
  struct statfs         spoolinfo;      /* FS info for spool directory */
 
193
  double                spoolsize;      /* FS size */
 
194
#endif /* HAVE_STATVFS */
 
195
  static const int nups[] =             /* number-up-supported values */
 
196
                { 1, 2, 4, 6, 9, 16 };
 
197
  static const int orients[4] =/* orientation-requested-supported values */
 
198
                {
 
199
                  IPP_PORTRAIT,
 
200
                  IPP_LANDSCAPE,
 
201
                  IPP_REVERSE_LANDSCAPE,
 
202
                  IPP_REVERSE_PORTRAIT
 
203
                };
 
204
  static const char * const holds[] =   /* job-hold-until-supported values */
 
205
                {
 
206
                  "no-hold",
 
207
                  "indefinite",
 
208
                  "day-time",
 
209
                  "evening",
 
210
                  "night",
 
211
                  "second-shift",
 
212
                  "third-shift",
 
213
                  "weekend"
 
214
                };
 
215
  static const char * const versions[] =/* ipp-versions-supported values */
 
216
                {
 
217
                  "1.0",
 
218
                  "1.1",
 
219
                  "2.0",
 
220
                  "2.1"
 
221
                };
 
222
  static const int      ops[] =         /* operations-supported values */
 
223
                {
 
224
                  IPP_PRINT_JOB,
 
225
                  IPP_VALIDATE_JOB,
 
226
                  IPP_CREATE_JOB,
 
227
                  IPP_SEND_DOCUMENT,
 
228
                  IPP_CANCEL_JOB,
 
229
                  IPP_GET_JOB_ATTRIBUTES,
 
230
                  IPP_GET_JOBS,
 
231
                  IPP_GET_PRINTER_ATTRIBUTES,
 
232
                  IPP_HOLD_JOB,
 
233
                  IPP_RELEASE_JOB,
 
234
                  IPP_RESTART_JOB,
 
235
                  IPP_PAUSE_PRINTER,
 
236
                  IPP_RESUME_PRINTER,
 
237
                  IPP_PURGE_JOBS,
 
238
                  IPP_SET_PRINTER_ATTRIBUTES,
 
239
                  IPP_SET_JOB_ATTRIBUTES,
 
240
                  IPP_GET_PRINTER_SUPPORTED_VALUES,
 
241
                  IPP_CREATE_PRINTER_SUBSCRIPTION,
 
242
                  IPP_CREATE_JOB_SUBSCRIPTION,
 
243
                  IPP_GET_SUBSCRIPTION_ATTRIBUTES,
 
244
                  IPP_GET_SUBSCRIPTIONS,
 
245
                  IPP_RENEW_SUBSCRIPTION,
 
246
                  IPP_CANCEL_SUBSCRIPTION,
 
247
                  IPP_GET_NOTIFICATIONS,
 
248
                  IPP_ENABLE_PRINTER,
 
249
                  IPP_DISABLE_PRINTER,
 
250
                  IPP_HOLD_NEW_JOBS,
 
251
                  IPP_RELEASE_HELD_NEW_JOBS,
 
252
                  IPP_CANCEL_JOBS,
 
253
                  IPP_CANCEL_MY_JOBS,
 
254
                  IPP_CLOSE_JOB,
 
255
                  CUPS_GET_DEFAULT,
 
256
                  CUPS_GET_PRINTERS,
 
257
                  CUPS_ADD_PRINTER,
 
258
                  CUPS_DELETE_PRINTER,
 
259
                  CUPS_GET_CLASSES,
 
260
                  CUPS_ADD_CLASS,
 
261
                  CUPS_DELETE_CLASS,
 
262
                  CUPS_ACCEPT_JOBS,
 
263
                  CUPS_REJECT_JOBS,
 
264
                  CUPS_SET_DEFAULT,
 
265
                  CUPS_GET_DEVICES,
 
266
                  CUPS_GET_PPDS,
 
267
                  CUPS_MOVE_JOB,
 
268
                  CUPS_AUTHENTICATE_JOB,
 
269
                  CUPS_GET_PPD,
 
270
                  CUPS_GET_DOCUMENT,
 
271
                  IPP_RESTART_JOB
 
272
                };
 
273
  static const char * const charsets[] =/* charset-supported values */
 
274
                {
 
275
                  "us-ascii",
 
276
                  "utf-8"
 
277
                };
 
278
  static const char * const compressions[] =
 
279
                {                       /* document-compression-supported values */
 
280
                  "none"
 
281
#ifdef HAVE_LIBZ
 
282
                  ,"gzip"
 
283
#endif /* HAVE_LIBZ */
 
284
                };
 
285
  static const char * const media_col_supported[] =
 
286
                {                       /* media-col-supported values */
 
287
                  "media-bottom-margin",
 
288
                  "media-left-margin",
 
289
                  "media-right-margin",
 
290
                  "media-size",
 
291
                  "media-source",
 
292
                  "media-top-margin",
 
293
                  "media-type"
 
294
                };
 
295
  static const char * const multiple_document_handling[] =
 
296
                {                       /* multiple-document-handling-supported values */
 
297
                  "separate-documents-uncollated-copies",
 
298
                  "separate-documents-collated-copies"
 
299
                };
 
300
  static const char * const notify_attrs[] =
 
301
                {                       /* notify-attributes-supported values */
 
302
                  "printer-state-change-time",
 
303
                  "notify-lease-expiration-time",
 
304
                  "notify-subscriber-user-name"
 
305
                };
 
306
  static const char * const notify_events[] =
 
307
                {                       /* notify-events-supported values */
 
308
                  "job-completed",
 
309
                  "job-config-changed",
 
310
                  "job-created",
 
311
                  "job-progress",
 
312
                  "job-state-changed",
 
313
                  "job-stopped",
 
314
                  "printer-added",
 
315
                  "printer-changed",
 
316
                  "printer-config-changed",
 
317
                  "printer-deleted",
 
318
                  "printer-finishings-changed",
 
319
                  "printer-media-changed",
 
320
                  "printer-modified",
 
321
                  "printer-restarted",
 
322
                  "printer-shutdown",
 
323
                  "printer-state-changed",
 
324
                  "printer-stopped",
 
325
                  "server-audit",
 
326
                  "server-restarted",
 
327
                  "server-started",
 
328
                  "server-stopped"
 
329
                };
 
330
  static const char * const job_creation[] =
 
331
                {                       /* job-creation-attributes-supported */
 
332
                  "copies",
 
333
                  "finishings",
 
334
                  "ipp-attribute-fidelity",
 
335
                  "job-hold-until",
 
336
                  "job-name",
 
337
                  "job-priority",
 
338
                  "job-sheets",
 
339
                  "media",
 
340
                  "media-col",
 
341
                  "multiple-document-handling",
 
342
                  "number-up",
 
343
                  "output-bin",
 
344
                  "orientation-requested",
 
345
                  "page-ranges",
 
346
                  "print-color-mode",
 
347
                  "print-quality",
 
348
                  "printer-resolution",
 
349
                  "sides"
 
350
                };
 
351
  static const char * const job_settable[] =
 
352
                {                       /* job-settable-attributes-supported */
 
353
                  "copies",
 
354
                  "finishings",
 
355
                  "job-hold-until",
 
356
                  "job-name",
 
357
                  "job-priority",
 
358
                  "media",
 
359
                  "media-col",
 
360
                  "multiple-document-handling",
 
361
                  "number-up",
 
362
                  "output-bin",
 
363
                  "orientation-requested",
 
364
                  "page-ranges",
 
365
                  "print-color-mode",
 
366
                  "print-quality",
 
367
                  "printer-resolution",
 
368
                  "sides"
 
369
                };
 
370
  static const char * const pdf_versions[] =
 
371
                {                       /* pdf-versions-supported */
 
372
                  "adobe-1.2",
 
373
                  "adobe-1.3",
 
374
                  "adobe-1.4",
 
375
                  "adobe-1.5",
 
376
                  "adobe-1.6",
 
377
                  "adobe-1.7",
 
378
                  "iso-19005-1_2005",
 
379
                  "iso-32000-1_2008",
 
380
                  "pwg-5102.3"
 
381
                };
 
382
  static const char * const printer_settable[] =
 
383
                {                       /* printer-settable-attributes-supported */
 
384
                  "printer-info",
 
385
                  "printer-location"
 
386
                };
 
387
  static const char * const which_jobs[] =
 
388
                {                       /* which-jobs-supported values */
 
389
                  "completed",
 
390
                  "not-completed",
 
391
                  "aborted",
 
392
                  "all",
 
393
                  "canceled",
 
394
                  "pending",
 
395
                  "pending-held",
 
396
                  "processing",
 
397
                  "processing-stopped"
 
398
                };
 
399
 
 
400
 
 
401
  if (CommonData)
 
402
    ippDelete(CommonData);
 
403
 
 
404
  CommonData = ippNew();
 
405
 
 
406
 /*
 
407
  * Get the maximum spool size based on the size of the filesystem used for
 
408
  * the RequestRoot directory.  If the host OS doesn't support the statfs call
 
409
  * or the filesystem is larger than 2TiB, always report INT_MAX.
 
410
  */
 
411
 
 
412
#ifdef HAVE_STATVFS
 
413
  if (statvfs(RequestRoot, &spoolinfo))
 
414
    k_supported = INT_MAX;
 
415
  else if ((spoolsize = (double)spoolinfo.f_frsize * spoolinfo.f_blocks / 1024) >
 
416
               INT_MAX)
 
417
    k_supported = INT_MAX;
 
418
  else
 
419
    k_supported = (int)spoolsize;
 
420
 
 
421
#elif defined(HAVE_STATFS)
 
422
  if (statfs(RequestRoot, &spoolinfo))
 
423
    k_supported = INT_MAX;
 
424
  else if ((spoolsize = (double)spoolinfo.f_bsize * spoolinfo.f_blocks / 1024) >
 
425
               INT_MAX)
 
426
    k_supported = INT_MAX;
 
427
  else
 
428
    k_supported = (int)spoolsize;
 
429
 
 
430
#else
 
431
  k_supported = INT_MAX;
 
432
#endif /* HAVE_STATVFS */
 
433
 
 
434
 /*
 
435
  * This list of attributes is sorted to improve performance when the
 
436
  * client provides a requested-attributes attribute...
 
437
  */
 
438
 
 
439
  /* charset-configured */
 
440
  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
 
441
               "charset-configured", NULL, "utf-8");
 
442
 
 
443
  /* charset-supported */
 
444
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
 
445
                "charset-supported", sizeof(charsets) / sizeof(charsets[0]),
 
446
                NULL, charsets);
 
447
 
 
448
  /* compression-supported */
 
449
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
450
                "compression-supported",
 
451
                sizeof(compressions) / sizeof(compressions[0]),
 
452
                NULL, compressions);
 
453
 
 
454
  /* copies-supported */
 
455
  ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
 
456
 
 
457
  /* cups-version */
 
458
  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT | IPP_TAG_COPY,
 
459
               "cups-version", NULL, CUPS_SVERSION + 6);
 
460
 
 
461
  /* generated-natural-language-supported (no IPP_TAG_COPY) */
 
462
  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
 
463
               "generated-natural-language-supported", NULL, DefaultLanguage);
 
464
 
 
465
  /* ipp-versions-supported */
 
466
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
467
                "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
 
468
                NULL, versions);
 
469
 
 
470
  /* ippget-event-life */
 
471
  ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
472
                "ippget-event-life", 15);
 
473
 
 
474
  /* job-creation-attributes-supported */
 
475
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
476
                "job-creation-attributes-supported",
 
477
                sizeof(job_creation) / sizeof(job_creation[0]),
 
478
                NULL, job_creation);
 
479
 
 
480
  /* job-hold-until-supported */
 
481
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
482
                "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]),
 
483
                NULL, holds);
 
484
 
 
485
  /* job-ids-supported */
 
486
  ippAddBoolean(CommonData, IPP_TAG_PRINTER, "job-ids-supported", 1);
 
487
 
 
488
  /* job-k-octets-supported */
 
489
  ippAddRange(CommonData, IPP_TAG_PRINTER, "job-k-octets-supported", 0,
 
490
              k_supported);
 
491
 
 
492
  /* job-priority-supported */
 
493
  ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
494
                "job-priority-supported", 100);
 
495
 
 
496
  /* job-settable-attributes-supported */
 
497
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
498
                "job-settable-attributes-supported",
 
499
                sizeof(job_settable) / sizeof(job_settable[0]),
 
500
                NULL, job_settable);
 
501
 
 
502
  /* job-sheets-supported */
 
503
  if (cupsArrayCount(Banners) > 0)
 
504
  {
 
505
   /*
 
506
    * Setup the job-sheets-supported attribute...
 
507
    */
 
508
 
 
509
    if (Classification && !ClassifyOverride)
 
510
      attr = ippAddString(CommonData, IPP_TAG_PRINTER,
 
511
                          IPP_TAG_NAME | IPP_TAG_COPY,
 
512
                          "job-sheets-supported", NULL, Classification);
 
513
    else
 
514
      attr = ippAddStrings(CommonData, IPP_TAG_PRINTER,
 
515
                           IPP_TAG_NAME | IPP_TAG_COPY,
 
516
                           "job-sheets-supported", cupsArrayCount(Banners) + 1,
 
517
                           NULL, NULL);
 
518
 
 
519
    if (attr == NULL)
 
520
      cupsdLogMessage(CUPSD_LOG_EMERG,
 
521
                      "Unable to allocate memory for "
 
522
                      "job-sheets-supported attribute: %s!", strerror(errno));
 
523
    else if (!Classification || ClassifyOverride)
 
524
    {
 
525
      cupsd_banner_t    *banner;        /* Current banner */
 
526
 
 
527
 
 
528
      attr->values[0].string.text = _cupsStrAlloc("none");
 
529
 
 
530
      for (i = 1, banner = (cupsd_banner_t *)cupsArrayFirst(Banners);
 
531
           banner;
 
532
           i ++, banner = (cupsd_banner_t *)cupsArrayNext(Banners))
 
533
        attr->values[i].string.text = banner->name;
 
534
    }
 
535
  }
 
536
  else
 
537
    ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
 
538
                 "job-sheets-supported", NULL, "none");
 
539
 
 
540
  /* jpeg-k-octets-supported */
 
541
  ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-k-octets-supported", 0,
 
542
              k_supported);
 
543
 
 
544
  /* jpeg-x-dimension-supported */
 
545
  ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-x-dimension-supported", 0,
 
546
              65535);
 
547
 
 
548
  /* jpeg-y-dimension-supported */
 
549
  ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-y-dimension-supported", 1,
 
550
              65535);
 
551
 
 
552
  /* media-col-supported */
 
553
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
554
                "media-col-supported",
 
555
                sizeof(media_col_supported) /
 
556
                    sizeof(media_col_supported[0]), NULL,
 
557
                media_col_supported);
 
558
 
 
559
  /* multiple-document-handling-supported */
 
560
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
561
                "multiple-document-handling-supported",
 
562
                sizeof(multiple_document_handling) /
 
563
                    sizeof(multiple_document_handling[0]), NULL,
 
564
                multiple_document_handling);
 
565
 
 
566
  /* multiple-document-jobs-supported */
 
567
  ippAddBoolean(CommonData, IPP_TAG_PRINTER,
 
568
                "multiple-document-jobs-supported", 1);
 
569
 
 
570
  /* multiple-operation-time-out */
 
571
  ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
572
                "multiple-operation-time-out", MultipleOperationTimeout);
 
573
 
 
574
  /* natural-language-configured (no IPP_TAG_COPY) */
 
575
  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
 
576
               "natural-language-configured", NULL, DefaultLanguage);
 
577
 
 
578
  /* notify-attributes-supported */
 
579
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
580
                "notify-attributes-supported",
 
581
                (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])),
 
582
                NULL, notify_attrs);
 
583
 
 
584
  /* notify-lease-duration-supported */
 
585
  ippAddRange(CommonData, IPP_TAG_PRINTER,
 
586
              "notify-lease-duration-supported", 0,
 
587
              MaxLeaseDuration ? MaxLeaseDuration : 2147483647);
 
588
 
 
589
  /* notify-max-events-supported */
 
590
  ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
591
               "notify-max-events-supported", MaxEvents);
 
592
 
 
593
  /* notify-events-supported */
 
594
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
595
                "notify-events-supported",
 
596
                (int)(sizeof(notify_events) / sizeof(notify_events[0])),
 
597
                NULL, notify_events);
 
598
 
 
599
  /* notify-pull-method-supported */
 
600
  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
601
               "notify-pull-method-supported", NULL, "ippget");
 
602
 
 
603
  /* notify-schemes-supported */
 
604
  snprintf(filename, sizeof(filename), "%s/notifier", ServerBin);
 
605
  if ((dir = cupsDirOpen(filename)) != NULL)
 
606
  {
 
607
    notifiers = cupsArrayNew((cups_array_func_t)strcmp, NULL);
 
608
 
 
609
    while ((dent = cupsDirRead(dir)) != NULL)
 
610
      if (S_ISREG(dent->fileinfo.st_mode) &&
 
611
          (dent->fileinfo.st_mode & S_IXOTH) != 0)
 
612
        cupsArrayAdd(notifiers, _cupsStrAlloc(dent->filename));
 
613
 
 
614
    if (cupsArrayCount(notifiers) > 0)
 
615
    {
 
616
      attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
617
                           "notify-schemes-supported",
 
618
                           cupsArrayCount(notifiers), NULL, NULL);
 
619
 
 
620
      for (i = 0, notifier = (char *)cupsArrayFirst(notifiers);
 
621
           notifier;
 
622
           i ++, notifier = (char *)cupsArrayNext(notifiers))
 
623
        attr->values[i].string.text = notifier;
 
624
    }
 
625
 
 
626
    cupsArrayDelete(notifiers);
 
627
    cupsDirClose(dir);
 
628
  }
 
629
 
 
630
  /* number-up-supported */
 
631
  ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
632
                 "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
 
633
 
 
634
  /* operations-supported */
 
635
  ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
 
636
                 "operations-supported", sizeof(ops) / sizeof(ops[0]), ops);
 
637
 
 
638
  /* orientation-requested-supported */
 
639
  ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
 
640
                 "orientation-requested-supported", 4, orients);
 
641
 
 
642
  /* page-ranges-supported */
 
643
  ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
 
644
 
 
645
  /* pdf-k-octets-supported */
 
646
  ippAddRange(CommonData, IPP_TAG_PRINTER, "pdf-k-octets-supported", 0,
 
647
              k_supported);
 
648
 
 
649
  /* pdf-versions-supported */
 
650
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
651
                "pdf-versions-supported",
 
652
                sizeof(pdf_versions) / sizeof(pdf_versions[0]), NULL,
 
653
                pdf_versions);
 
654
 
 
655
  /* pdl-override-supported */
 
656
  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
657
               "pdl-override-supported", NULL, "attempted");
 
658
 
 
659
  /* printer-op-policy-supported */
 
660
  attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
 
661
                       "printer-op-policy-supported", cupsArrayCount(Policies),
 
662
                       NULL, NULL);
 
663
  for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies);
 
664
       p;
 
665
       i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies))
 
666
    attr->values[i].string.text = p->name;
 
667
 
 
668
  /* printer-settable-attributes-supported */
 
669
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
670
                "printer-settable-attributes-supported",
 
671
                sizeof(printer_settable) / sizeof(printer_settable[0]),
 
672
                NULL, printer_settable);
 
673
 
 
674
  /* server-is-sharing-printers */
 
675
  ippAddBoolean(CommonData, IPP_TAG_PRINTER, "server-is-sharing-printers",
 
676
                BrowseLocalProtocols != 0 && Browsing);
 
677
 
 
678
  /* which-jobs-supported */
 
679
  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
 
680
                "which-jobs-supported",
 
681
                sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs);
 
682
}
 
683
 
 
684
 
 
685
/*
 
686
 * 'cupsdDeleteAllPrinters()' - Delete all printers from the system.
 
687
 */
 
688
 
 
689
void
 
690
cupsdDeleteAllPrinters(void)
 
691
{
 
692
  cupsd_printer_t       *p;             /* Pointer to current printer/class */
 
693
 
 
694
 
 
695
  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
 
696
       p;
 
697
       p = (cupsd_printer_t *)cupsArrayNext(Printers))
 
698
  {
 
699
    p->op_policy_ptr = DefaultPolicyPtr;
 
700
    cupsdDeletePrinter(p, 0);
 
701
  }
 
702
}
 
703
 
 
704
 
 
705
/*
 
706
 * 'cupsdDeletePrinter()' - Delete a printer from the system.
 
707
 */
 
708
 
 
709
int                                     /* O - 1 if classes affected, 0 otherwise */
 
710
cupsdDeletePrinter(
 
711
    cupsd_printer_t *p,                 /* I - Printer to delete */
 
712
    int             update)             /* I - Update printers.conf? */
 
713
{
 
714
  int   i,                              /* Looping var */
 
715
        changed = 0;                    /* Class changed? */
 
716
 
 
717
 
 
718
  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)",
 
719
                  p, p->name, update);
 
720
 
 
721
 /*
 
722
  * Save the current position in the Printers array...
 
723
  */
 
724
 
 
725
  cupsArraySave(Printers);
 
726
 
 
727
 /*
 
728
  * Stop printing on this printer...
 
729
  */
 
730
 
 
731
  cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
 
732
 
 
733
  p->state = IPP_PRINTER_STOPPED;       /* Force for browsed printers */
 
734
 
 
735
  if (p->job)
 
736
    cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE,
 
737
                     update ? "Job stopped due to printer being deleted." :
 
738
                              "Job stopped.");
 
739
 
 
740
 /*
 
741
  * Remove the printer from the list...
 
742
  */
 
743
 
 
744
  cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
745
                  "cupsdDeletePrinter: Removing %s from Printers", p->name);
 
746
  cupsArrayRemove(Printers, p);
 
747
 
 
748
 /*
 
749
  * If p is the default printer, assign a different one...
 
750
  */
 
751
 
 
752
  if (p == DefaultPrinter)
 
753
    DefaultPrinter = NULL;
 
754
 
 
755
 /*
 
756
  * Remove this printer from any classes...
 
757
  */
 
758
 
 
759
  changed = cupsdDeletePrinterFromClasses(p);
 
760
 
 
761
 /*
 
762
  * Deregister from any browse protocols...
 
763
  */
 
764
 
 
765
  cupsdDeregisterPrinter(p, 1);
 
766
 
 
767
 /*
 
768
  * Free all memory used by the printer...
 
769
  */
 
770
 
 
771
  if (p->printers != NULL)
 
772
    free(p->printers);
 
773
 
 
774
  delete_printer_filters(p);
 
775
 
 
776
  for (i = 0; i < p->num_reasons; i ++)
 
777
    _cupsStrFree(p->reasons[i]);
 
778
 
 
779
  ippDelete(p->attrs);
 
780
  ippDelete(p->ppd_attrs);
 
781
 
 
782
  mimeDeleteType(MimeDatabase, p->filetype);
 
783
  mimeDeleteType(MimeDatabase, p->prefiltertype);
 
784
 
 
785
  cupsdFreeStrings(&(p->users));
 
786
  cupsdFreeQuotas(p);
 
787
 
 
788
  cupsdClearString(&p->uri);
 
789
  cupsdClearString(&p->hostname);
 
790
  cupsdClearString(&p->name);
 
791
  cupsdClearString(&p->location);
 
792
  cupsdClearString(&p->make_model);
 
793
  cupsdClearString(&p->info);
 
794
  cupsdClearString(&p->job_sheets[0]);
 
795
  cupsdClearString(&p->job_sheets[1]);
 
796
  cupsdClearString(&p->device_uri);
 
797
  cupsdClearString(&p->ppd_timestamp);
 
798
  cupsdClearString(&p->sanitized_device_uri);
 
799
  cupsdClearString(&p->port_monitor);
 
800
  cupsdClearString(&p->op_policy);
 
801
  cupsdClearString(&p->error_policy);
 
802
 
 
803
  cupsdClearString(&p->alert);
 
804
  cupsdClearString(&p->alert_description);
 
805
 
 
806
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
 
807
  cupsdClearString(&p->pdl);
 
808
  cupsdClearString(&p->reg_name);
 
809
#endif /* HAVE_DNSSD || HAVE_AVAHI */
 
810
 
 
811
  cupsArrayDelete(p->filetypes);
 
812
 
 
813
  cupsFreeOptions(p->num_options, p->options);
 
814
 
 
815
  free(p);
 
816
 
 
817
 /*
 
818
  * Restore the previous position in the Printers array...
 
819
  */
 
820
 
 
821
  cupsArrayRestore(Printers);
 
822
 
 
823
  return (changed);
 
824
}
 
825
 
 
826
 
 
827
/*
 
828
 * 'cupsdFindDest()' - Find a destination in the list.
 
829
 */
 
830
 
 
831
cupsd_printer_t *                       /* O - Destination in list */
 
832
cupsdFindDest(const char *name)         /* I - Name of printer or class to find */
 
833
{
 
834
  cupsd_printer_t       key;            /* Search key */
 
835
 
 
836
 
 
837
  key.name = (char *)name;
 
838
  return ((cupsd_printer_t *)cupsArrayFind(Printers, &key));
 
839
}
 
840
 
 
841
 
 
842
/*
 
843
 * 'cupsdFindPrinter()' - Find a printer in the list.
 
844
 */
 
845
 
 
846
cupsd_printer_t *                       /* O - Printer in list */
 
847
cupsdFindPrinter(const char *name)      /* I - Name of printer to find */
 
848
{
 
849
  cupsd_printer_t       *p;             /* Printer in list */
 
850
 
 
851
 
 
852
  if ((p = cupsdFindDest(name)) != NULL && (p->type & CUPS_PRINTER_CLASS))
 
853
    return (NULL);
 
854
  else
 
855
    return (p);
 
856
}
 
857
 
 
858
 
 
859
/*
 
860
 * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file.
 
861
 */
 
862
 
 
863
void
 
864
cupsdLoadAllPrinters(void)
 
865
{
 
866
  int                   i;              /* Looping var */
 
867
  cups_file_t           *fp;            /* printers.conf file */
 
868
  int                   linenum;        /* Current line number */
 
869
  char                  line[4096],     /* Line from file */
 
870
                        *value,         /* Pointer to value */
 
871
                        *valueptr;      /* Pointer into value */
 
872
  cupsd_printer_t       *p;             /* Current printer */
 
873
 
 
874
 
 
875
 /*
 
876
  * Open the printers.conf file...
 
877
  */
 
878
 
 
879
  snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
 
880
  if ((fp = cupsdOpenConfFile(line)) == NULL)
 
881
    return;
 
882
 
 
883
 /*
 
884
  * Read printer configurations until we hit EOF...
 
885
  */
 
886
 
 
887
  linenum = 0;
 
888
  p       = NULL;
 
889
 
 
890
  while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
 
891
  {
 
892
   /*
 
893
    * Decode the directive...
 
894
    */
 
895
 
 
896
    if (!_cups_strcasecmp(line, "<Printer") ||
 
897
        !_cups_strcasecmp(line, "<DefaultPrinter"))
 
898
    {
 
899
     /*
 
900
      * <Printer name> or <DefaultPrinter name>
 
901
      */
 
902
 
 
903
      if (p == NULL && value)
 
904
      {
 
905
       /*
 
906
        * Add the printer and a base file type...
 
907
        */
 
908
 
 
909
        cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading printer %s...", value);
 
910
 
 
911
        p = cupsdAddPrinter(value);
 
912
        p->accepting = 1;
 
913
        p->state     = IPP_PRINTER_IDLE;
 
914
 
 
915
       /*
 
916
        * Set the default printer as needed...
 
917
        */
 
918
 
 
919
        if (!_cups_strcasecmp(line, "<DefaultPrinter"))
 
920
          DefaultPrinter = p;
 
921
      }
 
922
      else
 
923
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
924
                        "Syntax error on line %d of printers.conf.", linenum);
 
925
    }
 
926
    else if (!_cups_strcasecmp(line, "</Printer>"))
 
927
    {
 
928
      if (p != NULL)
 
929
      {
 
930
       /*
 
931
        * Close out the current printer...
 
932
        */
 
933
 
 
934
        cupsdSetPrinterAttrs(p);
 
935
 
 
936
        if (strncmp(p->device_uri, "file:", 5) &&
 
937
            p->state != IPP_PRINTER_STOPPED)
 
938
        {
 
939
         /*
 
940
          * See if the backend exists...
 
941
          */
 
942
 
 
943
          snprintf(line, sizeof(line), "%s/backend/%s", ServerBin,
 
944
                   p->device_uri);
 
945
 
 
946
          if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
 
947
            *valueptr = '\0';           /* Chop everything but URI scheme */
 
948
 
 
949
          if (access(line, 0))
 
950
          {
 
951
           /*
 
952
            * Backend does not exist, stop printer...
 
953
            */
 
954
 
 
955
            p->state = IPP_PRINTER_STOPPED;
 
956
            snprintf(p->state_message, sizeof(p->state_message),
 
957
                     "Backend %s does not exist!", line);
 
958
          }
 
959
        }
 
960
 
 
961
        p = NULL;
 
962
      }
 
963
      else
 
964
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
965
                        "Syntax error on line %d of printers.conf.", linenum);
 
966
    }
 
967
    else if (!p)
 
968
    {
 
969
      cupsdLogMessage(CUPSD_LOG_ERROR,
 
970
                      "Syntax error on line %d of printers.conf.", linenum);
 
971
    }
 
972
    else if (!_cups_strcasecmp(line, "UUID"))
 
973
    {
 
974
      if (value && !strncmp(value, "urn:uuid:", 9))
 
975
        cupsdSetString(&(p->uuid), value);
 
976
      else
 
977
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
978
                        "Bad UUID on line %d of printers.conf.", linenum);
 
979
    }
 
980
    else if (!_cups_strcasecmp(line, "AuthInfoRequired"))
 
981
    {
 
982
      if (!cupsdSetAuthInfoRequired(p, value, NULL))
 
983
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
984
                        "Bad AuthInfoRequired on line %d of printers.conf.",
 
985
                        linenum);
 
986
    }
 
987
    else if (!_cups_strcasecmp(line, "Info"))
 
988
    {
 
989
      if (value)
 
990
        cupsdSetString(&p->info, value);
 
991
    }
 
992
    else if (!_cups_strcasecmp(line, "MakeModel"))
 
993
    {
 
994
      if (value)
 
995
        cupsdSetString(&p->make_model, value);
 
996
    }
 
997
    else if (!_cups_strcasecmp(line, "PPDTimeStamp"))
 
998
    {
 
999
      if (value)
 
1000
        cupsdSetString(&p->ppd_timestamp, value);
 
1001
    }
 
1002
    else if (!_cups_strcasecmp(line, "Location"))
 
1003
    {
 
1004
      if (value)
 
1005
        cupsdSetString(&p->location, value);
 
1006
    }
 
1007
    else if (!_cups_strcasecmp(line, "DeviceURI"))
 
1008
    {
 
1009
      if (value)
 
1010
        cupsdSetDeviceURI(p, value);
 
1011
      else
 
1012
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1013
                        "Syntax error on line %d of printers.conf.", linenum);
 
1014
    }
 
1015
    else if (!_cups_strcasecmp(line, "Option") && value)
 
1016
    {
 
1017
     /*
 
1018
      * Option name value
 
1019
      */
 
1020
 
 
1021
      for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
 
1022
 
 
1023
      if (!*valueptr)
 
1024
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1025
                        "Syntax error on line %d of printers.conf.", linenum);
 
1026
      else
 
1027
      {
 
1028
        for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
 
1029
 
 
1030
        p->num_options = cupsAddOption(value, valueptr, p->num_options,
 
1031
                                       &(p->options));
 
1032
      }
 
1033
    }
 
1034
    else if (!_cups_strcasecmp(line, "PortMonitor"))
 
1035
    {
 
1036
      if (value && strcmp(value, "none"))
 
1037
        cupsdSetString(&p->port_monitor, value);
 
1038
      else if (value)
 
1039
        cupsdClearString(&p->port_monitor);
 
1040
      else
 
1041
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1042
                        "Syntax error on line %d of printers.conf.", linenum);
 
1043
    }
 
1044
    else if (!_cups_strcasecmp(line, "Reason"))
 
1045
    {
 
1046
      if (value &&
 
1047
          strcmp(value, "connecting-to-device") &&
 
1048
          strcmp(value, "cups-insecure-filter-warning") &&
 
1049
          strcmp(value, "cups-missing-filter-warning"))
 
1050
      {
 
1051
        for (i = 0 ; i < p->num_reasons; i ++)
 
1052
          if (!strcmp(value, p->reasons[i]))
 
1053
            break;
 
1054
 
 
1055
        if (i >= p->num_reasons &&
 
1056
            p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
 
1057
        {
 
1058
          p->reasons[p->num_reasons] = _cupsStrAlloc(value);
 
1059
          p->num_reasons ++;
 
1060
        }
 
1061
      }
 
1062
      else
 
1063
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1064
                        "Syntax error on line %d of printers.conf.", linenum);
 
1065
    }
 
1066
    else if (!_cups_strcasecmp(line, "State"))
 
1067
    {
 
1068
     /*
 
1069
      * Set the initial queue state...
 
1070
      */
 
1071
 
 
1072
      if (value && !_cups_strcasecmp(value, "idle"))
 
1073
        p->state = IPP_PRINTER_IDLE;
 
1074
      else if (value && !_cups_strcasecmp(value, "stopped"))
 
1075
      {
 
1076
        p->state = IPP_PRINTER_STOPPED;
 
1077
 
 
1078
        for (i = 0 ; i < p->num_reasons; i ++)
 
1079
          if (!strcmp("paused", p->reasons[i]))
 
1080
            break;
 
1081
 
 
1082
        if (i >= p->num_reasons &&
 
1083
            p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
 
1084
        {
 
1085
          p->reasons[p->num_reasons] = _cupsStrAlloc("paused");
 
1086
          p->num_reasons ++;
 
1087
        }
 
1088
      }
 
1089
      else
 
1090
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1091
                        "Syntax error on line %d of printers.conf.", linenum);
 
1092
    }
 
1093
    else if (!_cups_strcasecmp(line, "StateMessage"))
 
1094
    {
 
1095
     /*
 
1096
      * Set the initial queue state message...
 
1097
      */
 
1098
 
 
1099
      if (value)
 
1100
        strlcpy(p->state_message, value, sizeof(p->state_message));
 
1101
    }
 
1102
    else if (!_cups_strcasecmp(line, "StateTime"))
 
1103
    {
 
1104
     /*
 
1105
      * Set the state time...
 
1106
      */
 
1107
 
 
1108
      if (value)
 
1109
        p->state_time = atoi(value);
 
1110
    }
 
1111
    else if (!_cups_strcasecmp(line, "Accepting"))
 
1112
    {
 
1113
     /*
 
1114
      * Set the initial accepting state...
 
1115
      */
 
1116
 
 
1117
      if (value &&
 
1118
          (!_cups_strcasecmp(value, "yes") ||
 
1119
           !_cups_strcasecmp(value, "on") ||
 
1120
           !_cups_strcasecmp(value, "true")))
 
1121
        p->accepting = 1;
 
1122
      else if (value &&
 
1123
               (!_cups_strcasecmp(value, "no") ||
 
1124
                !_cups_strcasecmp(value, "off") ||
 
1125
                !_cups_strcasecmp(value, "false")))
 
1126
        p->accepting = 0;
 
1127
      else
 
1128
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1129
                        "Syntax error on line %d of printers.conf.", linenum);
 
1130
    }
 
1131
    else if (!_cups_strcasecmp(line, "Type"))
 
1132
    {
 
1133
      if (value)
 
1134
        p->type = atoi(value);
 
1135
      else
 
1136
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1137
                        "Syntax error on line %d of printers.conf.", linenum);
 
1138
    }
 
1139
    else if (!_cups_strcasecmp(line, "Shared"))
 
1140
    {
 
1141
     /*
 
1142
      * Set the initial shared state...
 
1143
      */
 
1144
 
 
1145
      if (value &&
 
1146
          (!_cups_strcasecmp(value, "yes") ||
 
1147
           !_cups_strcasecmp(value, "on") ||
 
1148
           !_cups_strcasecmp(value, "true")))
 
1149
        p->shared = 1;
 
1150
      else if (value &&
 
1151
               (!_cups_strcasecmp(value, "no") ||
 
1152
                !_cups_strcasecmp(value, "off") ||
 
1153
                !_cups_strcasecmp(value, "false")))
 
1154
        p->shared = 0;
 
1155
      else
 
1156
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1157
                        "Syntax error on line %d of printers.conf.", linenum);
 
1158
    }
 
1159
    else if (!_cups_strcasecmp(line, "ColorManaged"))
 
1160
    {
 
1161
     /*
 
1162
      * Set the initial color-managed state...
 
1163
      */
 
1164
 
 
1165
      if (value &&
 
1166
          (!_cups_strcasecmp(value, "yes") ||
 
1167
           !_cups_strcasecmp(value, "on") ||
 
1168
           !_cups_strcasecmp(value, "true")))
 
1169
        p->color_managed = 1;
 
1170
      else if (value &&
 
1171
               (!_cups_strcasecmp(value, "no") ||
 
1172
                !_cups_strcasecmp(value, "off") ||
 
1173
                !_cups_strcasecmp(value, "false")))
 
1174
        p->color_managed = 0;
 
1175
      else
 
1176
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1177
                        "Syntax error on line %d of printers.conf.", linenum);
 
1178
    }
 
1179
    else if (!_cups_strcasecmp(line, "JobSheets"))
 
1180
    {
 
1181
     /*
 
1182
      * Set the initial job sheets...
 
1183
      */
 
1184
 
 
1185
      if (value)
 
1186
      {
 
1187
        for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
 
1188
 
 
1189
        if (*valueptr)
 
1190
          *valueptr++ = '\0';
 
1191
 
 
1192
        cupsdSetString(&p->job_sheets[0], value);
 
1193
 
 
1194
        while (isspace(*valueptr & 255))
 
1195
          valueptr ++;
 
1196
 
 
1197
        if (*valueptr)
 
1198
        {
 
1199
          for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
 
1200
 
 
1201
          if (*valueptr)
 
1202
            *valueptr = '\0';
 
1203
 
 
1204
          cupsdSetString(&p->job_sheets[1], value);
 
1205
        }
 
1206
      }
 
1207
      else
 
1208
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1209
                        "Syntax error on line %d of printers.conf.", linenum);
 
1210
    }
 
1211
    else if (!_cups_strcasecmp(line, "AllowUser"))
 
1212
    {
 
1213
      if (value)
 
1214
      {
 
1215
        p->deny_users = 0;
 
1216
        cupsdAddString(&(p->users), value);
 
1217
      }
 
1218
      else
 
1219
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1220
                        "Syntax error on line %d of printers.conf.", linenum);
 
1221
    }
 
1222
    else if (!_cups_strcasecmp(line, "DenyUser"))
 
1223
    {
 
1224
      if (value)
 
1225
      {
 
1226
        p->deny_users = 1;
 
1227
        cupsdAddString(&(p->users), value);
 
1228
      }
 
1229
      else
 
1230
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1231
                        "Syntax error on line %d of printers.conf.", linenum);
 
1232
    }
 
1233
    else if (!_cups_strcasecmp(line, "QuotaPeriod"))
 
1234
    {
 
1235
      if (value)
 
1236
        p->quota_period = atoi(value);
 
1237
      else
 
1238
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1239
                        "Syntax error on line %d of printers.conf.", linenum);
 
1240
    }
 
1241
    else if (!_cups_strcasecmp(line, "PageLimit"))
 
1242
    {
 
1243
      if (value)
 
1244
        p->page_limit = atoi(value);
 
1245
      else
 
1246
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1247
                        "Syntax error on line %d of printers.conf.", linenum);
 
1248
    }
 
1249
    else if (!_cups_strcasecmp(line, "KLimit"))
 
1250
    {
 
1251
      if (value)
 
1252
        p->k_limit = atoi(value);
 
1253
      else
 
1254
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1255
                        "Syntax error on line %d of printers.conf.", linenum);
 
1256
    }
 
1257
    else if (!_cups_strcasecmp(line, "OpPolicy"))
 
1258
    {
 
1259
      if (value)
 
1260
      {
 
1261
        cupsd_policy_t *pol;            /* Policy */
 
1262
 
 
1263
 
 
1264
        if ((pol = cupsdFindPolicy(value)) != NULL)
 
1265
        {
 
1266
          cupsdSetString(&p->op_policy, value);
 
1267
          p->op_policy_ptr = pol;
 
1268
        }
 
1269
        else
 
1270
          cupsdLogMessage(CUPSD_LOG_ERROR,
 
1271
                          "Bad policy \"%s\" on line %d of printers.conf",
 
1272
                          value, linenum);
 
1273
      }
 
1274
      else
 
1275
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1276
                        "Syntax error on line %d of printers.conf.", linenum);
 
1277
    }
 
1278
    else if (!_cups_strcasecmp(line, "ErrorPolicy"))
 
1279
    {
 
1280
      if (value)
 
1281
        cupsdSetString(&p->error_policy, value);
 
1282
      else
 
1283
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1284
                        "Syntax error on line %d of printers.conf.", linenum);
 
1285
    }
 
1286
    else if (!_cups_strcasecmp(line, "Attribute") && value)
 
1287
    {
 
1288
      for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
 
1289
 
 
1290
      if (!*valueptr)
 
1291
        cupsdLogMessage(CUPSD_LOG_ERROR,
 
1292
                        "Syntax error on line %d of printers.conf.", linenum);
 
1293
      else
 
1294
      {
 
1295
        for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
 
1296
 
 
1297
        if (!p->attrs)
 
1298
          cupsdSetPrinterAttrs(p);
 
1299
 
 
1300
        if (!strcmp(value, "marker-change-time"))
 
1301
          p->marker_time = atoi(valueptr);
 
1302
        else
 
1303
          cupsdSetPrinterAttr(p, value, valueptr);
 
1304
      }
 
1305
    }
 
1306
    else if (_cups_strcasecmp(line, "Filter") &&
 
1307
             _cups_strcasecmp(line, "Prefilter") &&
 
1308
             _cups_strcasecmp(line, "Product"))
 
1309
    {
 
1310
     /*
 
1311
      * Something else we don't understand (and that wasn't used in a prior
 
1312
      * release of CUPS...
 
1313
      */
 
1314
 
 
1315
      cupsdLogMessage(CUPSD_LOG_ERROR,
 
1316
                      "Unknown configuration directive %s on line %d of "
 
1317
                      "printers.conf.", line, linenum);
 
1318
    }
 
1319
  }
 
1320
 
 
1321
  cupsFileClose(fp);
 
1322
}
 
1323
 
 
1324
 
 
1325
/*
 
1326
 * 'cupsdRenamePrinter()' - Rename a printer.
 
1327
 */
 
1328
 
 
1329
void
 
1330
cupsdRenamePrinter(
 
1331
    cupsd_printer_t *p,                 /* I - Printer */
 
1332
    const char      *name)              /* I - New name */
 
1333
{
 
1334
 /*
 
1335
  * Remove the printer from the array(s) first...
 
1336
  */
 
1337
 
 
1338
  cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
1339
                  "cupsdRenamePrinter: Removing %s from Printers", p->name);
 
1340
  cupsArrayRemove(Printers, p);
 
1341
 
 
1342
 /*
 
1343
  * Rename the printer type...
 
1344
  */
 
1345
 
 
1346
  mimeDeleteType(MimeDatabase, p->filetype);
 
1347
  p->filetype = mimeAddType(MimeDatabase, "printer", name);
 
1348
 
 
1349
  if (p->prefiltertype)
 
1350
  {
 
1351
    mimeDeleteType(MimeDatabase, p->prefiltertype);
 
1352
    p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);
 
1353
  }
 
1354
 
 
1355
 /*
 
1356
  * Rename the printer...
 
1357
  */
 
1358
 
 
1359
  cupsdSetString(&p->name, name);
 
1360
 
 
1361
 /*
 
1362
  * Reset printer attributes...
 
1363
  */
 
1364
 
 
1365
  cupsdSetPrinterAttrs(p);
 
1366
 
 
1367
 /*
 
1368
  * Add the printer back to the printer array(s)...
 
1369
  */
 
1370
 
 
1371
  cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
1372
                  "cupsdRenamePrinter: Adding %s to Printers", p->name);
 
1373
  cupsArrayAdd(Printers, p);
 
1374
}
 
1375
 
 
1376
 
 
1377
/*
 
1378
 * 'cupsdSaveAllPrinters()' - Save all printer definitions to the printers.conf
 
1379
 *                            file.
 
1380
 */
 
1381
 
 
1382
void
 
1383
cupsdSaveAllPrinters(void)
 
1384
{
 
1385
  int                   i;              /* Looping var */
 
1386
  cups_file_t           *fp;            /* printers.conf file */
 
1387
  char                  filename[1024], /* printers.conf filename */
 
1388
                        temp[1024],     /* Temporary string */
 
1389
                        value[2048],    /* Value string */
 
1390
                        *ptr,           /* Pointer into value */
 
1391
                        *name;          /* Current user/group name */
 
1392
  cupsd_printer_t       *printer;       /* Current printer class */
 
1393
  time_t                curtime;        /* Current time */
 
1394
  struct tm             *curdate;       /* Current date */
 
1395
  cups_option_t         *option;        /* Current option */
 
1396
  ipp_attribute_t       *marker;        /* Current marker attribute */
 
1397
 
 
1398
 
 
1399
 /*
 
1400
  * Create the printers.conf file...
 
1401
  */
 
1402
 
 
1403
  snprintf(filename, sizeof(filename), "%s/printers.conf", ServerRoot);
 
1404
 
 
1405
  if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL)
 
1406
    return;
 
1407
 
 
1408
  cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf...");
 
1409
 
 
1410
 /*
 
1411
  * Write a small header to the file...
 
1412
  */
 
1413
 
 
1414
  curtime = time(NULL);
 
1415
  curdate = localtime(&curtime);
 
1416
  strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
 
1417
 
 
1418
  cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n");
 
1419
  cupsFilePrintf(fp, "# Written by cupsd\n");
 
1420
  cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
 
1421
 
 
1422
 /*
 
1423
  * Write each local printer known to the system...
 
1424
  */
 
1425
 
 
1426
  for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
 
1427
       printer;
 
1428
       printer = (cupsd_printer_t *)cupsArrayNext(Printers))
 
1429
  {
 
1430
   /*
 
1431
    * Skip printer classes...
 
1432
    */
 
1433
 
 
1434
    if (printer->type & CUPS_PRINTER_CLASS)
 
1435
      continue;
 
1436
 
 
1437
   /*
 
1438
    * Write printers as needed...
 
1439
    */
 
1440
 
 
1441
    if (printer == DefaultPrinter)
 
1442
      cupsFilePrintf(fp, "<DefaultPrinter %s>\n", printer->name);
 
1443
    else
 
1444
      cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
 
1445
 
 
1446
    cupsFilePrintf(fp, "UUID %s\n", printer->uuid);
 
1447
 
 
1448
    if (printer->num_auth_info_required > 0)
 
1449
    {
 
1450
      switch (printer->num_auth_info_required)
 
1451
      {
 
1452
        case 1 :
 
1453
            strlcpy(value, printer->auth_info_required[0], sizeof(value));
 
1454
            break;
 
1455
 
 
1456
        case 2 :
 
1457
            snprintf(value, sizeof(value), "%s,%s",
 
1458
                     printer->auth_info_required[0],
 
1459
                     printer->auth_info_required[1]);
 
1460
            break;
 
1461
 
 
1462
        case 3 :
 
1463
        default :
 
1464
            snprintf(value, sizeof(value), "%s,%s,%s",
 
1465
                     printer->auth_info_required[0],
 
1466
                     printer->auth_info_required[1],
 
1467
                     printer->auth_info_required[2]);
 
1468
            break;
 
1469
      }
 
1470
 
 
1471
      cupsFilePutConf(fp, "AuthInfoRequired", value);
 
1472
    }
 
1473
 
 
1474
    if (printer->info)
 
1475
      cupsFilePutConf(fp, "Info", printer->info);
 
1476
 
 
1477
    if (printer->location)
 
1478
      cupsFilePutConf(fp, "Location", printer->location);
 
1479
 
 
1480
    if (printer->make_model)
 
1481
      cupsFilePutConf(fp, "MakeModel", printer->make_model);
 
1482
 
 
1483
    cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
 
1484
 
 
1485
    if (printer->ppd_timestamp)
 
1486
      cupsFilePutConf(fp, "PPDTimeStamp", printer->ppd_timestamp);
 
1487
 
 
1488
    if (printer->port_monitor)
 
1489
      cupsFilePutConf(fp, "PortMonitor", printer->port_monitor);
 
1490
 
 
1491
    if (printer->state == IPP_PRINTER_STOPPED)
 
1492
    {
 
1493
      cupsFilePuts(fp, "State Stopped\n");
 
1494
 
 
1495
      if (printer->state_message)
 
1496
        cupsFilePutConf(fp, "StateMessage", printer->state_message);
 
1497
    }
 
1498
    else
 
1499
      cupsFilePuts(fp, "State Idle\n");
 
1500
 
 
1501
    cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
 
1502
 
 
1503
    for (i = 0; i < printer->num_reasons; i ++)
 
1504
      if (strcmp(printer->reasons[i], "connecting-to-device") &&
 
1505
          strcmp(printer->reasons[i], "cups-insecure-filter-warning") &&
 
1506
          strcmp(printer->reasons[i], "cups-missing-filter-warning"))
 
1507
        cupsFilePutConf(fp, "Reason", printer->reasons[i]);
 
1508
 
 
1509
    cupsFilePrintf(fp, "Type %d\n", printer->type);
 
1510
 
 
1511
    if (printer->accepting)
 
1512
      cupsFilePuts(fp, "Accepting Yes\n");
 
1513
    else
 
1514
      cupsFilePuts(fp, "Accepting No\n");
 
1515
 
 
1516
    if (printer->shared)
 
1517
      cupsFilePuts(fp, "Shared Yes\n");
 
1518
    else
 
1519
      cupsFilePuts(fp, "Shared No\n");
 
1520
 
 
1521
    if (printer->color_managed)
 
1522
      cupsFilePuts(fp, "ColorManaged Yes\n");
 
1523
    else
 
1524
      cupsFilePuts(fp, "ColorManaged No\n");
 
1525
 
 
1526
    snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0],
 
1527
             printer->job_sheets[1]);
 
1528
    cupsFilePutConf(fp, "JobSheets", value);
 
1529
 
 
1530
    cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period);
 
1531
    cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
 
1532
    cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
 
1533
 
 
1534
    for (name = (char *)cupsArrayFirst(printer->users);
 
1535
         name;
 
1536
         name = (char *)cupsArrayNext(printer->users))
 
1537
      cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name);
 
1538
 
 
1539
    if (printer->op_policy)
 
1540
      cupsFilePutConf(fp, "OpPolicy", printer->op_policy);
 
1541
    if (printer->error_policy)
 
1542
      cupsFilePutConf(fp, "ErrorPolicy", printer->error_policy);
 
1543
 
 
1544
    for (i = printer->num_options, option = printer->options;
 
1545
         i > 0;
 
1546
         i --, option ++)
 
1547
    {
 
1548
      snprintf(value, sizeof(value), "%s %s", option->name, option->value);
 
1549
      cupsFilePutConf(fp, "Option", value);
 
1550
    }
 
1551
 
 
1552
    if ((marker = ippFindAttribute(printer->attrs, "marker-colors",
 
1553
                                   IPP_TAG_NAME)) != NULL)
 
1554
    {
 
1555
      snprintf(value, sizeof(value), "%s ", marker->name);
 
1556
 
 
1557
      for (i = 0, ptr = value + strlen(value);
 
1558
           i < marker->num_values && ptr < (value + sizeof(value) - 1);
 
1559
           i ++)
 
1560
      {
 
1561
        if (i)
 
1562
          *ptr++ = ',';
 
1563
 
 
1564
        strlcpy(ptr, marker->values[i].string.text,
 
1565
                value + sizeof(value) - ptr);
 
1566
        ptr += strlen(ptr);
 
1567
      }
 
1568
 
 
1569
      *ptr = '\0';
 
1570
      cupsFilePutConf(fp, "Attribute", value);
 
1571
    }
 
1572
 
 
1573
    if ((marker = ippFindAttribute(printer->attrs, "marker-levels",
 
1574
                                   IPP_TAG_INTEGER)) != NULL)
 
1575
    {
 
1576
      cupsFilePrintf(fp, "Attribute %s %d", marker->name,
 
1577
                     marker->values[0].integer);
 
1578
      for (i = 1; i < marker->num_values; i ++)
 
1579
        cupsFilePrintf(fp, ",%d", marker->values[i].integer);
 
1580
      cupsFilePuts(fp, "\n");
 
1581
    }
 
1582
 
 
1583
    if ((marker = ippFindAttribute(printer->attrs, "marker-low-levels",
 
1584
                                   IPP_TAG_INTEGER)) != NULL)
 
1585
    {
 
1586
      cupsFilePrintf(fp, "Attribute %s %d", marker->name,
 
1587
                     marker->values[0].integer);
 
1588
      for (i = 1; i < marker->num_values; i ++)
 
1589
        cupsFilePrintf(fp, ",%d", marker->values[i].integer);
 
1590
      cupsFilePuts(fp, "\n");
 
1591
    }
 
1592
 
 
1593
    if ((marker = ippFindAttribute(printer->attrs, "marker-high-levels",
 
1594
                                   IPP_TAG_INTEGER)) != NULL)
 
1595
    {
 
1596
      cupsFilePrintf(fp, "Attribute %s %d", marker->name,
 
1597
                     marker->values[0].integer);
 
1598
      for (i = 1; i < marker->num_values; i ++)
 
1599
        cupsFilePrintf(fp, ",%d", marker->values[i].integer);
 
1600
      cupsFilePuts(fp, "\n");
 
1601
    }
 
1602
 
 
1603
    if ((marker = ippFindAttribute(printer->attrs, "marker-message",
 
1604
                                   IPP_TAG_TEXT)) != NULL)
 
1605
    {
 
1606
      snprintf(value, sizeof(value), "%s %s", marker->name,
 
1607
               marker->values[0].string.text);
 
1608
 
 
1609
      cupsFilePutConf(fp, "Attribute", value);
 
1610
    }
 
1611
 
 
1612
    if ((marker = ippFindAttribute(printer->attrs, "marker-names",
 
1613
                                   IPP_TAG_NAME)) != NULL)
 
1614
    {
 
1615
      snprintf(value, sizeof(value), "%s ", marker->name);
 
1616
 
 
1617
      for (i = 0, ptr = value + strlen(value);
 
1618
           i < marker->num_values && ptr < (value + sizeof(value) - 1);
 
1619
           i ++)
 
1620
      {
 
1621
        if (i)
 
1622
          *ptr++ = ',';
 
1623
 
 
1624
        strlcpy(ptr, marker->values[i].string.text,
 
1625
                value + sizeof(value) - ptr);
 
1626
        ptr += strlen(ptr);
 
1627
      }
 
1628
 
 
1629
      *ptr = '\0';
 
1630
      cupsFilePutConf(fp, "Attribute", value);
 
1631
    }
 
1632
 
 
1633
    if ((marker = ippFindAttribute(printer->attrs, "marker-types",
 
1634
                                   IPP_TAG_KEYWORD)) != NULL)
 
1635
    {
 
1636
      snprintf(value, sizeof(value), "%s ", marker->name);
 
1637
 
 
1638
      for (i = 0, ptr = value + strlen(value);
 
1639
           i < marker->num_values && ptr < (value + sizeof(value) - 1);
 
1640
           i ++)
 
1641
      {
 
1642
        if (i)
 
1643
          *ptr++ = ',';
 
1644
 
 
1645
        strlcpy(ptr, marker->values[i].string.text,
 
1646
                value + sizeof(value) - ptr);
 
1647
        ptr += strlen(ptr);
 
1648
      }
 
1649
 
 
1650
      *ptr = '\0';
 
1651
      cupsFilePutConf(fp, "Attribute", value);
 
1652
    }
 
1653
 
 
1654
    if (printer->marker_time)
 
1655
      cupsFilePrintf(fp, "Attribute marker-change-time %ld\n",
 
1656
                     (long)printer->marker_time);
 
1657
 
 
1658
    cupsFilePuts(fp, "</Printer>\n");
 
1659
  }
 
1660
 
 
1661
  cupsdCloseCreatedConfFile(fp, filename);
 
1662
}
 
1663
 
 
1664
 
 
1665
/*
 
1666
 * 'cupsdSetAuthInfoRequired()' - Set the required authentication info.
 
1667
 */
 
1668
 
 
1669
int                                     /* O - 1 if value OK, 0 otherwise */
 
1670
cupsdSetAuthInfoRequired(
 
1671
    cupsd_printer_t *p,                 /* I - Printer */
 
1672
    const char      *values,            /* I - Plain text value (or NULL) */
 
1673
    ipp_attribute_t *attr)              /* I - IPP attribute value (or NULL) */
 
1674
{
 
1675
  int   i;                              /* Looping var */
 
1676
 
 
1677
 
 
1678
  p->num_auth_info_required = 0;
 
1679
 
 
1680
 /*
 
1681
  * Do we have a plain text value?
 
1682
  */
 
1683
 
 
1684
  if (values)
 
1685
  {
 
1686
   /*
 
1687
    * Yes, grab the keywords...
 
1688
    */
 
1689
 
 
1690
    const char  *end;                   /* End of current value */
 
1691
 
 
1692
 
 
1693
    while (*values && p->num_auth_info_required < 4)
 
1694
    {
 
1695
      if ((end = strchr(values, ',')) == NULL)
 
1696
        end = values + strlen(values);
 
1697
 
 
1698
      if ((end - values) == 4 && !strncmp(values, "none", 4))
 
1699
      {
 
1700
        if (p->num_auth_info_required != 0 || *end)
 
1701
          return (0);
 
1702
 
 
1703
        p->auth_info_required[p->num_auth_info_required] = "none";
 
1704
        p->num_auth_info_required ++;
 
1705
 
 
1706
        return (1);
 
1707
      }
 
1708
      else if ((end - values) == 9 && !strncmp(values, "negotiate", 9))
 
1709
      {
 
1710
        if (p->num_auth_info_required != 0 || *end)
 
1711
          return (0);
 
1712
 
 
1713
        p->auth_info_required[p->num_auth_info_required] = "negotiate";
 
1714
        p->num_auth_info_required ++;
 
1715
 
 
1716
       /*
 
1717
        * Don't allow sharing of queues that require Kerberos authentication.
 
1718
        */
 
1719
 
 
1720
        if (p->shared)
 
1721
        {
 
1722
          cupsdDeregisterPrinter(p, 1);
 
1723
          p->shared = 0;
 
1724
        }
 
1725
      }
 
1726
      else if ((end - values) == 6 && !strncmp(values, "domain", 6))
 
1727
      {
 
1728
        p->auth_info_required[p->num_auth_info_required] = "domain";
 
1729
        p->num_auth_info_required ++;
 
1730
      }
 
1731
      else if ((end - values) == 8 && !strncmp(values, "password", 8))
 
1732
      {
 
1733
        p->auth_info_required[p->num_auth_info_required] = "password";
 
1734
        p->num_auth_info_required ++;
 
1735
      }
 
1736
      else if ((end - values) == 8 && !strncmp(values, "username", 8))
 
1737
      {
 
1738
        p->auth_info_required[p->num_auth_info_required] = "username";
 
1739
        p->num_auth_info_required ++;
 
1740
      }
 
1741
      else
 
1742
        return (0);
 
1743
 
 
1744
      values = (*end) ? end + 1 : end;
 
1745
    }
 
1746
 
 
1747
    if (p->num_auth_info_required == 0)
 
1748
    {
 
1749
      p->auth_info_required[0]  = "none";
 
1750
      p->num_auth_info_required = 1;
 
1751
    }
 
1752
 
 
1753
   /*
 
1754
    * Update the printer-type value as needed...
 
1755
    */
 
1756
 
 
1757
    if (p->num_auth_info_required > 1 ||
 
1758
        strcmp(p->auth_info_required[0], "none"))
 
1759
      p->type |= CUPS_PRINTER_AUTHENTICATED;
 
1760
    else
 
1761
      p->type &= ~CUPS_PRINTER_AUTHENTICATED;
 
1762
 
 
1763
    return (1);
 
1764
  }
 
1765
 
 
1766
 /*
 
1767
  * Grab values from an attribute instead...
 
1768
  */
 
1769
 
 
1770
  if (!attr || attr->num_values > 4)
 
1771
    return (0);
 
1772
 
 
1773
  for (i = 0; i < attr->num_values; i ++)
 
1774
  {
 
1775
    if (!strcmp(attr->values[i].string.text, "none"))
 
1776
    {
 
1777
      if (p->num_auth_info_required != 0 || attr->num_values != 1)
 
1778
        return (0);
 
1779
 
 
1780
      p->auth_info_required[p->num_auth_info_required] = "none";
 
1781
      p->num_auth_info_required ++;
 
1782
 
 
1783
      return (1);
 
1784
    }
 
1785
    else if (!strcmp(attr->values[i].string.text, "negotiate"))
 
1786
    {
 
1787
      if (p->num_auth_info_required != 0 || attr->num_values != 1)
 
1788
        return (0);
 
1789
 
 
1790
      p->auth_info_required[p->num_auth_info_required] = "negotiate";
 
1791
      p->num_auth_info_required ++;
 
1792
 
 
1793
     /*
 
1794
      * Don't allow sharing of queues that require Kerberos authentication.
 
1795
      */
 
1796
 
 
1797
      if (p->shared)
 
1798
      {
 
1799
        cupsdDeregisterPrinter(p, 1);
 
1800
        p->shared = 0;
 
1801
      }
 
1802
 
 
1803
      return (1);
 
1804
    }
 
1805
    else if (!strcmp(attr->values[i].string.text, "domain"))
 
1806
    {
 
1807
      p->auth_info_required[p->num_auth_info_required] = "domain";
 
1808
      p->num_auth_info_required ++;
 
1809
    }
 
1810
    else if (!strcmp(attr->values[i].string.text, "password"))
 
1811
    {
 
1812
      p->auth_info_required[p->num_auth_info_required] = "password";
 
1813
      p->num_auth_info_required ++;
 
1814
    }
 
1815
    else if (!strcmp(attr->values[i].string.text, "username"))
 
1816
    {
 
1817
      p->auth_info_required[p->num_auth_info_required] = "username";
 
1818
      p->num_auth_info_required ++;
 
1819
    }
 
1820
    else
 
1821
      return (0);
 
1822
  }
 
1823
 
 
1824
  return (1);
 
1825
}
 
1826
 
 
1827
 
 
1828
/*
 
1829
 * 'cupsdSetDeviceURI()' - Set the device URI for a printer.
 
1830
 */
 
1831
 
 
1832
void
 
1833
cupsdSetDeviceURI(cupsd_printer_t *p,   /* I - Printer */
 
1834
                  const char      *uri) /* I - Device URI */
 
1835
{
 
1836
  char  buffer[1024],                   /* URI buffer */
 
1837
        *start,                         /* Start of data after scheme */
 
1838
        *slash,                         /* First slash after scheme:// */
 
1839
        *ptr;                           /* Pointer into user@host:port part */
 
1840
 
 
1841
 
 
1842
 /*
 
1843
  * Set the full device URI..
 
1844
  */
 
1845
 
 
1846
  cupsdSetString(&(p->device_uri), uri);
 
1847
 
 
1848
 /*
 
1849
  * Copy the device URI to a temporary buffer so we can sanitize any auth
 
1850
  * info in it...
 
1851
  */
 
1852
 
 
1853
  strlcpy(buffer, uri, sizeof(buffer));
 
1854
 
 
1855
 /*
 
1856
  * Find the end of the scheme:// part...
 
1857
  */
 
1858
 
 
1859
  if ((ptr = strchr(buffer, ':')) != NULL)
 
1860
  {
 
1861
    for (start = ptr + 1; *start; start ++)
 
1862
      if (*start != '/')
 
1863
        break;
 
1864
 
 
1865
   /*
 
1866
    * Find the next slash (/) in the URI...
 
1867
    */
 
1868
 
 
1869
    if ((slash = strchr(start, '/')) == NULL)
 
1870
      slash = start + strlen(start);    /* No slash, point to the end */
 
1871
 
 
1872
   /*
 
1873
    * Check for an @ sign before the slash...
 
1874
    */
 
1875
 
 
1876
    if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
 
1877
    {
 
1878
     /*
 
1879
      * Found an @ sign and it is before the resource part, so we have
 
1880
      * an authentication string.  Copy the remaining URI over the
 
1881
      * authentication string...
 
1882
      */
 
1883
 
 
1884
      _cups_strcpy(start, ptr + 1);
 
1885
    }
 
1886
  }
 
1887
 
 
1888
 /*
 
1889
  * Save the sanitized URI...
 
1890
  */
 
1891
 
 
1892
  cupsdSetString(&(p->sanitized_device_uri), buffer);
 
1893
}
 
1894
 
 
1895
 
 
1896
/*
 
1897
 * 'cupsdSetPrinterAttr()' - Set a printer attribute.
 
1898
 */
 
1899
 
 
1900
void
 
1901
cupsdSetPrinterAttr(
 
1902
    cupsd_printer_t *p,                 /* I - Printer */
 
1903
    const char      *name,              /* I - Attribute name */
 
1904
    char            *value)             /* I - Attribute value string */
 
1905
{
 
1906
  ipp_attribute_t       *attr;          /* Attribute */
 
1907
  int                   i,              /* Looping var */
 
1908
                        count;          /* Number of values */
 
1909
  char                  *ptr,           /* Pointer into value */
 
1910
                        *start,         /* Start of value */
 
1911
                        quote;          /* Quote character */
 
1912
  ipp_tag_t             value_tag;      /* Value tag for this attribute */
 
1913
 
 
1914
 
 
1915
 /*
 
1916
  * Don't allow empty values...
 
1917
  */
 
1918
 
 
1919
  if (!*value && strcmp(name, "marker-message"))
 
1920
  {
 
1921
    cupsdLogMessage(CUPSD_LOG_ERROR, "Ignoring empty \"%s\" attribute", name);
 
1922
    return;
 
1923
  }
 
1924
 
 
1925
 /*
 
1926
  * Count the number of values...
 
1927
  */
 
1928
 
 
1929
  for (count = 1, quote = '\0', ptr = value;
 
1930
       *ptr;
 
1931
       ptr ++)
 
1932
  {
 
1933
    if (*ptr == quote)
 
1934
      quote = '\0';
 
1935
    else if (quote)
 
1936
      continue;
 
1937
    else if (*ptr == '\\' && ptr[1])
 
1938
      ptr ++;
 
1939
    else if (*ptr == '\'' || *ptr == '\"')
 
1940
      quote = *ptr;
 
1941
    else if (*ptr == ',')
 
1942
      count ++;
 
1943
  }
 
1944
 
 
1945
 /*
 
1946
  * Then add or update the attribute as needed...
 
1947
  */
 
1948
 
 
1949
  if (!strcmp(name, "marker-levels") || !strcmp(name, "marker-low-levels") ||
 
1950
      !strcmp(name, "marker-high-levels"))
 
1951
  {
 
1952
   /*
 
1953
    * Integer values...
 
1954
    */
 
1955
 
 
1956
    if ((attr = ippFindAttribute(p->attrs, name, IPP_TAG_INTEGER)) != NULL &&
 
1957
        attr->num_values < count)
 
1958
    {
 
1959
      ippDeleteAttribute(p->attrs, attr);
 
1960
      attr = NULL;
 
1961
    }
 
1962
 
 
1963
    if (attr)
 
1964
      attr->num_values = count;
 
1965
    else
 
1966
      attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, name,
 
1967
                            count, NULL);
 
1968
 
 
1969
    if (!attr)
 
1970
    {
 
1971
      cupsdLogMessage(CUPSD_LOG_ERROR,
 
1972
                      "Unable to allocate memory for printer attribute "
 
1973
                      "(%d values)", count);
 
1974
      return;
 
1975
    }
 
1976
 
 
1977
    for (i = 0; i < count; i ++)
 
1978
    {
 
1979
      if ((ptr = strchr(value, ',')) != NULL)
 
1980
        *ptr++ = '\0';
 
1981
 
 
1982
      attr->values[i].integer = strtol(value, NULL, 10);
 
1983
 
 
1984
      if (ptr)
 
1985
        value = ptr;
 
1986
    }
 
1987
  }
 
1988
  else
 
1989
  {
 
1990
   /*
 
1991
    * Name or keyword values...
 
1992
    */
 
1993
 
 
1994
    if (!strcmp(name, "marker-types"))
 
1995
      value_tag = IPP_TAG_KEYWORD;
 
1996
    else if (!strcmp(name, "marker-message"))
 
1997
      value_tag = IPP_TAG_TEXT;
 
1998
    else
 
1999
      value_tag = IPP_TAG_NAME;
 
2000
 
 
2001
    if ((attr = ippFindAttribute(p->attrs, name, value_tag)) != NULL &&
 
2002
        attr->num_values < count)
 
2003
    {
 
2004
      ippDeleteAttribute(p->attrs, attr);
 
2005
      attr = NULL;
 
2006
    }
 
2007
 
 
2008
    if (attr)
 
2009
    {
 
2010
      for (i = 0; i < attr->num_values; i ++)
 
2011
        _cupsStrFree(attr->values[i].string.text);
 
2012
 
 
2013
      attr->num_values = count;
 
2014
    }
 
2015
    else
 
2016
      attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, value_tag, name,
 
2017
                           count, NULL, NULL);
 
2018
 
 
2019
    if (!attr)
 
2020
    {
 
2021
      cupsdLogMessage(CUPSD_LOG_ERROR,
 
2022
                      "Unable to allocate memory for printer attribute "
 
2023
                      "(%d values)", count);
 
2024
      return;
 
2025
    }
 
2026
 
 
2027
    for (i = 0, quote = '\0', ptr = value; i < count; i ++)
 
2028
    {
 
2029
      for (start = ptr; *ptr; ptr ++)
 
2030
      {
 
2031
        if (*ptr == quote)
 
2032
          *ptr = quote = '\0';
 
2033
        else if (quote)
 
2034
          continue;
 
2035
        else if (*ptr == '\\' && ptr[1])
 
2036
          _cups_strcpy(ptr, ptr + 1);
 
2037
        else if (*ptr == '\'' || *ptr == '\"')
 
2038
        {
 
2039
          quote = *ptr;
 
2040
 
 
2041
          if (ptr == start)
 
2042
            start ++;
 
2043
          else
 
2044
            _cups_strcpy(ptr, ptr + 1);
 
2045
        }
 
2046
        else if (*ptr == ',')
 
2047
        {
 
2048
          *ptr++ = '\0';
 
2049
          break;
 
2050
        }
 
2051
      }
 
2052
 
 
2053
      attr->values[i].string.text = _cupsStrAlloc(start);
 
2054
    }
 
2055
  }
 
2056
}
 
2057
 
 
2058
 
 
2059
/*
 
2060
 * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file.
 
2061
 */
 
2062
 
 
2063
void
 
2064
cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
 
2065
{
 
2066
  int           i;                      /* Looping var */
 
2067
  char          resource[HTTP_MAX_URI]; /* Resource portion of URI */
 
2068
  cupsd_location_t *auth;               /* Pointer to authentication element */
 
2069
  const char    *auth_supported;        /* Authentication supported */
 
2070
  ipp_t         *oldattrs;              /* Old printer attributes */
 
2071
  ipp_attribute_t *attr;                /* Attribute data */
 
2072
  char          *name,                  /* Current user/group name */
 
2073
                *filter;                /* Current filter */
 
2074
 
 
2075
 
 
2076
  DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
 
2077
                p->type));
 
2078
 
 
2079
 /*
 
2080
  * Make sure that we have the common attributes defined...
 
2081
  */
 
2082
 
 
2083
  if (!CommonData)
 
2084
    cupsdCreateCommonData();
 
2085
 
 
2086
 /*
 
2087
  * Clear out old filters, if any...
 
2088
  */
 
2089
 
 
2090
  delete_printer_filters(p);
 
2091
 
 
2092
 /*
 
2093
  * Figure out the authentication that is required for the printer.
 
2094
  */
 
2095
 
 
2096
  auth_supported = "requesting-user-name";
 
2097
 
 
2098
  if (p->type & CUPS_PRINTER_CLASS)
 
2099
    snprintf(resource, sizeof(resource), "/classes/%s", p->name);
 
2100
  else
 
2101
    snprintf(resource, sizeof(resource), "/printers/%s", p->name);
 
2102
 
 
2103
  if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
 
2104
      auth->type == CUPSD_AUTH_NONE)
 
2105
    auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
 
2106
 
 
2107
  if (auth)
 
2108
  {
 
2109
    int auth_type;              /* Authentication type */
 
2110
 
 
2111
 
 
2112
    if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
 
2113
      auth_type = cupsdDefaultAuthType();
 
2114
 
 
2115
    if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
 
2116
      auth_supported = "basic";
 
2117
    else if (auth_type == CUPSD_AUTH_DIGEST)
 
2118
      auth_supported = "digest";
 
2119
#ifdef HAVE_GSSAPI
 
2120
    else if (auth_type == CUPSD_AUTH_NEGOTIATE)
 
2121
      auth_supported = "negotiate";
 
2122
#endif /* HAVE_GSSAPI */
 
2123
 
 
2124
    if (auth_type != CUPSD_AUTH_NONE)
 
2125
      p->type |= CUPS_PRINTER_AUTHENTICATED;
 
2126
    else
 
2127
      p->type &= ~CUPS_PRINTER_AUTHENTICATED;
 
2128
  }
 
2129
  else
 
2130
    p->type &= ~CUPS_PRINTER_AUTHENTICATED;
 
2131
 
 
2132
 /*
 
2133
  * Create the required IPP attributes for a printer...
 
2134
  */
 
2135
 
 
2136
  oldattrs = p->attrs;
 
2137
  p->attrs = ippNew();
 
2138
 
 
2139
  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
2140
               "uri-authentication-supported", NULL, auth_supported);
 
2141
  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
2142
               "uri-security-supported", NULL, "none");
 
2143
  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
 
2144
               p->name);
 
2145
  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
 
2146
               NULL, p->location ? p->location : "");
 
2147
  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
 
2148
               NULL, p->info ? p->info : "");
 
2149
  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL,
 
2150
               p->uuid);
 
2151
  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
 
2152
               "ppd-timestamp", NULL, p->ppd_timestamp ? p->ppd_timestamp : "*");
 
2153
 
 
2154
  if (cupsArrayCount(p->users) > 0)
 
2155
  {
 
2156
    if (p->deny_users)
 
2157
      attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
 
2158
                           "requesting-user-name-denied",
 
2159
                           cupsArrayCount(p->users), NULL, NULL);
 
2160
    else
 
2161
      attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
 
2162
                           "requesting-user-name-allowed",
 
2163
                           cupsArrayCount(p->users), NULL, NULL);
 
2164
 
 
2165
    for (i = 0, name = (char *)cupsArrayFirst(p->users);
 
2166
         name;
 
2167
         i ++, name = (char *)cupsArrayNext(p->users))
 
2168
      attr->values[i].string.text = _cupsStrAlloc(name);
 
2169
  }
 
2170
 
 
2171
  ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
2172
                "job-quota-period", p->quota_period);
 
2173
  ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
2174
                "job-k-limit", p->k_limit);
 
2175
  ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
2176
                "job-page-limit", p->page_limit);
 
2177
  if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
 
2178
    ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
2179
                  "auth-info-required", p->num_auth_info_required, NULL,
 
2180
                  p->auth_info_required);
 
2181
 
 
2182
  if (cupsArrayCount(Banners) > 0)
 
2183
  {
 
2184
   /*
 
2185
    * Setup the job-sheets-default attribute...
 
2186
    */
 
2187
 
 
2188
    attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
 
2189
                         "job-sheets-default", 2, NULL, NULL);
 
2190
 
 
2191
    if (attr != NULL)
 
2192
    {
 
2193
      attr->values[0].string.text = _cupsStrAlloc(Classification ?
 
2194
                                           Classification : p->job_sheets[0]);
 
2195
      attr->values[1].string.text = _cupsStrAlloc(Classification ?
 
2196
                                           Classification : p->job_sheets[1]);
 
2197
    }
 
2198
  }
 
2199
 
 
2200
  p->raw    = 0;
 
2201
  p->remote = 0;
 
2202
 
 
2203
 /*
 
2204
  * Assign additional attributes depending on whether this is a printer
 
2205
  * or class...
 
2206
  */
 
2207
 
 
2208
  if (p->type & CUPS_PRINTER_CLASS)
 
2209
  {
 
2210
    p->raw = 1;
 
2211
    p->type &= ~CUPS_PRINTER_OPTIONS;
 
2212
 
 
2213
   /*
 
2214
    * Add class-specific attributes...
 
2215
    */
 
2216
 
 
2217
    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
 
2218
                 "printer-make-and-model", NULL, "Local Printer Class");
 
2219
    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
 
2220
                 "file:///dev/null");
 
2221
 
 
2222
    if (p->num_printers > 0)
 
2223
    {
 
2224
     /*
 
2225
      * Add a list of member names; URIs are added in copy_printer_attrs...
 
2226
      */
 
2227
 
 
2228
      attr    = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
 
2229
                              "member-names", p->num_printers, NULL, NULL);
 
2230
      p->type |= CUPS_PRINTER_OPTIONS;
 
2231
 
 
2232
      for (i = 0; i < p->num_printers; i ++)
 
2233
      {
 
2234
        if (attr != NULL)
 
2235
          attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name);
 
2236
 
 
2237
        p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
 
2238
      }
 
2239
    }
 
2240
  }
 
2241
  else
 
2242
  {
 
2243
   /*
 
2244
    * Add printer-specific attributes...
 
2245
    */
 
2246
 
 
2247
    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
 
2248
                 p->sanitized_device_uri);
 
2249
 
 
2250
   /*
 
2251
    * Assign additional attributes from the PPD file (if any)...
 
2252
    */
 
2253
 
 
2254
    load_ppd(p);
 
2255
 
 
2256
   /*
 
2257
    * Add filters for printer...
 
2258
    */
 
2259
 
 
2260
    cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
 
2261
                              "cups-insecure-filter-warning");
 
2262
 
 
2263
    if (p->pc && p->pc->filters)
 
2264
    {
 
2265
      for (filter = (char *)cupsArrayFirst(p->pc->filters);
 
2266
           filter;
 
2267
           filter = (char *)cupsArrayNext(p->pc->filters))
 
2268
        add_printer_filter(p, p->filetype, filter);
 
2269
    }
 
2270
    else if (!(p->type & CUPS_PRINTER_REMOTE))
 
2271
    {
 
2272
      char      interface[1024];        /* Interface script */
 
2273
 
 
2274
 
 
2275
      snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot,
 
2276
               p->name);
 
2277
      if (!access(interface, X_OK))
 
2278
      {
 
2279
       /*
 
2280
        * Yes, we have a System V style interface script; use it!
 
2281
        */
 
2282
 
 
2283
        snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s",
 
2284
                 ServerRoot, p->name);
 
2285
        add_printer_filter(p, p->filetype, interface);
 
2286
      }
 
2287
      else
 
2288
      {
 
2289
       /*
 
2290
        * Add a filter from application/vnd.cups-raw to printer/name to
 
2291
        * handle "raw" printing by users.
 
2292
        */
 
2293
 
 
2294
        add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
 
2295
 
 
2296
       /*
 
2297
        * Add a PostScript filter, since this is still possibly PS printer.
 
2298
        */
 
2299
 
 
2300
        add_printer_filter(p, p->filetype,
 
2301
                           "application/vnd.cups-postscript 0 -");
 
2302
      }
 
2303
    }
 
2304
 
 
2305
    if (p->pc && p->pc->prefilters)
 
2306
    {
 
2307
      if (!p->prefiltertype)
 
2308
        p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
 
2309
 
 
2310
      for (filter = (char *)cupsArrayFirst(p->pc->prefilters);
 
2311
           filter;
 
2312
           filter = (char *)cupsArrayNext(p->pc->prefilters))
 
2313
        add_printer_filter(p, p->prefiltertype, filter);
 
2314
    }
 
2315
  }
 
2316
 
 
2317
 /*
 
2318
  * Copy marker attributes as needed...
 
2319
  */
 
2320
 
 
2321
  if (oldattrs)
 
2322
  {
 
2323
    ipp_attribute_t *oldattr;           /* Old attribute */
 
2324
 
 
2325
 
 
2326
    if ((oldattr = ippFindAttribute(oldattrs, "marker-colors",
 
2327
                                    IPP_TAG_NAME)) != NULL)
 
2328
    {
 
2329
      if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
 
2330
                                "marker-colors", oldattr->num_values, NULL,
 
2331
                                NULL)) != NULL)
 
2332
      {
 
2333
        for (i = 0; i < oldattr->num_values; i ++)
 
2334
          attr->values[i].string.text =
 
2335
              _cupsStrAlloc(oldattr->values[i].string.text);
 
2336
      }
 
2337
    }
 
2338
 
 
2339
    if ((oldattr = ippFindAttribute(oldattrs, "marker-levels",
 
2340
                                    IPP_TAG_INTEGER)) != NULL)
 
2341
    {
 
2342
      if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
2343
                                 "marker-levels", oldattr->num_values,
 
2344
                                 NULL)) != NULL)
 
2345
      {
 
2346
        for (i = 0; i < oldattr->num_values; i ++)
 
2347
          attr->values[i].integer = oldattr->values[i].integer;
 
2348
      }
 
2349
    }
 
2350
 
 
2351
    if ((oldattr = ippFindAttribute(oldattrs, "marker-message",
 
2352
                                    IPP_TAG_TEXT)) != NULL)
 
2353
      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "marker-message",
 
2354
                   NULL, oldattr->values[0].string.text);
 
2355
 
 
2356
    if ((oldattr = ippFindAttribute(oldattrs, "marker-low-levels",
 
2357
                                    IPP_TAG_INTEGER)) != NULL)
 
2358
    {
 
2359
      if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
2360
                                 "marker-low-levels", oldattr->num_values,
 
2361
                                 NULL)) != NULL)
 
2362
      {
 
2363
        for (i = 0; i < oldattr->num_values; i ++)
 
2364
          attr->values[i].integer = oldattr->values[i].integer;
 
2365
      }
 
2366
    }
 
2367
 
 
2368
    if ((oldattr = ippFindAttribute(oldattrs, "marker-high-levels",
 
2369
                                    IPP_TAG_INTEGER)) != NULL)
 
2370
    {
 
2371
      if ((attr = ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
2372
                                 "marker-high-levels", oldattr->num_values,
 
2373
                                 NULL)) != NULL)
 
2374
      {
 
2375
        for (i = 0; i < oldattr->num_values; i ++)
 
2376
          attr->values[i].integer = oldattr->values[i].integer;
 
2377
      }
 
2378
    }
 
2379
 
 
2380
    if ((oldattr = ippFindAttribute(oldattrs, "marker-names",
 
2381
                                    IPP_TAG_NAME)) != NULL)
 
2382
    {
 
2383
      if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
 
2384
                                "marker-names", oldattr->num_values, NULL,
 
2385
                                NULL)) != NULL)
 
2386
      {
 
2387
        for (i = 0; i < oldattr->num_values; i ++)
 
2388
          attr->values[i].string.text =
 
2389
              _cupsStrAlloc(oldattr->values[i].string.text);
 
2390
      }
 
2391
    }
 
2392
 
 
2393
    if ((oldattr = ippFindAttribute(oldattrs, "marker-types",
 
2394
                                    IPP_TAG_KEYWORD)) != NULL)
 
2395
    {
 
2396
      if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
2397
                                "marker-types", oldattr->num_values, NULL,
 
2398
                                NULL)) != NULL)
 
2399
      {
 
2400
        for (i = 0; i < oldattr->num_values; i ++)
 
2401
          attr->values[i].string.text =
 
2402
              _cupsStrAlloc(oldattr->values[i].string.text);
 
2403
      }
 
2404
    }
 
2405
 
 
2406
    ippDelete(oldattrs);
 
2407
  }
 
2408
 
 
2409
 /*
 
2410
  * Force sharing off for remote queues...
 
2411
  */
 
2412
 
 
2413
  if (p->type & CUPS_PRINTER_REMOTE)
 
2414
    p->shared = 0;
 
2415
 
 
2416
 /*
 
2417
  * Populate the document-format-supported attribute...
 
2418
  */
 
2419
 
 
2420
  add_printer_formats(p);
 
2421
 
 
2422
  DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
 
2423
                p->type));
 
2424
 
 
2425
 /*
 
2426
  * Add name-default attributes...
 
2427
  */
 
2428
 
 
2429
  add_printer_defaults(p);
 
2430
 
 
2431
 /*
 
2432
  * Let the browse protocols reflect the change
 
2433
  */
 
2434
 
 
2435
  cupsdRegisterPrinter(p);
 
2436
}
 
2437
 
 
2438
 
 
2439
/*
 
2440
 * 'cupsdSetPrinterReasons()' - Set/update the reasons strings.
 
2441
 */
 
2442
 
 
2443
int                                     /* O - 1 if something changed, 0 otherwise */
 
2444
cupsdSetPrinterReasons(
 
2445
    cupsd_printer_t *p,                 /* I - Printer */
 
2446
    const char      *s)                 /* I - Reasons strings */
 
2447
{
 
2448
  int           i,                      /* Looping var */
 
2449
                changed = 0;            /* Did something change? */
 
2450
  const char    *sptr;                  /* Pointer into reasons */
 
2451
  char          reason[255],            /* Reason string */
 
2452
                *rptr;                  /* Pointer into reason */
 
2453
 
 
2454
 
 
2455
  cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
2456
                  "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s);
 
2457
 
 
2458
  if (s[0] == '-' || s[0] == '+')
 
2459
  {
 
2460
   /*
 
2461
    * Add/remove reasons...
 
2462
    */
 
2463
 
 
2464
    sptr = s + 1;
 
2465
  }
 
2466
  else
 
2467
  {
 
2468
   /*
 
2469
    * Replace reasons...
 
2470
    */
 
2471
 
 
2472
    sptr = s;
 
2473
 
 
2474
    for (i = 0; i < p->num_reasons; i ++)
 
2475
      _cupsStrFree(p->reasons[i]);
 
2476
 
 
2477
    p->num_reasons = 0;
 
2478
    changed        = 1;
 
2479
 
 
2480
    dirty_printer(p);
 
2481
  }
 
2482
 
 
2483
  if (!strcmp(s, "none"))
 
2484
    return (changed);
 
2485
 
 
2486
 /*
 
2487
  * Loop through all of the reasons...
 
2488
  */
 
2489
 
 
2490
  while (*sptr)
 
2491
  {
 
2492
   /*
 
2493
    * Skip leading whitespace and commas...
 
2494
    */
 
2495
 
 
2496
    while (isspace(*sptr & 255) || *sptr == ',')
 
2497
      sptr ++;
 
2498
 
 
2499
    for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++)
 
2500
      if (rptr < (reason + sizeof(reason) - 1))
 
2501
        *rptr++ = *sptr;
 
2502
 
 
2503
    if (rptr == reason)
 
2504
      break;
 
2505
 
 
2506
    *rptr = '\0';
 
2507
 
 
2508
    if (s[0] == '-')
 
2509
    {
 
2510
     /*
 
2511
      * Remove reason...
 
2512
      */
 
2513
 
 
2514
      for (i = 0; i < p->num_reasons; i ++)
 
2515
        if (!strcmp(reason, p->reasons[i]))
 
2516
        {
 
2517
         /*
 
2518
          * Found a match, so remove it...
 
2519
          */
 
2520
 
 
2521
          p->num_reasons --;
 
2522
          changed = 1;
 
2523
          _cupsStrFree(p->reasons[i]);
 
2524
 
 
2525
          if (i < p->num_reasons)
 
2526
            memmove(p->reasons + i, p->reasons + i + 1,
 
2527
                    (p->num_reasons - i) * sizeof(char *));
 
2528
 
 
2529
          if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED)
 
2530
            cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
 
2531
 
 
2532
          if (strcmp(reason, "connecting-to-device"))
 
2533
            dirty_printer(p);
 
2534
          break;
 
2535
        }
 
2536
    }
 
2537
    else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
 
2538
    {
 
2539
     /*
 
2540
      * Add reason...
 
2541
      */
 
2542
 
 
2543
      for (i = 0; i < p->num_reasons; i ++)
 
2544
        if (!strcmp(reason, p->reasons[i]))
 
2545
          break;
 
2546
 
 
2547
      if (i >= p->num_reasons)
 
2548
      {
 
2549
        if (!strncmp(reason, "cups-ipp-missing-", 17) ||
 
2550
            !strncmp(reason, "cups-ipp-wrong-", 15))
 
2551
          log_ipp_conformance(p, reason);
 
2552
 
 
2553
        if (i >= (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
 
2554
        {
 
2555
          cupsdLogMessage(CUPSD_LOG_ALERT,
 
2556
                          "Too many printer-state-reasons values for %s (%d)",
 
2557
                          p->name, i + 1);
 
2558
          return (changed);
 
2559
        }
 
2560
 
 
2561
        p->reasons[i] = _cupsStrAlloc(reason);
 
2562
        p->num_reasons ++;
 
2563
        changed = 1;
 
2564
 
 
2565
        if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED)
 
2566
          cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
 
2567
 
 
2568
        if (strcmp(reason, "connecting-to-device"))
 
2569
          dirty_printer(p);
 
2570
      }
 
2571
    }
 
2572
  }
 
2573
 
 
2574
  return (changed);
 
2575
}
 
2576
 
 
2577
 
 
2578
/*
 
2579
 * 'cupsdSetPrinterState()' - Update the current state of a printer.
 
2580
 */
 
2581
 
 
2582
void
 
2583
cupsdSetPrinterState(
 
2584
    cupsd_printer_t *p,                 /* I - Printer to change */
 
2585
    ipp_pstate_t    s,                  /* I - New state */
 
2586
    int             update)             /* I - Update printers.conf? */
 
2587
{
 
2588
  cupsd_job_t   *job;                   /* Current job */
 
2589
  ipp_pstate_t  old_state;              /* Old printer state */
 
2590
  static const char * const printer_states[] =
 
2591
  {                                     /* State strings */
 
2592
    "idle",
 
2593
    "processing",
 
2594
    "stopped"
 
2595
  };
 
2596
 
 
2597
 
 
2598
 /*
 
2599
  * Set the new state...
 
2600
  */
 
2601
 
 
2602
  old_state = p->state;
 
2603
  p->state  = s;
 
2604
 
 
2605
  if (old_state != s)
 
2606
  {
 
2607
    cupsdAddEvent(s == IPP_PRINTER_STOPPED ? CUPSD_EVENT_PRINTER_STOPPED :
 
2608
                      CUPSD_EVENT_PRINTER_STATE, p, NULL,
 
2609
                  "%s \"%s\" state changed to %s.",
 
2610
                  (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
 
2611
                  p->name, printer_states[p->state - IPP_PRINTER_IDLE]);
 
2612
 
 
2613
   /*
 
2614
    * Let the browse code know this needs to be updated...
 
2615
    */
 
2616
 
 
2617
    p->state_time = time(NULL);
 
2618
  }
 
2619
 
 
2620
 /*
 
2621
  * Set/clear the paused reason as needed...
 
2622
  */
 
2623
 
 
2624
  if (s == IPP_PRINTER_STOPPED)
 
2625
    cupsdSetPrinterReasons(p, "+paused");
 
2626
  else
 
2627
    cupsdSetPrinterReasons(p, "-paused");
 
2628
 
 
2629
  if (old_state != s)
 
2630
  {
 
2631
    for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
 
2632
         job;
 
2633
         job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
 
2634
      if (job->reasons && job->state_value == IPP_JOB_PENDING &&
 
2635
          !_cups_strcasecmp(job->dest, p->name))
 
2636
        ippSetString(job->attrs, &job->reasons, 0,
 
2637
                     s == IPP_PRINTER_STOPPED ? "printer-stopped" : "none");
 
2638
  }
 
2639
 
 
2640
 /*
 
2641
  * Clear the message for the queue when going to processing...
 
2642
  */
 
2643
 
 
2644
  if (s == IPP_PRINTER_PROCESSING)
 
2645
    p->state_message[0] = '\0';
 
2646
 
 
2647
 /*
 
2648
  * Let the browse protocols reflect the change...
 
2649
  */
 
2650
 
 
2651
  if (update)
 
2652
    cupsdRegisterPrinter(p);
 
2653
 
 
2654
 /*
 
2655
  * Save the printer configuration if a printer goes from idle or processing
 
2656
  * to stopped (or visa-versa)...
 
2657
  */
 
2658
 
 
2659
  if (update &&
 
2660
      (old_state == IPP_PRINTER_STOPPED) != (s == IPP_PRINTER_STOPPED))
 
2661
    dirty_printer(p);
 
2662
}
 
2663
 
 
2664
 
 
2665
/*
 
2666
 * 'cupsdStopPrinter()' - Stop a printer from printing any jobs...
 
2667
 */
 
2668
 
 
2669
void
 
2670
cupsdStopPrinter(cupsd_printer_t *p,    /* I - Printer to stop */
 
2671
                 int             update)/* I - Update printers.conf? */
 
2672
{
 
2673
 /*
 
2674
  * Set the printer state...
 
2675
  */
 
2676
 
 
2677
  cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update);
 
2678
 
 
2679
 /*
 
2680
  * See if we have a job printing on this printer...
 
2681
  */
 
2682
 
 
2683
  if (p->job && p->job->state_value == IPP_JOB_PROCESSING)
 
2684
    cupsdSetJobState(p->job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
 
2685
                     "Job stopped due to printer being paused.");
 
2686
}
 
2687
 
 
2688
 
 
2689
/*
 
2690
 * 'cupsdUpdatePrinterPPD()' - Update keywords in a printer's PPD file.
 
2691
 */
 
2692
 
 
2693
int                                     /* O - 1 if successful, 0 otherwise */
 
2694
cupsdUpdatePrinterPPD(
 
2695
    cupsd_printer_t *p,                 /* I - Printer */
 
2696
    int             num_keywords,       /* I - Number of keywords */
 
2697
    cups_option_t   *keywords)          /* I - Keywords */
 
2698
{
 
2699
  int           i;                      /* Looping var */
 
2700
  cups_file_t   *src,                   /* Original file */
 
2701
                *dst;                   /* New file */
 
2702
  char          srcfile[1024],          /* Original filename */
 
2703
                dstfile[1024],          /* New filename */
 
2704
                line[1024],             /* Line from file */
 
2705
                keystring[41];          /* Keyword from line */
 
2706
  cups_option_t *keyword;               /* Current keyword */
 
2707
 
 
2708
 
 
2709
  cupsdLogMessage(CUPSD_LOG_INFO, "Updating keywords in PPD file for %s...",
 
2710
                  p->name);
 
2711
 
 
2712
 /*
 
2713
  * Get the old and new PPD filenames...
 
2714
  */
 
2715
 
 
2716
  snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd.O", ServerRoot, p->name);
 
2717
  snprintf(dstfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
 
2718
 
 
2719
 /*
 
2720
  * Rename the old file and open the old and new...
 
2721
  */
 
2722
 
 
2723
  if (rename(dstfile, srcfile))
 
2724
  {
 
2725
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup PPD file for %s: %s",
 
2726
                    p->name, strerror(errno));
 
2727
    return (0);
 
2728
  }
 
2729
 
 
2730
  if ((src = cupsFileOpen(srcfile, "r")) == NULL)
 
2731
  {
 
2732
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open PPD file \"%s\": %s",
 
2733
                    srcfile, strerror(errno));
 
2734
    rename(srcfile, dstfile);
 
2735
    return (0);
 
2736
  }
 
2737
 
 
2738
  if ((dst = cupsFileOpen(dstfile, "w")) == NULL)
 
2739
  {
 
2740
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create PPD file \"%s\": %s",
 
2741
                    dstfile, strerror(errno));
 
2742
    cupsFileClose(src);
 
2743
    rename(srcfile, dstfile);
 
2744
    return (0);
 
2745
  }
 
2746
 
 
2747
 /*
 
2748
  * Copy the first line and then write out all of the keywords...
 
2749
  */
 
2750
 
 
2751
  if (!cupsFileGets(src, line, sizeof(line)))
 
2752
  {
 
2753
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read PPD file \"%s\": %s",
 
2754
                    srcfile, strerror(errno));
 
2755
    cupsFileClose(src);
 
2756
    cupsFileClose(dst);
 
2757
    rename(srcfile, dstfile);
 
2758
    return (0);
 
2759
  }
 
2760
 
 
2761
  cupsFilePrintf(dst, "%s\n", line);
 
2762
 
 
2763
  for (i = num_keywords, keyword = keywords; i > 0; i --, keyword ++)
 
2764
  {
 
2765
    cupsdLogMessage(CUPSD_LOG_DEBUG, "*%s: %s", keyword->name, keyword->value);
 
2766
    cupsFilePrintf(dst, "*%s: %s\n", keyword->name, keyword->value);
 
2767
  }
 
2768
 
 
2769
 /*
 
2770
  * Then copy the rest of the PPD file, dropping any keywords we changed.
 
2771
  */
 
2772
 
 
2773
  while (cupsFileGets(src, line, sizeof(line)))
 
2774
  {
 
2775
   /*
 
2776
    * Skip keywords we've already set...
 
2777
    */
 
2778
 
 
2779
    if (sscanf(line, "*%40[^:]:", keystring) == 1 &&
 
2780
        cupsGetOption(keystring, num_keywords, keywords))
 
2781
      continue;
 
2782
 
 
2783
   /*
 
2784
    * Otherwise write the line...
 
2785
    */
 
2786
 
 
2787
    cupsFilePrintf(dst, "%s\n", line);
 
2788
  }
 
2789
 
 
2790
 /*
 
2791
  * Close files and return...
 
2792
  */
 
2793
 
 
2794
  cupsFileClose(src);
 
2795
  cupsFileClose(dst);
 
2796
 
 
2797
  return (1);
 
2798
}
 
2799
 
 
2800
 
 
2801
/*
 
2802
 * 'cupsdUpdatePrinters()' - Update printers after a partial reload.
 
2803
 */
 
2804
 
 
2805
void
 
2806
cupsdUpdatePrinters(void)
 
2807
{
 
2808
  cupsd_printer_t       *p;             /* Current printer */
 
2809
 
 
2810
 
 
2811
 /*
 
2812
  * Loop through the printers and recreate the printer attributes
 
2813
  * for any local printers since the policy and/or access control
 
2814
  * stuff may have changed.  Also, if browsing is disabled, remove
 
2815
  * any remote printers...
 
2816
  */
 
2817
 
 
2818
  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
 
2819
       p;
 
2820
       p = (cupsd_printer_t *)cupsArrayNext(Printers))
 
2821
  {
 
2822
   /*
 
2823
    * Update the operation policy pointer...
 
2824
    */
 
2825
 
 
2826
    if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL)
 
2827
      p->op_policy_ptr = DefaultPolicyPtr;
 
2828
 
 
2829
   /*
 
2830
    * Update printer attributes...
 
2831
    */
 
2832
 
 
2833
    cupsdSetPrinterAttrs(p);
 
2834
  }
 
2835
}
 
2836
 
 
2837
 
 
2838
/*
 
2839
 * 'cupsdValidateDest()' - Validate a printer/class destination.
 
2840
 */
 
2841
 
 
2842
const char *                            /* O - Printer or class name */
 
2843
cupsdValidateDest(
 
2844
    const char      *uri,               /* I - Printer URI */
 
2845
    cups_ptype_t    *dtype,             /* O - Type (printer or class) */
 
2846
    cupsd_printer_t **printer)          /* O - Printer pointer */
 
2847
{
 
2848
  cupsd_printer_t       *p;             /* Current printer */
 
2849
  char                  localname[1024],/* Localized hostname */
 
2850
                        *lptr,          /* Pointer into localized hostname */
 
2851
                        *sptr,          /* Pointer into server name */
 
2852
                        *rptr,          /* Pointer into resource */
 
2853
                        scheme[32],     /* Scheme portion of URI */
 
2854
                        username[64],   /* Username portion of URI */
 
2855
                        hostname[HTTP_MAX_HOST],
 
2856
                                        /* Host portion of URI */
 
2857
                        resource[HTTP_MAX_URI];
 
2858
                                        /* Resource portion of URI */
 
2859
  int                   port;           /* Port portion of URI */
 
2860
 
 
2861
 
 
2862
  DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
 
2863
                dtype, printer));
 
2864
 
 
2865
 /*
 
2866
  * Initialize return values...
 
2867
  */
 
2868
 
 
2869
  if (printer)
 
2870
    *printer = NULL;
 
2871
 
 
2872
  if (dtype)
 
2873
    *dtype = (cups_ptype_t)0;
 
2874
 
 
2875
 /*
 
2876
  * Pull the hostname and resource from the URI...
 
2877
  */
 
2878
 
 
2879
  httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
 
2880
                  username, sizeof(username), hostname, sizeof(hostname),
 
2881
                  &port, resource, sizeof(resource));
 
2882
 
 
2883
 /*
 
2884
  * See if the resource is a class or printer...
 
2885
  */
 
2886
 
 
2887
  if (!strncmp(resource, "/classes/", 9))
 
2888
  {
 
2889
   /*
 
2890
    * Class...
 
2891
    */
 
2892
 
 
2893
    rptr = resource + 9;
 
2894
  }
 
2895
  else if (!strncmp(resource, "/printers/", 10))
 
2896
  {
 
2897
   /*
 
2898
    * Printer...
 
2899
    */
 
2900
 
 
2901
    rptr = resource + 10;
 
2902
  }
 
2903
  else
 
2904
  {
 
2905
   /*
 
2906
    * Bad resource name...
 
2907
    */
 
2908
 
 
2909
    return (NULL);
 
2910
  }
 
2911
 
 
2912
 /*
 
2913
  * See if the printer or class name exists...
 
2914
  */
 
2915
 
 
2916
  p = cupsdFindDest(rptr);
 
2917
 
 
2918
  if (p == NULL && strchr(rptr, '@') == NULL)
 
2919
    return (NULL);
 
2920
  else if (p != NULL)
 
2921
  {
 
2922
    if (printer)
 
2923
      *printer = p;
 
2924
 
 
2925
    if (dtype)
 
2926
      *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
 
2927
 
 
2928
    return (p->name);
 
2929
  }
 
2930
 
 
2931
 /*
 
2932
  * Change localhost to the server name...
 
2933
  */
 
2934
 
 
2935
  if (!_cups_strcasecmp(hostname, "localhost"))
 
2936
    strlcpy(hostname, ServerName, sizeof(hostname));
 
2937
 
 
2938
  strlcpy(localname, hostname, sizeof(localname));
 
2939
 
 
2940
  if (!_cups_strcasecmp(hostname, ServerName))
 
2941
  {
 
2942
   /*
 
2943
    * Localize the hostname...
 
2944
    */
 
2945
 
 
2946
    lptr = strchr(localname, '.');
 
2947
    sptr = strchr(ServerName, '.');
 
2948
 
 
2949
    if (sptr != NULL && lptr != NULL)
 
2950
    {
 
2951
     /*
 
2952
      * Strip the common domain name components...
 
2953
      */
 
2954
 
 
2955
      while (lptr != NULL)
 
2956
      {
 
2957
        if (!_cups_strcasecmp(lptr, sptr))
 
2958
        {
 
2959
          *lptr = '\0';
 
2960
          break;
 
2961
        }
 
2962
        else
 
2963
          lptr = strchr(lptr + 1, '.');
 
2964
      }
 
2965
    }
 
2966
  }
 
2967
 
 
2968
  DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
 
2969
 
 
2970
 /*
 
2971
  * Find a matching printer or class...
 
2972
  */
 
2973
 
 
2974
  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
 
2975
       p;
 
2976
       p = (cupsd_printer_t *)cupsArrayNext(Printers))
 
2977
    if (!_cups_strcasecmp(p->hostname, localname) &&
 
2978
        !_cups_strcasecmp(p->name, rptr))
 
2979
    {
 
2980
      if (printer)
 
2981
        *printer = p;
 
2982
 
 
2983
      if (dtype)
 
2984
        *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
 
2985
 
 
2986
      return (p->name);
 
2987
    }
 
2988
 
 
2989
  return (NULL);
 
2990
}
 
2991
 
 
2992
 
 
2993
/*
 
2994
 * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications
 
2995
 *                          that need it...
 
2996
 */
 
2997
 
 
2998
void
 
2999
cupsdWritePrintcap(void)
 
3000
{
 
3001
  int                   i;              /* Looping var */
 
3002
  cups_file_t           *fp;            /* Printcap file */
 
3003
  cupsd_printer_t       *p;             /* Current printer */
 
3004
 
 
3005
 
 
3006
 /*
 
3007
  * See if we have a printcap file; if not, don't bother writing it.
 
3008
  */
 
3009
 
 
3010
  if (!Printcap || !*Printcap)
 
3011
    return;
 
3012
 
 
3013
  cupsdLogMessage(CUPSD_LOG_INFO, "Generating printcap %s...", Printcap);
 
3014
 
 
3015
 /*
 
3016
  * Open the printcap file...
 
3017
  */
 
3018
 
 
3019
  if ((fp = cupsFileOpen(Printcap, "w")) == NULL)
 
3020
    return;
 
3021
 
 
3022
 /*
 
3023
  * Put a comment header at the top so that users will know where the
 
3024
  * data has come from...
 
3025
  */
 
3026
 
 
3027
  if (PrintcapFormat != PRINTCAP_PLIST)
 
3028
    cupsFilePrintf(fp, "# This file was automatically generated by cupsd(8) "
 
3029
                       "from the\n"
 
3030
                       "# %s/printers.conf file.  All changes to this file\n"
 
3031
                       "# will be lost.\n", ServerRoot);
 
3032
 
 
3033
 /*
 
3034
  * Write a new printcap with the current list of printers.
 
3035
  */
 
3036
 
 
3037
  switch (PrintcapFormat)
 
3038
  {
 
3039
    case PRINTCAP_BSD :
 
3040
       /*
 
3041
        * Each printer is put in the file as:
 
3042
        *
 
3043
        *    Printer1:
 
3044
        *    Printer2:
 
3045
        *    Printer3:
 
3046
        *    ...
 
3047
        *    PrinterN:
 
3048
        */
 
3049
 
 
3050
        if (DefaultPrinter)
 
3051
          cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name,
 
3052
                         DefaultPrinter->info, ServerName,
 
3053
                         DefaultPrinter->name);
 
3054
 
 
3055
        for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
 
3056
             p;
 
3057
             p = (cupsd_printer_t *)cupsArrayNext(Printers))
 
3058
          if (p != DefaultPrinter)
 
3059
            cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info,
 
3060
                           ServerName, p->name);
 
3061
        break;
 
3062
 
 
3063
    case PRINTCAP_PLIST :
 
3064
       /*
 
3065
        * Each printer is written as a dictionary in a plist file.
 
3066
        * Currently the printer-name, printer-info, printer-is-accepting-jobs,
 
3067
        * printer-location, printer-make-and-model, printer-state,
 
3068
        * printer-state-reasons, printer-type, and (sanitized) device-uri.
 
3069
        */
 
3070
 
 
3071
        cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 
3072
                         "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD "
 
3073
                         "PLIST 1.0//EN\" \"http://www.apple.com/DTDs/"
 
3074
                         "PropertyList-1.0.dtd\">\n"
 
3075
                         "<plist version=\"1.0\">\n"
 
3076
                         "<array>\n");
 
3077
 
 
3078
        for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
 
3079
             p;
 
3080
             p = (cupsd_printer_t *)cupsArrayNext(Printers))
 
3081
        {
 
3082
          cupsFilePuts(fp, "\t<dict>\n"
 
3083
                           "\t\t<key>printer-name</key>\n"
 
3084
                           "\t\t<string>");
 
3085
          write_xml_string(fp, p->name);
 
3086
          cupsFilePuts(fp, "</string>\n"
 
3087
                           "\t\t<key>printer-info</key>\n"
 
3088
                           "\t\t<string>");
 
3089
          write_xml_string(fp, p->info);
 
3090
          cupsFilePrintf(fp, "</string>\n"
 
3091
                             "\t\t<key>printer-is-accepting-jobs</key>\n"
 
3092
                             "\t\t<%s/>\n"
 
3093
                             "\t\t<key>printer-location</key>\n"
 
3094
                             "\t\t<string>", p->accepting ? "true" : "false");
 
3095
 
 
3096
          write_xml_string(fp, p->location);
 
3097
          cupsFilePuts(fp, "</string>\n"
 
3098
                           "\t\t<key>printer-make-and-model</key>\n"
 
3099
                           "\t\t<string>");
 
3100
          write_xml_string(fp, p->make_model);
 
3101
          cupsFilePrintf(fp, "</string>\n"
 
3102
                             "\t\t<key>printer-state</key>\n"
 
3103
                             "\t\t<integer>%d</integer>\n"
 
3104
                             "\t\t<key>printer-state-reasons</key>\n"
 
3105
                             "\t\t<array>\n", p->state);
 
3106
          for (i = 0; i < p->num_reasons; i ++)
 
3107
          {
 
3108
            cupsFilePuts(fp, "\t\t\t<string>");
 
3109
            write_xml_string(fp, p->reasons[i]);
 
3110
            cupsFilePuts(fp, "</string>\n");
 
3111
          }
 
3112
          cupsFilePrintf(fp, "\t\t</array>\n"
 
3113
                             "\t\t<key>printer-type</key>\n"
 
3114
                             "\t\t<integer>%d</integer>\n"
 
3115
                             "\t\t<key>device-uri</key>\n"
 
3116
                             "\t\t<string>", p->type);
 
3117
          write_xml_string(fp, p->sanitized_device_uri);
 
3118
          cupsFilePuts(fp, "</string>\n"
 
3119
                           "\t</dict>\n");
 
3120
        }
 
3121
        cupsFilePuts(fp, "</array>\n"
 
3122
                         "</plist>\n");
 
3123
        break;
 
3124
 
 
3125
    case PRINTCAP_SOLARIS :
 
3126
       /*
 
3127
        * Each printer is put in the file as:
 
3128
        *
 
3129
        *    _all:all=Printer1,Printer2,Printer3,...,PrinterN
 
3130
        *    _default:use=DefaultPrinter
 
3131
        *    Printer1:\
 
3132
        *            :bsdaddr=ServerName,Printer1:\
 
3133
        *            :description=Description:
 
3134
        *    Printer2:
 
3135
        *            :bsdaddr=ServerName,Printer2:\
 
3136
        *            :description=Description:
 
3137
        *    Printer3:
 
3138
        *            :bsdaddr=ServerName,Printer3:\
 
3139
        *            :description=Description:
 
3140
        *    ...
 
3141
        *    PrinterN:
 
3142
        *            :bsdaddr=ServerName,PrinterN:\
 
3143
        *            :description=Description:
 
3144
        */
 
3145
 
 
3146
        cupsFilePuts(fp, "_all:all=");
 
3147
        for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
 
3148
             p;
 
3149
             p = (cupsd_printer_t *)cupsArrayCurrent(Printers))
 
3150
          cupsFilePrintf(fp, "%s%c", p->name,
 
3151
                         cupsArrayNext(Printers) ? ',' : '\n');
 
3152
 
 
3153
        if (DefaultPrinter)
 
3154
          cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name);
 
3155
 
 
3156
        for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
 
3157
             p;
 
3158
             p = (cupsd_printer_t *)cupsArrayNext(Printers))
 
3159
          cupsFilePrintf(fp, "%s:\\\n"
 
3160
                             "\t:bsdaddr=%s,%s:\\\n"
 
3161
                             "\t:description=%s:\n",
 
3162
                         p->name, ServerName, p->name,
 
3163
                         p->info ? p->info : "");
 
3164
        break;
 
3165
  }
 
3166
 
 
3167
 /*
 
3168
  * Close the file...
 
3169
  */
 
3170
 
 
3171
  cupsFileClose(fp);
 
3172
}
 
3173
 
 
3174
 
 
3175
/*
 
3176
 * 'add_printer_defaults()' - Add name-default attributes to the printer attributes.
 
3177
 */
 
3178
 
 
3179
static void
 
3180
add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
 
3181
{
 
3182
  int           i;                      /* Looping var */
 
3183
  int           num_options;            /* Number of default options */
 
3184
  cups_option_t *options,               /* Default options */
 
3185
                *option;                /* Current option */
 
3186
  char          name[256];              /* name-default */
 
3187
 
 
3188
 
 
3189
 /*
 
3190
  * Maintain a common array of default attribute names...
 
3191
  */
 
3192
 
 
3193
  if (!CommonDefaults)
 
3194
  {
 
3195
    CommonDefaults = cupsArrayNew((cups_array_func_t)strcmp, NULL);
 
3196
 
 
3197
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default"));
 
3198
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default"));
 
3199
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default"));
 
3200
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-account-id-default"));
 
3201
    cupsArrayAdd(CommonDefaults,
 
3202
                 _cupsStrAlloc("job-accounting-user-id-default"));
 
3203
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
 
3204
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
 
3205
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
 
3206
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default"));
 
3207
    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
 
3208
    cupsArrayAdd(CommonDefaults,
 
3209
                 _cupsStrAlloc("orientation-requested-default"));
 
3210
  }
 
3211
 
 
3212
 /*
 
3213
  * Add all of the default options from the .conf files...
 
3214
  */
 
3215
 
 
3216
  for (num_options = 0, options = NULL, i = p->num_options, option = p->options;
 
3217
       i > 0;
 
3218
       i --, option ++)
 
3219
  {
 
3220
    if (strcmp(option->name, "ipp-options") &&
 
3221
        strcmp(option->name, "job-sheets") &&
 
3222
        strcmp(option->name, "lease-duration"))
 
3223
    {
 
3224
      snprintf(name, sizeof(name), "%s-default", option->name);
 
3225
      num_options = cupsAddOption(name, option->value, num_options, &options);
 
3226
 
 
3227
      if (!cupsArrayFind(CommonDefaults, name))
 
3228
        cupsArrayAdd(CommonDefaults, _cupsStrAlloc(name));
 
3229
    }
 
3230
  }
 
3231
 
 
3232
 /*
 
3233
  * Convert options to IPP attributes...
 
3234
  */
 
3235
 
 
3236
  cupsEncodeOptions2(p->attrs, num_options, options, IPP_TAG_PRINTER);
 
3237
  cupsFreeOptions(num_options, options);
 
3238
 
 
3239
 /*
 
3240
  * Add standard -default attributes as needed...
 
3241
  */
 
3242
 
 
3243
  if (!cupsGetOption("copies", p->num_options, p->options))
 
3244
    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default",
 
3245
                  1);
 
3246
 
 
3247
  if (!cupsGetOption("document-format", p->num_options, p->options))
 
3248
    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
 
3249
                 "document-format-default", NULL, "application/octet-stream");
 
3250
 
 
3251
  if (!cupsGetOption("job-hold-until", p->num_options, p->options))
 
3252
    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
3253
                 "job-hold-until-default", NULL, "no-hold");
 
3254
 
 
3255
  if (!cupsGetOption("job-priority", p->num_options, p->options))
 
3256
    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
3257
                  "job-priority-default", 50);
 
3258
 
 
3259
  if (!cupsGetOption("number-up", p->num_options, p->options))
 
3260
    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
3261
                  "number-up-default", 1);
 
3262
 
 
3263
  if (!cupsGetOption("notify-lease-duration", p->num_options, p->options))
 
3264
    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
3265
                  "notify-lease-duration-default", DefaultLeaseDuration);
 
3266
 
 
3267
  if (!cupsGetOption("notify-events", p->num_options, p->options))
 
3268
    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
3269
                 "notify-events-default", NULL, "job-completed");
 
3270
 
 
3271
  if (!cupsGetOption("orientation-requested", p->num_options, p->options))
 
3272
    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
 
3273
                 "orientation-requested-default", NULL, NULL);
 
3274
 
 
3275
  if (!cupsGetOption("print-quality", p->num_options, p->options))
 
3276
    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
 
3277
                  "print-quality-default", IPP_QUALITY_NORMAL);
 
3278
}
 
3279
 
 
3280
 
 
3281
/*
 
3282
 * 'add_printer_filter()' - Add a MIME filter for a printer.
 
3283
 */
 
3284
 
 
3285
static void
 
3286
add_printer_filter(
 
3287
    cupsd_printer_t  *p,                /* I - Printer to add to */
 
3288
    mime_type_t      *filtertype,       /* I - Filter or prefilter MIME type */
 
3289
    const char       *filter)           /* I - Filter to add */
 
3290
{
 
3291
  char          super[MIME_MAX_SUPER],  /* Super-type for filter */
 
3292
                type[MIME_MAX_TYPE],    /* Type for filter */
 
3293
                dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */
 
3294
                dtype[MIME_MAX_TYPE],   /* Destination type for filter */
 
3295
                dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2],
 
3296
                                        /* Destination super/type */
 
3297
                program[1024];          /* Program/filter name */
 
3298
  int           cost;                   /* Cost of filter */
 
3299
  size_t        maxsize = 0;            /* Maximum supported file size */
 
3300
  mime_type_t   *temptype,              /* MIME type looping var */
 
3301
                *desttype;              /* Destination MIME type */
 
3302
  mime_filter_t *filterptr;             /* MIME filter */
 
3303
  char          filename[1024];         /* Full filter filename */
 
3304
 
 
3305
 
 
3306
  cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
3307
                  "add_printer_filter(p=%p(%s), filtertype=%p(%s/%s), "
 
3308
                  "filter=\"%s\")", p, p->name, filtertype, filtertype->super,
 
3309
                  filtertype->type, filter);
 
3310
 
 
3311
 /*
 
3312
  * Parse the filter string; it should be in one of the following formats:
 
3313
  *
 
3314
  *     source/type cost program
 
3315
  *     source/type cost maxsize(nnnn) program
 
3316
  *     source/type dest/type cost program
 
3317
  *     source/type dest/type cost maxsize(nnnn) program
 
3318
  */
 
3319
 
 
3320
  if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
 
3321
             super, type, dsuper, dtype, &cost, program) == 6)
 
3322
  {
 
3323
    snprintf(dest, sizeof(dest), "%s/%s/%s", p->name, dsuper, dtype);
 
3324
 
 
3325
    if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL)
 
3326
    {
 
3327
      desttype = mimeAddType(MimeDatabase, "printer", dest);
 
3328
      if (!p->dest_types)
 
3329
        p->dest_types = cupsArrayNew(NULL, NULL);
 
3330
 
 
3331
      cupsArrayAdd(p->dest_types, desttype);
 
3332
    }
 
3333
 
 
3334
  }
 
3335
  else
 
3336
  {
 
3337
    if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost,
 
3338
               program) == 4)
 
3339
    {
 
3340
      desttype = filtertype;
 
3341
    }
 
3342
    else
 
3343
    {
 
3344
      cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
 
3345
                      p->name, filter);
 
3346
      return;
 
3347
    }
 
3348
  }
 
3349
 
 
3350
  if (!strncmp(program, "maxsize(", 8))
 
3351
  {
 
3352
    char        *ptr;                   /* Pointer into maxsize(nnnn) program */
 
3353
 
 
3354
    maxsize = strtoll(program + 8, &ptr, 10);
 
3355
 
 
3356
    if (*ptr != ')')
 
3357
    {
 
3358
      cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
 
3359
                      p->name, filter);
 
3360
      return;
 
3361
    }
 
3362
 
 
3363
    ptr ++;
 
3364
    while (_cups_isspace(*ptr))
 
3365
      ptr ++;
 
3366
 
 
3367
    _cups_strcpy(program, ptr);
 
3368
  }
 
3369
 
 
3370
 /*
 
3371
  * Check permissions on the filter and its containing directory...
 
3372
  */
 
3373
 
 
3374
  if (strcmp(program, "-"))
 
3375
  {
 
3376
    if (program[0] == '/')
 
3377
      strlcpy(filename, program, sizeof(filename));
 
3378
    else
 
3379
      snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
 
3380
 
 
3381
    _cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
 
3382
                   cupsdLogFCMessage, p);
 
3383
  }
 
3384
 
 
3385
 /*
 
3386
  * Add the filter to the MIME database, supporting wildcards as needed...
 
3387
  */
 
3388
 
 
3389
  for (temptype = mimeFirstType(MimeDatabase);
 
3390
       temptype;
 
3391
       temptype = mimeNextType(MimeDatabase))
 
3392
    if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
 
3393
         !_cups_strcasecmp(temptype->super, super)) &&
 
3394
        (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
 
3395
    {
 
3396
      if (desttype != filtertype)
 
3397
      {
 
3398
        cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
3399
                        "add_printer_filter: %s: adding filter %s/%s %s/%s %d "
 
3400
                        "%s", p->name, temptype->super, temptype->type,
 
3401
                        desttype->super, desttype->type,
 
3402
                        cost, program);
 
3403
        filterptr = mimeAddFilter(MimeDatabase, temptype, desttype, cost,
 
3404
                                  program);
 
3405
 
 
3406
        if (!mimeFilterLookup(MimeDatabase, desttype, filtertype))
 
3407
        {
 
3408
          cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
3409
                          "add_printer_filter: %s: adding filter %s/%s %s/%s "
 
3410
                          "0 -", p->name, desttype->super, desttype->type,
 
3411
                          filtertype->super, filtertype->type);
 
3412
          mimeAddFilter(MimeDatabase, desttype, filtertype, 0, "-");
 
3413
        }
 
3414
      }
 
3415
      else
 
3416
      {
 
3417
        cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
3418
                        "add_printer_filter: %s: adding filter %s/%s %s/%s %d "
 
3419
                        "%s", p->name, temptype->super, temptype->type,
 
3420
                        filtertype->super, filtertype->type,
 
3421
                        cost, program);
 
3422
        filterptr = mimeAddFilter(MimeDatabase, temptype, filtertype, cost,
 
3423
                                  program);
 
3424
      }
 
3425
 
 
3426
      if (filterptr)
 
3427
        filterptr->maxsize = maxsize;
 
3428
    }
 
3429
}
 
3430
 
 
3431
 
 
3432
/*
 
3433
 * 'add_printer_formats()' - Add document-format-supported values for a printer.
 
3434
 */
 
3435
 
 
3436
static void
 
3437
add_printer_formats(cupsd_printer_t *p) /* I - Printer */
 
3438
{
 
3439
  int           i;                      /* Looping var */
 
3440
  mime_type_t   *type;                  /* Current MIME type */
 
3441
  cups_array_t  *filters;               /* Filters */
 
3442
  ipp_attribute_t *attr;                /* document-format-supported attribute */
 
3443
  char          mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE + 2];
 
3444
                                        /* MIME type name */
 
3445
 
 
3446
 
 
3447
 /*
 
3448
  * Raw (and remote) queues advertise all of the supported MIME
 
3449
  * types...
 
3450
  */
 
3451
 
 
3452
  cupsArrayDelete(p->filetypes);
 
3453
  p->filetypes = NULL;
 
3454
 
 
3455
  if (p->raw)
 
3456
  {
 
3457
    ippAddStrings(p->attrs, IPP_TAG_PRINTER,
 
3458
                  (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
 
3459
                  "document-format-supported", NumMimeTypes, NULL, MimeTypes);
 
3460
    return;
 
3461
  }
 
3462
 
 
3463
 /*
 
3464
  * Otherwise, loop through the supported MIME types and see if there
 
3465
  * are filters for them...
 
3466
  */
 
3467
 
 
3468
  cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_formats: %d types, %d filters",
 
3469
                  mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
 
3470
 
 
3471
  p->filetypes = cupsArrayNew(NULL, NULL);
 
3472
 
 
3473
  for (type = mimeFirstType(MimeDatabase);
 
3474
       type;
 
3475
       type = mimeNextType(MimeDatabase))
 
3476
  {
 
3477
    if (!_cups_strcasecmp(type->super, "printer"))
 
3478
      continue;
 
3479
 
 
3480
    snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
 
3481
 
 
3482
    if ((filters = mimeFilter(MimeDatabase, type, p->filetype, NULL)) != NULL)
 
3483
    {
 
3484
      cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
3485
                      "add_printer_formats: %s: %s needs %d filters",
 
3486
                      p->name, mimetype, cupsArrayCount(filters));
 
3487
 
 
3488
      cupsArrayDelete(filters);
 
3489
      cupsArrayAdd(p->filetypes, type);
 
3490
    }
 
3491
    else
 
3492
      cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
3493
                      "add_printer_formats: %s: %s not supported",
 
3494
                      p->name, mimetype);
 
3495
  }
 
3496
 
 
3497
 /*
 
3498
  * Add the file formats that can be filtered...
 
3499
  */
 
3500
 
 
3501
  if ((type = mimeType(MimeDatabase, "application", "octet-stream")) == NULL ||
 
3502
      !cupsArrayFind(p->filetypes, type))
 
3503
    i = 1;
 
3504
  else
 
3505
    i = 0;
 
3506
 
 
3507
  cupsdLogMessage(CUPSD_LOG_DEBUG2,
 
3508
                  "add_printer_formats: %s: %d supported types",
 
3509
                  p->name, cupsArrayCount(p->filetypes) + i);
 
3510
 
 
3511
  attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
 
3512
                       "document-format-supported",
 
3513
                       cupsArrayCount(p->filetypes) + i, NULL, NULL);
 
3514
 
 
3515
  if (i)
 
3516
    attr->values[0].string.text = _cupsStrAlloc("application/octet-stream");
 
3517
 
 
3518
  for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
 
3519
       type;
 
3520
       i ++, type = (mime_type_t *)cupsArrayNext(p->filetypes))
 
3521
  {
 
3522
    snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
 
3523
 
 
3524
    attr->values[i].string.text = _cupsStrAlloc(mimetype);
 
3525
  }
 
3526
 
 
3527
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
 
3528
  {
 
3529
    char                pdl[1024];      /* Buffer to build pdl list */
 
3530
    mime_filter_t       *filter;        /* MIME filter looping var */
 
3531
 
 
3532
 
 
3533
   /*
 
3534
    * We only support raw printing if this is not a Tioga PrintJobMgr based
 
3535
    * queue and if application/octet-stream is a known type...
 
3536
    */
 
3537
 
 
3538
    for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters);
 
3539
         filter;
 
3540
         filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
 
3541
    {
 
3542
      if (filter->dst == p->filetype && filter->filter &&
 
3543
          strstr(filter->filter, "PrintJobMgr"))
 
3544
        break;
 
3545
    }
 
3546
 
 
3547
    pdl[0] = '\0';
 
3548
 
 
3549
    if (!filter && mimeType(MimeDatabase, "application", "octet-stream"))
 
3550
      strlcat(pdl, "application/octet-stream,", sizeof(pdl));
 
3551
 
 
3552
   /*
 
3553
    * Then list a bunch of formats that are supported by the printer...
 
3554
    */
 
3555
 
 
3556
    for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
 
3557
         type;
 
3558
         type = (mime_type_t *)cupsArrayNext(p->filetypes))
 
3559
    {
 
3560
      if (!_cups_strcasecmp(type->super, "application"))
 
3561
      {
 
3562
        if (!_cups_strcasecmp(type->type, "pdf"))
 
3563
          strlcat(pdl, "application/pdf,", sizeof(pdl));
 
3564
        else if (!_cups_strcasecmp(type->type, "postscript"))
 
3565
          strlcat(pdl, "application/postscript,", sizeof(pdl));
 
3566
      }
 
3567
      else if (!_cups_strcasecmp(type->super, "image"))
 
3568
      {
 
3569
        if (!_cups_strcasecmp(type->type, "urf"))
 
3570
          strlcat(pdl, "image/urf,", sizeof(pdl));
 
3571
        else if (!_cups_strcasecmp(type->type, "jpeg"))
 
3572
          strlcat(pdl, "image/jpeg,", sizeof(pdl));
 
3573
        else if (!_cups_strcasecmp(type->type, "png"))
 
3574
          strlcat(pdl, "image/png,", sizeof(pdl));
 
3575
        else if (!_cups_strcasecmp(type->type, "pwg-raster"))
 
3576
          strlcat(pdl, "image/pwg-raster,", sizeof(pdl));
 
3577
      }
 
3578
    }
 
3579
 
 
3580
    if (pdl[0])
 
3581
      pdl[strlen(pdl) - 1] = '\0';      /* Remove trailing comma */
 
3582
 
 
3583
    cupsdSetString(&p->pdl, pdl);
 
3584
  }
 
3585
#endif /* HAVE_DNSSD || HAVE_AVAHI */
 
3586
}
 
3587
 
 
3588
 
 
3589
/*
 
3590
 * 'compare_printers()' - Compare two printers.
 
3591
 */
 
3592
 
 
3593
static int                              /* O - Result of comparison */
 
3594
compare_printers(void *first,           /* I - First printer */
 
3595
                 void *second,          /* I - Second printer */
 
3596
                 void *data)            /* I - App data (not used) */
 
3597
{
 
3598
  (void)data;
 
3599
 
 
3600
  return (_cups_strcasecmp(((cupsd_printer_t *)first)->name,
 
3601
                     ((cupsd_printer_t *)second)->name));
 
3602
}
 
3603
 
 
3604
 
 
3605
/*
 
3606
 * 'delete_printer_filters()' - Delete all MIME filters for a printer.
 
3607
 */
 
3608
 
 
3609
static void
 
3610
delete_printer_filters(
 
3611
    cupsd_printer_t *p)                 /* I - Printer to remove from */
 
3612
{
 
3613
  mime_filter_t *filter;                /* MIME filter looping var */
 
3614
  mime_type_t   *type;                  /* Destination types for filters */
 
3615
 
 
3616
 
 
3617
 /*
 
3618
  * Range check input...
 
3619
  */
 
3620
 
 
3621
  if (p == NULL)
 
3622
    return;
 
3623
 
 
3624
 /*
 
3625
  * Remove all filters from the MIME database that have a destination
 
3626
  * type == printer...
 
3627
  */
 
3628
 
 
3629
  for (filter = mimeFirstFilter(MimeDatabase);
 
3630
       filter;
 
3631
       filter = mimeNextFilter(MimeDatabase))
 
3632
    if (filter->dst == p->filetype || filter->dst == p->prefiltertype ||
 
3633
        cupsArrayFind(p->dest_types, filter->dst))
 
3634
    {
 
3635
     /*
 
3636
      * Delete the current filter...
 
3637
      */
 
3638
 
 
3639
      mimeDeleteFilter(MimeDatabase, filter);
 
3640
    }
 
3641
 
 
3642
  for (type = (mime_type_t *)cupsArrayFirst(p->dest_types);
 
3643
       type;
 
3644
       type = (mime_type_t *)cupsArrayNext(p->dest_types))
 
3645
    mimeDeleteType(MimeDatabase, type);
 
3646
 
 
3647
  cupsArrayDelete(p->dest_types);
 
3648
  p->dest_types = NULL;
 
3649
 
 
3650
  cupsdSetPrinterReasons(p, "-cups-insecure-filter-warning"
 
3651
                            ",cups-missing-filter-warning");
 
3652
}
 
3653
 
 
3654
 
 
3655
/*
 
3656
 * 'dirty_printer()' - Mark config and state files dirty for the specified
 
3657
 *                     printer.
 
3658
 */
 
3659
 
 
3660
static void
 
3661
dirty_printer(cupsd_printer_t *p)       /* I - Printer */
 
3662
{
 
3663
  if (p->type & CUPS_PRINTER_CLASS)
 
3664
    cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
 
3665
  else
 
3666
    cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
 
3667
 
 
3668
  if (PrintcapFormat == PRINTCAP_PLIST)
 
3669
    cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
 
3670
}
 
3671
 
 
3672
 
 
3673
/*
 
3674
 * 'load_ppd()' - Load a cached PPD file, updating the cache as needed.
 
3675
 */
 
3676
 
 
3677
static void
 
3678
load_ppd(cupsd_printer_t *p)            /* I - Printer */
 
3679
{
 
3680
  int           i, j, k;                /* Looping vars */
 
3681
  char          cache_name[1024];       /* Cache filename */
 
3682
  struct stat   cache_info;             /* Cache file info */
 
3683
  ppd_file_t    *ppd;                   /* PPD file */
 
3684
  char          ppd_name[1024];         /* PPD filename */
 
3685
  struct stat   ppd_info;               /* PPD file info */
 
3686
  int           num_media;              /* Number of media options */
 
3687
  ppd_size_t    *size;                  /* Current PPD size */
 
3688
  ppd_option_t  *duplex,                /* Duplex option */
 
3689
                *output_bin,            /* OutputBin option */
 
3690
                *output_mode,           /* OutputMode option */
 
3691
                *resolution;            /* (Set|JCL|)Resolution option */
 
3692
  ppd_choice_t  *choice,                /* Current PPD choice */
 
3693
                *input_slot,            /* Current input slot */
 
3694
                *media_type;            /* Current media type */
 
3695
  ppd_attr_t    *ppd_attr;              /* PPD attribute */
 
3696
  int           xdpi,                   /* Horizontal resolution */
 
3697
                ydpi;                   /* Vertical resolution */
 
3698
  const char    *resptr;                /* Pointer into resolution keyword */
 
3699
  _pwg_size_t   *pwgsize;               /* Current PWG size */
 
3700
  _pwg_map_t    *pwgsource,             /* Current PWG source */
 
3701
                *pwgtype;               /* Current PWG type */
 
3702
  ipp_attribute_t *attr;                /* Attribute data */
 
3703
  _ipp_value_t  *val;                   /* Attribute value */
 
3704
  int           num_finishings,         /* Number of finishings */
 
3705
                finishings[5];          /* finishings-supported values */
 
3706
  int           num_qualities,          /* Number of print-quality values */
 
3707
                qualities[3];           /* print-quality values */
 
3708
  int           num_margins,            /* Number of media-*-margin-supported values */
 
3709
                margins[16];            /* media-*-margin-supported values */
 
3710
  const char    *filter,                /* Current filter */
 
3711
                *mandatory;             /* Current mandatory attribute */
 
3712
  static const char * const sides[3] =  /* sides-supported values */
 
3713
                {
 
3714
                  "one-sided",
 
3715
                  "two-sided-long-edge",
 
3716
                  "two-sided-short-edge"
 
3717
                };
 
3718
  static const char * const standard_commands[] =
 
3719
                {                       /* Standard CUPS commands */
 
3720
                  "AutoConfigure",
 
3721
                  "Clean",
 
3722
                  "PrintSelfTestPage"
 
3723
                };
 
3724
 
 
3725
 
 
3726
 /*
 
3727
  * Check to see if the cache is up-to-date...
 
3728
  */
 
3729
 
 
3730
  snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name);
 
3731
  if (stat(cache_name, &cache_info))
 
3732
    cache_info.st_mtime = 0;
 
3733
 
 
3734
  snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name);
 
3735
  if (stat(ppd_name, &ppd_info))
 
3736
    ppd_info.st_mtime = 1;
 
3737
 
 
3738
  ippDelete(p->ppd_attrs);
 
3739
  p->ppd_attrs = NULL;
 
3740
 
 
3741
  _ppdCacheDestroy(p->pc);
 
3742
  p->pc = NULL;
 
3743
 
 
3744
  if (cache_info.st_mtime >= ppd_info.st_mtime)
 
3745
  {
 
3746
    cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name);
 
3747
 
 
3748
    if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL &&
 
3749
        p->ppd_attrs)
 
3750
    {
 
3751
     /*
 
3752
      * Loaded successfully!
 
3753
      */
 
3754
 
 
3755
      return;
 
3756
    }
 
3757
  }
 
3758
 
 
3759
 /*
 
3760
  * Reload PPD attributes from disk...
 
3761
  */
 
3762
 
 
3763
  cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
 
3764
 
 
3765
  cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name);
 
3766
 
 
3767
  p->type &= ~CUPS_PRINTER_OPTIONS;
 
3768
  p->type |= CUPS_PRINTER_BW;
 
3769
 
 
3770
  finishings[0]  = IPP_FINISHINGS_NONE;
 
3771
  num_finishings = 1;
 
3772
 
 
3773
  p->ppd_attrs = ippNew();
 
3774
 
 
3775
  if ((ppd = _ppdOpenFile(ppd_name, _PPD_LOCALIZATION_NONE)) != NULL)
 
3776
  {
 
3777
   /*
 
3778
    * Add make/model and other various attributes...
 
3779
    */
 
3780
 
 
3781
    p->pc = _ppdCacheCreateWithPPD(ppd);
 
3782
 
 
3783
    if (!p->pc)
 
3784
      cupsdLogMessage(CUPSD_LOG_WARN, "Unable to create cache of \"%s\": %s",
 
3785
                      ppd_name, cupsLastErrorString());
 
3786
 
 
3787
    ppdMarkDefaults(ppd);
 
3788
 
 
3789
    if (ppd->color_device)
 
3790
      p->type |= CUPS_PRINTER_COLOR;
 
3791
    if (ppd->variable_sizes)
 
3792
      p->type |= CUPS_PRINTER_VARIABLE;
 
3793
    if (!ppd->manual_copies)
 
3794
      p->type |= CUPS_PRINTER_COPIES;
 
3795
    if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
 
3796
      if (ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
 
3797
        p->type |= CUPS_PRINTER_FAX;
 
3798
 
 
3799
    ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported",
 
3800
                  ppd->color_device);
 
3801
 
 
3802
    if (p->pc && p->pc->charge_info_uri)
 
3803
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
 
3804
                   "printer-charge-info-uri", NULL, p->pc->charge_info_uri);
 
3805
 
 
3806
    if (p->pc && p->pc->account_id)
 
3807
      ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "job-account-id-supported",
 
3808
                    1);
 
3809
 
 
3810
    if (p->pc && p->pc->accounting_user_id)
 
3811
      ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER,
 
3812
                    "job-accounting-user-id-supported", 1);
 
3813
 
 
3814
    if (p->pc && p->pc->password)
 
3815
    {
 
3816
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
3817
                   "job-password-encryption-supported", NULL, "none");
 
3818
      ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
3819
                    "job-password-supported", strlen(p->pc->password));
 
3820
    }
 
3821
 
 
3822
    if (ppd->throughput)
 
3823
    {
 
3824
      ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
3825
                    "pages-per-minute", ppd->throughput);
 
3826
      if (ppd->color_device)
 
3827
        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
3828
                      "pages-per-minute-color", ppd->throughput);
 
3829
    }
 
3830
    else
 
3831
    {
 
3832
     /*
 
3833
      * When there is no speed information, just say "1 page per minute".
 
3834
      */
 
3835
 
 
3836
      ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
3837
                    "pages-per-minute", 1);
 
3838
      if (ppd->color_device)
 
3839
        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
3840
                      "pages-per-minute-color", 1);
 
3841
    }
 
3842
 
 
3843
    num_qualities = 0;
 
3844
 
 
3845
    if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL)
 
3846
    {
 
3847
      if (ppdFindChoice(output_mode, "draft") ||
 
3848
          ppdFindChoice(output_mode, "fast"))
 
3849
        qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
 
3850
 
 
3851
      qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
 
3852
 
 
3853
      if (ppdFindChoice(output_mode, "best") ||
 
3854
          ppdFindChoice(output_mode, "high"))
 
3855
        qualities[num_qualities ++] = IPP_QUALITY_HIGH;
 
3856
    }
 
3857
    else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
 
3858
    {
 
3859
      do
 
3860
      {
 
3861
        if (strstr(ppd_attr->spec, "draft") ||
 
3862
            strstr(ppd_attr->spec, "Draft"))
 
3863
        {
 
3864
          qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
 
3865
          break;
 
3866
        }
 
3867
      }
 
3868
      while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset",
 
3869
                                         NULL)) != NULL);
 
3870
 
 
3871
      qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
 
3872
      qualities[num_qualities ++] = IPP_QUALITY_HIGH;
 
3873
    }
 
3874
    else
 
3875
      qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
 
3876
 
 
3877
    ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
 
3878
                   "print-quality-supported", num_qualities, qualities);
 
3879
 
 
3880
    if (ppd->nickname)
 
3881
    {
 
3882
     /*
 
3883
      * The NickName can be localized in the character set specified
 
3884
      * by the LanugageEncoding attribute.  However, ppdOpen2() has
 
3885
      * already converted the ppd->nickname member to UTF-8 for us
 
3886
      * (the original attribute value is available separately)
 
3887
      */
 
3888
 
 
3889
      cupsdSetString(&p->make_model, ppd->nickname);
 
3890
    }
 
3891
    else if (ppd->modelname)
 
3892
    {
 
3893
     /*
 
3894
      * Model name can only contain specific characters...
 
3895
      */
 
3896
 
 
3897
      cupsdSetString(&p->make_model, ppd->modelname);
 
3898
    }
 
3899
    else
 
3900
      cupsdSetString(&p->make_model, "Bad PPD File");
 
3901
 
 
3902
    ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
 
3903
                 "printer-make-and-model", NULL, p->make_model);
 
3904
 
 
3905
   /*
 
3906
    * Add media options from the PPD file...
 
3907
    */
 
3908
 
 
3909
    if (ppd->num_sizes == 0 || !p->pc)
 
3910
    {
 
3911
      if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
 
3912
        cupsdLogMessage(CUPSD_LOG_CRIT,
 
3913
                        "The PPD file for printer %s contains no media "
 
3914
                        "options and is therefore invalid!", p->name);
 
3915
 
 
3916
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
3917
                   "media-default", NULL, "unknown");
 
3918
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
3919
                   "media-supported", NULL, "unknown");
 
3920
    }
 
3921
    else
 
3922
    {
 
3923
     /*
 
3924
      * media-default
 
3925
      */
 
3926
 
 
3927
      if ((size = ppdPageSize(ppd, NULL)) != NULL)
 
3928
        pwgsize = _ppdCacheGetSize(p->pc, size->name);
 
3929
      else
 
3930
        pwgsize = NULL;
 
3931
 
 
3932
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
3933
                   "media-default", NULL,
 
3934
                   pwgsize ? pwgsize->map.pwg : "unknown");
 
3935
 
 
3936
     /*
 
3937
      * media-col-default
 
3938
      */
 
3939
 
 
3940
      if (pwgsize)
 
3941
      {
 
3942
        ipp_t   *col;                   /* Collection value */
 
3943
 
 
3944
        input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
 
3945
        media_type = ppdFindMarkedChoice(ppd, "MediaType");
 
3946
        col        = new_media_col(pwgsize,
 
3947
                                   input_slot ?
 
3948
                                       _ppdCacheGetSource(p->pc,
 
3949
                                                          input_slot->choice) :
 
3950
                                       NULL,
 
3951
                                   media_type ?
 
3952
                                       _ppdCacheGetType(p->pc,
 
3953
                                                        media_type->choice) :
 
3954
                                       NULL);
 
3955
 
 
3956
        ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
 
3957
                         col);
 
3958
        ippDelete(col);
 
3959
      }
 
3960
 
 
3961
     /*
 
3962
      * media-supported
 
3963
      */
 
3964
 
 
3965
      num_media = p->pc->num_sizes;
 
3966
      if (p->pc->custom_min_keyword)
 
3967
        num_media += 2;
 
3968
 
 
3969
      if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
3970
                                "media-supported", num_media, NULL,
 
3971
                                NULL)) != NULL)
 
3972
      {
 
3973
        val = attr->values;
 
3974
 
 
3975
        for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
 
3976
             i > 0;
 
3977
             i --, pwgsize ++, val ++)
 
3978
          val->string.text = _cupsStrAlloc(pwgsize->map.pwg);
 
3979
 
 
3980
        if (p->pc->custom_min_keyword)
 
3981
        {
 
3982
          val->string.text = _cupsStrAlloc(p->pc->custom_min_keyword);
 
3983
          val ++;
 
3984
          val->string.text = _cupsStrAlloc(p->pc->custom_max_keyword);
 
3985
        }
 
3986
      }
 
3987
 
 
3988
     /*
 
3989
      * media-size-supported
 
3990
      */
 
3991
 
 
3992
      num_media = p->pc->num_sizes;
 
3993
      if (p->pc->custom_min_keyword)
 
3994
        num_media ++;
 
3995
 
 
3996
      if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
 
3997
                                    "media-size-supported", num_media,
 
3998
                                    NULL)) != NULL)
 
3999
      {
 
4000
        val = attr->values;
 
4001
 
 
4002
        for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
 
4003
             i > 0;
 
4004
             i --, pwgsize ++, val ++)
 
4005
        {
 
4006
          val->collection = ippNew();
 
4007
          ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4008
                        "x-dimension", pwgsize->width);
 
4009
          ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4010
                        "y-dimension", pwgsize->length);
 
4011
        }
 
4012
 
 
4013
        if (p->pc->custom_min_keyword)
 
4014
        {
 
4015
          val->collection = ippNew();
 
4016
          ippAddRange(val->collection, IPP_TAG_PRINTER, "x-dimension",
 
4017
                      p->pc->custom_min_width, p->pc->custom_max_width);
 
4018
          ippAddRange(val->collection, IPP_TAG_PRINTER, "y-dimension",
 
4019
                      p->pc->custom_min_length, p->pc->custom_max_length);
 
4020
        }
 
4021
      }
 
4022
 
 
4023
     /*
 
4024
      * media-source-supported
 
4025
      */
 
4026
 
 
4027
      if (p->pc->num_sources > 0 &&
 
4028
          (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4029
                                "media-source-supported", p->pc->num_sources,
 
4030
                                NULL, NULL)) != NULL)
 
4031
      {
 
4032
        for (i = p->pc->num_sources, pwgsource = p->pc->sources,
 
4033
                 val = attr->values;
 
4034
             i > 0;
 
4035
             i --, pwgsource ++, val ++)
 
4036
          val->string.text = _cupsStrAlloc(pwgsource->pwg);
 
4037
      }
 
4038
 
 
4039
     /*
 
4040
      * media-type-supported
 
4041
      */
 
4042
 
 
4043
      if (p->pc->num_types > 0 &&
 
4044
          (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4045
                                "media-type-supported", p->pc->num_types,
 
4046
                                NULL, NULL)) != NULL)
 
4047
      {
 
4048
        for (i = p->pc->num_types, pwgtype = p->pc->types,
 
4049
                 val = attr->values;
 
4050
             i > 0;
 
4051
             i --, pwgtype ++, val ++)
 
4052
          val->string.text = _cupsStrAlloc(pwgtype->pwg);
 
4053
      }
 
4054
 
 
4055
     /*
 
4056
      * media-*-margin-supported
 
4057
      */
 
4058
 
 
4059
      for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
 
4060
           i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
 
4061
           i --, pwgsize ++)
 
4062
      {
 
4063
        for (j = 0; j < num_margins; j ++)
 
4064
          if (pwgsize->bottom == margins[j])
 
4065
            break;
 
4066
 
 
4067
        if (j >= num_margins)
 
4068
        {
 
4069
          margins[num_margins] = pwgsize->bottom;
 
4070
          num_margins ++;
 
4071
        }
 
4072
      }
 
4073
 
 
4074
      if (num_margins > 0)
 
4075
        ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4076
                       "media-bottom-margin-supported", num_margins, margins);
 
4077
      else
 
4078
        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4079
                      "media-bottom-margin-supported", 0);
 
4080
 
 
4081
      for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
 
4082
           i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
 
4083
           i --, pwgsize ++)
 
4084
      {
 
4085
        for (j = 0; j < num_margins; j ++)
 
4086
          if (pwgsize->left == margins[j])
 
4087
            break;
 
4088
 
 
4089
        if (j >= num_margins)
 
4090
        {
 
4091
          margins[num_margins] = pwgsize->left;
 
4092
          num_margins ++;
 
4093
        }
 
4094
      }
 
4095
 
 
4096
      if (num_margins > 0)
 
4097
        ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4098
                       "media-left-margin-supported", num_margins, margins);
 
4099
      else
 
4100
        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4101
                      "media-left-margin-supported", 0);
 
4102
 
 
4103
      for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
 
4104
           i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
 
4105
           i --, pwgsize ++)
 
4106
      {
 
4107
        for (j = 0; j < num_margins; j ++)
 
4108
          if (pwgsize->right == margins[j])
 
4109
            break;
 
4110
 
 
4111
        if (j >= num_margins)
 
4112
        {
 
4113
          margins[num_margins] = pwgsize->right;
 
4114
          num_margins ++;
 
4115
        }
 
4116
      }
 
4117
 
 
4118
      if (num_margins > 0)
 
4119
        ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4120
                       "media-right-margin-supported", num_margins, margins);
 
4121
      else
 
4122
        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4123
                      "media-right-margin-supported", 0);
 
4124
 
 
4125
      for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
 
4126
           i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
 
4127
           i --, pwgsize ++)
 
4128
      {
 
4129
        for (j = 0; j < num_margins; j ++)
 
4130
          if (pwgsize->top == margins[j])
 
4131
            break;
 
4132
 
 
4133
        if (j >= num_margins)
 
4134
        {
 
4135
          margins[num_margins] = pwgsize->top;
 
4136
          num_margins ++;
 
4137
        }
 
4138
      }
 
4139
 
 
4140
      if (num_margins > 0)
 
4141
        ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4142
                       "media-top-margin-supported", num_margins, margins);
 
4143
      else
 
4144
        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
4145
                      "media-top-margin-supported", 0);
 
4146
 
 
4147
     /*
 
4148
      * media-col-database
 
4149
      */
 
4150
 
 
4151
      num_media = p->pc->num_sizes;
 
4152
      if (p->pc->num_sources)
 
4153
      {
 
4154
        if (p->pc->num_types > 0)
 
4155
          num_media += p->pc->num_sizes * p->pc->num_sources *
 
4156
                       p->pc->num_types;
 
4157
        else
 
4158
          num_media += p->pc->num_sizes * p->pc->num_sources;
 
4159
      }
 
4160
      else if (p->pc->num_types)
 
4161
        num_media += p->pc->num_sizes * p->pc->num_types;
 
4162
 
 
4163
      if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
 
4164
                                    "media-col-database", num_media,
 
4165
                                    NULL)) != NULL)
 
4166
      {
 
4167
        for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values;
 
4168
             i > 0;
 
4169
             i --, pwgsize ++)
 
4170
        {
 
4171
         /*
 
4172
          * Start by adding the page size without source or type...
 
4173
          */
 
4174
 
 
4175
          ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd);
 
4176
 
 
4177
          val->collection = new_media_col(pwgsize, NULL, NULL);
 
4178
          val ++;
 
4179
 
 
4180
         /*
 
4181
          * Then add the specific, supported combinations of size, source, and
 
4182
          * type...
 
4183
          */
 
4184
 
 
4185
          if (p->pc->num_sources > 0)
 
4186
          {
 
4187
            for (j = p->pc->num_sources, pwgsource = p->pc->sources;
 
4188
                 j > 0;
 
4189
                 j --, pwgsource ++)
 
4190
            {
 
4191
              ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
 
4192
 
 
4193
              if (p->pc->num_types > 0)
 
4194
              {
 
4195
                for (k = p->pc->num_types, pwgtype = p->pc->types;
 
4196
                     k > 0;
 
4197
                     k --, pwgtype ++)
 
4198
                {
 
4199
                  if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
 
4200
                  {
 
4201
                    val->collection = new_media_col(pwgsize, pwgsource->pwg,
 
4202
                                                    pwgtype->pwg);
 
4203
                    val ++;
 
4204
                  }
 
4205
                }
 
4206
              }
 
4207
              else if (!ppdConflicts(ppd))
 
4208
              {
 
4209
                val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL);
 
4210
                val ++;
 
4211
              }
 
4212
            }
 
4213
          }
 
4214
          else if (p->pc->num_types > 0)
 
4215
          {
 
4216
            for (j = p->pc->num_types, pwgtype = p->pc->types;
 
4217
                 j > 0;
 
4218
                 j --, pwgtype ++)
 
4219
            {
 
4220
              if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
 
4221
              {
 
4222
                val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg);
 
4223
                val ++;
 
4224
              }
 
4225
            }
 
4226
          }
 
4227
        }
 
4228
 
 
4229
       /*
 
4230
        * Update the number of media-col-database values...
 
4231
        */
 
4232
 
 
4233
        attr->num_values = val - attr->values;
 
4234
      }
 
4235
    }
 
4236
 
 
4237
   /*
 
4238
    * Output bin...
 
4239
    */
 
4240
 
 
4241
    if (p->pc && p->pc->num_bins > 0)
 
4242
    {
 
4243
      attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4244
                           "output-bin-supported", p->pc->num_bins,
 
4245
                           NULL, NULL);
 
4246
 
 
4247
      if (attr != NULL)
 
4248
      {
 
4249
        for (i = 0, val = attr->values;
 
4250
             i < p->pc->num_bins;
 
4251
             i ++, val ++)
 
4252
          val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg);
 
4253
      }
 
4254
 
 
4255
      if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
 
4256
      {
 
4257
        for (i = 0; i < p->pc->num_bins; i ++)
 
4258
          if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice))
 
4259
            break;
 
4260
 
 
4261
        if (i >= p->pc->num_bins)
 
4262
          i = 0;
 
4263
 
 
4264
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4265
                     "output-bin-default", NULL, p->pc->bins[i].pwg);
 
4266
      }
 
4267
      else
 
4268
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4269
                     "output-bin-default", NULL, p->pc->bins[0].pwg);
 
4270
    }
 
4271
    else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
 
4272
                                     NULL)) != NULL &&
 
4273
              !_cups_strcasecmp(ppd_attr->value, "Reverse")) ||
 
4274
             (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */
 
4275
              (!_cups_strcasecmp(ppd->manufacturer, "epson") ||
 
4276
               !_cups_strcasecmp(ppd->manufacturer, "lexmark"))))
 
4277
    {
 
4278
     /*
 
4279
      * Report that this printer has a single output bin that leaves pages face
 
4280
      * up.
 
4281
      */
 
4282
 
 
4283
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4284
                   "output-bin-supported", NULL, "face-up");
 
4285
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4286
                   "output-bin-default", NULL, "face-up");
 
4287
    }
 
4288
    else
 
4289
    {
 
4290
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4291
                   "output-bin-supported", NULL, "face-down");
 
4292
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4293
                   "output-bin-default", NULL, "face-down");
 
4294
    }
 
4295
 
 
4296
   /*
 
4297
    * print-color-mode...
 
4298
    */
 
4299
 
 
4300
    if (ppd->color_device)
 
4301
    {
 
4302
      static const char * const color_modes[] =
 
4303
      {
 
4304
        "monochrome",
 
4305
        "color"
 
4306
      };
 
4307
 
 
4308
      ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4309
                    "print-color-mode-supported", 2, NULL, color_modes);
 
4310
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4311
                   "print-color-mode-default", NULL, "color");
 
4312
    }
 
4313
    else
 
4314
    {
 
4315
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4316
                   "print-color-mode-supported", NULL, "monochrome");
 
4317
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4318
                   "print-color-mode-default", NULL, "monochrome");
 
4319
    }
 
4320
 
 
4321
   /*
 
4322
    * Mandatory job attributes, if any...
 
4323
    */
 
4324
 
 
4325
    if (p->pc && cupsArrayCount(p->pc->mandatory) > 0)
 
4326
    {
 
4327
      int       count = cupsArrayCount(p->pc->mandatory);
 
4328
                                        /* Number of mandatory attributes */
 
4329
 
 
4330
      attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4331
                           "printer-mandatory-job-attributes", count, NULL,
 
4332
                           NULL);
 
4333
 
 
4334
      for (val = attr->values,
 
4335
               mandatory = (char *)cupsArrayFirst(p->pc->mandatory);
 
4336
           mandatory;
 
4337
           val ++, mandatory = (char *)cupsArrayNext(p->pc->mandatory))
 
4338
        val->string.text = _cupsStrAlloc(mandatory);
 
4339
    }
 
4340
 
 
4341
   /*
 
4342
    * Printer resolutions...
 
4343
    */
 
4344
 
 
4345
    if ((resolution = ppdFindOption(ppd, "Resolution")) == NULL)
 
4346
      if ((resolution = ppdFindOption(ppd, "JCLResolution")) == NULL)
 
4347
        if ((resolution = ppdFindOption(ppd, "SetResolution")) == NULL)
 
4348
          resolution = ppdFindOption(ppd, "CNRes_PGP");
 
4349
 
 
4350
    if (resolution)
 
4351
    {
 
4352
     /*
 
4353
      * Report all supported resolutions...
 
4354
      */
 
4355
 
 
4356
      attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER,
 
4357
                               "printer-resolution-supported",
 
4358
                               resolution->num_choices, IPP_RES_PER_INCH,
 
4359
                               NULL, NULL);
 
4360
 
 
4361
      for (i = 0, choice = resolution->choices;
 
4362
           i < resolution->num_choices;
 
4363
           i ++, choice ++)
 
4364
      {
 
4365
        xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10);
 
4366
        if (resptr > choice->choice && xdpi > 0 && *resptr == 'x')
 
4367
          ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
 
4368
 
 
4369
        if (xdpi <= 0 || ydpi <= 0)
 
4370
        {
 
4371
          cupsdLogMessage(CUPSD_LOG_WARN,
 
4372
                          "Bad resolution \"%s\" for printer %s.",
 
4373
                          choice->choice, p->name);
 
4374
          xdpi = ydpi = 300;
 
4375
        }
 
4376
 
 
4377
        attr->values[i].resolution.xres  = xdpi;
 
4378
        attr->values[i].resolution.yres  = ydpi;
 
4379
        attr->values[i].resolution.units = IPP_RES_PER_INCH;
 
4380
 
 
4381
        if (choice->marked)
 
4382
          ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
 
4383
                           "printer-resolution-default", IPP_RES_PER_INCH,
 
4384
                           xdpi, ydpi);
 
4385
      }
 
4386
    }
 
4387
    else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL &&
 
4388
             ppd_attr->value)
 
4389
    {
 
4390
     /*
 
4391
      * Just the DefaultResolution to report...
 
4392
      */
 
4393
 
 
4394
      xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
 
4395
      if (resptr > ppd_attr->value && xdpi > 0)
 
4396
      {
 
4397
        if (*resptr == 'x')
 
4398
          ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
 
4399
        else
 
4400
          ydpi = xdpi;
 
4401
      }
 
4402
 
 
4403
      if (xdpi <= 0 || ydpi <= 0)
 
4404
      {
 
4405
        cupsdLogMessage(CUPSD_LOG_WARN,
 
4406
                        "Bad default resolution \"%s\" for printer %s.",
 
4407
                        ppd_attr->value, p->name);
 
4408
        xdpi = ydpi = 300;
 
4409
      }
 
4410
 
 
4411
      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
 
4412
                       "printer-resolution-default", IPP_RES_PER_INCH,
 
4413
                       xdpi, ydpi);
 
4414
      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
 
4415
                       "printer-resolution-supported", IPP_RES_PER_INCH,
 
4416
                       xdpi, ydpi);
 
4417
    }
 
4418
    else
 
4419
    {
 
4420
     /*
 
4421
      * No resolutions in PPD - make one up...
 
4422
      */
 
4423
 
 
4424
      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
 
4425
                       "printer-resolution-default", IPP_RES_PER_INCH,
 
4426
                       300, 300);
 
4427
      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
 
4428
                       "printer-resolution-supported", IPP_RES_PER_INCH,
 
4429
                       300, 300);
 
4430
    }
 
4431
 
 
4432
   /*
 
4433
    * Duplexing, etc...
 
4434
    */
 
4435
 
 
4436
    ppdMarkDefaults(ppd);
 
4437
 
 
4438
    if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
 
4439
      if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
 
4440
        if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
 
4441
          if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
 
4442
            duplex = ppdFindOption(ppd, "JCLDuplex");
 
4443
 
 
4444
    if (duplex && duplex->num_choices > 1 &&
 
4445
        !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
 
4446
    {
 
4447
      p->type |= CUPS_PRINTER_DUPLEX;
 
4448
 
 
4449
      ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4450
                    "sides-supported", 3, NULL, sides);
 
4451
 
 
4452
      if (!_cups_strcasecmp(duplex->defchoice, "DuplexTumble"))
 
4453
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4454
                     "sides-default", NULL, "two-sided-short-edge");
 
4455
      else if (!_cups_strcasecmp(duplex->defchoice, "DuplexNoTumble"))
 
4456
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4457
                     "sides-default", NULL, "two-sided-long-edge");
 
4458
      else
 
4459
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4460
                     "sides-default", NULL, "one-sided");
 
4461
    }
 
4462
    else
 
4463
    {
 
4464
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4465
                   "sides-supported", NULL, "one-sided");
 
4466
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4467
                   "sides-default", NULL, "one-sided");
 
4468
    }
 
4469
 
 
4470
    if (ppdFindOption(ppd, "Collate") != NULL)
 
4471
      p->type |= CUPS_PRINTER_COLLATE;
 
4472
 
 
4473
    if (ppdFindOption(ppd, "StapleLocation") != NULL)
 
4474
    {
 
4475
      p->type |= CUPS_PRINTER_STAPLE;
 
4476
      finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
 
4477
    }
 
4478
 
 
4479
    if (ppdFindOption(ppd, "BindEdge") != NULL)
 
4480
    {
 
4481
      p->type |= CUPS_PRINTER_BIND;
 
4482
      finishings[num_finishings++] = IPP_FINISHINGS_BIND;
 
4483
    }
 
4484
 
 
4485
    for (i = 0; i < ppd->num_sizes; i ++)
 
4486
      if (ppd->sizes[i].length > 1728)
 
4487
        p->type |= CUPS_PRINTER_LARGE;
 
4488
      else if (ppd->sizes[i].length > 1008)
 
4489
        p->type |= CUPS_PRINTER_MEDIUM;
 
4490
      else
 
4491
        p->type |= CUPS_PRINTER_SMALL;
 
4492
 
 
4493
    if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL &&
 
4494
        ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
 
4495
    {
 
4496
      if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL &&
 
4497
          ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
 
4498
        p->type |= CUPS_PRINTER_SCANNER;
 
4499
      else
 
4500
        p->type |= CUPS_PRINTER_MFP;
 
4501
    }
 
4502
 
 
4503
   /*
 
4504
    * Scan the filters in the PPD file...
 
4505
    */
 
4506
 
 
4507
    if (p->pc)
 
4508
    {
 
4509
      for (filter = (const char *)cupsArrayFirst(p->pc->filters);
 
4510
           filter;
 
4511
           filter = (const char *)cupsArrayNext(p->pc->filters))
 
4512
      {
 
4513
        if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) &&
 
4514
            _cups_isspace(filter[28]))
 
4515
        {
 
4516
          p->type |= CUPS_PRINTER_COMMANDS;
 
4517
          break;
 
4518
        }
 
4519
      }
 
4520
    }
 
4521
 
 
4522
    if (p->type & CUPS_PRINTER_COMMANDS)
 
4523
    {
 
4524
      char      *commands,              /* Copy of commands */
 
4525
                *start,                 /* Start of name */
 
4526
                *end;                   /* End of name */
 
4527
      int       count;                  /* Number of commands */
 
4528
 
 
4529
      if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL)
 
4530
      {
 
4531
        for (count = 0, start = ppd_attr->value; *start; count ++)
 
4532
        {
 
4533
          while (_cups_isspace(*start))
 
4534
            start ++;
 
4535
 
 
4536
          if (!*start)
 
4537
            break;
 
4538
 
 
4539
          while (*start && !isspace(*start & 255))
 
4540
            start ++;
 
4541
        }
 
4542
      }
 
4543
      else
 
4544
        count = 0;
 
4545
 
 
4546
      if (count > 0)
 
4547
      {
 
4548
       /*
 
4549
        * Make a copy of the commands string and count how many commands there
 
4550
        * are...
 
4551
        */
 
4552
 
 
4553
        attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4554
                             "printer-commands", count, NULL, NULL);
 
4555
 
 
4556
        commands = strdup(ppd_attr->value);
 
4557
 
 
4558
        for (count = 0, start = commands; *start; count ++)
 
4559
        {
 
4560
          while (isspace(*start & 255))
 
4561
            start ++;
 
4562
 
 
4563
          if (!*start)
 
4564
            break;
 
4565
 
 
4566
          end = start;
 
4567
          while (*end && !isspace(*end & 255))
 
4568
            end ++;
 
4569
 
 
4570
          if (*end)
 
4571
            *end++ = '\0';
 
4572
 
 
4573
          attr->values[count].string.text = _cupsStrAlloc(start);
 
4574
 
 
4575
          start = end;
 
4576
        }
 
4577
 
 
4578
        free(commands);
 
4579
      }
 
4580
      else
 
4581
      {
 
4582
       /*
 
4583
        * Add the standard list of commands...
 
4584
        */
 
4585
 
 
4586
        ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4587
                      "printer-commands",
 
4588
                      (int)(sizeof(standard_commands) /
 
4589
                            sizeof(standard_commands[0])), NULL,
 
4590
                      standard_commands);
 
4591
      }
 
4592
    }
 
4593
    else
 
4594
    {
 
4595
     /*
 
4596
      * No commands supported...
 
4597
      */
 
4598
 
 
4599
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
 
4600
                   "printer-commands", NULL, "none");
 
4601
    }
 
4602
 
 
4603
   /*
 
4604
    * Show current and available port monitors for this printer...
 
4605
    */
 
4606
 
 
4607
    ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
 
4608
                 NULL, p->port_monitor ? p->port_monitor : "none");
 
4609
 
 
4610
    for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
 
4611
         ppd_attr;
 
4612
         i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
 
4613
 
 
4614
    if (ppd->protocols)
 
4615
    {
 
4616
      if (strstr(ppd->protocols, "TBCP"))
 
4617
        i ++;
 
4618
      else if (strstr(ppd->protocols, "BCP"))
 
4619
        i ++;
 
4620
    }
 
4621
 
 
4622
    attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
 
4623
                         "port-monitor-supported", i, NULL, NULL);
 
4624
 
 
4625
    attr->values[0].string.text = _cupsStrAlloc("none");
 
4626
 
 
4627
    for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
 
4628
         ppd_attr;
 
4629
         i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
 
4630
      attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value);
 
4631
 
 
4632
    if (ppd->protocols)
 
4633
    {
 
4634
      if (strstr(ppd->protocols, "TBCP"))
 
4635
        attr->values[i].string.text = _cupsStrAlloc("tbcp");
 
4636
      else if (strstr(ppd->protocols, "BCP"))
 
4637
        attr->values[i].string.text = _cupsStrAlloc("bcp");
 
4638
    }
 
4639
 
 
4640
    if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
 
4641
      p->type |= CUPS_PRINTER_REMOTE;
 
4642
 
 
4643
#ifdef HAVE_APPLICATIONSERVICES_H
 
4644
   /*
 
4645
    * Convert the file referenced in APPrinterIconPath to a 128x128 PNG
 
4646
    * and save it as cacheDir/printername.png
 
4647
    */
 
4648
 
 
4649
    if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL &&
 
4650
        ppd_attr->value &&
 
4651
        !_cupsFileCheck(ppd_attr->value, _CUPS_FILE_CHECK_FILE, !RunUser,
 
4652
                        cupsdLogFCMessage, p))
 
4653
    {
 
4654
      CGImageRef        imageRef = NULL;/* Current icon image */
 
4655
      CGImageRef        biggestIconRef = NULL;
 
4656
                                        /* Biggest icon image */
 
4657
      CGImageRef        closestTo128IconRef = NULL;
 
4658
                                        /* Icon image closest to and >= 128 */
 
4659
      CGImageSourceRef  sourceRef;      /* The file's image source */
 
4660
      char              outPath[HTTP_MAX_URI];
 
4661
                                        /* The path to the PNG file */
 
4662
      CFURLRef          outUrl;         /* The URL made from the outPath */
 
4663
      CFURLRef          icnsFileUrl;    /* The URL of the original ICNS icon file */
 
4664
      CGImageDestinationRef destRef;    /* The image destination to write */
 
4665
      size_t            bytesPerRow;    /* The bytes per row used for resizing */
 
4666
      CGContextRef      context;        /* The CG context used for resizing */
 
4667
 
 
4668
      snprintf(outPath, sizeof(outPath), "%s/%s.png", CacheDir, p->name);
 
4669
      outUrl      = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
 
4670
                                                            (UInt8 *)outPath,
 
4671
                                                            strlen(outPath),
 
4672
                                                            FALSE);
 
4673
      icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
 
4674
                                                            (UInt8 *)ppd_attr->value,
 
4675
                                                            strlen(ppd_attr->value),
 
4676
                                                            FALSE);
 
4677
      if (outUrl && icnsFileUrl)
 
4678
      {
 
4679
        sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL);
 
4680
        if (sourceRef)
 
4681
        {
 
4682
          for (i = 0; i < CGImageSourceGetCount(sourceRef); i ++)
 
4683
          {
 
4684
            imageRef = CGImageSourceCreateImageAtIndex(sourceRef, i, NULL);
 
4685
            if (!imageRef)
 
4686
              continue;
 
4687
 
 
4688
            if (CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef))
 
4689
            {
 
4690
             /*
 
4691
              * Loop through remembering the icon closest to 128 but >= 128
 
4692
              * and then remember the largest icon.
 
4693
              */
 
4694
 
 
4695
              if (CGImageGetWidth(imageRef) >= 128 &&
 
4696
                  (!closestTo128IconRef ||
 
4697
                   CGImageGetWidth(imageRef) <
 
4698
                       CGImageGetWidth(closestTo128IconRef)))
 
4699
              {
 
4700
                CGImageRelease(closestTo128IconRef);
 
4701
                CGImageRetain(imageRef);
 
4702
                closestTo128IconRef = imageRef;
 
4703
              }
 
4704
 
 
4705
              if (!biggestIconRef ||
 
4706
                  CGImageGetWidth(imageRef) > CGImageGetWidth(biggestIconRef))
 
4707
              {
 
4708
                CGImageRelease(biggestIconRef);
 
4709
                CGImageRetain(imageRef);
 
4710
                biggestIconRef = imageRef;
 
4711
              }
 
4712
            }
 
4713
 
 
4714
            CGImageRelease(imageRef);
 
4715
          }
 
4716
 
 
4717
          if (biggestIconRef)
 
4718
          {
 
4719
           /*
 
4720
            * If biggestIconRef is NULL, we found no icons. Otherwise we first
 
4721
            * want the closest to 128, but if none are larger than 128, we want
 
4722
            * the largest icon available.
 
4723
            */
 
4724
 
 
4725
            imageRef = closestTo128IconRef ? closestTo128IconRef :
 
4726
                                             biggestIconRef;
 
4727
            CGImageRetain(imageRef);
 
4728
            CGImageRelease(biggestIconRef);
 
4729
            if (closestTo128IconRef)
 
4730
              CGImageRelease(closestTo128IconRef);
 
4731
            destRef = CGImageDestinationCreateWithURL(outUrl, kUTTypePNG, 1,
 
4732
                                                      NULL);
 
4733
            if (destRef)
 
4734
            {
 
4735
              if (CGImageGetWidth(imageRef) != 128)
 
4736
              {
 
4737
                bytesPerRow = CGImageGetBytesPerRow(imageRef) /
 
4738
                              CGImageGetWidth(imageRef) * 128;
 
4739
                context     = CGBitmapContextCreate(NULL, 128, 128,
 
4740
                                                    CGImageGetBitsPerComponent(imageRef),
 
4741
                                                    bytesPerRow,
 
4742
                                                    CGImageGetColorSpace(imageRef),
 
4743
                                                    kCGImageAlphaPremultipliedFirst);
 
4744
                if (context)
 
4745
                {
 
4746
                  CGContextDrawImage(context, CGRectMake(0, 0, 128, 128),
 
4747
                                     imageRef);
 
4748
                  CGImageRelease(imageRef);
 
4749
                  imageRef = CGBitmapContextCreateImage(context);
 
4750
                  CGContextRelease(context);
 
4751
                }
 
4752
              }
 
4753
 
 
4754
              CGImageDestinationAddImage(destRef, imageRef, NULL);
 
4755
              CGImageDestinationFinalize(destRef);
 
4756
              CFRelease(destRef);
 
4757
            }
 
4758
 
 
4759
            CGImageRelease(imageRef);
 
4760
          }
 
4761
 
 
4762
          CFRelease(sourceRef);
 
4763
        }
 
4764
      }
 
4765
 
 
4766
      if (outUrl)
 
4767
        CFRelease(outUrl);
 
4768
 
 
4769
      if (icnsFileUrl)
 
4770
        CFRelease(icnsFileUrl);
 
4771
    }
 
4772
#endif /* HAVE_APPLICATIONSERVICES_H */
 
4773
 
 
4774
   /*
 
4775
    * Close the PPD and set the type...
 
4776
    */
 
4777
 
 
4778
    ppdClose(ppd);
 
4779
  }
 
4780
  else if (!access(ppd_name, 0))
 
4781
  {
 
4782
    int                 pline;          /* PPD line number */
 
4783
    ppd_status_t        pstatus;        /* PPD load status */
 
4784
 
 
4785
 
 
4786
    pstatus = ppdLastError(&pline);
 
4787
 
 
4788
    cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
 
4789
                    p->name);
 
4790
 
 
4791
    if (pstatus <= PPD_ALLOC_ERROR)
 
4792
      cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
 
4793
    else
 
4794
      cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
 
4795
                      ppdErrorString(pstatus), pline);
 
4796
 
 
4797
    cupsdLogMessage(CUPSD_LOG_INFO,
 
4798
                    "Hint: Run \"cupstestppd %s\" and fix any errors.",
 
4799
                    ppd_name);
 
4800
  }
 
4801
  else
 
4802
  {
 
4803
   /*
 
4804
    * If we have an interface script, add a filter entry for it...
 
4805
    */
 
4806
 
 
4807
    char        interface[1024];        /* Interface script */
 
4808
 
 
4809
 
 
4810
    snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot,
 
4811
             p->name);
 
4812
    if (!access(interface, X_OK))
 
4813
    {
 
4814
     /*
 
4815
      * Yes, we have a System V style interface script; use it!
 
4816
      */
 
4817
 
 
4818
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
 
4819
                   "printer-make-and-model", NULL,
 
4820
                   "Local System V Printer");
 
4821
    }
 
4822
    else if (((!strncmp(p->device_uri, "ipp://", 6) ||
 
4823
               !strncmp(p->device_uri, "ipps://", 7)) &&
 
4824
              (strstr(p->device_uri, "/printers/") != NULL ||
 
4825
               strstr(p->device_uri, "/classes/") != NULL)) ||
 
4826
             ((strstr(p->device_uri, "._ipp.") != NULL ||
 
4827
               strstr(p->device_uri, "._ipps.") != NULL) &&
 
4828
              !strcmp(p->device_uri + strlen(p->device_uri) - 5, "/cups")))
 
4829
    {
 
4830
     /*
 
4831
      * Tell the client this is really a hard-wired remote printer.
 
4832
      */
 
4833
 
 
4834
      p->type |= CUPS_PRINTER_REMOTE;
 
4835
 
 
4836
     /*
 
4837
      * Point the printer-uri-supported attribute to the
 
4838
      * remote printer...
 
4839
      */
 
4840
 
 
4841
      if (strchr(p->device_uri, '?'))
 
4842
      {
 
4843
       /*
 
4844
        * Strip trailing "?options" from URI...
 
4845
        */
 
4846
 
 
4847
        char    resource[HTTP_MAX_URI], /* New URI */
 
4848
                *ptr;                   /* Pointer into URI */
 
4849
 
 
4850
        strlcpy(resource, p->device_uri, sizeof(resource));
 
4851
        if ((ptr = strchr(resource, '?')) != NULL)
 
4852
          *ptr = '\0';
 
4853
 
 
4854
        ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
 
4855
                     "printer-uri-supported", NULL, resource);
 
4856
      }
 
4857
      else
 
4858
        ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
 
4859
                     "printer-uri-supported", NULL, p->device_uri);
 
4860
 
 
4861
     /*
 
4862
      * Then set the make-and-model accordingly...
 
4863
      */
 
4864
 
 
4865
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
 
4866
                   "printer-make-and-model", NULL, "Remote Printer");
 
4867
 
 
4868
     /*
 
4869
      * Print all files directly...
 
4870
      */
 
4871
 
 
4872
      p->raw    = 1;
 
4873
      p->remote = 1;
 
4874
    }
 
4875
    else
 
4876
    {
 
4877
     /*
 
4878
      * Otherwise we have neither - treat this as a "dumb" printer
 
4879
      * with no PPD file...
 
4880
      */
 
4881
 
 
4882
      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
 
4883
                   "printer-make-and-model", NULL, "Local Raw Printer");
 
4884
 
 
4885
      p->raw = 1;
 
4886
    }
 
4887
  }
 
4888
 
 
4889
  ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
 
4890
                 "finishings-supported", num_finishings, finishings);
 
4891
  ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
 
4892
                "finishings-default", IPP_FINISHINGS_NONE);
 
4893
 
 
4894
  if (ppd && p->pc)
 
4895
  {
 
4896
   /*
 
4897
    * Save cached PPD attributes to disk...
 
4898
    */
 
4899
 
 
4900
    cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name);
 
4901
 
 
4902
    _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs);
 
4903
  }
 
4904
  else
 
4905
  {
 
4906
   /*
 
4907
    * Remove cache files...
 
4908
    */
 
4909
 
 
4910
    if (cache_info.st_mtime)
 
4911
      unlink(cache_name);
 
4912
  }
 
4913
}
 
4914
 
 
4915
 
 
4916
/*
 
4917
 * 'log_ipp_conformance()' - Log an IPP conformance issue with a printer.
 
4918
 */
 
4919
 
 
4920
static void
 
4921
log_ipp_conformance(
 
4922
    cupsd_printer_t *p,                 /* I - Printer */
 
4923
    const char      *reason)            /* I - Printer state reason */
 
4924
{
 
4925
  const char    *message;               /* Message to log */
 
4926
#ifdef __APPLE__
 
4927
  aslmsg        aslm;                   /* Apple System Log message */
 
4928
#endif /* __APPLE__ */
 
4929
 
 
4930
 
 
4931
 /*
 
4932
  * Strip the leading "cups-ipp-" from the reason and create a log message for
 
4933
  * it...
 
4934
  */
 
4935
 
 
4936
  reason += 9;
 
4937
  if (!strcmp(reason, "missing-cancel-job"))
 
4938
    message = "Printer does not support REQUIRED Cancel-Job operation.";
 
4939
  else if (!strcmp(reason, "missing-get-job-attributes"))
 
4940
    message = "Printer does not support REQUIRED Get-Job-Attributes operation.";
 
4941
  else if (!strcmp(reason, "missing-print-job"))
 
4942
    message = "Printer does not support REQUIRED Print-Job operation.";
 
4943
  else if (!strcmp(reason, "missing-validate-job"))
 
4944
    message = "Printer does not support REQUIRED Validate-Job operation.";
 
4945
  else if (!strcmp(reason, "missing-get-printer-attributes"))
 
4946
    message = "Printer does not support REQUIRED Get-Printer-Attributes operation.";
 
4947
  else if (!strcmp(reason, "missing-send-document"))
 
4948
    message = "Printer supports Create-Job but not Send-Document operation.";
 
4949
  else if (!strcmp(reason, "missing-job-history"))
 
4950
    message = "Printer does not provide REQUIRED job history.";
 
4951
  else if (!strcmp(reason, "missing-job-id"))
 
4952
    message = "Printer does not provide REQUIRED job-id attribute.";
 
4953
  else if (!strcmp(reason, "missing-job-state"))
 
4954
    message = "Printer does not provide REQUIRED job-state attribute.";
 
4955
  else if (!strcmp(reason, "missing-operations-supported"))
 
4956
    message = "Printer does not provide REQUIRED operations-supported "
 
4957
              "attribute.";
 
4958
  else if (!strcmp(reason, "missing-printer-is-accepting-jobs"))
 
4959
    message = "Printer does not provide REQUIRED printer-is-accepting-jobs "
 
4960
              "attribute.";
 
4961
  else if (!strcmp(reason, "missing-printer-state-reasons"))
 
4962
    message = "Printer does not provide REQUIRED printer-state-reasons "
 
4963
              "attribute.";
 
4964
  else if (!strcmp(reason, "wrong-http-version"))
 
4965
    message = "Printer does not use REQUIRED HTTP/1.1 transport.";
 
4966
  else
 
4967
    message = "Unknown IPP conformance failure.";
 
4968
 
 
4969
  cupsdLogMessage(CUPSD_LOG_WARN, "%s: %s", p->name, message);
 
4970
 
 
4971
#ifdef __APPLE__
 
4972
 /*
 
4973
  * Report the failure information to Apple if the user opts into providing
 
4974
  * feedback to Apple...
 
4975
  */
 
4976
 
 
4977
  aslm = asl_new(ASL_TYPE_MSG);
 
4978
  if (aslm)
 
4979
  {
 
4980
    asl_set(aslm, "com.apple.message.domain", "com.apple.printing.ipp.conformance");
 
4981
    asl_set(aslm, "com.apple.message.domain_scope", "com.apple.printing.ipp.conformance");
 
4982
    asl_set(aslm, "com.apple.message.signature", reason);
 
4983
    asl_set(aslm, "com.apple.message.signature2",
 
4984
            p->make_model ? p->make_model : "Unknown");
 
4985
    asl_log(NULL, aslm, ASL_LEVEL_NOTICE, "%s: %s",
 
4986
            p->make_model ? p->make_model : "Unknown", message);
 
4987
    asl_free(aslm);
 
4988
  }
 
4989
#endif /* __APPLE__ */
 
4990
}
 
4991
 
 
4992
 
 
4993
/*
 
4994
 * 'new_media_col()' - Create a media-col collection value.
 
4995
 */
 
4996
 
 
4997
static ipp_t *                          /* O - Collection value */
 
4998
new_media_col(_pwg_size_t *size,        /* I - media-size/margin values */
 
4999
              const char  *source,      /* I - media-source value */
 
5000
              const char  *type)        /* I - media-type value */
 
5001
{
 
5002
  ipp_t *media_col,                     /* Collection value */
 
5003
        *media_size;                    /* media-size value */
 
5004
 
 
5005
 
 
5006
  media_col = ippNew();
 
5007
 
 
5008
  media_size = ippNew();
 
5009
  ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
5010
                "x-dimension", size->width);
 
5011
  ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
5012
                "y-dimension", size->length);
 
5013
  ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size);
 
5014
  ippDelete(media_size);
 
5015
 
 
5016
  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
5017
                "media-bottom-margin", size->bottom);
 
5018
  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
5019
                "media-left-margin", size->left);
 
5020
  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
5021
                "media-right-margin", size->right);
 
5022
  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
 
5023
                "media-top-margin", size->top);
 
5024
 
 
5025
  if (source)
 
5026
    ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source",
 
5027
                 NULL, source);
 
5028
 
 
5029
  if (type)
 
5030
    ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type",
 
5031
                 NULL, type);
 
5032
 
 
5033
  return (media_col);
 
5034
}
 
5035
 
 
5036
 
 
5037
/*
 
5038
 * 'write_xml_string()' - Write a string with XML escaping.
 
5039
 */
 
5040
 
 
5041
static void
 
5042
write_xml_string(cups_file_t *fp,       /* I - File to write to */
 
5043
                 const char  *s)        /* I - String to write */
 
5044
{
 
5045
  const char    *start;                 /* Start of current sequence */
 
5046
 
 
5047
 
 
5048
  if (!s)
 
5049
    return;
 
5050
 
 
5051
  for (start = s; *s; s ++)
 
5052
  {
 
5053
    if (*s == '&')
 
5054
    {
 
5055
      if (s > start)
 
5056
        cupsFileWrite(fp, start, s - start);
 
5057
 
 
5058
      cupsFilePuts(fp, "&amp;");
 
5059
      start = s + 1;
 
5060
    }
 
5061
    else if (*s == '<')
 
5062
    {
 
5063
      if (s > start)
 
5064
        cupsFileWrite(fp, start, s - start);
 
5065
 
 
5066
      cupsFilePuts(fp, "&lt;");
 
5067
      start = s + 1;
 
5068
    }
 
5069
  }
 
5070
 
 
5071
  if (s > start)
 
5072
    cupsFilePuts(fp, start);
 
5073
}
 
5074
 
 
5075
 
 
5076
/*
 
5077
 * End of "$Id: printers.c 10996 2013-05-29 11:51:34Z msweet $".
 
5078
 */