Imported Upstream version 2.2.7
[platform/upstream/cups.git] / cups / ipp-support.c
1 /*
2  * Internet Printing Protocol support functions for CUPS.
3  *
4  * Copyright © 2007-2018 by Apple Inc.
5  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
6  *
7  * These coded instructions, statements, and computer programs are the
8  * property of Apple Inc. and are protected by Federal copyright
9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
10  * which should have been included with this file.  If this file is
11  * missing or damaged, see the license at "http://www.cups.org/".
12  *
13  * This file is subject to the Apple OS-Developed Software exception.
14  */
15
16 /*
17  * Include necessary headers...
18  */
19
20 #include "cups-private.h"
21
22
23 /*
24  * Local globals...
25  */
26
27 static const char * const ipp_states[] =
28                 {
29                   "IPP_STATE_ERROR",
30                   "IPP_STATE_IDLE",
31                   "IPP_STATE_HEADER",
32                   "IPP_STATE_ATTRIBUTE",
33                   "IPP_STATE_DATA"
34                 };
35 static const char * const ipp_status_oks[] =    /* "OK" status codes */
36                 {                               /* (name) = abandoned standard value */
37                   "successful-ok",
38                   "successful-ok-ignored-or-substituted-attributes",
39                   "successful-ok-conflicting-attributes",
40                   "successful-ok-ignored-subscriptions",
41                   "(successful-ok-ignored-notifications)",
42                   "successful-ok-too-many-events",
43                   "(successful-ok-but-cancel-subscription)",
44                   "successful-ok-events-complete"
45                 },
46                 * const ipp_status_400s[] =     /* Client errors */
47                 {                               /* (name) = abandoned standard value */
48                   "client-error-bad-request",
49                   "client-error-forbidden",
50                   "client-error-not-authenticated",
51                   "client-error-not-authorized",
52                   "client-error-not-possible",
53                   "client-error-timeout",
54                   "client-error-not-found",
55                   "client-error-gone",
56                   "client-error-request-entity-too-large",
57                   "client-error-request-value-too-long",
58                   "client-error-document-format-not-supported",
59                   "client-error-attributes-or-values-not-supported",
60                   "client-error-uri-scheme-not-supported",
61                   "client-error-charset-not-supported",
62                   "client-error-conflicting-attributes",
63                   "client-error-compression-not-supported",
64                   "client-error-compression-error",
65                   "client-error-document-format-error",
66                   "client-error-document-access-error",
67                   "client-error-attributes-not-settable",
68                   "client-error-ignored-all-subscriptions",
69                   "client-error-too-many-subscriptions",
70                   "(client-error-ignored-all-notifications)",
71                   "(client-error-client-print-support-file-not-found)",
72                   "client-error-document-password-error",
73                   "client-error-document-permission-error",
74                   "client-error-document-security-error",
75                   "client-error-document-unprintable-error",
76                   "client-error-account-info-needed",
77                   "client-error-account-closed",
78                   "client-error-account-limit-reached",
79                   "client-error-account-authorization-failed",
80                   "client-error-not-fetchable"
81                 },
82                 * const ipp_status_480s[] =     /* Vendor client errors */
83                 {
84                   /* 0x0480 - 0x048F */
85                   "0x0480",
86                   "0x0481",
87                   "0x0482",
88                   "0x0483",
89                   "0x0484",
90                   "0x0485",
91                   "0x0486",
92                   "0x0487",
93                   "0x0488",
94                   "0x0489",
95                   "0x048A",
96                   "0x048B",
97                   "0x048C",
98                   "0x048D",
99                   "0x048E",
100                   "0x048F",
101                   /* 0x0490 - 0x049F */
102                   "0x0490",
103                   "0x0491",
104                   "0x0492",
105                   "0x0493",
106                   "0x0494",
107                   "0x0495",
108                   "0x0496",
109                   "0x0497",
110                   "0x0498",
111                   "0x0499",
112                   "0x049A",
113                   "0x049B",
114                   "cups-error-account-info-needed",
115                   "cups-error-account-closed",
116                   "cups-error-account-limit-reached",
117                   "cups-error-account-authorization-failed"
118                 },
119                 * const ipp_status_500s[] =             /* Server errors */
120                 {
121                   "server-error-internal-error",
122                   "server-error-operation-not-supported",
123                   "server-error-service-unavailable",
124                   "server-error-version-not-supported",
125                   "server-error-device-error",
126                   "server-error-temporary-error",
127                   "server-error-not-accepting-jobs",
128                   "server-error-busy",
129                   "server-error-job-canceled",
130                   "server-error-multiple-document-jobs-not-supported",
131                   "server-error-printer-is-deactivated",
132                   "server-error-too-many-jobs",
133                   "server-error-too-many-documents"
134                 },
135                 * const ipp_status_1000s[] =            /* CUPS internal */
136                 {
137                   "cups-authentication-canceled",
138                   "cups-pki-error",
139                   "cups-upgrade-required"
140                 };
141 static const char * const ipp_std_ops[] =
142                 {
143                   /* 0x0000 - 0x000f */
144                   "0x0000",
145                   "0x0001",
146                   "Print-Job",
147                   "Print-URI",
148                   "Validate-Job",
149                   "Create-Job",
150                   "Send-Document",
151                   "Send-URI",
152                   "Cancel-Job",
153                   "Get-Job-Attributes",
154                   "Get-Jobs",
155                   "Get-Printer-Attributes",
156                   "Hold-Job",
157                   "Release-Job",
158                   "Restart-Job",
159                   "0x000f",
160
161                   /* 0x0010 - 0x001f */
162                   "Pause-Printer",
163                   "Resume-Printer",
164                   "Purge-Jobs",
165                   "Set-Printer-Attributes",
166                   "Set-Job-Attributes",
167                   "Get-Printer-Supported-Values",
168                   "Create-Printer-Subscriptions",
169                   "Create-Job-Subscriptions",
170                   "Get-Subscription-Attributes",
171                   "Get-Subscriptions",
172                   "Renew-Subscription",
173                   "Cancel-Subscription",
174                   "Get-Notifications",
175                   "(Send-Notifications)",
176                   "(Get-Resource-Attributes)",
177                   "(Get-Resource-Data)",
178
179                   /* 0x0020 - 0x002f */
180                   "(Get-Resources)",
181                   "(Get-Printer-Support-Files)",
182                   "Enable-Printer",
183                   "Disable-Printer",
184                   "Pause-Printer-After-Current-Job",
185                   "Hold-New-Jobs",
186                   "Release-Held-New-Jobs",
187                   "Deactivate-Printer",
188                   "Activate-Printer",
189                   "Restart-Printer",
190                   "Shutdown-Printer",
191                   "Startup-Printer",
192                   "Reprocess-Job",
193                   "Cancel-Current-Job",
194                   "Suspend-Current-Job",
195                   "Resume-Job",
196
197                   /* 0x0030 - 0x003f */
198                   "Promote-Job",
199                   "Schedule-Job-After",
200                   "0x0032",
201                   "Cancel-Document",
202                   "Get-Document-Attributes",
203                   "Get-Documents",
204                   "Delete-Document",
205                   "Set-Document-Attributes",
206                   "Cancel-Jobs",
207                   "Cancel-My-Jobs",
208                   "Resubmit-Job",
209                   "Close-Job",
210                   "Identify-Printer",
211                   "Validate-Document",
212                   "Add-Document-Images",
213                   "Acknowledge-Document",
214
215                   /* 0x0040 - 0x004a */
216                   "Acknowledge-Identify-Printer",
217                   "Acknowledge-Job",
218                   "Fetch-Document",
219                   "Fetch-Job",
220                   "Get-Output-Device-Attributes",
221                   "Update-Active-Jobs",
222                   "Deregister-Output-Device",
223                   "Update-Document-Status",
224                   "Update-Job-Status",
225                   "Update-Output-Device-Attributes",
226                   "Get-Next-Document-Data"
227                 },
228                 * const ipp_cups_ops[] =
229                 {
230                   "CUPS-Get-Default",
231                   "CUPS-Get-Printers",
232                   "CUPS-Add-Modify-Printer",
233                   "CUPS-Delete-Printer",
234                   "CUPS-Get-Classes",
235                   "CUPS-Add-Modify-Class",
236                   "CUPS-Delete-Class",
237                   "CUPS-Accept-Jobs",
238                   "CUPS-Reject-Jobs",
239                   "CUPS-Set-Default",
240                   "CUPS-Get-Devices",
241                   "CUPS-Get-PPDs",
242                   "CUPS-Move-Job",
243                   "CUPS-Authenticate-Job",
244                   "CUPS-Get-PPD"
245                 },
246                 * const ipp_cups_ops2[] =
247                 {
248                   "CUPS-Get-Document",
249                   "CUPS-Create-Local-Printer"
250                 },
251                 * const ipp_tag_names[] =
252                 {                       /* Value/group tag names */
253                   "zero",               /* 0x00 */
254                   "operation-attributes-tag",
255                                         /* 0x01 */
256                   "job-attributes-tag", /* 0x02 */
257                   "end-of-attributes-tag",
258                                         /* 0x03 */
259                   "printer-attributes-tag",
260                                         /* 0x04 */
261                   "unsupported-attributes-tag",
262                                         /* 0x05 */
263                   "subscription-attributes-tag",
264                                         /* 0x06 */
265                   "event-notification-attributes-tag",
266                                         /* 0x07 */
267                   "(resource-attributes-tag)",
268                                         /* 0x08 */
269                   "document-attributes-tag",
270                                         /* 0x09 */
271                   "0x0a",               /* 0x0a */
272                   "0x0b",               /* 0x0b */
273                   "0x0c",               /* 0x0c */
274                   "0x0d",               /* 0x0d */
275                   "0x0e",               /* 0x0e */
276                   "0x0f",               /* 0x0f */
277                   "unsupported",        /* 0x10 */
278                   "default",            /* 0x11 */
279                   "unknown",            /* 0x12 */
280                   "no-value",           /* 0x13 */
281                   "0x14",               /* 0x14 */
282                   "not-settable",       /* 0x15 */
283                   "delete-attribute",   /* 0x16 */
284                   "admin-define",       /* 0x17 */
285                   "0x18",               /* 0x18 */
286                   "0x19",               /* 0x19 */
287                   "0x1a",               /* 0x1a */
288                   "0x1b",               /* 0x1b */
289                   "0x1c",               /* 0x1c */
290                   "0x1d",               /* 0x1d */
291                   "0x1e",               /* 0x1e */
292                   "0x1f",               /* 0x1f */
293                   "0x20",               /* 0x20 */
294                   "integer",            /* 0x21 */
295                   "boolean",            /* 0x22 */
296                   "enum",               /* 0x23 */
297                   "0x24",               /* 0x24 */
298                   "0x25",               /* 0x25 */
299                   "0x26",               /* 0x26 */
300                   "0x27",               /* 0x27 */
301                   "0x28",               /* 0x28 */
302                   "0x29",               /* 0x29 */
303                   "0x2a",               /* 0x2a */
304                   "0x2b",               /* 0x2b */
305                   "0x2c",               /* 0x2c */
306                   "0x2d",               /* 0x2d */
307                   "0x2e",               /* 0x2e */
308                   "0x2f",               /* 0x2f */
309                   "octetString",        /* 0x30 */
310                   "dateTime",           /* 0x31 */
311                   "resolution",         /* 0x32 */
312                   "rangeOfInteger",     /* 0x33 */
313                   "collection",         /* 0x34 */
314                   "textWithLanguage",   /* 0x35 */
315                   "nameWithLanguage",   /* 0x36 */
316                   "endCollection",      /* 0x37 */
317                   "0x38",               /* 0x38 */
318                   "0x39",               /* 0x39 */
319                   "0x3a",               /* 0x3a */
320                   "0x3b",               /* 0x3b */
321                   "0x3c",               /* 0x3c */
322                   "0x3d",               /* 0x3d */
323                   "0x3e",               /* 0x3e */
324                   "0x3f",               /* 0x3f */
325                   "0x40",               /* 0x40 */
326                   "textWithoutLanguage",/* 0x41 */
327                   "nameWithoutLanguage",/* 0x42 */
328                   "0x43",               /* 0x43 */
329                   "keyword",            /* 0x44 */
330                   "uri",                /* 0x45 */
331                   "uriScheme",          /* 0x46 */
332                   "charset",            /* 0x47 */
333                   "naturalLanguage",    /* 0x48 */
334                   "mimeMediaType",      /* 0x49 */
335                   "memberAttrName"      /* 0x4a */
336                 };
337 static const char * const ipp_document_states[] =
338                 {                       /* document-state-enums */
339                   "pending",
340                   "4",
341                   "processing",
342                   "processing-stopped", /* IPPSIX */
343                   "canceled",
344                   "aborted",
345                   "completed"
346                 },
347                 * const ipp_finishings[] =
348                 {                       /* finishings enums */
349                   "none",
350                   "staple",
351                   "punch",
352                   "cover",
353                   "bind",
354                   "saddle-stitch",
355                   "edge-stitch",
356                   "fold",
357                   "trim",
358                   "bale",
359                   "booklet-maker",
360                   "jog-offset",
361                   "coat",               /* Finishings 2.0 */
362                   "laminate",           /* Finishings 2.0 */
363                   "17",
364                   "18",
365                   "19",
366                   "staple-top-left",
367                   "staple-bottom-left",
368                   "staple-top-right",
369                   "staple-bottom-right",
370                   "edge-stitch-left",
371                   "edge-stitch-top",
372                   "edge-stitch-right",
373                   "edge-stitch-bottom",
374                   "staple-dual-left",
375                   "staple-dual-top",
376                   "staple-dual-right",
377                   "staple-dual-bottom",
378                   "staple-triple-left", /* Finishings 2.0 */
379                   "staple-triple-top",  /* Finishings 2.0 */
380                   "staple-triple-right",/* Finishings 2.0 */
381                   "staple-triple-bottom",/* Finishings 2.0 */
382                   "36",
383                   "37",
384                   "38",
385                   "39",
386                   "40",
387                   "41",
388                   "42",
389                   "43",
390                   "44",
391                   "45",
392                   "46",
393                   "47",
394                   "48",
395                   "49",
396                   "bind-left",
397                   "bind-top",
398                   "bind-right",
399                   "bind-bottom",
400                   "54",
401                   "55",
402                   "56",
403                   "57",
404                   "58",
405                   "59",
406                   "trim-after-pages",
407                   "trim-after-documents",
408                   "trim-after-copies",
409                   "trim-after-job",
410                   "64",
411                   "65",
412                   "66",
413                   "67",
414                   "68",
415                   "69",
416                   "punch-top-left",     /* Finishings 2.0 */
417                   "punch-bottom-left",  /* Finishings 2.0 */
418                   "punch-top-right",    /* Finishings 2.0 */
419                   "punch-bottom-right", /* Finishings 2.0 */
420                   "punch-dual-left",    /* Finishings 2.0 */
421                   "punch-dual-top",     /* Finishings 2.0 */
422                   "punch-dual-right",   /* Finishings 2.0 */
423                   "punch-dual-bottom",  /* Finishings 2.0 */
424                   "punch-triple-left",  /* Finishings 2.0 */
425                   "punch-triple-top",   /* Finishings 2.0 */
426                   "punch-triple-right", /* Finishings 2.0 */
427                   "punch-triple-bottom",/* Finishings 2.0 */
428                   "punch-quad-left",    /* Finishings 2.0 */
429                   "punch-quad-top",     /* Finishings 2.0 */
430                   "punch-quad-right",   /* Finishings 2.0 */
431                   "punch-quad-bottom",  /* Finishings 2.0 */
432                   "punch-multiple-left",/* Finishings 2.1/Canon */
433                   "punch-multiple-top", /* Finishings 2.1/Canon */
434                   "punch-multiple-right",/* Finishings 2.1/Canon */
435                   "punch-multiple-bottom",/* Finishings 2.1/Canon */
436                   "fold-accordian",     /* Finishings 2.0 */
437                   "fold-double-gate",   /* Finishings 2.0 */
438                   "fold-gate",          /* Finishings 2.0 */
439                   "fold-half",          /* Finishings 2.0 */
440                   "fold-half-z",        /* Finishings 2.0 */
441                   "fold-left-gate",     /* Finishings 2.0 */
442                   "fold-letter",        /* Finishings 2.0 */
443                   "fold-parallel",      /* Finishings 2.0 */
444                   "fold-poster",        /* Finishings 2.0 */
445                   "fold-right-gate",    /* Finishings 2.0 */
446                   "fold-z",             /* Finishings 2.0 */
447                   "fold-engineering-z"  /* Finishings 2.1 */
448                 },
449                 * const ipp_finishings_vendor[] =
450                 {
451                   /* 0x40000000 to 0x4000000F */
452                   "0x40000000",
453                   "0x40000001",
454                   "0x40000002",
455                   "0x40000003",
456                   "0x40000004",
457                   "0x40000005",
458                   "0x40000006",
459                   "0x40000007",
460                   "0x40000008",
461                   "0x40000009",
462                   "0x4000000A",
463                   "0x4000000B",
464                   "0x4000000C",
465                   "0x4000000D",
466                   "0x4000000E",
467                   "0x4000000F",
468                   /* 0x40000010 to 0x4000001F */
469                   "0x40000010",
470                   "0x40000011",
471                   "0x40000012",
472                   "0x40000013",
473                   "0x40000014",
474                   "0x40000015",
475                   "0x40000016",
476                   "0x40000017",
477                   "0x40000018",
478                   "0x40000019",
479                   "0x4000001A",
480                   "0x4000001B",
481                   "0x4000001C",
482                   "0x4000001D",
483                   "0x4000001E",
484                   "0x4000001F",
485                   /* 0x40000020 to 0x4000002F */
486                   "0x40000020",
487                   "0x40000021",
488                   "0x40000022",
489                   "0x40000023",
490                   "0x40000024",
491                   "0x40000025",
492                   "0x40000026",
493                   "0x40000027",
494                   "0x40000028",
495                   "0x40000029",
496                   "0x4000002A",
497                   "0x4000002B",
498                   "0x4000002C",
499                   "0x4000002D",
500                   "0x4000002E",
501                   "0x4000002F",
502                   /* 0x40000030 to 0x4000003F */
503                   "0x40000030",
504                   "0x40000031",
505                   "0x40000032",
506                   "0x40000033",
507                   "0x40000034",
508                   "0x40000035",
509                   "0x40000036",
510                   "0x40000037",
511                   "0x40000038",
512                   "0x40000039",
513                   "0x4000003A",
514                   "0x4000003B",
515                   "0x4000003C",
516                   "0x4000003D",
517                   "0x4000003E",
518                   "0x4000003F",
519                   /* 0x40000040 - 0x4000004F */
520                   "0x40000040",
521                   "0x40000041",
522                   "0x40000042",
523                   "0x40000043",
524                   "0x40000044",
525                   "0x40000045",
526                   "cups-punch-top-left",
527                   "cups-punch-bottom-left",
528                   "cups-punch-top-right",
529                   "cups-punch-bottom-right",
530                   "cups-punch-dual-left",
531                   "cups-punch-dual-top",
532                   "cups-punch-dual-right",
533                   "cups-punch-dual-bottom",
534                   "cups-punch-triple-left",
535                   "cups-punch-triple-top",
536                   /* 0x40000050 - 0x4000005F */
537                   "cups-punch-triple-right",
538                   "cups-punch-triple-bottom",
539                   "cups-punch-quad-left",
540                   "cups-punch-quad-top",
541                   "cups-punch-quad-right",
542                   "cups-punch-quad-bottom",
543                   "0x40000056",
544                   "0x40000057",
545                   "0x40000058",
546                   "0x40000059",
547                   "cups-fold-accordian",
548                   "cups-fold-double-gate",
549                   "cups-fold-gate",
550                   "cups-fold-half",
551                   "cups-fold-half-z",
552                   "cups-fold-left-gate",
553                   /* 0x40000060 - 0x40000064 */
554                   "cups-fold-letter",
555                   "cups-fold-parallel",
556                   "cups-fold-poster",
557                   "cups-fold-right-gate",
558                   "cups-fold-z"
559                 },
560                 * const ipp_job_collation_types[] =
561                 {                       /* job-collation-type enums */
562                   "uncollated-sheets",
563                   "collated-documents",
564                   "uncollated-documents"
565                 },
566                 * const ipp_job_states[] =
567                 {                       /* job-state enums */
568                   "pending",
569                   "pending-held",
570                   "processing",
571                   "processing-stopped",
572                   "canceled",
573                   "aborted",
574                   "completed"
575                 },
576                 * const ipp_orientation_requesteds[] =
577                 {                       /* orientation-requested enums */
578                   "portrait",
579                   "landscape",
580                   "reverse-landscape",
581                   "reverse-portrait",
582                   "none"
583                 },
584                 * const ipp_print_qualities[] =
585                 {                       /* print-quality enums */
586                   "draft",
587                   "normal",
588                   "high"
589                 },
590                 * const ipp_printer_states[] =
591                 {                       /* printer-state enums */
592                   "idle",
593                   "processing",
594                   "stopped",
595                 };
596
597
598 /*
599  * Local functions...
600  */
601
602 static size_t   ipp_col_string(ipp_t *col, char *buffer, size_t bufsize);
603
604
605 /*
606  * 'ippAttributeString()' - Convert the attribute's value to a string.
607  *
608  * Returns the number of bytes that would be written, not including the
609  * trailing nul. The buffer pointer can be NULL to get the required length,
610  * just like (v)snprintf.
611  *
612  * @since CUPS 1.6/macOS 10.8@
613  */
614
615 size_t                                  /* O - Number of bytes less nul */
616 ippAttributeString(
617     ipp_attribute_t *attr,              /* I - Attribute */
618     char            *buffer,            /* I - String buffer or NULL */
619     size_t          bufsize)            /* I - Size of string buffer */
620 {
621   int           i;                      /* Looping var */
622   char          *bufptr,                /* Pointer into buffer */
623                 *bufend,                /* End of buffer */
624                 temp[256];              /* Temporary string */
625   const char    *ptr,                   /* Pointer into string */
626                 *end;                   /* Pointer to end of string */
627   _ipp_value_t  *val;                   /* Current value */
628
629
630   if (!attr || !attr->name)
631   {
632     if (buffer)
633       *buffer = '\0';
634
635     return (0);
636   }
637
638   bufptr = buffer;
639   if (buffer)
640     bufend = buffer + bufsize - 1;
641   else
642     bufend = NULL;
643
644   for (i = attr->num_values, val = attr->values; i > 0; i --, val ++)
645   {
646     if (val > attr->values)
647     {
648       if (buffer && bufptr < bufend)
649         *bufptr++ = ',';
650       else
651         bufptr ++;
652     }
653
654     switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
655     {
656       case IPP_TAG_ENUM :
657           ptr = ippEnumString(attr->name, val->integer);
658
659           if (buffer && bufptr < bufend)
660             strlcpy(bufptr, ptr, (size_t)(bufend - bufptr + 1));
661
662           bufptr += strlen(ptr);
663           break;
664
665       case IPP_TAG_INTEGER :
666           if (buffer && bufptr < bufend)
667             bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%d", val->integer);
668           else
669             bufptr += snprintf(temp, sizeof(temp), "%d", val->integer);
670           break;
671
672       case IPP_TAG_BOOLEAN :
673           if (buffer && bufptr < bufend)
674             strlcpy(bufptr, val->boolean ? "true" : "false", (size_t)(bufend - bufptr + 1));
675
676           bufptr += val->boolean ? 4 : 5;
677           break;
678
679       case IPP_TAG_RANGE :
680           if (buffer && bufptr < bufend)
681             bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%d-%d", val->range.lower, val->range.upper);
682           else
683             bufptr += snprintf(temp, sizeof(temp), "%d-%d", val->range.lower, val->range.upper);
684           break;
685
686       case IPP_TAG_RESOLUTION :
687           if (val->resolution.xres == val->resolution.yres)
688           {
689             if (buffer && bufptr < bufend)
690               bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%d%s", val->resolution.xres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
691             else
692               bufptr += snprintf(temp, sizeof(temp), "%d%s", val->resolution.xres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
693           }
694           else if (buffer && bufptr < bufend)
695             bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%dx%d%s", val->resolution.xres, val->resolution.yres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
696           else
697             bufptr += snprintf(temp, sizeof(temp), "%dx%d%s", val->resolution.xres, val->resolution.yres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
698           break;
699
700       case IPP_TAG_DATE :
701           {
702             unsigned year;              /* Year */
703
704             year = ((unsigned)val->date[0] << 8) + (unsigned)val->date[1];
705
706             if (val->date[9] == 0 && val->date[10] == 0)
707               snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ",
708                        year, val->date[2], val->date[3], val->date[4],
709                        val->date[5], val->date[6]);
710             else
711               snprintf(temp, sizeof(temp),
712                        "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
713                        year, val->date[2], val->date[3], val->date[4],
714                        val->date[5], val->date[6], val->date[8], val->date[9],
715                        val->date[10]);
716
717             if (buffer && bufptr < bufend)
718               strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
719
720             bufptr += strlen(temp);
721           }
722           break;
723
724       case IPP_TAG_TEXT :
725       case IPP_TAG_NAME :
726       case IPP_TAG_KEYWORD :
727       case IPP_TAG_CHARSET :
728       case IPP_TAG_URI :
729       case IPP_TAG_URISCHEME :
730       case IPP_TAG_MIMETYPE :
731       case IPP_TAG_LANGUAGE :
732       case IPP_TAG_TEXTLANG :
733       case IPP_TAG_NAMELANG :
734           if (!val->string.text)
735             break;
736
737           for (ptr = val->string.text; *ptr; ptr ++)
738           {
739             if (*ptr == '\\' || *ptr == '\"' || *ptr == '[')
740             {
741               if (buffer && bufptr < bufend)
742                 *bufptr = '\\';
743               bufptr ++;
744             }
745
746             if (buffer && bufptr < bufend)
747               *bufptr = *ptr;
748             bufptr ++;
749           }
750
751           if (val->string.language)
752           {
753            /*
754             * Add "[language]" to end of string...
755             */
756
757             if (buffer && bufptr < bufend)
758               *bufptr = '[';
759             bufptr ++;
760
761             if (buffer && bufptr < bufend)
762               strlcpy(bufptr, val->string.language, (size_t)(bufend - bufptr));
763             bufptr += strlen(val->string.language);
764
765             if (buffer && bufptr < bufend)
766               *bufptr = ']';
767             bufptr ++;
768           }
769           break;
770
771       case IPP_TAG_BEGIN_COLLECTION :
772           if (buffer && bufptr < bufend)
773             bufptr += ipp_col_string(val->collection, bufptr, (size_t)(bufend - bufptr + 1));
774           else
775             bufptr += ipp_col_string(val->collection, NULL, 0);
776           break;
777
778       case IPP_TAG_STRING :
779           for (ptr = val->unknown.data, end = ptr + val->unknown.length;
780                ptr < end; ptr ++)
781           {
782             if (*ptr == '\\' || _cups_isspace(*ptr))
783             {
784               if (buffer && bufptr < bufend)
785                 *bufptr = '\\';
786               bufptr ++;
787
788               if (buffer && bufptr < bufend)
789                 *bufptr = *ptr;
790               bufptr ++;
791             }
792             else if (!isprint(*ptr & 255))
793             {
794               if (buffer && bufptr < bufend)
795                 bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "\\%03o", *ptr & 255);
796               else
797                 bufptr += snprintf(temp, sizeof(temp), "\\%03o", *ptr & 255);
798             }
799             else
800             {
801               if (buffer && bufptr < bufend)
802                 *bufptr = *ptr;
803               bufptr ++;
804             }
805           }
806           break;
807
808       default :
809           ptr = ippTagString(attr->value_tag);
810           if (buffer && bufptr < bufend)
811             strlcpy(bufptr, ptr, (size_t)(bufend - bufptr + 1));
812           bufptr += strlen(ptr);
813           break;
814     }
815   }
816
817   if (buffer && bufptr < bufend)
818     *bufptr = '\0';
819   else if (bufend)
820     *bufend = '\0';
821
822   return ((size_t)(bufptr - buffer));
823 }
824
825
826 /*
827  * 'ippCreateRequestedArray()' - Create a CUPS array of attribute names from the
828  *                               given requested-attributes attribute.
829  *
830  * This function creates a (sorted) CUPS array of attribute names matching the
831  * list of "requested-attribute" values supplied in an IPP request.  All IANA-
832  * registered values are supported in addition to the CUPS IPP extension
833  * attributes.
834  *
835  * The @code request@ parameter specifies the request message that was read from
836  * the client.
837  *
838  * @code NULL@ is returned if all attributes should be returned.  Otherwise, the
839  * result is a sorted array of attribute names, where @code cupsArrayFind(array,
840  * "attribute-name")@ will return a non-NULL pointer.  The array must be freed
841  * using the @code cupsArrayDelete@ function.
842  *
843  * @since CUPS 1.7/macOS 10.9@
844  */
845
846 cups_array_t *                          /* O - CUPS array or @code NULL@ if all */
847 ippCreateRequestedArray(ipp_t *request) /* I - IPP request */
848 {
849   int                   i, j,           /* Looping vars */
850                         count,          /* Number of values */
851                         added;          /* Was name added? */
852   ipp_attribute_t       *requested;     /* requested-attributes attribute */
853   cups_array_t          *ra;            /* Requested attributes array */
854   const char            *value;         /* Current value */
855   /* The following lists come from the current IANA IPP registry of attributes */
856   static const char * const document_description[] =
857   {                                     /* document-description group */
858     "compression",
859     "copies-actual",
860     "cover-back-actual",
861     "cover-front-actual",
862     "current-page-order",
863     "date-time-at-completed",
864     "date-time-at-creation",
865     "date-time-at-processing",
866     "detailed-status-messages",
867     "document-access-errors",
868     "document-charset",
869     "document-digital-signature",
870     "document-format",
871     "document-format-details",
872     "document-format-detected",
873     "document-format-version",
874     "document-format-version-detected",
875     "document-job-id",
876     "document-job-uri",
877     "document-message",
878     "document-metadata",
879     "document-name",
880     "document-natural-language",
881     "document-number",
882     "document-printer-uri",
883     "document-state",
884     "document-state-message",
885     "document-state-reasons",
886     "document-uri",
887     "document-uuid",
888     "errors-count",
889     "finishings-actual",
890     "finishings-col-actual",
891     "force-front-side-actual",
892     "imposition-template-actual",
893     "impressions",
894     "impressions-completed",
895     "impressions-completed-current-copy",
896     "insert-sheet-actual",
897     "k-octets",
898     "k-octets-processed",
899     "last-document",
900     "materials-col-actual",             /* IPP 3D */
901     "media-actual",
902     "media-col-actual",
903     "media-input-tray-check-actual",
904     "media-sheets",
905     "media-sheets-completed",
906     "more-info",
907     "multiple-object-handling-actual",  /* IPP 3D */
908     "number-up-actual",
909     "orientation-requested-actual",
910     "output-bin-actual",
911     "output-device-assigned",
912     "overrides-actual",
913     "page-delivery-actual",
914     "page-order-received-actual",
915     "page-ranges-actual",
916     "pages",
917     "pages-completed",
918     "pages-completed-current-copy",
919     "platform-temperature-actual",      /* IPP 3D */
920     "presentation-direction-number-up-actual",
921     "print-accuracy-actual",            /* IPP 3D */
922     "print-base-actual",                /* IPP 3D */
923     "print-color-mode-actual",
924     "print-content-optimize-actual",
925     "print-objects-actual",             /* IPP 3D */
926     "print-quality-actual",
927     "print-rendering-intent-actual",
928     "print-scaling-actual",             /* IPP Paid Printing */
929     "print-supports-actual",            /* IPP 3D */
930     "printer-resolution-actual",
931     "printer-up-time",
932     "separator-sheets-actual",
933     "sheet-completed-copy-number",
934     "sides-actual",
935     "time-at-completed",
936     "time-at-creation",
937     "time-at-processing",
938     "x-image-position-actual",
939     "x-image-shift-actual",
940     "x-side1-image-shift-actual",
941     "x-side2-image-shift-actual",
942     "y-image-position-actual",
943     "y-image-shift-actual",
944     "y-side1-image-shift-actual",
945     "y-side2-image-shift-actual"
946   };
947   static const char * const document_template[] =
948   {                                     /* document-template group */
949     "copies",
950     "copies-default",
951     "copies-supported",
952     "cover-back",
953     "cover-back-default",
954     "cover-back-supported",
955     "cover-front",
956     "cover-front-default",
957     "cover-front-supported",
958     "feed-orientation",
959     "feed-orientation-default",
960     "feed-orientation-supported",
961     "finishings",
962     "finishings-col",
963     "finishings-col-database",
964     "finishings-col-default",
965     "finishings-col-ready",
966     "finishings-col-supported",
967     "finishings-default",
968     "finishings-ready",
969     "finishings-supported",
970     "font-name-requested",
971     "font-name-requested-default",
972     "font-name-requested-supported",
973     "font-size-requested",
974     "font-size-requested-default",
975     "font-size-requested-supported",
976     "force-front-side",
977     "force-front-side-default",
978     "force-front-side-supported",
979     "imposition-template",
980     "imposition-template-default",
981     "imposition-template-supported",
982     "insert-after-page-number-supported",
983     "insert-count-supported",
984     "insert-sheet",
985     "insert-sheet-default",
986     "insert-sheet-supported",
987     "material-amount-units-supported",  /* IPP 3D */
988     "material-diameter-supported",      /* IPP 3D */
989     "material-purpose-supported",       /* IPP 3D */
990     "material-rate-supported",          /* IPP 3D */
991     "material-rate-units-supported",    /* IPP 3D */
992     "material-shell-thickness-supported",/* IPP 3D */
993     "material-temperature-supported",   /* IPP 3D */
994     "material-type-supported",          /* IPP 3D */
995     "materials-col",                    /* IPP 3D */
996     "materials-col-database",           /* IPP 3D */
997     "materials-col-default",            /* IPP 3D */
998     "materials-col-ready",              /* IPP 3D */
999     "materials-col-supported",          /* IPP 3D */
1000     "max-materials-col-supported",      /* IPP 3D */
1001     "max-stitching-locations-supported",
1002     "media",
1003     "media-back-coating-supported",
1004     "media-bottom-margin-supported",
1005     "media-col",
1006     "media-col-default",
1007     "media-col-ready",
1008     "media-col-supported",
1009     "media-color-supported",
1010     "media-default",
1011     "media-front-coating-supported",
1012     "media-grain-supported",
1013     "media-hole-count-supported",
1014     "media-info-supported",
1015     "media-input-tray-check",
1016     "media-input-tray-check-default",
1017     "media-input-tray-check-supported",
1018     "media-key-supported",
1019     "media-left-margin-supported",
1020     "media-order-count-supported",
1021     "media-pre-printed-supported",
1022     "media-ready",
1023     "media-recycled-supported",
1024     "media-right-margin-supported",
1025     "media-size-supported",
1026     "media-source-supported",
1027     "media-supported",
1028     "media-thickness-supported",
1029     "media-top-margin-supported",
1030     "media-type-supported",
1031     "media-weight-metric-supported",
1032     "multiple-document-handling",
1033     "multiple-document-handling-default",
1034     "multiple-document-handling-supported",
1035     "multiple-object-handling",         /* IPP 3D */
1036     "multiple-object-handling-default", /* IPP 3D */
1037     "multiple-object-handling-supported",/* IPP 3D */
1038     "number-up",
1039     "number-up-default",
1040     "number-up-supported",
1041     "orientation-requested",
1042     "orientation-requested-default",
1043     "orientation-requested-supported",
1044     "output-mode",                      /* CUPS extension */
1045     "output-mode-default",              /* CUPS extension */
1046     "output-mode-supported",            /* CUPS extension */
1047     "overrides",
1048     "overrides-supported",
1049     "page-delivery",
1050     "page-delivery-default",
1051     "page-delivery-supported",
1052     "page-order-received",
1053     "page-order-received-default",
1054     "page-order-received-supported",
1055     "page-ranges",
1056     "page-ranges-supported",
1057     "pages-per-subset",
1058     "pages-per-subset-supported",
1059     "pdl-init-file",
1060     "pdl-init-file-default",
1061     "pdl-init-file-entry-supported",
1062     "pdl-init-file-location-supported",
1063     "pdl-init-file-name-subdirectory-supported",
1064     "pdl-init-file-name-supported",
1065     "pdl-init-file-supported",
1066     "platform-temperature",             /* IPP 3D */
1067     "platform-temperature-default",     /* IPP 3D */
1068     "platform-temperature-supported",   /* IPP 3D */
1069     "presentation-direction-number-up",
1070     "presentation-direction-number-up-default",
1071     "presentation-direction-number-up-supported",
1072     "print-accuracy",                   /* IPP 3D */
1073     "print-accuracy-default",           /* IPP 3D */
1074     "print-accuracy-supported",         /* IPP 3D */
1075     "print-base",                       /* IPP 3D */
1076     "print-base-default",               /* IPP 3D */
1077     "print-base-supported",             /* IPP 3D */
1078     "print-color-mode",
1079     "print-color-mode-default",
1080     "print-color-mode-supported",
1081     "print-content-optimize",
1082     "print-content-optimize-default",
1083     "print-content-optimize-supported",
1084     "print-objects",                    /* IPP 3D */
1085     "print-objects-default",            /* IPP 3D */
1086     "print-objects-supported",          /* IPP 3D */
1087     "print-quality",
1088     "print-quality-default",
1089     "print-quality-supported",
1090     "print-rendering-intent",
1091     "print-rendering-intent-default",
1092     "print-rendering-intent-supported",
1093     "print-scaling",                    /* IPP Paid Printing */
1094     "print-scaling-default",            /* IPP Paid Printing */
1095     "print-scaling-supported",          /* IPP Paid Printing */
1096     "print-supports",                   /* IPP 3D */
1097     "print-supports-default",           /* IPP 3D */
1098     "print-supports-supported",         /* IPP 3D */
1099     "printer-resolution",
1100     "printer-resolution-default",
1101     "printer-resolution-supported",
1102     "separator-sheets",
1103     "separator-sheets-default",
1104     "separator-sheets-supported",
1105     "sheet-collate",
1106     "sheet-collate-default",
1107     "sheet-collate-supported",
1108     "sides",
1109     "sides-default",
1110     "sides-supported",
1111     "stitching-locations-supported",
1112     "stitching-offset-supported",
1113     "x-image-position",
1114     "x-image-position-default",
1115     "x-image-position-supported",
1116     "x-image-shift",
1117     "x-image-shift-default",
1118     "x-image-shift-supported",
1119     "x-side1-image-shift",
1120     "x-side1-image-shift-default",
1121     "x-side1-image-shift-supported",
1122     "x-side2-image-shift",
1123     "x-side2-image-shift-default",
1124     "x-side2-image-shift-supported",
1125     "y-image-position",
1126     "y-image-position-default",
1127     "y-image-position-supported",
1128     "y-image-shift",
1129     "y-image-shift-default",
1130     "y-image-shift-supported",
1131     "y-side1-image-shift",
1132     "y-side1-image-shift-default",
1133     "y-side1-image-shift-supported",
1134     "y-side2-image-shift",
1135     "y-side2-image-shift-default",
1136     "y-side2-image-shift-supported"
1137   };
1138   static const char * const job_description[] =
1139   {                                     /* job-description group */
1140     "compression-supplied",
1141     "copies-actual",
1142     "cover-back-actual",
1143     "cover-front-actual",
1144     "current-page-order",
1145     "date-time-at-completed",
1146     "date-time-at-creation",
1147     "date-time-at-processing",
1148     "destination-statuses",
1149     "document-charset-supplied",
1150     "document-digital-signature-supplied",
1151     "document-format-details-supplied",
1152     "document-format-supplied",
1153     "document-message-supplied",
1154     "document-metadata",
1155     "document-name-supplied",
1156     "document-natural-language-supplied",
1157     "document-overrides-actual",
1158     "errors-count",
1159     "finishings-actual",
1160     "finishings-col-actual",
1161     "force-front-side-actual",
1162     "imposition-template-actual",
1163     "impressions-completed-current-copy",
1164     "insert-sheet-actual",
1165     "job-account-id-actual",
1166     "job-accounting-sheets-actual",
1167     "job-accounting-user-id-actual",
1168     "job-attribute-fidelity",
1169     "job-charge-info",                  /* CUPS extension */
1170     "job-collation-type",
1171     "job-collation-type-actual",
1172     "job-copies-actual",
1173     "job-cover-back-actual",
1174     "job-cover-front-actual",
1175     "job-detailed-status-message",
1176     "job-document-access-errors",
1177     "job-error-sheet-actual",
1178     "job-finishings-actual",
1179     "job-finishings-col-actual",
1180     "job-hold-until-actual",
1181     "job-id",
1182     "job-impressions",
1183     "job-impressions-completed",
1184     "job-k-octets",
1185     "job-k-octets-processed",
1186     "job-mandatory-attributes",
1187     "job-media-progress",               /* CUPS extension */
1188     "job-media-sheets",
1189     "job-media-sheets-completed",
1190     "job-message-from-operator",
1191     "job-more-info",
1192     "job-name",
1193     "job-originating-host-name",        /* CUPS extension */
1194     "job-originating-user-name",
1195     "job-originating-user-uri",
1196     "job-pages",
1197     "job-pages-completed",
1198     "job-pages-completed-current-copy",
1199     "job-printer-state-message",        /* CUPS extension */
1200     "job-printer-state-reasons",        /* CUPS extension */
1201     "job-printer-up-time",
1202     "job-printer-uri",
1203     "job-priority-actual",
1204     "job-save-printer-make-and-model",
1205     "job-sheet-message-actual",
1206     "job-sheets-actual",
1207     "job-sheets-col-actual",
1208     "job-state",
1209     "job-state-message",
1210     "job-state-reasons",
1211     "job-uri",
1212     "job-uuid",
1213     "materials-col-actual",             /* IPP 3D */
1214     "media-actual",
1215     "media-col-actual",
1216     "media-check-input-tray-actual",
1217     "multiple-document-handling-actual",
1218     "multiple-object-handling-actual",  /* IPP 3D */
1219     "number-of-documents",
1220     "number-of-intervening-jobs",
1221     "number-up-actual",
1222     "orientation-requested-actual",
1223     "original-requesting-user-name",
1224     "output-bin-actual",
1225     "output-device-assigned",
1226     "overrides-actual",
1227     "page-delivery-actual",
1228     "page-order-received-actual",
1229     "page-ranges-actual",
1230     "platform-temperature-actual",      /* IPP 3D */
1231     "presentation-direction-number-up-actual",
1232     "print-accuracy-actual",            /* IPP 3D */
1233     "print-base-actual",                /* IPP 3D */
1234     "print-color-mode-actual",
1235     "print-content-optimize-actual",
1236     "print-objects-actual",             /* IPP 3D */
1237     "print-quality-actual",
1238     "print-rendering-intent-actual",
1239     "print-scaling-actual",             /* IPP Paid Printing */
1240     "print-supports-actual",            /* IPP 3D */
1241     "printer-resolution-actual",
1242     "separator-sheets-actual",
1243     "sheet-collate-actual",
1244     "sheet-completed-copy-number",
1245     "sheet-completed-document-number",
1246     "sides-actual",
1247     "time-at-completed",
1248     "time-at-creation",
1249     "time-at-processing",
1250     "warnings-count",
1251     "x-image-position-actual",
1252     "x-image-shift-actual",
1253     "x-side1-image-shift-actual",
1254     "x-side2-image-shift-actual",
1255     "y-image-position-actual",
1256     "y-image-shift-actual",
1257     "y-side1-image-shift-actual",
1258     "y-side2-image-shift-actual"
1259   };
1260   static const char * const job_template[] =
1261   {                                     /* job-template group */
1262     "accuracy-units-supported",         /* IPP 3D */
1263     "confirmation-sheet-print",         /* IPP FaxOut */
1264     "confirmation-sheet-print-default",
1265     "copies",
1266     "copies-default",
1267     "copies-supported",
1268     "cover-back",
1269     "cover-back-default",
1270     "cover-back-supported",
1271     "cover-front",
1272     "cover-front-default",
1273     "cover-front-supported",
1274     "cover-sheet-info",                 /* IPP FaxOut */
1275     "cover-sheet-info-default",
1276     "cover-sheet-info-supported",
1277     "destination-uri-schemes-supported",/* IPP FaxOut */
1278     "destination-uris",                 /* IPP FaxOut */
1279     "destination-uris-supported",
1280     "feed-orientation",
1281     "feed-orientation-default",
1282     "feed-orientation-supported",
1283     "finishings",
1284     "finishings-col",
1285     "finishings-col-database",
1286     "finishings-col-default",
1287     "finishings-col-ready",
1288     "finishings-col-supported",
1289     "finishings-default",
1290     "finishings-ready",
1291     "finishings-supported",
1292     "font-name-requested",
1293     "font-name-requested-default",
1294     "font-name-requested-supported",
1295     "font-size-requested",
1296     "font-size-requested-default",
1297     "font-size-requested-supported",
1298     "force-front-side",
1299     "force-front-side-default",
1300     "force-front-side-supported",
1301     "imposition-template",
1302     "imposition-template-default",
1303     "imposition-template-supported",
1304     "insert-after-page-number-supported",
1305     "insert-count-supported",
1306     "insert-sheet",
1307     "insert-sheet-default",
1308     "insert-sheet-supported",
1309     "job-account-id",
1310     "job-account-id-default",
1311     "job-account-id-supported",
1312     "job-accounting-sheets"
1313     "job-accounting-sheets-default"
1314     "job-accounting-sheets-supported"
1315     "job-accounting-user-id",
1316     "job-accounting-user-id-default",
1317     "job-accounting-user-id-supported",
1318     "job-copies",
1319     "job-copies-default",
1320     "job-copies-supported",
1321     "job-cover-back",
1322     "job-cover-back-default",
1323     "job-cover-back-supported",
1324     "job-cover-front",
1325     "job-cover-front-default",
1326     "job-cover-front-supported",
1327     "job-delay-output-until",
1328     "job-delay-output-until-default",
1329     "job-delay-output-until-supported",
1330     "job-delay-output-until-time",
1331     "job-delay-output-until-time-default",
1332     "job-delay-output-until-time-supported",
1333     "job-error-action",
1334     "job-error-action-default",
1335     "job-error-action-supported",
1336     "job-error-sheet",
1337     "job-error-sheet-default",
1338     "job-error-sheet-supported",
1339     "job-finishings",
1340     "job-finishings-col",
1341     "job-finishings-col-default",
1342     "job-finishings-col-supported",
1343     "job-finishings-default",
1344     "job-finishings-supported",
1345     "job-hold-until",
1346     "job-hold-until-default",
1347     "job-hold-until-supported",
1348     "job-hold-until-time",
1349     "job-hold-until-time-default",
1350     "job-hold-until-time-supported",
1351     "job-message-to-operator",
1352     "job-message-to-operator-default",
1353     "job-message-to-operator-supported",
1354     "job-phone-number",
1355     "job-phone-number-default",
1356     "job-phone-number-supported",
1357     "job-priority",
1358     "job-priority-default",
1359     "job-priority-supported",
1360     "job-recipient-name",
1361     "job-recipient-name-default",
1362     "job-recipient-name-supported",
1363     "job-save-disposition",
1364     "job-save-disposition-default",
1365     "job-save-disposition-supported",
1366     "job-sheets",
1367     "job-sheets-col",
1368     "job-sheets-col-default",
1369     "job-sheets-col-supported",
1370     "job-sheets-default",
1371     "job-sheets-supported",
1372     "logo-uri-schemes-supported",
1373     "material-amount-units-supported",  /* IPP 3D */
1374     "material-diameter-supported",      /* IPP 3D */
1375     "material-purpose-supported",       /* IPP 3D */
1376     "material-rate-supported",          /* IPP 3D */
1377     "material-rate-units-supported",    /* IPP 3D */
1378     "material-shell-thickness-supported",/* IPP 3D */
1379     "material-temperature-supported",   /* IPP 3D */
1380     "material-type-supported",          /* IPP 3D */
1381     "materials-col",                    /* IPP 3D */
1382     "materials-col-database",           /* IPP 3D */
1383     "materials-col-default",            /* IPP 3D */
1384     "materials-col-ready",              /* IPP 3D */
1385     "materials-col-supported",          /* IPP 3D */
1386     "max-materials-col-supported",      /* IPP 3D */
1387     "max-save-info-supported",
1388     "max-stitching-locations-supported",
1389     "media",
1390     "media-back-coating-supported",
1391     "media-bottom-margin-supported",
1392     "media-col",
1393     "media-col-default",
1394     "media-col-ready",
1395     "media-col-supported",
1396     "media-color-supported",
1397     "media-default",
1398     "media-front-coating-supported",
1399     "media-grain-supported",
1400     "media-hole-count-supported",
1401     "media-info-supported",
1402     "media-input-tray-check",
1403     "media-input-tray-check-default",
1404     "media-input-tray-check-supported",
1405     "media-key-supported",
1406     "media-left-margin-supported",
1407     "media-order-count-supported",
1408     "media-pre-printed-supported",
1409     "media-ready",
1410     "media-recycled-supported",
1411     "media-right-margin-supported",
1412     "media-size-supported",
1413     "media-source-supported",
1414     "media-supported",
1415     "media-thickness-supported",
1416     "media-top-margin-supported",
1417     "media-type-supported",
1418     "media-weight-metric-supported",
1419     "multiple-document-handling",
1420     "multiple-document-handling-default",
1421     "multiple-document-handling-supported",
1422     "multiple-object-handling",         /* IPP 3D */
1423     "multiple-object-handling-default", /* IPP 3D */
1424     "multiple-object-handling-supported",/* IPP 3D */
1425     "number-of-retries",                /* IPP FaxOut */
1426     "number-of-retries-default",
1427     "number-of-retries-supported",
1428     "number-up",
1429     "number-up-default",
1430     "number-up-supported",
1431     "orientation-requested",
1432     "orientation-requested-default",
1433     "orientation-requested-supported",
1434     "output-bin",
1435     "output-bin-default",
1436     "output-bin-supported",
1437     "output-device",
1438     "output-device-default",
1439     "output-device-supported",
1440     "output-mode",                      /* CUPS extension */
1441     "output-mode-default",              /* CUPS extension */
1442     "output-mode-supported",            /* CUPS extension */
1443     "overrides",
1444     "overrides-supported",
1445     "page-delivery",
1446     "page-delivery-default",
1447     "page-delivery-supported",
1448     "page-order-received",
1449     "page-order-received-default",
1450     "page-order-received-supported",
1451     "page-ranges",
1452     "page-ranges-supported",
1453     "pages-per-subset",
1454     "pages-per-subset-supported",
1455     "pdl-init-file",
1456     "pdl-init-file-default",
1457     "pdl-init-file-entry-supported",
1458     "pdl-init-file-location-supported",
1459     "pdl-init-file-name-subdirectory-supported",
1460     "pdl-init-file-name-supported",
1461     "pdl-init-file-supported",
1462     "platform-temperature",             /* IPP 3D */
1463     "platform-temperature-default",     /* IPP 3D */
1464     "platform-temperature-supported",   /* IPP 3D */
1465     "presentation-direction-number-up",
1466     "presentation-direction-number-up-default",
1467     "presentation-direction-number-up-supported",
1468     "print-accuracy",                   /* IPP 3D */
1469     "print-accuracy-default",           /* IPP 3D */
1470     "print-accuracy-supported",         /* IPP 3D */
1471     "print-base",                       /* IPP 3D */
1472     "print-base-default",               /* IPP 3D */
1473     "print-base-supported",             /* IPP 3D */
1474     "print-color-mode",
1475     "print-color-mode-default",
1476     "print-color-mode-supported",
1477     "print-content-optimize",
1478     "print-content-optimize-default",
1479     "print-content-optimize-supported",
1480     "print-objects",                    /* IPP 3D */
1481     "print-objects-default",            /* IPP 3D */
1482     "print-objects-supported",          /* IPP 3D */
1483     "print-quality",
1484     "print-quality-default",
1485     "print-quality-supported",
1486     "print-rendering-intent",
1487     "print-rendering-intent-default",
1488     "print-rendering-intent-supported",
1489     "print-scaling",                    /* IPP Paid Printing */
1490     "print-scaling-default",            /* IPP Paid Printing */
1491     "print-scaling-supported",          /* IPP Paid Printing */
1492     "print-supports",                   /* IPP 3D */
1493     "print-supports-default",           /* IPP 3D */
1494     "print-supports-supported",         /* IPP 3D */
1495     "printer-resolution",
1496     "printer-resolution-default",
1497     "printer-resolution-supported",
1498     "proof-print",
1499     "proof-print-default",
1500     "proof-print-supported",
1501     "retry-interval",                   /* IPP FaxOut */
1502     "retry-interval-default",
1503     "retry-interval-supported",
1504     "retry-timeout",                    /* IPP FaxOut */
1505     "retry-timeout-default",
1506     "retry-timeout-supported",
1507     "save-disposition-supported",
1508     "save-document-format-default",
1509     "save-document-format-supported",
1510     "save-location-default",
1511     "save-location-supported",
1512     "save-name-subdirectory-supported",
1513     "save-name-supported",
1514     "separator-sheets",
1515     "separator-sheets-default",
1516     "separator-sheets-supported",
1517     "sheet-collate",
1518     "sheet-collate-default",
1519     "sheet-collate-supported",
1520     "sides",
1521     "sides-default",
1522     "sides-supported",
1523     "stitching-locations-supported",
1524     "stitching-offset-supported",
1525     "x-image-position",
1526     "x-image-position-default",
1527     "x-image-position-supported",
1528     "x-image-shift",
1529     "x-image-shift-default",
1530     "x-image-shift-supported",
1531     "x-side1-image-shift",
1532     "x-side1-image-shift-default",
1533     "x-side1-image-shift-supported",
1534     "x-side2-image-shift",
1535     "x-side2-image-shift-default",
1536     "x-side2-image-shift-supported",
1537     "y-image-position",
1538     "y-image-position-default",
1539     "y-image-position-supported",
1540     "y-image-shift",
1541     "y-image-shift-default",
1542     "y-image-shift-supported",
1543     "y-side1-image-shift",
1544     "y-side1-image-shift-default",
1545     "y-side1-image-shift-supported",
1546     "y-side2-image-shift",
1547     "y-side2-image-shift-default",
1548     "y-side2-image-shift-supported"
1549   };
1550   static const char * const printer_description[] =
1551   {                                     /* printer-description group */
1552     "auth-info-required",               /* CUPS extension */
1553     "charset-configured",
1554     "charset-supported",
1555     "color-supported",
1556     "compression-supported",
1557     "device-service-count",
1558     "device-uri",                       /* CUPS extension */
1559     "device-uuid",
1560     "document-charset-default",
1561     "document-charset-supported",
1562     "document-creation-attributes-supported",
1563     "document-digital-signature-default",
1564     "document-digital-signature-supported",
1565     "document-format-default",
1566     "document-format-details-default",
1567     "document-format-details-supported",
1568     "document-format-supported",
1569     "document-format-varying-attributes",
1570     "document-format-version-default",
1571     "document-format-version-supported",
1572     "document-natural-language-default",
1573     "document-natural-language-supported",
1574     "document-password-supported",
1575     "generated-natural-language-supported",
1576     "identify-actions-default",
1577     "identify-actions-supported",
1578     "input-source-supported",
1579     "ipp-features-supported",
1580     "ipp-versions-supported",
1581     "ippget-event-life",
1582     "job-authorization-uri-supported",  /* CUPS extension */
1583     "job-constraints-supported",
1584     "job-creation-attributes-supported",
1585     "job-finishings-col-ready",
1586     "job-finishings-ready",
1587     "job-ids-supported",
1588     "job-impressions-supported",
1589     "job-k-limit",                      /* CUPS extension */
1590     "job-k-octets-supported",
1591     "job-media-sheets-supported",
1592     "job-page-limit",                   /* CUPS extension */
1593     "job-password-encryption-supported",
1594     "job-password-supported",
1595     "job-presets-supported",            /* IPP Presets */
1596     "job-quota-period",                 /* CUPS extension */
1597     "job-resolvers-supported",
1598     "job-settable-attributes-supported",
1599     "job-spooling-supported",
1600     "job-triggers-supported",           /* IPP Presets */
1601     "jpeg-k-octets-supported",          /* CUPS extension */
1602     "jpeg-x-dimension-supported",       /* CUPS extension */
1603     "jpeg-y-dimension-supported",       /* CUPS extension */
1604     "landscape-orientation-requested-preferred",
1605                                         /* CUPS extension */
1606     "marker-change-time",               /* CUPS extension */
1607     "marker-colors",                    /* CUPS extension */
1608     "marker-high-levels",               /* CUPS extension */
1609     "marker-levels",                    /* CUPS extension */
1610     "marker-low-levels",                /* CUPS extension */
1611     "marker-message",                   /* CUPS extension */
1612     "marker-names",                     /* CUPS extension */
1613     "marker-types",                     /* CUPS extension */
1614     "member-names",                     /* CUPS extension */
1615     "member-uris",                      /* CUPS extension */
1616     "multiple-destination-uris-supported",/* IPP FaxOut */
1617     "multiple-document-jobs-supported",
1618     "multiple-operation-time-out",
1619     "multiple-operation-time-out-action",
1620     "natural-language-configured",
1621     "operations-supported",
1622     "pages-per-minute",
1623     "pages-per-minute-color",
1624     "pdf-k-octets-supported",           /* CUPS extension */
1625     "pdf-features-supported",           /* IPP 3D */
1626     "pdf-versions-supported",           /* CUPS extension */
1627     "pdl-override-supported",
1628     "port-monitor",                     /* CUPS extension */
1629     "port-monitor-supported",           /* CUPS extension */
1630     "preferred-attributes-supported",
1631     "printer-alert",
1632     "printer-alert-description",
1633     "printer-charge-info",
1634     "printer-charge-info-uri",
1635     "printer-commands",                 /* CUPS extension */
1636     "printer-config-change-date-time",
1637     "printer-config-change-time",
1638     "printer-current-time",
1639     "printer-detailed-status-messages",
1640     "printer-device-id",
1641     "printer-dns-sd-name",              /* CUPS extension */
1642     "printer-driver-installer",
1643     "printer-fax-log-uri",              /* IPP FaxOut */
1644     "printer-fax-modem-info",           /* IPP FaxOut */
1645     "printer-fax-modem-name",           /* IPP FaxOut */
1646     "printer-fax-modem-number",         /* IPP FaxOut */
1647     "printer-firmware-name",            /* PWG 5110.1 */
1648     "printer-firmware-patches",         /* PWG 5110.1 */
1649     "printer-firmware-string-version",  /* PWG 5110.1 */
1650     "printer-firmware-version",         /* PWG 5110.1 */
1651     "printer-geo-location",
1652     "printer-get-attributes-supported",
1653     "printer-icc-profiles",
1654     "printer-icons",
1655     "printer-id",                       /* CUPS extension */
1656     "printer-info",
1657     "printer-input-tray",               /* IPP JPS3 */
1658     "printer-is-accepting-jobs",
1659     "printer-is-shared",                /* CUPS extension */
1660     "printer-is-temporary",             /* CUPS extension */
1661     "printer-kind",                     /* IPP Paid Printing */
1662     "printer-location",
1663     "printer-make-and-model",
1664     "printer-mandatory-job-attributes",
1665     "printer-message-date-time",
1666     "printer-message-from-operator",
1667     "printer-message-time",
1668     "printer-more-info",
1669     "printer-more-info-manufacturer",
1670     "printer-name",
1671     "printer-native-formats",
1672     "printer-organization",
1673     "printer-organizational-unit",
1674     "printer-output-tray",              /* IPP JPS3 */
1675     "printer-queue-id",                 /* CUPS extension */
1676     "printer-settable-attributes-supported",
1677     "printer-state",
1678     "printer-state-change-date-time",
1679     "printer-state-change-time",
1680     "printer-state-message",
1681     "printer-state-reasons",
1682     "printer-supply",
1683     "printer-supply-description",
1684     "printer-supply-info-uri",
1685     "printer-type",                     /* CUPS extension */
1686     "printer-up-time",
1687     "printer-uri-supported",
1688     "printer-uuid",
1689     "printer-xri-supported",
1690     "pwg-raster-document-resolution-supported",
1691     "pwg-raster-document-sheet-back",
1692     "pwg-raster-document-type-supported",
1693     "queued-job-count",
1694     "reference-uri-schemes-supported",
1695     "repertoire-supported",
1696     "requesting-user-name-allowed",     /* CUPS extension */
1697     "requesting-user-name-denied",      /* CUPS extension */
1698     "requesting-user-uri-supported",
1699     "subordinate-printers-supported",
1700     "urf-supported",                    /* CUPS extension */
1701     "uri-authentication-supported",
1702     "uri-security-supported",
1703     "user-defined-value-supported",
1704     "which-jobs-supported",
1705     "xri-authentication-supported",
1706     "xri-security-supported",
1707     "xri-uri-scheme-supported"
1708   };
1709   static const char * const subscription_description[] =
1710   {                                     /* subscription-description group */
1711     "notify-job-id",
1712     "notify-lease-expiration-time",
1713     "notify-printer-up-time",
1714     "notify-printer-uri",
1715     "notify-sequence-number",
1716     "notify-subscriber-user-name",
1717     "notify-subscriber-user-uri",
1718     "notify-subscription-id",
1719     "subscriptions-uuid"
1720   };
1721   static const char * const subscription_template[] =
1722   {                                     /* subscription-template group */
1723     "notify-attributes",
1724     "notify-attributes-supported",
1725     "notify-charset",
1726     "notify-events",
1727     "notify-events-default",
1728     "notify-events-supported",
1729     "notify-lease-duration",
1730     "notify-lease-duration-default",
1731     "notify-lease-duration-supported",
1732     "notify-max-events-supported",
1733     "notify-natural-language",
1734     "notify-pull-method",
1735     "notify-pull-method-supported",
1736     "notify-recipient-uri",
1737     "notify-schemes-supported",
1738     "notify-time-interval",
1739     "notify-user-data"
1740   };
1741
1742
1743  /*
1744   * Get the requested-attributes attribute...
1745   */
1746
1747   if ((requested = ippFindAttribute(request, "requested-attributes",
1748                                     IPP_TAG_KEYWORD)) == NULL)
1749   {
1750    /*
1751     * The Get-Jobs operation defaults to "job-id" and "job-uri", all others
1752     * default to "all"...
1753     */
1754
1755     if (ippGetOperation(request) == IPP_OP_GET_JOBS)
1756     {
1757       ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
1758       cupsArrayAdd(ra, "job-id");
1759       cupsArrayAdd(ra, "job-uri");
1760
1761       return (ra);
1762     }
1763     else
1764       return (NULL);
1765   }
1766
1767  /*
1768   * If the attribute contains a single "all" keyword, return NULL...
1769   */
1770
1771   count = ippGetCount(requested);
1772   if (count == 1 && !strcmp(ippGetString(requested, 0, NULL), "all"))
1773     return (NULL);
1774
1775  /*
1776   * Create an array using "strcmp" as the comparison function...
1777   */
1778
1779   ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
1780
1781   for (i = 0; i < count; i ++)
1782   {
1783     added = 0;
1784     value = ippGetString(requested, i, NULL);
1785
1786     if (!strcmp(value, "document-description") || !strcmp(value, "all"))
1787     {
1788       for (j = 0;
1789            j < (int)(sizeof(document_description) /
1790                      sizeof(document_description[0]));
1791            j ++)
1792         cupsArrayAdd(ra, (void *)document_description[j]);
1793
1794       added = 1;
1795     }
1796
1797     if (!strcmp(value, "document-template") || !strcmp(value, "all"))
1798     {
1799       for (j = 0;
1800            j < (int)(sizeof(document_template) / sizeof(document_template[0]));
1801            j ++)
1802         cupsArrayAdd(ra, (void *)document_template[j]);
1803
1804       added = 1;
1805     }
1806
1807     if (!strcmp(value, "job-description") || !strcmp(value, "all"))
1808     {
1809       for (j = 0;
1810            j < (int)(sizeof(job_description) / sizeof(job_description[0]));
1811            j ++)
1812         cupsArrayAdd(ra, (void *)job_description[j]);
1813
1814       added = 1;
1815     }
1816
1817     if (!strcmp(value, "job-template") || !strcmp(value, "all"))
1818     {
1819       for (j = 0;
1820            j < (int)(sizeof(job_template) / sizeof(job_template[0]));
1821            j ++)
1822         cupsArrayAdd(ra, (void *)job_template[j]);
1823
1824       added = 1;
1825     }
1826
1827     if (!strcmp(value, "printer-description") || !strcmp(value, "all"))
1828     {
1829       for (j = 0;
1830            j < (int)(sizeof(printer_description) /
1831                      sizeof(printer_description[0]));
1832            j ++)
1833         cupsArrayAdd(ra, (void *)printer_description[j]);
1834
1835       added = 1;
1836     }
1837
1838     if (!strcmp(value, "subscription-description") || !strcmp(value, "all"))
1839     {
1840       for (j = 0;
1841            j < (int)(sizeof(subscription_description) /
1842                      sizeof(subscription_description[0]));
1843            j ++)
1844         cupsArrayAdd(ra, (void *)subscription_description[j]);
1845
1846       added = 1;
1847     }
1848
1849     if (!strcmp(value, "subscription-template") || !strcmp(value, "all"))
1850     {
1851       for (j = 0;
1852            j < (int)(sizeof(subscription_template) /
1853                      sizeof(subscription_template[0]));
1854            j ++)
1855         cupsArrayAdd(ra, (void *)subscription_template[j]);
1856
1857       added = 1;
1858     }
1859
1860     if (!added)
1861       cupsArrayAdd(ra, (void *)value);
1862   }
1863
1864   return (ra);
1865 }
1866
1867
1868 /*
1869  * 'ippEnumString()' - Return a string corresponding to the enum value.
1870  */
1871
1872 const char *                            /* O - Enum string */
1873 ippEnumString(const char *attrname,     /* I - Attribute name */
1874               int        enumvalue)     /* I - Enum value */
1875 {
1876   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
1877
1878
1879  /*
1880   * Check for standard enum values...
1881   */
1882
1883   if (!strcmp(attrname, "document-state") &&
1884       enumvalue >= 3 &&
1885       enumvalue < (3 + (int)(sizeof(ipp_document_states) /
1886                              sizeof(ipp_document_states[0]))))
1887     return (ipp_document_states[enumvalue - 3]);
1888   else if (!strcmp(attrname, "finishings") ||
1889            !strcmp(attrname, "finishings-actual") ||
1890            !strcmp(attrname, "finishings-default") ||
1891            !strcmp(attrname, "finishings-ready") ||
1892            !strcmp(attrname, "finishings-supported") ||
1893            !strcmp(attrname, "job-finishings") ||
1894            !strcmp(attrname, "job-finishings-default") ||
1895            !strcmp(attrname, "job-finishings-supported"))
1896   {
1897     if (enumvalue >= 3 &&
1898         enumvalue < (3 + (int)(sizeof(ipp_finishings) /
1899                                sizeof(ipp_finishings[0]))))
1900       return (ipp_finishings[enumvalue - 3]);
1901     else if (enumvalue >= 0x40000000 &&
1902              enumvalue <= (0x40000000 + (int)(sizeof(ipp_finishings_vendor) /
1903                                               sizeof(ipp_finishings_vendor[0]))))
1904       return (ipp_finishings_vendor[enumvalue - 0x40000000]);
1905   }
1906   else if ((!strcmp(attrname, "job-collation-type") ||
1907             !strcmp(attrname, "job-collation-type-actual")) &&
1908            enumvalue >= 3 &&
1909            enumvalue < (3 + (int)(sizeof(ipp_job_collation_types) /
1910                                   sizeof(ipp_job_collation_types[0]))))
1911     return (ipp_job_collation_types[enumvalue - 3]);
1912   else if (!strcmp(attrname, "job-state") &&
1913            enumvalue >= IPP_JSTATE_PENDING && enumvalue <= IPP_JSTATE_COMPLETED)
1914     return (ipp_job_states[enumvalue - IPP_JSTATE_PENDING]);
1915   else if (!strcmp(attrname, "operations-supported"))
1916     return (ippOpString((ipp_op_t)enumvalue));
1917   else if ((!strcmp(attrname, "orientation-requested") ||
1918             !strcmp(attrname, "orientation-requested-actual") ||
1919             !strcmp(attrname, "orientation-requested-default") ||
1920             !strcmp(attrname, "orientation-requested-supported")) &&
1921            enumvalue >= 3 &&
1922            enumvalue < (3 + (int)(sizeof(ipp_orientation_requesteds) /
1923                                   sizeof(ipp_orientation_requesteds[0]))))
1924     return (ipp_orientation_requesteds[enumvalue - 3]);
1925   else if ((!strcmp(attrname, "print-quality") ||
1926             !strcmp(attrname, "print-quality-actual") ||
1927             !strcmp(attrname, "print-quality-default") ||
1928             !strcmp(attrname, "print-quality-supported")) &&
1929            enumvalue >= 3 &&
1930            enumvalue < (3 + (int)(sizeof(ipp_print_qualities) /
1931                                   sizeof(ipp_print_qualities[0]))))
1932     return (ipp_print_qualities[enumvalue - 3]);
1933   else if (!strcmp(attrname, "printer-state") &&
1934            enumvalue >= IPP_PSTATE_IDLE && enumvalue <= IPP_PSTATE_STOPPED)
1935     return (ipp_printer_states[enumvalue - IPP_PSTATE_IDLE]);
1936
1937  /*
1938   * Not a standard enum value, just return the decimal equivalent...
1939   */
1940
1941   snprintf(cg->ipp_unknown, sizeof(cg->ipp_unknown), "%d", enumvalue);
1942   return (cg->ipp_unknown);
1943 }
1944
1945
1946 /*
1947  * 'ippEnumValue()' - Return the value associated with a given enum string.
1948  */
1949
1950 int                                     /* O - Enum value or -1 if unknown */
1951 ippEnumValue(const char *attrname,      /* I - Attribute name */
1952              const char *enumstring)    /* I - Enum string */
1953 {
1954   int           i,                      /* Looping var */
1955                 num_strings;            /* Number of strings to compare */
1956   const char * const *strings;          /* Strings to compare */
1957
1958
1959  /*
1960   * If the string is just a number, return it...
1961   */
1962
1963   if (isdigit(*enumstring & 255))
1964     return ((int)strtol(enumstring, NULL, 0));
1965
1966  /*
1967   * Otherwise look up the string...
1968   */
1969
1970   if (!strcmp(attrname, "document-state"))
1971   {
1972     num_strings = (int)(sizeof(ipp_document_states) / sizeof(ipp_document_states[0]));
1973     strings     = ipp_document_states;
1974   }
1975   else if (!strcmp(attrname, "finishings") ||
1976            !strcmp(attrname, "finishings-actual") ||
1977            !strcmp(attrname, "finishings-default") ||
1978            !strcmp(attrname, "finishings-ready") ||
1979            !strcmp(attrname, "finishings-supported"))
1980   {
1981     for (i = 0;
1982          i < (int)(sizeof(ipp_finishings_vendor) /
1983                    sizeof(ipp_finishings_vendor[0]));
1984          i ++)
1985       if (!strcmp(enumstring, ipp_finishings_vendor[i]))
1986         return (i + 0x40000000);
1987
1988     num_strings = (int)(sizeof(ipp_finishings) / sizeof(ipp_finishings[0]));
1989     strings     = ipp_finishings;
1990   }
1991   else if (!strcmp(attrname, "job-collation-type") ||
1992            !strcmp(attrname, "job-collation-type-actual"))
1993   {
1994     num_strings = (int)(sizeof(ipp_job_collation_types) /
1995                         sizeof(ipp_job_collation_types[0]));
1996     strings     = ipp_job_collation_types;
1997   }
1998   else if (!strcmp(attrname, "job-state"))
1999   {
2000     num_strings = (int)(sizeof(ipp_job_states) / sizeof(ipp_job_states[0]));
2001     strings     = ipp_job_states;
2002   }
2003   else if (!strcmp(attrname, "operations-supported"))
2004     return (ippOpValue(enumstring));
2005   else if (!strcmp(attrname, "orientation-requested") ||
2006            !strcmp(attrname, "orientation-requested-actual") ||
2007            !strcmp(attrname, "orientation-requested-default") ||
2008            !strcmp(attrname, "orientation-requested-supported"))
2009   {
2010     num_strings = (int)(sizeof(ipp_orientation_requesteds) /
2011                         sizeof(ipp_orientation_requesteds[0]));
2012     strings     = ipp_orientation_requesteds;
2013   }
2014   else if (!strcmp(attrname, "print-quality") ||
2015            !strcmp(attrname, "print-quality-actual") ||
2016            !strcmp(attrname, "print-quality-default") ||
2017            !strcmp(attrname, "print-quality-supported"))
2018   {
2019     num_strings = (int)(sizeof(ipp_print_qualities) / sizeof(ipp_print_qualities[0]));
2020     strings     = ipp_print_qualities;
2021   }
2022   else if (!strcmp(attrname, "printer-state"))
2023   {
2024     num_strings = (int)(sizeof(ipp_printer_states) / sizeof(ipp_printer_states[0]));
2025     strings     = ipp_printer_states;
2026   }
2027   else
2028     return (-1);
2029
2030   for (i = 0; i < num_strings; i ++)
2031     if (!strcmp(enumstring, strings[i]))
2032       return (i + 3);
2033
2034   return (-1);
2035 }
2036
2037
2038 /*
2039  * 'ippErrorString()' - Return a name for the given status code.
2040  */
2041
2042 const char *                            /* O - Text string */
2043 ippErrorString(ipp_status_t error)      /* I - Error status */
2044 {
2045   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
2046
2047
2048  /*
2049   * See if the error code is a known value...
2050   */
2051
2052   if (error >= IPP_STATUS_OK && error <= IPP_STATUS_OK_EVENTS_COMPLETE)
2053     return (ipp_status_oks[error]);
2054   else if (error == IPP_STATUS_REDIRECTION_OTHER_SITE)
2055     return ("redirection-other-site");
2056   else if (error == IPP_STATUS_CUPS_SEE_OTHER)
2057     return ("cups-see-other");
2058   else if (error >= IPP_STATUS_ERROR_BAD_REQUEST &&
2059            error <= IPP_STATUS_ERROR_ACCOUNT_AUTHORIZATION_FAILED)
2060     return (ipp_status_400s[error - IPP_STATUS_ERROR_BAD_REQUEST]);
2061   else if (error >= 0x480 &&
2062            error <= IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED)
2063     return (ipp_status_480s[error - 0x0480]);
2064   else if (error >= IPP_STATUS_ERROR_INTERNAL &&
2065            error <= IPP_STATUS_ERROR_TOO_MANY_DOCUMENTS)
2066     return (ipp_status_500s[error - IPP_STATUS_ERROR_INTERNAL]);
2067   else if (error >= IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED &&
2068            error <= IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED)
2069     return (ipp_status_1000s[error -
2070                              IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED]);
2071
2072  /*
2073   * No, build an "0xxxxx" error string...
2074   */
2075
2076   sprintf(cg->ipp_unknown, "0x%04x", error);
2077
2078   return (cg->ipp_unknown);
2079 }
2080
2081
2082 /*
2083  * 'ippErrorValue()' - Return a status code for the given name.
2084  *
2085  * @since CUPS 1.2/macOS 10.5@
2086  */
2087
2088 ipp_status_t                            /* O - IPP status code */
2089 ippErrorValue(const char *name)         /* I - Name */
2090 {
2091   size_t        i;                      /* Looping var */
2092
2093
2094   for (i = 0; i < (sizeof(ipp_status_oks) / sizeof(ipp_status_oks[0])); i ++)
2095     if (!_cups_strcasecmp(name, ipp_status_oks[i]))
2096       return ((ipp_status_t)i);
2097
2098   if (!_cups_strcasecmp(name, "redirection-other-site"))
2099     return (IPP_STATUS_REDIRECTION_OTHER_SITE);
2100
2101   if (!_cups_strcasecmp(name, "cups-see-other"))
2102     return (IPP_STATUS_CUPS_SEE_OTHER);
2103
2104   for (i = 0; i < (sizeof(ipp_status_400s) / sizeof(ipp_status_400s[0])); i ++)
2105     if (!_cups_strcasecmp(name, ipp_status_400s[i]))
2106       return ((ipp_status_t)(i + 0x400));
2107
2108   for (i = 0; i < (sizeof(ipp_status_480s) / sizeof(ipp_status_480s[0])); i ++)
2109     if (!_cups_strcasecmp(name, ipp_status_480s[i]))
2110       return ((ipp_status_t)(i + 0x480));
2111
2112   for (i = 0; i < (sizeof(ipp_status_500s) / sizeof(ipp_status_500s[0])); i ++)
2113     if (!_cups_strcasecmp(name, ipp_status_500s[i]))
2114       return ((ipp_status_t)(i + 0x500));
2115
2116   for (i = 0; i < (sizeof(ipp_status_1000s) / sizeof(ipp_status_1000s[0])); i ++)
2117     if (!_cups_strcasecmp(name, ipp_status_1000s[i]))
2118       return ((ipp_status_t)(i + 0x1000));
2119
2120   return ((ipp_status_t)-1);
2121 }
2122
2123
2124 /*
2125  * 'ippOpString()' - Return a name for the given operation id.
2126  *
2127  * @since CUPS 1.2/macOS 10.5@
2128  */
2129
2130 const char *                            /* O - Name */
2131 ippOpString(ipp_op_t op)                /* I - Operation ID */
2132 {
2133   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
2134
2135
2136  /*
2137   * See if the operation ID is a known value...
2138   */
2139
2140   if (op >= IPP_OP_PRINT_JOB && op < (ipp_op_t)(sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])))
2141     return (ipp_std_ops[op]);
2142   else if (op == IPP_OP_PRIVATE)
2143     return ("windows-ext");
2144   else if (op >= IPP_OP_CUPS_GET_DEFAULT && op <= IPP_OP_CUPS_GET_PPD)
2145     return (ipp_cups_ops[op - IPP_OP_CUPS_GET_DEFAULT]);
2146   else if (op >= IPP_OP_CUPS_GET_DOCUMENT && op <= IPP_OP_CUPS_CREATE_LOCAL_PRINTER)
2147     return (ipp_cups_ops2[op - IPP_OP_CUPS_GET_DOCUMENT]);
2148
2149  /*
2150   * No, build an "0xxxxx" operation string...
2151   */
2152
2153   sprintf(cg->ipp_unknown, "0x%04x", op);
2154
2155   return (cg->ipp_unknown);
2156 }
2157
2158
2159 /*
2160  * 'ippOpValue()' - Return an operation id for the given name.
2161  *
2162  * @since CUPS 1.2/macOS 10.5@
2163  */
2164
2165 ipp_op_t                                /* O - Operation ID */
2166 ippOpValue(const char *name)            /* I - Textual name */
2167 {
2168   size_t        i;                      /* Looping var */
2169
2170
2171   if (!strncmp(name, "0x", 2))
2172     return ((ipp_op_t)strtol(name + 2, NULL, 16));
2173
2174   for (i = 0; i < (sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])); i ++)
2175     if (!_cups_strcasecmp(name, ipp_std_ops[i]))
2176       return ((ipp_op_t)i);
2177
2178   if (!_cups_strcasecmp(name, "windows-ext"))
2179     return (IPP_OP_PRIVATE);
2180
2181   for (i = 0; i < (sizeof(ipp_cups_ops) / sizeof(ipp_cups_ops[0])); i ++)
2182     if (!_cups_strcasecmp(name, ipp_cups_ops[i]))
2183       return ((ipp_op_t)(i + 0x4001));
2184
2185   for (i = 0; i < (sizeof(ipp_cups_ops2) / sizeof(ipp_cups_ops2[0])); i ++)
2186     if (!_cups_strcasecmp(name, ipp_cups_ops2[i]))
2187       return ((ipp_op_t)(i + 0x4027));
2188
2189   if (!_cups_strcasecmp(name, "Create-Job-Subscription"))
2190     return (IPP_OP_CREATE_JOB_SUBSCRIPTIONS);
2191
2192   if (!_cups_strcasecmp(name, "Create-Printer-Subscription"))
2193     return (IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS);
2194
2195   if (!_cups_strcasecmp(name, "CUPS-Add-Class"))
2196     return (IPP_OP_CUPS_ADD_MODIFY_CLASS);
2197
2198   if (!_cups_strcasecmp(name, "CUPS-Add-Printer"))
2199     return (IPP_OP_CUPS_ADD_MODIFY_PRINTER);
2200
2201   return (IPP_OP_CUPS_INVALID);
2202 }
2203
2204
2205 /*
2206  * 'ippPort()' - Return the default IPP port number.
2207  */
2208
2209 int                                     /* O - Port number */
2210 ippPort(void)
2211 {
2212   _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
2213
2214
2215   DEBUG_puts("ippPort()");
2216
2217   if (!cg->ipp_port)
2218     _cupsSetDefaults();
2219
2220   DEBUG_printf(("1ippPort: Returning %d...", cg->ipp_port));
2221
2222   return (cg->ipp_port);
2223 }
2224
2225
2226 /*
2227  * 'ippSetPort()' - Set the default port number.
2228  */
2229
2230 void
2231 ippSetPort(int p)                       /* I - Port number to use */
2232 {
2233   DEBUG_printf(("ippSetPort(p=%d)", p));
2234
2235   _cupsGlobals()->ipp_port = p;
2236 }
2237
2238
2239 /*
2240  * 'ippStateString()' - Return the name corresponding to a state value.
2241  *
2242  * @since CUPS 2.0/OS 10.10@
2243  */
2244
2245 const char *                            /* O - State name */
2246 ippStateString(ipp_state_t state)       /* I - State value */
2247 {
2248   if (state >= IPP_STATE_ERROR && state <= IPP_STATE_DATA)
2249     return (ipp_states[state - IPP_STATE_ERROR]);
2250   else
2251     return ("UNKNOWN");
2252 }
2253
2254
2255 /*
2256  * 'ippTagString()' - Return the tag name corresponding to a tag value.
2257  *
2258  * The returned names are defined in RFC 8011 and the IANA IPP Registry.
2259  *
2260  * @since CUPS 1.4/macOS 10.6@
2261  */
2262
2263 const char *                            /* O - Tag name */
2264 ippTagString(ipp_tag_t tag)             /* I - Tag value */
2265 {
2266   tag &= IPP_TAG_CUPS_MASK;
2267
2268   if (tag < (ipp_tag_t)(sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])))
2269     return (ipp_tag_names[tag]);
2270   else
2271     return ("UNKNOWN");
2272 }
2273
2274
2275 /*
2276  * 'ippTagValue()' - Return the tag value corresponding to a tag name.
2277  *
2278  * The tag names are defined in RFC 8011 and the IANA IPP Registry.
2279  *
2280  * @since CUPS 1.4/macOS 10.6@
2281  */
2282
2283 ipp_tag_t                               /* O - Tag value */
2284 ippTagValue(const char *name)           /* I - Tag name */
2285 {
2286   size_t        i;                      /* Looping var */
2287
2288
2289   for (i = 0; i < (sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])); i ++)
2290     if (!_cups_strcasecmp(name, ipp_tag_names[i]))
2291       return ((ipp_tag_t)i);
2292
2293   if (!_cups_strcasecmp(name, "operation"))
2294     return (IPP_TAG_OPERATION);
2295   else if (!_cups_strcasecmp(name, "job"))
2296     return (IPP_TAG_JOB);
2297   else if (!_cups_strcasecmp(name, "printer"))
2298     return (IPP_TAG_PRINTER);
2299   else if (!_cups_strcasecmp(name, "unsupported"))
2300     return (IPP_TAG_UNSUPPORTED_GROUP);
2301   else if (!_cups_strcasecmp(name, "subscription"))
2302     return (IPP_TAG_SUBSCRIPTION);
2303   else if (!_cups_strcasecmp(name, "event"))
2304     return (IPP_TAG_EVENT_NOTIFICATION);
2305   else if (!_cups_strcasecmp(name, "language"))
2306     return (IPP_TAG_LANGUAGE);
2307   else if (!_cups_strcasecmp(name, "mimetype"))
2308     return (IPP_TAG_MIMETYPE);
2309   else if (!_cups_strcasecmp(name, "name"))
2310     return (IPP_TAG_NAME);
2311   else if (!_cups_strcasecmp(name, "text"))
2312     return (IPP_TAG_TEXT);
2313   else if (!_cups_strcasecmp(name, "begCollection"))
2314     return (IPP_TAG_BEGIN_COLLECTION);
2315   else
2316     return (IPP_TAG_ZERO);
2317 }
2318
2319
2320 /*
2321  * 'ipp_col_string()' - Convert a collection to a string.
2322  */
2323
2324 static size_t                           /* O - Number of bytes */
2325 ipp_col_string(ipp_t  *col,             /* I - Collection attribute */
2326                char   *buffer,          /* I - Buffer or NULL */
2327                size_t bufsize)          /* I - Size of buffer */
2328 {
2329   char                  *bufptr,        /* Position in buffer */
2330                         *bufend,        /* End of buffer */
2331                         prefix = '{',   /* Prefix character */
2332                         temp[256];      /* Temporary string */
2333   ipp_attribute_t       *attr;          /* Current member attribute */
2334
2335
2336   if (!col)
2337   {
2338     if (buffer)
2339       *buffer = '\0';
2340
2341     return (0);
2342   }
2343
2344   bufptr = buffer;
2345   bufend = buffer + bufsize - 1;
2346
2347   for (attr = col->attrs; attr; attr = attr->next)
2348   {
2349     if (!attr->name)
2350       continue;
2351
2352     if (buffer && bufptr < bufend)
2353       *bufptr = prefix;
2354     bufptr ++;
2355     prefix = ' ';
2356
2357     if (buffer && bufptr < bufend)
2358       bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%s=", attr->name);
2359     else
2360       bufptr += strlen(attr->name) + 1;
2361
2362     if (buffer && bufptr < bufend)
2363       bufptr += ippAttributeString(attr, bufptr, (size_t)(bufend - bufptr + 1));
2364     else
2365       bufptr += ippAttributeString(attr, temp, sizeof(temp));
2366   }
2367
2368   if (prefix == '{')
2369   {
2370     if (buffer && bufptr < bufend)
2371       *bufptr = prefix;
2372     bufptr ++;
2373   }
2374
2375   if (buffer && bufptr < bufend)
2376     *bufptr = '}';
2377   bufptr ++;
2378
2379   return ((size_t)(bufptr - buffer));
2380 }