~ubuntu-branches/ubuntu/trusty/cups/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/color-management-extension.patch/scheduler/printers.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2013-10-31 13:34:55 UTC
  • mfrom: (139.1.1 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20131031133455-w9ykn8rbtc4p7o4w
Tags: 1.7.0-0ubuntu2
debian/rules: Call dh_auto_clean only if the file Makedefs is present, to
avoid a FTBFS.

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