Home | History | Annotate | Download | only in cups
      1 /*
      2  * Internet Printing Protocol support functions for CUPS.
      3  *
      4  * Copyright 2007-2017 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-default",
    964     "finishings-col-supported",
    965     "finishings-default",
    966     "finishings-supported",
    967     "font-name-requested",
    968     "font-name-requested-default",
    969     "font-name-requested-supported",
    970     "font-size-requested",
    971     "font-size-requested-default",
    972     "font-size-requested-supported",
    973     "force-front-side",
    974     "force-front-side-default",
    975     "force-front-side-supported",
    976     "imposition-template",
    977     "imposition-template-default",
    978     "imposition-template-supported",
    979     "insert-after-page-number-supported",
    980     "insert-count-supported",
    981     "insert-sheet",
    982     "insert-sheet-default",
    983     "insert-sheet-supported",
    984     "material-amount-units-supported",	/* IPP 3D */
    985     "material-diameter-supported",	/* IPP 3D */
    986     "material-purpose-supported",	/* IPP 3D */
    987     "material-rate-supported",		/* IPP 3D */
    988     "material-rate-units-supported",	/* IPP 3D */
    989     "material-shell-thickness-supported",/* IPP 3D */
    990     "material-temperature-supported",	/* IPP 3D */
    991     "material-type-supported",		/* IPP 3D */
    992     "materials-col",			/* IPP 3D */
    993     "materials-col-database",		/* IPP 3D */
    994     "materials-col-default",		/* IPP 3D */
    995     "materials-col-ready",		/* IPP 3D */
    996     "materials-col-supported",		/* IPP 3D */
    997     "max-materials-col-supported",	/* IPP 3D */
    998     "max-stitching-locations-supported",
    999     "media",
   1000     "media-back-coating-supported",
   1001     "media-bottom-margin-supported",
   1002     "media-col",
   1003     "media-col-default",
   1004     "media-col-supported",
   1005     "media-color-supported",
   1006     "media-default",
   1007     "media-front-coating-supported",
   1008     "media-grain-supported",
   1009     "media-hole-count-supported",
   1010     "media-info-supported",
   1011     "media-input-tray-check",
   1012     "media-input-tray-check-default",
   1013     "media-input-tray-check-supported",
   1014     "media-key-supported",
   1015     "media-left-margin-supported",
   1016     "media-order-count-supported",
   1017     "media-pre-printed-supported",
   1018     "media-recycled-supported",
   1019     "media-right-margin-supported",
   1020     "media-size-supported",
   1021     "media-source-supported",
   1022     "media-supported",
   1023     "media-thickness-supported",
   1024     "media-top-margin-supported",
   1025     "media-type-supported",
   1026     "media-weight-metric-supported",
   1027     "multiple-document-handling",
   1028     "multiple-document-handling-default",
   1029     "multiple-document-handling-supported",
   1030     "multiple-object-handling",		/* IPP 3D */
   1031     "multiple-object-handling-default",	/* IPP 3D */
   1032     "multiple-object-handling-supported",/* IPP 3D */
   1033     "number-up",
   1034     "number-up-default",
   1035     "number-up-supported",
   1036     "orientation-requested",
   1037     "orientation-requested-default",
   1038     "orientation-requested-supported",
   1039     "output-mode",			/* CUPS extension */
   1040     "output-mode-default",		/* CUPS extension */
   1041     "output-mode-supported",		/* CUPS extension */
   1042     "overrides",
   1043     "overrides-supported",
   1044     "page-delivery",
   1045     "page-delivery-default",
   1046     "page-delivery-supported",
   1047     "page-order-received",
   1048     "page-order-received-default",
   1049     "page-order-received-supported",
   1050     "page-ranges",
   1051     "page-ranges-supported",
   1052     "pages-per-subset",
   1053     "pages-per-subset-supported",
   1054     "pdl-init-file",
   1055     "pdl-init-file-default",
   1056     "pdl-init-file-entry-supported",
   1057     "pdl-init-file-location-supported",
   1058     "pdl-init-file-name-subdirectory-supported",
   1059     "pdl-init-file-name-supported",
   1060     "pdl-init-file-supported",
   1061     "platform-temperature",		/* IPP 3D */
   1062     "platform-temperature-default",	/* IPP 3D */
   1063     "platform-temperature-supported",	/* IPP 3D */
   1064     "presentation-direction-number-up",
   1065     "presentation-direction-number-up-default",
   1066     "presentation-direction-number-up-supported",
   1067     "print-accuracy",			/* IPP 3D */
   1068     "print-accuracy-default",		/* IPP 3D */
   1069     "print-accuracy-supported",		/* IPP 3D */
   1070     "print-base",			/* IPP 3D */
   1071     "print-base-default",		/* IPP 3D */
   1072     "print-base-supported",		/* IPP 3D */
   1073     "print-color-mode",
   1074     "print-color-mode-default",
   1075     "print-color-mode-supported",
   1076     "print-content-optimize",
   1077     "print-content-optimize-default",
   1078     "print-content-optimize-supported",
   1079     "print-objects",			/* IPP 3D */
   1080     "print-objects-default",		/* IPP 3D */
   1081     "print-objects-supported",		/* IPP 3D */
   1082     "print-quality",
   1083     "print-quality-default",
   1084     "print-quality-supported",
   1085     "print-rendering-intent",
   1086     "print-rendering-intent-default",
   1087     "print-rendering-intent-supported",
   1088     "print-scaling",			/* IPP Paid Printing */
   1089     "print-scaling-default",		/* IPP Paid Printing */
   1090     "print-scaling-supported",		/* IPP Paid Printing */
   1091     "print-supports",			/* IPP 3D */
   1092     "print-supports-default",		/* IPP 3D */
   1093     "print-supports-supported",		/* IPP 3D */
   1094     "printer-resolution",
   1095     "printer-resolution-default",
   1096     "printer-resolution-supported",
   1097     "separator-sheets",
   1098     "separator-sheets-default",
   1099     "separator-sheets-supported",
   1100     "sheet-collate",
   1101     "sheet-collate-default",
   1102     "sheet-collate-supported",
   1103     "sides",
   1104     "sides-default",
   1105     "sides-supported",
   1106     "stitching-locations-supported",
   1107     "stitching-offset-supported",
   1108     "x-image-position",
   1109     "x-image-position-default",
   1110     "x-image-position-supported",
   1111     "x-image-shift",
   1112     "x-image-shift-default",
   1113     "x-image-shift-supported",
   1114     "x-side1-image-shift",
   1115     "x-side1-image-shift-default",
   1116     "x-side1-image-shift-supported",
   1117     "x-side2-image-shift",
   1118     "x-side2-image-shift-default",
   1119     "x-side2-image-shift-supported",
   1120     "y-image-position",
   1121     "y-image-position-default",
   1122     "y-image-position-supported",
   1123     "y-image-shift",
   1124     "y-image-shift-default",
   1125     "y-image-shift-supported",
   1126     "y-side1-image-shift",
   1127     "y-side1-image-shift-default",
   1128     "y-side1-image-shift-supported",
   1129     "y-side2-image-shift",
   1130     "y-side2-image-shift-default",
   1131     "y-side2-image-shift-supported"
   1132   };
   1133   static const char * const job_description[] =
   1134   {					/* job-description group */
   1135     "compression-supplied",
   1136     "copies-actual",
   1137     "cover-back-actual",
   1138     "cover-front-actual",
   1139     "current-page-order",
   1140     "date-time-at-completed",
   1141     "date-time-at-creation",
   1142     "date-time-at-processing",
   1143     "destination-statuses",
   1144     "document-charset-supplied",
   1145     "document-digital-signature-supplied",
   1146     "document-format-details-supplied",
   1147     "document-format-supplied",
   1148     "document-message-supplied",
   1149     "document-metadata",
   1150     "document-name-supplied",
   1151     "document-natural-language-supplied",
   1152     "document-overrides-actual",
   1153     "errors-count",
   1154     "finishings-actual",
   1155     "finishings-col-actual",
   1156     "force-front-side-actual",
   1157     "imposition-template-actual",
   1158     "impressions-completed-current-copy",
   1159     "insert-sheet-actual",
   1160     "job-account-id-actual",
   1161     "job-accounting-sheets-actual",
   1162     "job-accounting-user-id-actual",
   1163     "job-attribute-fidelity",
   1164     "job-charge-info",			/* CUPS extension */
   1165     "job-collation-type",
   1166     "job-collation-type-actual",
   1167     "job-copies-actual",
   1168     "job-cover-back-actual",
   1169     "job-cover-front-actual",
   1170     "job-detailed-status-message",
   1171     "job-document-access-errors",
   1172     "job-error-sheet-actual",
   1173     "job-finishings-actual",
   1174     "job-finishings-col-actual",
   1175     "job-hold-until-actual",
   1176     "job-id",
   1177     "job-impressions",
   1178     "job-impressions-completed",
   1179     "job-k-octets",
   1180     "job-k-octets-processed",
   1181     "job-mandatory-attributes",
   1182     "job-media-progress",		/* CUPS extension */
   1183     "job-media-sheets",
   1184     "job-media-sheets-completed",
   1185     "job-message-from-operator",
   1186     "job-more-info",
   1187     "job-name",
   1188     "job-originating-host-name",	/* CUPS extension */
   1189     "job-originating-user-name",
   1190     "job-originating-user-uri",
   1191     "job-pages",
   1192     "job-pages-completed",
   1193     "job-pages-completed-current-copy",
   1194     "job-printer-state-message",	/* CUPS extension */
   1195     "job-printer-state-reasons",	/* CUPS extension */
   1196     "job-printer-up-time",
   1197     "job-printer-uri",
   1198     "job-priority-actual",
   1199     "job-save-printer-make-and-model",
   1200     "job-sheet-message-actual",
   1201     "job-sheets-actual",
   1202     "job-sheets-col-actual",
   1203     "job-state",
   1204     "job-state-message",
   1205     "job-state-reasons",
   1206     "job-uri",
   1207     "job-uuid",
   1208     "materials-col-actual",		/* IPP 3D */
   1209     "media-actual",
   1210     "media-col-actual",
   1211     "media-check-input-tray-actual",
   1212     "multiple-document-handling-actual",
   1213     "multiple-object-handling-actual",	/* IPP 3D */
   1214     "number-of-documents",
   1215     "number-of-intervening-jobs",
   1216     "number-up-actual",
   1217     "orientation-requested-actual",
   1218     "original-requesting-user-name",
   1219     "output-bin-actual",
   1220     "output-device-assigned",
   1221     "overrides-actual",
   1222     "page-delivery-actual",
   1223     "page-order-received-actual",
   1224     "page-ranges-actual",
   1225     "platform-temperature-actual",	/* IPP 3D */
   1226     "presentation-direction-number-up-actual",
   1227     "print-accuracy-actual",		/* IPP 3D */
   1228     "print-base-actual",		/* IPP 3D */
   1229     "print-color-mode-actual",
   1230     "print-content-optimize-actual",
   1231     "print-objects-actual",		/* IPP 3D */
   1232     "print-quality-actual",
   1233     "print-rendering-intent-actual",
   1234     "print-scaling-actual",		/* IPP Paid Printing */
   1235     "print-supports-actual",		/* IPP 3D */
   1236     "printer-resolution-actual",
   1237     "separator-sheets-actual",
   1238     "sheet-collate-actual",
   1239     "sheet-completed-copy-number",
   1240     "sheet-completed-document-number",
   1241     "sides-actual",
   1242     "time-at-completed",
   1243     "time-at-creation",
   1244     "time-at-processing",
   1245     "warnings-count",
   1246     "x-image-position-actual",
   1247     "x-image-shift-actual",
   1248     "x-side1-image-shift-actual",
   1249     "x-side2-image-shift-actual",
   1250     "y-image-position-actual",
   1251     "y-image-shift-actual",
   1252     "y-side1-image-shift-actual",
   1253     "y-side2-image-shift-actual"
   1254   };
   1255   static const char * const job_template[] =
   1256   {					/* job-template group */
   1257     "accuracy-units-supported",		/* IPP 3D */
   1258     "confirmation-sheet-print",		/* IPP FaxOut */
   1259     "confirmation-sheet-print-default",
   1260     "copies",
   1261     "copies-default",
   1262     "copies-supported",
   1263     "cover-back",
   1264     "cover-back-default",
   1265     "cover-back-supported",
   1266     "cover-front",
   1267     "cover-front-default",
   1268     "cover-front-supported",
   1269     "cover-sheet-info",			/* IPP FaxOut */
   1270     "cover-sheet-info-default",
   1271     "cover-sheet-info-supported",
   1272     "destination-uri-schemes-supported",/* IPP FaxOut */
   1273     "destination-uris",			/* IPP FaxOut */
   1274     "destination-uris-supported",
   1275     "feed-orientation",
   1276     "feed-orientation-default",
   1277     "feed-orientation-supported",
   1278     "finishings",
   1279     "finishings-col",
   1280     "finishings-col-default",
   1281     "finishings-col-supported",
   1282     "finishings-default",
   1283     "finishings-supported",
   1284     "font-name-requested",
   1285     "font-name-requested-default",
   1286     "font-name-requested-supported",
   1287     "font-size-requested",
   1288     "font-size-requested-default",
   1289     "font-size-requested-supported",
   1290     "force-front-side",
   1291     "force-front-side-default",
   1292     "force-front-side-supported",
   1293     "imposition-template",
   1294     "imposition-template-default",
   1295     "imposition-template-supported",
   1296     "insert-after-page-number-supported",
   1297     "insert-count-supported",
   1298     "insert-sheet",
   1299     "insert-sheet-default",
   1300     "insert-sheet-supported",
   1301     "job-account-id",
   1302     "job-account-id-default",
   1303     "job-account-id-supported",
   1304     "job-accounting-sheets"
   1305     "job-accounting-sheets-default"
   1306     "job-accounting-sheets-supported"
   1307     "job-accounting-user-id",
   1308     "job-accounting-user-id-default",
   1309     "job-accounting-user-id-supported",
   1310     "job-copies",
   1311     "job-copies-default",
   1312     "job-copies-supported",
   1313     "job-cover-back",
   1314     "job-cover-back-default",
   1315     "job-cover-back-supported",
   1316     "job-cover-front",
   1317     "job-cover-front-default",
   1318     "job-cover-front-supported",
   1319     "job-delay-output-until",
   1320     "job-delay-output-until-default",
   1321     "job-delay-output-until-supported",
   1322     "job-delay-output-until-time",
   1323     "job-delay-output-until-time-default",
   1324     "job-delay-output-until-time-supported",
   1325     "job-error-action",
   1326     "job-error-action-default",
   1327     "job-error-action-supported",
   1328     "job-error-sheet",
   1329     "job-error-sheet-default",
   1330     "job-error-sheet-supported",
   1331     "job-finishings",
   1332     "job-finishings-col",
   1333     "job-finishings-col-default",
   1334     "job-finishings-col-supported",
   1335     "job-finishings-default",
   1336     "job-finishings-supported",
   1337     "job-hold-until",
   1338     "job-hold-until-default",
   1339     "job-hold-until-supported",
   1340     "job-hold-until-time",
   1341     "job-hold-until-time-default",
   1342     "job-hold-until-time-supported",
   1343     "job-message-to-operator",
   1344     "job-message-to-operator-default",
   1345     "job-message-to-operator-supported",
   1346     "job-phone-number",
   1347     "job-phone-number-default",
   1348     "job-phone-number-supported",
   1349     "job-priority",
   1350     "job-priority-default",
   1351     "job-priority-supported",
   1352     "job-recipient-name",
   1353     "job-recipient-name-default",
   1354     "job-recipient-name-supported",
   1355     "job-save-disposition",
   1356     "job-save-disposition-default",
   1357     "job-save-disposition-supported",
   1358     "job-sheets",
   1359     "job-sheets-col",
   1360     "job-sheets-col-default",
   1361     "job-sheets-col-supported",
   1362     "job-sheets-default",
   1363     "job-sheets-supported",
   1364     "logo-uri-schemes-supported",
   1365     "material-amount-units-supported",	/* IPP 3D */
   1366     "material-diameter-supported",	/* IPP 3D */
   1367     "material-purpose-supported",	/* IPP 3D */
   1368     "material-rate-supported",		/* IPP 3D */
   1369     "material-rate-units-supported",	/* IPP 3D */
   1370     "material-shell-thickness-supported",/* IPP 3D */
   1371     "material-temperature-supported",	/* IPP 3D */
   1372     "material-type-supported",		/* IPP 3D */
   1373     "materials-col",			/* IPP 3D */
   1374     "materials-col-database",		/* IPP 3D */
   1375     "materials-col-default",		/* IPP 3D */
   1376     "materials-col-ready",		/* IPP 3D */
   1377     "materials-col-supported",		/* IPP 3D */
   1378     "max-materials-col-supported",	/* IPP 3D */
   1379     "max-save-info-supported",
   1380     "max-stitching-locations-supported",
   1381     "media",
   1382     "media-back-coating-supported",
   1383     "media-bottom-margin-supported",
   1384     "media-col",
   1385     "media-col-default",
   1386     "media-col-supported",
   1387     "media-color-supported",
   1388     "media-default",
   1389     "media-front-coating-supported",
   1390     "media-grain-supported",
   1391     "media-hole-count-supported",
   1392     "media-info-supported",
   1393     "media-input-tray-check",
   1394     "media-input-tray-check-default",
   1395     "media-input-tray-check-supported",
   1396     "media-key-supported",
   1397     "media-left-margin-supported",
   1398     "media-order-count-supported",
   1399     "media-pre-printed-supported",
   1400     "media-recycled-supported",
   1401     "media-right-margin-supported",
   1402     "media-size-supported",
   1403     "media-source-supported",
   1404     "media-supported",
   1405     "media-thickness-supported",
   1406     "media-top-margin-supported",
   1407     "media-type-supported",
   1408     "media-weight-metric-supported",
   1409     "multiple-document-handling",
   1410     "multiple-document-handling-default",
   1411     "multiple-document-handling-supported",
   1412     "multiple-object-handling",		/* IPP 3D */
   1413     "multiple-object-handling-default",	/* IPP 3D */
   1414     "multiple-object-handling-supported",/* IPP 3D */
   1415     "number-of-retries",		/* IPP FaxOut */
   1416     "number-of-retries-default",
   1417     "number-of-retries-supported",
   1418     "number-up",
   1419     "number-up-default",
   1420     "number-up-supported",
   1421     "orientation-requested",
   1422     "orientation-requested-default",
   1423     "orientation-requested-supported",
   1424     "output-bin",
   1425     "output-bin-default",
   1426     "output-bin-supported",
   1427     "output-device",
   1428     "output-device-default",
   1429     "output-device-supported",
   1430     "output-mode",			/* CUPS extension */
   1431     "output-mode-default",		/* CUPS extension */
   1432     "output-mode-supported",		/* CUPS extension */
   1433     "overrides",
   1434     "overrides-supported",
   1435     "page-delivery",
   1436     "page-delivery-default",
   1437     "page-delivery-supported",
   1438     "page-order-received",
   1439     "page-order-received-default",
   1440     "page-order-received-supported",
   1441     "page-ranges",
   1442     "page-ranges-supported",
   1443     "pages-per-subset",
   1444     "pages-per-subset-supported",
   1445     "pdl-init-file",
   1446     "pdl-init-file-default",
   1447     "pdl-init-file-entry-supported",
   1448     "pdl-init-file-location-supported",
   1449     "pdl-init-file-name-subdirectory-supported",
   1450     "pdl-init-file-name-supported",
   1451     "pdl-init-file-supported",
   1452     "platform-temperature",		/* IPP 3D */
   1453     "platform-temperature-default",	/* IPP 3D */
   1454     "platform-temperature-supported",	/* IPP 3D */
   1455     "presentation-direction-number-up",
   1456     "presentation-direction-number-up-default",
   1457     "presentation-direction-number-up-supported",
   1458     "print-accuracy",			/* IPP 3D */
   1459     "print-accuracy-default",		/* IPP 3D */
   1460     "print-accuracy-supported",		/* IPP 3D */
   1461     "print-base",			/* IPP 3D */
   1462     "print-base-default",		/* IPP 3D */
   1463     "print-base-supported",		/* IPP 3D */
   1464     "print-color-mode",
   1465     "print-color-mode-default",
   1466     "print-color-mode-supported",
   1467     "print-content-optimize",
   1468     "print-content-optimize-default",
   1469     "print-content-optimize-supported",
   1470     "print-objects",			/* IPP 3D */
   1471     "print-objects-default",		/* IPP 3D */
   1472     "print-objects-supported",		/* IPP 3D */
   1473     "print-quality",
   1474     "print-quality-default",
   1475     "print-quality-supported",
   1476     "print-rendering-intent",
   1477     "print-rendering-intent-default",
   1478     "print-rendering-intent-supported",
   1479     "print-scaling",			/* IPP Paid Printing */
   1480     "print-scaling-default",		/* IPP Paid Printing */
   1481     "print-scaling-supported",		/* IPP Paid Printing */
   1482     "print-supports",			/* IPP 3D */
   1483     "print-supports-default",		/* IPP 3D */
   1484     "print-supports-supported",		/* IPP 3D */
   1485     "printer-resolution",
   1486     "printer-resolution-default",
   1487     "printer-resolution-supported",
   1488     "proof-print",
   1489     "proof-print-default",
   1490     "proof-print-supported",
   1491     "retry-interval",			/* IPP FaxOut */
   1492     "retry-interval-default",
   1493     "retry-interval-supported",
   1494     "retry-timeout",			/* IPP FaxOut */
   1495     "retry-timeout-default",
   1496     "retry-timeout-supported",
   1497     "save-disposition-supported",
   1498     "save-document-format-default",
   1499     "save-document-format-supported",
   1500     "save-location-default",
   1501     "save-location-supported",
   1502     "save-name-subdirectory-supported",
   1503     "save-name-supported",
   1504     "separator-sheets",
   1505     "separator-sheets-default",
   1506     "separator-sheets-supported",
   1507     "sheet-collate",
   1508     "sheet-collate-default",
   1509     "sheet-collate-supported",
   1510     "sides",
   1511     "sides-default",
   1512     "sides-supported",
   1513     "stitching-locations-supported",
   1514     "stitching-offset-supported",
   1515     "x-image-position",
   1516     "x-image-position-default",
   1517     "x-image-position-supported",
   1518     "x-image-shift",
   1519     "x-image-shift-default",
   1520     "x-image-shift-supported",
   1521     "x-side1-image-shift",
   1522     "x-side1-image-shift-default",
   1523     "x-side1-image-shift-supported",
   1524     "x-side2-image-shift",
   1525     "x-side2-image-shift-default",
   1526     "x-side2-image-shift-supported",
   1527     "y-image-position",
   1528     "y-image-position-default",
   1529     "y-image-position-supported",
   1530     "y-image-shift",
   1531     "y-image-shift-default",
   1532     "y-image-shift-supported",
   1533     "y-side1-image-shift",
   1534     "y-side1-image-shift-default",
   1535     "y-side1-image-shift-supported",
   1536     "y-side2-image-shift",
   1537     "y-side2-image-shift-default",
   1538     "y-side2-image-shift-supported"
   1539   };
   1540   static const char * const printer_description[] =
   1541   {					/* printer-description group */
   1542     "auth-info-required",		/* CUPS extension */
   1543     "charset-configured",
   1544     "charset-supported",
   1545     "color-supported",
   1546     "compression-supported",
   1547     "device-service-count",
   1548     "device-uri",			/* CUPS extension */
   1549     "device-uuid",
   1550     "document-charset-default",
   1551     "document-charset-supported",
   1552     "document-creation-attributes-supported",
   1553     "document-digital-signature-default",
   1554     "document-digital-signature-supported",
   1555     "document-format-default",
   1556     "document-format-details-default",
   1557     "document-format-details-supported",
   1558     "document-format-supported",
   1559     "document-format-varying-attributes",
   1560     "document-format-version-default",
   1561     "document-format-version-supported",
   1562     "document-natural-language-default",
   1563     "document-natural-language-supported",
   1564     "document-password-supported",
   1565     "generated-natural-language-supported",
   1566     "identify-actions-default",
   1567     "identify-actions-supported",
   1568     "input-source-supported",
   1569     "ipp-features-supported",
   1570     "ipp-versions-supported",
   1571     "ippget-event-life",
   1572     "job-authorization-uri-supported",	/* CUPS extension */
   1573     "job-constraints-supported",
   1574     "job-creation-attributes-supported",
   1575     "job-finishings-col-ready",
   1576     "job-finishings-ready",
   1577     "job-ids-supported",
   1578     "job-impressions-supported",
   1579     "job-k-limit",			/* CUPS extension */
   1580     "job-k-octets-supported",
   1581     "job-media-sheets-supported",
   1582     "job-page-limit",			/* CUPS extension */
   1583     "job-password-encryption-supported",
   1584     "job-password-supported",
   1585     "job-quota-period",			/* CUPS extension */
   1586     "job-resolvers-supported",
   1587     "job-settable-attributes-supported",
   1588     "job-spooling-supported",
   1589     "jpeg-k-octets-supported",		/* CUPS extension */
   1590     "jpeg-x-dimension-supported",	/* CUPS extension */
   1591     "jpeg-y-dimension-supported",	/* CUPS extension */
   1592     "landscape-orientation-requested-preferred",
   1593 					/* CUPS extension */
   1594     "marker-change-time",		/* CUPS extension */
   1595     "marker-colors",			/* CUPS extension */
   1596     "marker-high-levels",		/* CUPS extension */
   1597     "marker-levels",			/* CUPS extension */
   1598     "marker-low-levels",		/* CUPS extension */
   1599     "marker-message",			/* CUPS extension */
   1600     "marker-names",			/* CUPS extension */
   1601     "marker-types",			/* CUPS extension */
   1602     "media-col-ready",
   1603     "media-ready",
   1604     "member-names",			/* CUPS extension */
   1605     "member-uris",			/* CUPS extension */
   1606     "multiple-destination-uris-supported",/* IPP FaxOut */
   1607     "multiple-document-jobs-supported",
   1608     "multiple-operation-time-out",
   1609     "multiple-operation-time-out-action",
   1610     "natural-language-configured",
   1611     "operations-supported",
   1612     "pages-per-minute",
   1613     "pages-per-minute-color",
   1614     "pdf-k-octets-supported",		/* CUPS extension */
   1615     "pdf-features-supported",		/* IPP 3D */
   1616     "pdf-versions-supported",		/* CUPS extension */
   1617     "pdl-override-supported",
   1618     "port-monitor",			/* CUPS extension */
   1619     "port-monitor-supported",		/* CUPS extension */
   1620     "preferred-attributes-supported",
   1621     "printer-alert",
   1622     "printer-alert-description",
   1623     "printer-charge-info",
   1624     "printer-charge-info-uri",
   1625     "printer-commands",			/* CUPS extension */
   1626     "printer-current-time",
   1627     "printer-detailed-status-messages",
   1628     "printer-device-id",
   1629     "printer-dns-sd-name",		/* CUPS extension */
   1630     "printer-driver-installer",
   1631     "printer-fax-log-uri",		/* IPP FaxOut */
   1632     "printer-fax-modem-info",		/* IPP FaxOut */
   1633     "printer-fax-modem-name",		/* IPP FaxOut */
   1634     "printer-fax-modem-number",		/* IPP FaxOut */
   1635     "printer-firmware-name",		/* PWG 5110.1 */
   1636     "printer-firmware-patches",		/* PWG 5110.1 */
   1637     "printer-firmware-string-version",	/* PWG 5110.1 */
   1638     "printer-firmware-version",		/* PWG 5110.1 */
   1639     "printer-geo-location",
   1640     "printer-get-attributes-supported",
   1641     "printer-icc-profiles",
   1642     "printer-icons",
   1643     "printer-id",               	/* CUPS extension */
   1644     "printer-info",
   1645     "printer-input-tray",		/* IPP JPS3 */
   1646     "printer-is-accepting-jobs",
   1647     "printer-is-shared",		/* CUPS extension */
   1648     "printer-is-temporary",		/* CUPS extension */
   1649     "printer-kind",			/* IPP Paid Printing */
   1650     "printer-location",
   1651     "printer-make-and-model",
   1652     "printer-mandatory-job-attributes",
   1653     "printer-message-date-time",
   1654     "printer-message-from-operator",
   1655     "printer-message-time",
   1656     "printer-more-info",
   1657     "printer-more-info-manufacturer",
   1658     "printer-name",
   1659     "printer-native-formats",
   1660     "printer-organization",
   1661     "printer-organizational-unit",
   1662     "printer-output-tray",		/* IPP JPS3 */
   1663     "printer-queue-id",			/* CUPS extension */
   1664     "printer-settable-attributes-supported",
   1665     "printer-state",
   1666     "printer-state-change-date-time",
   1667     "printer-state-change-time",
   1668     "printer-state-message",
   1669     "printer-state-reasons",
   1670     "printer-supply",
   1671     "printer-supply-description",
   1672     "printer-supply-info-uri",
   1673     "printer-type",			/* CUPS extension */
   1674     "printer-up-time",
   1675     "printer-uri-supported",
   1676     "printer-uuid",
   1677     "printer-xri-supported",
   1678     "pwg-raster-document-resolution-supported",
   1679     "pwg-raster-document-sheet-back",
   1680     "pwg-raster-document-type-supported",
   1681     "queued-job-count",
   1682     "reference-uri-schemes-supported",
   1683     "repertoire-supported",
   1684     "requesting-user-name-allowed",	/* CUPS extension */
   1685     "requesting-user-name-denied",	/* CUPS extension */
   1686     "requesting-user-uri-supported",
   1687     "subordinate-printers-supported",
   1688     "urf-supported",			/* CUPS extension */
   1689     "uri-authentication-supported",
   1690     "uri-security-supported",
   1691     "user-defined-value-supported",
   1692     "which-jobs-supported",
   1693     "xri-authentication-supported",
   1694     "xri-security-supported",
   1695     "xri-uri-scheme-supported"
   1696   };
   1697   static const char * const subscription_description[] =
   1698   {					/* subscription-description group */
   1699     "notify-job-id",
   1700     "notify-lease-expiration-time",
   1701     "notify-printer-up-time",
   1702     "notify-printer-uri",
   1703     "notify-sequence-number",
   1704     "notify-subscriber-user-name",
   1705     "notify-subscriber-user-uri",
   1706     "notify-subscription-id",
   1707     "subscriptions-uuid"
   1708   };
   1709   static const char * const subscription_template[] =
   1710   {					/* subscription-template group */
   1711     "notify-attributes",
   1712     "notify-attributes-supported",
   1713     "notify-charset",
   1714     "notify-events",
   1715     "notify-events-default",
   1716     "notify-events-supported",
   1717     "notify-lease-duration",
   1718     "notify-lease-duration-default",
   1719     "notify-lease-duration-supported",
   1720     "notify-max-events-supported",
   1721     "notify-natural-language",
   1722     "notify-pull-method",
   1723     "notify-pull-method-supported",
   1724     "notify-recipient-uri",
   1725     "notify-schemes-supported",
   1726     "notify-time-interval",
   1727     "notify-user-data"
   1728   };
   1729 
   1730 
   1731  /*
   1732   * Get the requested-attributes attribute...
   1733   */
   1734 
   1735   if ((requested = ippFindAttribute(request, "requested-attributes",
   1736                                     IPP_TAG_KEYWORD)) == NULL)
   1737   {
   1738    /*
   1739     * The Get-Jobs operation defaults to "job-id" and "job-uri", all others
   1740     * default to "all"...
   1741     */
   1742 
   1743     if (ippGetOperation(request) == IPP_OP_GET_JOBS)
   1744     {
   1745       ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
   1746       cupsArrayAdd(ra, "job-id");
   1747       cupsArrayAdd(ra, "job-uri");
   1748 
   1749       return (ra);
   1750     }
   1751     else
   1752       return (NULL);
   1753   }
   1754 
   1755  /*
   1756   * If the attribute contains a single "all" keyword, return NULL...
   1757   */
   1758 
   1759   count = ippGetCount(requested);
   1760   if (count == 1 && !strcmp(ippGetString(requested, 0, NULL), "all"))
   1761     return (NULL);
   1762 
   1763  /*
   1764   * Create an array using "strcmp" as the comparison function...
   1765   */
   1766 
   1767   ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
   1768 
   1769   for (i = 0; i < count; i ++)
   1770   {
   1771     added = 0;
   1772     value = ippGetString(requested, i, NULL);
   1773 
   1774     if (!strcmp(value, "document-description") || !strcmp(value, "all"))
   1775     {
   1776       for (j = 0;
   1777            j < (int)(sizeof(document_description) /
   1778                      sizeof(document_description[0]));
   1779            j ++)
   1780         cupsArrayAdd(ra, (void *)document_description[j]);
   1781 
   1782       added = 1;
   1783     }
   1784 
   1785     if (!strcmp(value, "document-template") || !strcmp(value, "all"))
   1786     {
   1787       for (j = 0;
   1788            j < (int)(sizeof(document_template) / sizeof(document_template[0]));
   1789            j ++)
   1790         cupsArrayAdd(ra, (void *)document_template[j]);
   1791 
   1792       added = 1;
   1793     }
   1794 
   1795     if (!strcmp(value, "job-description") || !strcmp(value, "all"))
   1796     {
   1797       for (j = 0;
   1798            j < (int)(sizeof(job_description) / sizeof(job_description[0]));
   1799            j ++)
   1800         cupsArrayAdd(ra, (void *)job_description[j]);
   1801 
   1802       added = 1;
   1803     }
   1804 
   1805     if (!strcmp(value, "job-template") || !strcmp(value, "all"))
   1806     {
   1807       for (j = 0;
   1808            j < (int)(sizeof(job_template) / sizeof(job_template[0]));
   1809            j ++)
   1810         cupsArrayAdd(ra, (void *)job_template[j]);
   1811 
   1812       added = 1;
   1813     }
   1814 
   1815     if (!strcmp(value, "printer-description") || !strcmp(value, "all"))
   1816     {
   1817       for (j = 0;
   1818            j < (int)(sizeof(printer_description) /
   1819                      sizeof(printer_description[0]));
   1820            j ++)
   1821         cupsArrayAdd(ra, (void *)printer_description[j]);
   1822 
   1823       added = 1;
   1824     }
   1825 
   1826     if (!strcmp(value, "subscription-description") || !strcmp(value, "all"))
   1827     {
   1828       for (j = 0;
   1829            j < (int)(sizeof(subscription_description) /
   1830                      sizeof(subscription_description[0]));
   1831            j ++)
   1832         cupsArrayAdd(ra, (void *)subscription_description[j]);
   1833 
   1834       added = 1;
   1835     }
   1836 
   1837     if (!strcmp(value, "subscription-template") || !strcmp(value, "all"))
   1838     {
   1839       for (j = 0;
   1840            j < (int)(sizeof(subscription_template) /
   1841                      sizeof(subscription_template[0]));
   1842            j ++)
   1843         cupsArrayAdd(ra, (void *)subscription_template[j]);
   1844 
   1845       added = 1;
   1846     }
   1847 
   1848     if (!added)
   1849       cupsArrayAdd(ra, (void *)value);
   1850   }
   1851 
   1852   return (ra);
   1853 }
   1854 
   1855 
   1856 /*
   1857  * 'ippEnumString()' - Return a string corresponding to the enum value.
   1858  */
   1859 
   1860 const char *				/* O - Enum string */
   1861 ippEnumString(const char *attrname,	/* I - Attribute name */
   1862               int        enumvalue)	/* I - Enum value */
   1863 {
   1864   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
   1865 
   1866 
   1867  /*
   1868   * Check for standard enum values...
   1869   */
   1870 
   1871   if (!strcmp(attrname, "document-state") &&
   1872       enumvalue >= 3 &&
   1873       enumvalue < (3 + (int)(sizeof(ipp_document_states) /
   1874 			     sizeof(ipp_document_states[0]))))
   1875     return (ipp_document_states[enumvalue - 3]);
   1876   else if (!strcmp(attrname, "finishings") ||
   1877 	   !strcmp(attrname, "finishings-actual") ||
   1878 	   !strcmp(attrname, "finishings-default") ||
   1879 	   !strcmp(attrname, "finishings-ready") ||
   1880 	   !strcmp(attrname, "finishings-supported") ||
   1881 	   !strcmp(attrname, "job-finishings") ||
   1882 	   !strcmp(attrname, "job-finishings-default") ||
   1883 	   !strcmp(attrname, "job-finishings-supported"))
   1884   {
   1885     if (enumvalue >= 3 &&
   1886         enumvalue < (3 + (int)(sizeof(ipp_finishings) /
   1887 			       sizeof(ipp_finishings[0]))))
   1888       return (ipp_finishings[enumvalue - 3]);
   1889     else if (enumvalue >= 0x40000000 &&
   1890              enumvalue <= (0x40000000 + (int)(sizeof(ipp_finishings_vendor) /
   1891                                               sizeof(ipp_finishings_vendor[0]))))
   1892       return (ipp_finishings_vendor[enumvalue - 0x40000000]);
   1893   }
   1894   else if ((!strcmp(attrname, "job-collation-type") ||
   1895             !strcmp(attrname, "job-collation-type-actual")) &&
   1896            enumvalue >= 3 &&
   1897            enumvalue < (3 + (int)(sizeof(ipp_job_collation_types) /
   1898 				  sizeof(ipp_job_collation_types[0]))))
   1899     return (ipp_job_collation_types[enumvalue - 3]);
   1900   else if (!strcmp(attrname, "job-state") &&
   1901 	   enumvalue >= IPP_JSTATE_PENDING && enumvalue <= IPP_JSTATE_COMPLETED)
   1902     return (ipp_job_states[enumvalue - IPP_JSTATE_PENDING]);
   1903   else if (!strcmp(attrname, "operations-supported"))
   1904     return (ippOpString((ipp_op_t)enumvalue));
   1905   else if ((!strcmp(attrname, "orientation-requested") ||
   1906             !strcmp(attrname, "orientation-requested-actual") ||
   1907             !strcmp(attrname, "orientation-requested-default") ||
   1908             !strcmp(attrname, "orientation-requested-supported")) &&
   1909            enumvalue >= 3 &&
   1910            enumvalue < (3 + (int)(sizeof(ipp_orientation_requesteds) /
   1911 				  sizeof(ipp_orientation_requesteds[0]))))
   1912     return (ipp_orientation_requesteds[enumvalue - 3]);
   1913   else if ((!strcmp(attrname, "print-quality") ||
   1914             !strcmp(attrname, "print-quality-actual") ||
   1915             !strcmp(attrname, "print-quality-default") ||
   1916             !strcmp(attrname, "print-quality-supported")) &&
   1917            enumvalue >= 3 &&
   1918            enumvalue < (3 + (int)(sizeof(ipp_print_qualities) /
   1919 				  sizeof(ipp_print_qualities[0]))))
   1920     return (ipp_print_qualities[enumvalue - 3]);
   1921   else if (!strcmp(attrname, "printer-state") &&
   1922            enumvalue >= IPP_PSTATE_IDLE && enumvalue <= IPP_PSTATE_STOPPED)
   1923     return (ipp_printer_states[enumvalue - IPP_PSTATE_IDLE]);
   1924 
   1925  /*
   1926   * Not a standard enum value, just return the decimal equivalent...
   1927   */
   1928 
   1929   snprintf(cg->ipp_unknown, sizeof(cg->ipp_unknown), "%d", enumvalue);
   1930   return (cg->ipp_unknown);
   1931 }
   1932 
   1933 
   1934 /*
   1935  * 'ippEnumValue()' - Return the value associated with a given enum string.
   1936  */
   1937 
   1938 int					/* O - Enum value or -1 if unknown */
   1939 ippEnumValue(const char *attrname,	/* I - Attribute name */
   1940              const char *enumstring)	/* I - Enum string */
   1941 {
   1942   int		i,			/* Looping var */
   1943 		num_strings;		/* Number of strings to compare */
   1944   const char * const *strings;		/* Strings to compare */
   1945 
   1946 
   1947  /*
   1948   * If the string is just a number, return it...
   1949   */
   1950 
   1951   if (isdigit(*enumstring & 255))
   1952     return ((int)strtol(enumstring, NULL, 0));
   1953 
   1954  /*
   1955   * Otherwise look up the string...
   1956   */
   1957 
   1958   if (!strcmp(attrname, "document-state"))
   1959   {
   1960     num_strings = (int)(sizeof(ipp_document_states) / sizeof(ipp_document_states[0]));
   1961     strings     = ipp_document_states;
   1962   }
   1963   else if (!strcmp(attrname, "finishings") ||
   1964 	   !strcmp(attrname, "finishings-actual") ||
   1965 	   !strcmp(attrname, "finishings-default") ||
   1966 	   !strcmp(attrname, "finishings-ready") ||
   1967 	   !strcmp(attrname, "finishings-supported"))
   1968   {
   1969     for (i = 0;
   1970          i < (int)(sizeof(ipp_finishings_vendor) /
   1971                    sizeof(ipp_finishings_vendor[0]));
   1972          i ++)
   1973       if (!strcmp(enumstring, ipp_finishings_vendor[i]))
   1974 	return (i + 0x40000000);
   1975 
   1976     num_strings = (int)(sizeof(ipp_finishings) / sizeof(ipp_finishings[0]));
   1977     strings     = ipp_finishings;
   1978   }
   1979   else if (!strcmp(attrname, "job-collation-type") ||
   1980            !strcmp(attrname, "job-collation-type-actual"))
   1981   {
   1982     num_strings = (int)(sizeof(ipp_job_collation_types) /
   1983                         sizeof(ipp_job_collation_types[0]));
   1984     strings     = ipp_job_collation_types;
   1985   }
   1986   else if (!strcmp(attrname, "job-state"))
   1987   {
   1988     num_strings = (int)(sizeof(ipp_job_states) / sizeof(ipp_job_states[0]));
   1989     strings     = ipp_job_states;
   1990   }
   1991   else if (!strcmp(attrname, "operations-supported"))
   1992     return (ippOpValue(enumstring));
   1993   else if (!strcmp(attrname, "orientation-requested") ||
   1994            !strcmp(attrname, "orientation-requested-actual") ||
   1995            !strcmp(attrname, "orientation-requested-default") ||
   1996            !strcmp(attrname, "orientation-requested-supported"))
   1997   {
   1998     num_strings = (int)(sizeof(ipp_orientation_requesteds) /
   1999                         sizeof(ipp_orientation_requesteds[0]));
   2000     strings     = ipp_orientation_requesteds;
   2001   }
   2002   else if (!strcmp(attrname, "print-quality") ||
   2003            !strcmp(attrname, "print-quality-actual") ||
   2004            !strcmp(attrname, "print-quality-default") ||
   2005            !strcmp(attrname, "print-quality-supported"))
   2006   {
   2007     num_strings = (int)(sizeof(ipp_print_qualities) / sizeof(ipp_print_qualities[0]));
   2008     strings     = ipp_print_qualities;
   2009   }
   2010   else if (!strcmp(attrname, "printer-state"))
   2011   {
   2012     num_strings = (int)(sizeof(ipp_printer_states) / sizeof(ipp_printer_states[0]));
   2013     strings     = ipp_printer_states;
   2014   }
   2015   else
   2016     return (-1);
   2017 
   2018   for (i = 0; i < num_strings; i ++)
   2019     if (!strcmp(enumstring, strings[i]))
   2020       return (i + 3);
   2021 
   2022   return (-1);
   2023 }
   2024 
   2025 
   2026 /*
   2027  * 'ippErrorString()' - Return a name for the given status code.
   2028  */
   2029 
   2030 const char *				/* O - Text string */
   2031 ippErrorString(ipp_status_t error)	/* I - Error status */
   2032 {
   2033   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
   2034 
   2035 
   2036  /*
   2037   * See if the error code is a known value...
   2038   */
   2039 
   2040   if (error >= IPP_STATUS_OK && error <= IPP_STATUS_OK_EVENTS_COMPLETE)
   2041     return (ipp_status_oks[error]);
   2042   else if (error == IPP_STATUS_REDIRECTION_OTHER_SITE)
   2043     return ("redirection-other-site");
   2044   else if (error == IPP_STATUS_CUPS_SEE_OTHER)
   2045     return ("cups-see-other");
   2046   else if (error >= IPP_STATUS_ERROR_BAD_REQUEST &&
   2047            error <= IPP_STATUS_ERROR_ACCOUNT_AUTHORIZATION_FAILED)
   2048     return (ipp_status_400s[error - IPP_STATUS_ERROR_BAD_REQUEST]);
   2049   else if (error >= 0x480 &&
   2050            error <= IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED)
   2051     return (ipp_status_480s[error - 0x0480]);
   2052   else if (error >= IPP_STATUS_ERROR_INTERNAL &&
   2053            error <= IPP_STATUS_ERROR_TOO_MANY_DOCUMENTS)
   2054     return (ipp_status_500s[error - IPP_STATUS_ERROR_INTERNAL]);
   2055   else if (error >= IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED &&
   2056            error <= IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED)
   2057     return (ipp_status_1000s[error -
   2058                              IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED]);
   2059 
   2060  /*
   2061   * No, build an "0xxxxx" error string...
   2062   */
   2063 
   2064   sprintf(cg->ipp_unknown, "0x%04x", error);
   2065 
   2066   return (cg->ipp_unknown);
   2067 }
   2068 
   2069 
   2070 /*
   2071  * 'ippErrorValue()' - Return a status code for the given name.
   2072  *
   2073  * @since CUPS 1.2/macOS 10.5@
   2074  */
   2075 
   2076 ipp_status_t				/* O - IPP status code */
   2077 ippErrorValue(const char *name)		/* I - Name */
   2078 {
   2079   size_t	i;			/* Looping var */
   2080 
   2081 
   2082   for (i = 0; i < (sizeof(ipp_status_oks) / sizeof(ipp_status_oks[0])); i ++)
   2083     if (!_cups_strcasecmp(name, ipp_status_oks[i]))
   2084       return ((ipp_status_t)i);
   2085 
   2086   if (!_cups_strcasecmp(name, "redirection-other-site"))
   2087     return (IPP_STATUS_REDIRECTION_OTHER_SITE);
   2088 
   2089   if (!_cups_strcasecmp(name, "cups-see-other"))
   2090     return (IPP_STATUS_CUPS_SEE_OTHER);
   2091 
   2092   for (i = 0; i < (sizeof(ipp_status_400s) / sizeof(ipp_status_400s[0])); i ++)
   2093     if (!_cups_strcasecmp(name, ipp_status_400s[i]))
   2094       return ((ipp_status_t)(i + 0x400));
   2095 
   2096   for (i = 0; i < (sizeof(ipp_status_480s) / sizeof(ipp_status_480s[0])); i ++)
   2097     if (!_cups_strcasecmp(name, ipp_status_480s[i]))
   2098       return ((ipp_status_t)(i + 0x480));
   2099 
   2100   for (i = 0; i < (sizeof(ipp_status_500s) / sizeof(ipp_status_500s[0])); i ++)
   2101     if (!_cups_strcasecmp(name, ipp_status_500s[i]))
   2102       return ((ipp_status_t)(i + 0x500));
   2103 
   2104   for (i = 0; i < (sizeof(ipp_status_1000s) / sizeof(ipp_status_1000s[0])); i ++)
   2105     if (!_cups_strcasecmp(name, ipp_status_1000s[i]))
   2106       return ((ipp_status_t)(i + 0x1000));
   2107 
   2108   return ((ipp_status_t)-1);
   2109 }
   2110 
   2111 
   2112 /*
   2113  * 'ippOpString()' - Return a name for the given operation id.
   2114  *
   2115  * @since CUPS 1.2/macOS 10.5@
   2116  */
   2117 
   2118 const char *				/* O - Name */
   2119 ippOpString(ipp_op_t op)		/* I - Operation ID */
   2120 {
   2121   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
   2122 
   2123 
   2124  /*
   2125   * See if the operation ID is a known value...
   2126   */
   2127 
   2128   if (op >= IPP_OP_PRINT_JOB && op < (ipp_op_t)(sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])))
   2129     return (ipp_std_ops[op]);
   2130   else if (op == IPP_OP_PRIVATE)
   2131     return ("windows-ext");
   2132   else if (op >= IPP_OP_CUPS_GET_DEFAULT && op <= IPP_OP_CUPS_GET_PPD)
   2133     return (ipp_cups_ops[op - IPP_OP_CUPS_GET_DEFAULT]);
   2134   else if (op >= IPP_OP_CUPS_GET_DOCUMENT && op <= IPP_OP_CUPS_CREATE_LOCAL_PRINTER)
   2135     return (ipp_cups_ops2[op - IPP_OP_CUPS_GET_DOCUMENT]);
   2136 
   2137  /*
   2138   * No, build an "0xxxxx" operation string...
   2139   */
   2140 
   2141   sprintf(cg->ipp_unknown, "0x%04x", op);
   2142 
   2143   return (cg->ipp_unknown);
   2144 }
   2145 
   2146 
   2147 /*
   2148  * 'ippOpValue()' - Return an operation id for the given name.
   2149  *
   2150  * @since CUPS 1.2/macOS 10.5@
   2151  */
   2152 
   2153 ipp_op_t				/* O - Operation ID */
   2154 ippOpValue(const char *name)		/* I - Textual name */
   2155 {
   2156   size_t	i;			/* Looping var */
   2157 
   2158 
   2159   if (!strncmp(name, "0x", 2))
   2160     return ((ipp_op_t)strtol(name + 2, NULL, 16));
   2161 
   2162   for (i = 0; i < (sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])); i ++)
   2163     if (!_cups_strcasecmp(name, ipp_std_ops[i]))
   2164       return ((ipp_op_t)i);
   2165 
   2166   if (!_cups_strcasecmp(name, "windows-ext"))
   2167     return (IPP_OP_PRIVATE);
   2168 
   2169   for (i = 0; i < (sizeof(ipp_cups_ops) / sizeof(ipp_cups_ops[0])); i ++)
   2170     if (!_cups_strcasecmp(name, ipp_cups_ops[i]))
   2171       return ((ipp_op_t)(i + 0x4001));
   2172 
   2173   for (i = 0; i < (sizeof(ipp_cups_ops2) / sizeof(ipp_cups_ops2[0])); i ++)
   2174     if (!_cups_strcasecmp(name, ipp_cups_ops2[i]))
   2175       return ((ipp_op_t)(i + 0x4027));
   2176 
   2177   if (!_cups_strcasecmp(name, "Create-Job-Subscription"))
   2178     return (IPP_OP_CREATE_JOB_SUBSCRIPTIONS);
   2179 
   2180   if (!_cups_strcasecmp(name, "Create-Printer-Subscription"))
   2181     return (IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS);
   2182 
   2183   if (!_cups_strcasecmp(name, "CUPS-Add-Class"))
   2184     return (IPP_OP_CUPS_ADD_MODIFY_CLASS);
   2185 
   2186   if (!_cups_strcasecmp(name, "CUPS-Add-Printer"))
   2187     return (IPP_OP_CUPS_ADD_MODIFY_PRINTER);
   2188 
   2189   return (IPP_OP_CUPS_INVALID);
   2190 }
   2191 
   2192 
   2193 /*
   2194  * 'ippPort()' - Return the default IPP port number.
   2195  */
   2196 
   2197 int					/* O - Port number */
   2198 ippPort(void)
   2199 {
   2200   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
   2201 
   2202 
   2203   DEBUG_puts("ippPort()");
   2204 
   2205   if (!cg->ipp_port)
   2206     _cupsSetDefaults();
   2207 
   2208   DEBUG_printf(("1ippPort: Returning %d...", cg->ipp_port));
   2209 
   2210   return (cg->ipp_port);
   2211 }
   2212 
   2213 
   2214 /*
   2215  * 'ippSetPort()' - Set the default port number.
   2216  */
   2217 
   2218 void
   2219 ippSetPort(int p)			/* I - Port number to use */
   2220 {
   2221   DEBUG_printf(("ippSetPort(p=%d)", p));
   2222 
   2223   _cupsGlobals()->ipp_port = p;
   2224 }
   2225 
   2226 
   2227 /*
   2228  * 'ippStateString()' - Return the name corresponding to a state value.
   2229  *
   2230  * @since CUPS 2.0/OS 10.10@
   2231  */
   2232 
   2233 const char *				/* O - State name */
   2234 ippStateString(ipp_state_t state)	/* I - State value */
   2235 {
   2236   if (state >= IPP_STATE_ERROR && state <= IPP_STATE_DATA)
   2237     return (ipp_states[state - IPP_STATE_ERROR]);
   2238   else
   2239     return ("UNKNOWN");
   2240 }
   2241 
   2242 
   2243 /*
   2244  * 'ippTagString()' - Return the tag name corresponding to a tag value.
   2245  *
   2246  * The returned names are defined in RFC 8011 and the IANA IPP Registry.
   2247  *
   2248  * @since CUPS 1.4/macOS 10.6@
   2249  */
   2250 
   2251 const char *				/* O - Tag name */
   2252 ippTagString(ipp_tag_t tag)		/* I - Tag value */
   2253 {
   2254   tag &= IPP_TAG_CUPS_MASK;
   2255 
   2256   if (tag < (ipp_tag_t)(sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])))
   2257     return (ipp_tag_names[tag]);
   2258   else
   2259     return ("UNKNOWN");
   2260 }
   2261 
   2262 
   2263 /*
   2264  * 'ippTagValue()' - Return the tag value corresponding to a tag name.
   2265  *
   2266  * The tag names are defined in RFC 8011 and the IANA IPP Registry.
   2267  *
   2268  * @since CUPS 1.4/macOS 10.6@
   2269  */
   2270 
   2271 ipp_tag_t				/* O - Tag value */
   2272 ippTagValue(const char *name)		/* I - Tag name */
   2273 {
   2274   size_t	i;			/* Looping var */
   2275 
   2276 
   2277   for (i = 0; i < (sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])); i ++)
   2278     if (!_cups_strcasecmp(name, ipp_tag_names[i]))
   2279       return ((ipp_tag_t)i);
   2280 
   2281   if (!_cups_strcasecmp(name, "operation"))
   2282     return (IPP_TAG_OPERATION);
   2283   else if (!_cups_strcasecmp(name, "job"))
   2284     return (IPP_TAG_JOB);
   2285   else if (!_cups_strcasecmp(name, "printer"))
   2286     return (IPP_TAG_PRINTER);
   2287   else if (!_cups_strcasecmp(name, "unsupported"))
   2288     return (IPP_TAG_UNSUPPORTED_GROUP);
   2289   else if (!_cups_strcasecmp(name, "subscription"))
   2290     return (IPP_TAG_SUBSCRIPTION);
   2291   else if (!_cups_strcasecmp(name, "event"))
   2292     return (IPP_TAG_EVENT_NOTIFICATION);
   2293   else if (!_cups_strcasecmp(name, "language"))
   2294     return (IPP_TAG_LANGUAGE);
   2295   else if (!_cups_strcasecmp(name, "mimetype"))
   2296     return (IPP_TAG_MIMETYPE);
   2297   else if (!_cups_strcasecmp(name, "name"))
   2298     return (IPP_TAG_NAME);
   2299   else if (!_cups_strcasecmp(name, "text"))
   2300     return (IPP_TAG_TEXT);
   2301   else if (!_cups_strcasecmp(name, "begCollection"))
   2302     return (IPP_TAG_BEGIN_COLLECTION);
   2303   else
   2304     return (IPP_TAG_ZERO);
   2305 }
   2306 
   2307 
   2308 /*
   2309  * 'ipp_col_string()' - Convert a collection to a string.
   2310  */
   2311 
   2312 static size_t				/* O - Number of bytes */
   2313 ipp_col_string(ipp_t  *col,		/* I - Collection attribute */
   2314                char   *buffer,		/* I - Buffer or NULL */
   2315                size_t bufsize)		/* I - Size of buffer */
   2316 {
   2317   char			*bufptr,	/* Position in buffer */
   2318 			*bufend,	/* End of buffer */
   2319 			prefix = '{',	/* Prefix character */
   2320 			temp[256];	/* Temporary string */
   2321   ipp_attribute_t	*attr;		/* Current member attribute */
   2322 
   2323 
   2324   if (!col)
   2325   {
   2326     if (buffer)
   2327       *buffer = '\0';
   2328 
   2329     return (0);
   2330   }
   2331 
   2332   bufptr = buffer;
   2333   bufend = buffer + bufsize - 1;
   2334 
   2335   for (attr = col->attrs; attr; attr = attr->next)
   2336   {
   2337     if (!attr->name)
   2338       continue;
   2339 
   2340     if (buffer && bufptr < bufend)
   2341       *bufptr = prefix;
   2342     bufptr ++;
   2343     prefix = ' ';
   2344 
   2345     if (buffer && bufptr < bufend)
   2346       bufptr += snprintf(bufptr, (size_t)(bufend - bufptr + 1), "%s=", attr->name);
   2347     else
   2348       bufptr += strlen(attr->name) + 1;
   2349 
   2350     if (buffer && bufptr < bufend)
   2351       bufptr += ippAttributeString(attr, bufptr, (size_t)(bufend - bufptr + 1));
   2352     else
   2353       bufptr += ippAttributeString(attr, temp, sizeof(temp));
   2354   }
   2355 
   2356   if (prefix == '{')
   2357   {
   2358     if (buffer && bufptr < bufend)
   2359       *bufptr = prefix;
   2360     bufptr ++;
   2361   }
   2362 
   2363   if (buffer && bufptr < bufend)
   2364     *bufptr = '}';
   2365   bufptr ++;
   2366 
   2367   return ((size_t)(bufptr - buffer));
   2368 }
   2369