1/* 2 * "$Id: encode.c 11742 2014-03-26 21:14:15Z msweet $" 3 * 4 * Option encoding routines for CUPS. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 1997-2007 by Easy Software Products. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * which should have been included with this file. If this file is 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * This file is subject to the Apple OS-Developed Software exception. 16 */ 17 18/* 19 * Include necessary headers... 20 */ 21 22#include "cups-private.h" 23 24 25/* 26 * Local list of option names, the value tags they should use, and the list of 27 * supported operations... 28 * 29 * **** THIS LIST MUST BE SORTED BY ATTRIBUTE NAME **** 30 */ 31 32static const ipp_op_t ipp_job_creation[] = 33{ 34 IPP_OP_PRINT_JOB, 35 IPP_OP_PRINT_URI, 36 IPP_OP_VALIDATE_JOB, 37 IPP_OP_CREATE_JOB, 38 IPP_OP_HOLD_JOB, 39 IPP_OP_SET_JOB_ATTRIBUTES, 40 IPP_OP_CUPS_NONE 41}; 42 43static const ipp_op_t ipp_doc_creation[] = 44{ 45 IPP_OP_PRINT_JOB, 46 IPP_OP_PRINT_URI, 47 IPP_OP_SEND_DOCUMENT, 48 IPP_OP_SEND_URI, 49 IPP_OP_SET_JOB_ATTRIBUTES, 50 IPP_OP_SET_DOCUMENT_ATTRIBUTES, 51 IPP_OP_CUPS_NONE 52}; 53 54static const ipp_op_t ipp_sub_creation[] = 55{ 56 IPP_OP_PRINT_JOB, 57 IPP_OP_PRINT_URI, 58 IPP_OP_CREATE_JOB, 59 IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS, 60 IPP_OP_CREATE_JOB_SUBSCRIPTIONS, 61 IPP_OP_CUPS_NONE 62}; 63 64static const ipp_op_t ipp_all_print[] = 65{ 66 IPP_OP_PRINT_JOB, 67 IPP_OP_PRINT_URI, 68 IPP_OP_VALIDATE_JOB, 69 IPP_OP_CREATE_JOB, 70 IPP_OP_SEND_DOCUMENT, 71 IPP_OP_SEND_URI, 72 IPP_OP_CUPS_NONE 73}; 74 75static const ipp_op_t ipp_set_printer[] = 76{ 77 IPP_OP_SET_PRINTER_ATTRIBUTES, 78 IPP_OP_CUPS_ADD_MODIFY_PRINTER, 79 IPP_OP_CUPS_ADD_MODIFY_CLASS, 80 IPP_OP_CUPS_NONE 81}; 82 83static const ipp_op_t cups_schemes[] = 84{ 85 IPP_OP_CUPS_GET_DEVICES, 86 IPP_OP_CUPS_GET_PPDS, 87 IPP_OP_CUPS_NONE 88}; 89 90static const ipp_op_t cups_get_ppds[] = 91{ 92 IPP_OP_CUPS_GET_PPDS, 93 IPP_OP_CUPS_NONE 94}; 95 96static const ipp_op_t cups_ppd_name[] = 97{ 98 IPP_OP_CUPS_ADD_MODIFY_PRINTER, 99 IPP_OP_CUPS_GET_PPD, 100 IPP_OP_CUPS_NONE 101}; 102 103static const _ipp_option_t ipp_options[] = 104{ 105 { 1, "auth-info", IPP_TAG_TEXT, IPP_TAG_JOB }, 106 { 1, "auth-info-default", IPP_TAG_TEXT, IPP_TAG_PRINTER }, 107 { 1, "auth-info-required", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, 108 { 0, "blackplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, 109 { 0, "blackplot-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, 110 { 0, "brightness", IPP_TAG_INTEGER, IPP_TAG_JOB }, 111 { 0, "brightness-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 112 { 0, "columns", IPP_TAG_INTEGER, IPP_TAG_JOB }, 113 { 0, "columns-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 114 { 0, "compression", IPP_TAG_KEYWORD, IPP_TAG_OPERATION, 115 IPP_TAG_ZERO, 116 ipp_doc_creation }, 117 { 0, "copies", IPP_TAG_INTEGER, IPP_TAG_JOB, 118 IPP_TAG_DOCUMENT }, 119 { 0, "copies-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 120 { 0, "device-uri", IPP_TAG_URI, IPP_TAG_PRINTER }, 121 { 1, "document-copies", IPP_TAG_RANGE, IPP_TAG_JOB, 122 IPP_TAG_DOCUMENT, 123 ipp_doc_creation }, 124 { 0, "document-format", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION, 125 IPP_TAG_ZERO, 126 ipp_doc_creation }, 127 { 0, "document-format-default", IPP_TAG_MIMETYPE, IPP_TAG_PRINTER }, 128 { 1, "document-numbers", IPP_TAG_RANGE, IPP_TAG_JOB, 129 IPP_TAG_DOCUMENT, 130 ipp_all_print }, 131 { 1, "exclude-schemes", IPP_TAG_NAME, IPP_TAG_OPERATION, 132 IPP_TAG_ZERO, 133 cups_schemes }, 134 { 1, "finishings", IPP_TAG_ENUM, IPP_TAG_JOB, 135 IPP_TAG_DOCUMENT }, 136 { 1, "finishings-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, 137 { 0, "fit-to-page", IPP_TAG_BOOLEAN, IPP_TAG_JOB, 138 IPP_TAG_DOCUMENT }, 139 { 0, "fit-to-page-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, 140 { 0, "fitplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, 141 { 0, "fitplot-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, 142 { 0, "gamma", IPP_TAG_INTEGER, IPP_TAG_JOB }, 143 { 0, "gamma-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 144 { 0, "hue", IPP_TAG_INTEGER, IPP_TAG_JOB }, 145 { 0, "hue-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 146 { 1, "include-schemes", IPP_TAG_NAME, IPP_TAG_OPERATION, 147 IPP_TAG_ZERO, 148 cups_schemes }, 149 { 0, "job-account-id", IPP_TAG_NAME, IPP_TAG_JOB }, 150 { 0, "job-account-id-default",IPP_TAG_NAME, IPP_TAG_PRINTER }, 151 { 0, "job-accounting-user-id", IPP_TAG_NAME, IPP_TAG_JOB }, 152 { 0, "job-accounting-user-id-default", IPP_TAG_NAME, IPP_TAG_PRINTER }, 153 { 0, "job-authorization-uri", IPP_TAG_URI, IPP_TAG_OPERATION }, 154 { 0, "job-cancel-after", IPP_TAG_INTEGER, IPP_TAG_JOB }, 155 { 0, "job-cancel-after-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 156 { 0, "job-hold-until", IPP_TAG_KEYWORD, IPP_TAG_JOB }, 157 { 0, "job-id", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 158 { 0, "job-impressions", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 159 { 0, "job-impressions-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 160 { 0, "job-k-limit", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 161 { 0, "job-k-octets", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 162 { 0, "job-k-octets-completed",IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 163 { 0, "job-media-sheets", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 164 { 0, "job-media-sheets-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 165 { 0, "job-page-limit", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 166 { 0, "job-password", IPP_TAG_STRING, IPP_TAG_OPERATION, 167 IPP_TAG_ZERO, 168 ipp_job_creation }, 169 { 0, "job-password-encryption", IPP_TAG_KEYWORD, IPP_TAG_OPERATION, 170 IPP_TAG_ZERO, 171 ipp_job_creation }, 172 { 0, "job-priority", IPP_TAG_INTEGER, IPP_TAG_JOB }, 173 { 0, "job-quota-period", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 174 { 1, "job-sheets", IPP_TAG_NAME, IPP_TAG_JOB }, 175 { 1, "job-sheets-default", IPP_TAG_NAME, IPP_TAG_PRINTER }, 176 { 0, "job-state", IPP_TAG_ENUM, IPP_TAG_ZERO }, /* never send as option */ 177 { 0, "job-state-message", IPP_TAG_TEXT, IPP_TAG_ZERO }, /* never send as option */ 178 { 0, "job-state-reasons", IPP_TAG_KEYWORD, IPP_TAG_ZERO }, /* never send as option */ 179 { 0, "job-uuid", IPP_TAG_URI, IPP_TAG_JOB }, 180 { 0, "landscape", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, 181 { 1, "marker-change-time", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 182 { 1, "marker-colors", IPP_TAG_NAME, IPP_TAG_PRINTER }, 183 { 1, "marker-high-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 184 { 1, "marker-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 185 { 1, "marker-low-levels", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 186 { 0, "marker-message", IPP_TAG_TEXT, IPP_TAG_PRINTER }, 187 { 1, "marker-names", IPP_TAG_NAME, IPP_TAG_PRINTER }, 188 { 1, "marker-types", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, 189 { 1, "media", IPP_TAG_KEYWORD, IPP_TAG_JOB, 190 IPP_TAG_DOCUMENT }, 191 { 0, "media-col", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB, 192 IPP_TAG_DOCUMENT }, 193 { 0, "media-col-default", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER }, 194 { 0, "media-color", IPP_TAG_KEYWORD, IPP_TAG_JOB, 195 IPP_TAG_DOCUMENT }, 196 { 1, "media-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, 197 { 0, "media-key", IPP_TAG_KEYWORD, IPP_TAG_JOB, 198 IPP_TAG_DOCUMENT }, 199 { 0, "media-size", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB, 200 IPP_TAG_DOCUMENT }, 201 { 0, "media-type", IPP_TAG_KEYWORD, IPP_TAG_JOB, 202 IPP_TAG_DOCUMENT }, 203 { 0, "mirror", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, 204 { 0, "mirror-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, 205 { 0, "natural-scaling", IPP_TAG_INTEGER, IPP_TAG_JOB }, 206 { 0, "natural-scaling-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 207 { 0, "notify-charset", IPP_TAG_CHARSET, IPP_TAG_SUBSCRIPTION }, 208 { 1, "notify-events", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION }, 209 { 1, "notify-events-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, 210 { 0, "notify-lease-duration", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION }, 211 { 0, "notify-lease-duration-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 212 { 0, "notify-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_SUBSCRIPTION }, 213 { 0, "notify-pull-method", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION }, 214 { 0, "notify-recipient-uri", IPP_TAG_URI, IPP_TAG_SUBSCRIPTION }, 215 { 0, "notify-time-interval", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION }, 216 { 0, "notify-user-data", IPP_TAG_STRING, IPP_TAG_SUBSCRIPTION }, 217 { 0, "number-up", IPP_TAG_INTEGER, IPP_TAG_JOB, 218 IPP_TAG_DOCUMENT }, 219 { 0, "number-up-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 220 { 0, "orientation-requested", IPP_TAG_ENUM, IPP_TAG_JOB, 221 IPP_TAG_DOCUMENT }, 222 { 0, "orientation-requested-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, 223 { 1, "overrides", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB, 224 IPP_TAG_DOCUMENT }, 225 { 0, "page-bottom", IPP_TAG_INTEGER, IPP_TAG_JOB }, 226 { 0, "page-bottom-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 227 { 0, "page-left", IPP_TAG_INTEGER, IPP_TAG_JOB }, 228 { 0, "page-left-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 229 { 1, "page-ranges", IPP_TAG_RANGE, IPP_TAG_JOB, 230 IPP_TAG_DOCUMENT }, 231 { 1, "page-ranges-default", IPP_TAG_RANGE, IPP_TAG_PRINTER }, 232 { 0, "page-right", IPP_TAG_INTEGER, IPP_TAG_JOB }, 233 { 0, "page-right-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 234 { 0, "page-top", IPP_TAG_INTEGER, IPP_TAG_JOB }, 235 { 0, "page-top-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 236 { 1, "pages", IPP_TAG_RANGE, IPP_TAG_JOB, 237 IPP_TAG_DOCUMENT }, 238 { 0, "penwidth", IPP_TAG_INTEGER, IPP_TAG_JOB }, 239 { 0, "penwidth-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 240 { 0, "port-monitor", IPP_TAG_NAME, IPP_TAG_PRINTER }, 241 { 0, "ppd-device-id", IPP_TAG_TEXT, IPP_TAG_OPERATION, 242 IPP_TAG_ZERO, 243 cups_get_ppds }, 244 { 0, "ppd-make", IPP_TAG_TEXT, IPP_TAG_OPERATION, 245 IPP_TAG_ZERO, 246 cups_get_ppds }, 247 { 0, "ppd-make-and-model", IPP_TAG_TEXT, IPP_TAG_OPERATION, 248 IPP_TAG_ZERO, 249 cups_get_ppds }, 250 { 0, "ppd-model-number", IPP_TAG_INTEGER, IPP_TAG_OPERATION, 251 IPP_TAG_ZERO, 252 cups_get_ppds }, 253 { 0, "ppd-name", IPP_TAG_NAME, IPP_TAG_OPERATION, 254 IPP_TAG_ZERO, 255 cups_ppd_name }, 256 { 0, "ppd-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_OPERATION, 257 IPP_TAG_ZERO, 258 cups_get_ppds }, 259 { 0, "ppd-product", IPP_TAG_TEXT, IPP_TAG_OPERATION, 260 IPP_TAG_ZERO, 261 cups_get_ppds }, 262 { 0, "ppd-psversion", IPP_TAG_TEXT, IPP_TAG_OPERATION, 263 IPP_TAG_ZERO, 264 cups_get_ppds }, 265 { 0, "ppd-type", IPP_TAG_KEYWORD, IPP_TAG_OPERATION, 266 IPP_TAG_ZERO, 267 cups_get_ppds }, 268 { 0, "ppi", IPP_TAG_INTEGER, IPP_TAG_JOB }, 269 { 0, "ppi-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 270 { 0, "prettyprint", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, 271 { 0, "prettyprint-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, 272 { 0, "print-quality", IPP_TAG_ENUM, IPP_TAG_JOB, 273 IPP_TAG_DOCUMENT }, 274 { 0, "print-quality-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, 275 { 1, "printer-commands", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, 276 { 0, "printer-error-policy", IPP_TAG_NAME, IPP_TAG_PRINTER }, 277 { 0, "printer-info", IPP_TAG_TEXT, IPP_TAG_PRINTER }, 278 { 0, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, 279 { 0, "printer-is-shared", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, 280 { 0, "printer-location", IPP_TAG_TEXT, IPP_TAG_PRINTER }, 281 { 0, "printer-make-and-model", IPP_TAG_TEXT, IPP_TAG_PRINTER }, 282 { 0, "printer-more-info", IPP_TAG_URI, IPP_TAG_PRINTER }, 283 { 0, "printer-op-policy", IPP_TAG_NAME, IPP_TAG_PRINTER }, 284 { 0, "printer-resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB, 285 IPP_TAG_DOCUMENT }, 286 { 0, "printer-state", IPP_TAG_ENUM, IPP_TAG_PRINTER }, 287 { 0, "printer-state-change-time", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 288 { 1, "printer-state-reasons", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, 289 { 0, "printer-type", IPP_TAG_ENUM, IPP_TAG_PRINTER }, 290 { 0, "printer-uri", IPP_TAG_URI, IPP_TAG_OPERATION }, 291 { 1, "printer-uri-supported", IPP_TAG_URI, IPP_TAG_PRINTER }, 292 { 0, "queued-job-count", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 293 { 0, "raw", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION }, 294 { 1, "requested-attributes", IPP_TAG_NAME, IPP_TAG_OPERATION }, 295 { 1, "requesting-user-name-allowed", IPP_TAG_NAME, IPP_TAG_PRINTER }, 296 { 1, "requesting-user-name-denied", IPP_TAG_NAME, IPP_TAG_PRINTER }, 297 { 0, "resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB }, 298 { 0, "resolution-default", IPP_TAG_RESOLUTION, IPP_TAG_PRINTER }, 299 { 0, "saturation", IPP_TAG_INTEGER, IPP_TAG_JOB }, 300 { 0, "saturation-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 301 { 0, "scaling", IPP_TAG_INTEGER, IPP_TAG_JOB }, 302 { 0, "scaling-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, 303 { 0, "sides", IPP_TAG_KEYWORD, IPP_TAG_JOB, 304 IPP_TAG_DOCUMENT }, 305 { 0, "sides-default", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, 306 { 0, "time-at-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 307 { 0, "time-at-creation", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 308 { 0, "time-at-processing", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */ 309 { 0, "wrap", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, 310 { 0, "wrap-default", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, 311 { 0, "x-dimension", IPP_TAG_INTEGER, IPP_TAG_JOB, 312 IPP_TAG_DOCUMENT }, 313 { 0, "y-dimension", IPP_TAG_INTEGER, IPP_TAG_JOB, 314 IPP_TAG_DOCUMENT } 315}; 316 317 318/* 319 * Local functions... 320 */ 321 322static int compare_ipp_options(_ipp_option_t *a, _ipp_option_t *b); 323 324 325/* 326 * 'cupsEncodeOptions()' - Encode printer options into IPP attributes. 327 * 328 * This function adds operation, job, and then subscription attributes, 329 * in that order. Use the cupsEncodeOptions2() function to add attributes 330 * for a single group. 331 */ 332 333void 334cupsEncodeOptions(ipp_t *ipp, /* I - Request to add to */ 335 int num_options, /* I - Number of options */ 336 cups_option_t *options) /* I - Options */ 337{ 338 DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)", ipp, num_options, options)); 339 340 /* 341 * Add the options in the proper groups & order... 342 */ 343 344 cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_OPERATION); 345 cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_JOB); 346 cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_SUBSCRIPTION); 347} 348 349 350/* 351 * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group. 352 * 353 * This function only adds attributes for a single group. Call this 354 * function multiple times for each group, or use cupsEncodeOptions() 355 * to add the standard groups. 356 * 357 * @since CUPS 1.2/OS X 10.5@ 358 */ 359 360void 361cupsEncodeOptions2( 362 ipp_t *ipp, /* I - Request to add to */ 363 int num_options, /* I - Number of options */ 364 cups_option_t *options, /* I - Options */ 365 ipp_tag_t group_tag) /* I - Group to encode */ 366{ 367 int i, j; /* Looping vars */ 368 int count; /* Number of values */ 369 char *s, /* Pointer into option value */ 370 *val, /* Pointer to option value */ 371 *copy, /* Copy of option value */ 372 *sep, /* Option separator */ 373 quote; /* Quote character */ 374 ipp_attribute_t *attr; /* IPP attribute */ 375 ipp_tag_t value_tag; /* IPP value tag */ 376 cups_option_t *option; /* Current option */ 377 ipp_t *collection; /* Collection value */ 378 int num_cols; /* Number of collection values */ 379 cups_option_t *cols; /* Collection values */ 380 ipp_op_t op; /* Operation for this request */ 381 const ipp_op_t *ops; /* List of allowed operations */ 382 383 384 DEBUG_printf(("cupsEncodeOptions2(ipp=%p(%s), num_options=%d, options=%p, " 385 "group_tag=%x)", ipp, 386 ipp ? ippOpString(ippGetOperation(ipp)) : "", num_options, 387 options, group_tag)); 388 389 /* 390 * Range check input... 391 */ 392 393 if (!ipp || num_options < 1 || !options) 394 return; 395 396 /* 397 * Do special handling for the document-format/raw options... 398 */ 399 400 op = ippGetOperation(ipp); 401 402 if (group_tag == IPP_TAG_OPERATION && 403 (op == IPP_OP_PRINT_JOB || op == IPP_OP_PRINT_URI || 404 op == IPP_OP_SEND_DOCUMENT || op == IPP_OP_SEND_URI)) 405 { 406 /* 407 * Handle the document format stuff first... 408 */ 409 410 if ((val = (char *)cupsGetOption("document-format", num_options, 411 options)) != NULL) 412 ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", 413 NULL, val); 414 else if (cupsGetOption("raw", num_options, options)) 415 ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", 416 NULL, "application/vnd.cups-raw"); 417 else 418 ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", 419 NULL, "application/octet-stream"); 420 } 421 422 /* 423 * Then loop through the options... 424 */ 425 426 for (i = num_options, option = options; i > 0; i --, option ++) 427 { 428 _ipp_option_t *match; /* Matching attribute */ 429 430 431 /* 432 * Skip document format options that are handled above... 433 */ 434 435 if (!_cups_strcasecmp(option->name, "raw") || 436 !_cups_strcasecmp(option->name, "document-format") || 437 !option->name[0]) 438 continue; 439 440 /* 441 * Figure out the proper value and group tags for this option... 442 */ 443 444 if ((match = _ippFindOption(option->name)) != NULL) 445 { 446 if (match->group_tag != group_tag && match->alt_group_tag != group_tag) 447 continue; 448 449 value_tag = match->value_tag; 450 451 if (match->operations) 452 ops = match->operations; 453 else if (group_tag == IPP_TAG_JOB) 454 ops = ipp_job_creation; 455 else if (group_tag == IPP_TAG_DOCUMENT) 456 ops = ipp_doc_creation; 457 else if (group_tag == IPP_TAG_SUBSCRIPTION) 458 ops = ipp_sub_creation; 459 else if (group_tag == IPP_TAG_PRINTER) 460 ops = ipp_set_printer; 461 else 462 { 463 DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); 464 continue; 465 } 466 } 467 else 468 { 469 int namelen; /* Length of name */ 470 471 472 namelen = (int)strlen(option->name); 473 474 if (namelen < 10 || 475 (strcmp(option->name + namelen - 8, "-default") && 476 strcmp(option->name + namelen - 10, "-supported"))) 477 { 478 if (group_tag != IPP_TAG_JOB && group_tag != IPP_TAG_DOCUMENT) 479 { 480 DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); 481 continue; 482 } 483 } 484 else if (group_tag != IPP_TAG_PRINTER) 485 { 486 DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); 487 continue; 488 } 489 490 if (group_tag == IPP_TAG_JOB) 491 ops = ipp_job_creation; 492 else if (group_tag == IPP_TAG_DOCUMENT) 493 ops = ipp_doc_creation; 494 else 495 ops = ipp_set_printer; 496 497 if (!_cups_strcasecmp(option->value, "true") || 498 !_cups_strcasecmp(option->value, "false")) 499 value_tag = IPP_TAG_BOOLEAN; 500 else 501 value_tag = IPP_TAG_NAME; 502 } 503 504 /* 505 * Verify that we send this attribute for this operation... 506 */ 507 508 while (*ops != IPP_OP_CUPS_NONE) 509 if (op == *ops) 510 break; 511 else 512 ops ++; 513 514 if (*ops == IPP_OP_CUPS_NONE && op != IPP_OP_CUPS_NONE) 515 { 516 DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); 517 continue; 518 } 519 520 /* 521 * Count the number of values... 522 */ 523 524 if (match && match->multivalue) 525 { 526 for (count = 1, sep = option->value, quote = 0; *sep; sep ++) 527 { 528 if (*sep == quote) 529 quote = 0; 530 else if (!quote && (*sep == '\'' || *sep == '\"')) 531 { 532 /* 533 * Skip quoted option value... 534 */ 535 536 quote = *sep++; 537 } 538 else if (*sep == ',' && !quote) 539 count ++; 540 else if (*sep == '\\' && sep[1]) 541 sep ++; 542 } 543 } 544 else 545 count = 1; 546 547 DEBUG_printf(("2cupsEncodeOptions2: option=\"%s\", count=%d", 548 option->name, count)); 549 550 /* 551 * Allocate memory for the attribute values... 552 */ 553 554 if ((attr = ippAddStrings(ipp, group_tag, value_tag, option->name, count, 555 NULL, NULL)) == NULL) 556 { 557 /* 558 * Ran out of memory! 559 */ 560 561 DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for attributes!"); 562 return; 563 } 564 565 if (count > 1) 566 { 567 /* 568 * Make a copy of the value we can fiddle with... 569 */ 570 571 if ((copy = strdup(option->value)) == NULL) 572 { 573 /* 574 * Ran out of memory! 575 */ 576 577 DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for value copy!"); 578 ippDeleteAttribute(ipp, attr); 579 return; 580 } 581 582 val = copy; 583 } 584 else 585 { 586 /* 587 * Since we have a single value, use the value directly... 588 */ 589 590 val = option->value; 591 copy = NULL; 592 } 593 594 /* 595 * Scan the value string for values... 596 */ 597 598 for (j = 0, sep = val; j < count; val = sep, j ++) 599 { 600 /* 601 * Find the end of this value and mark it if needed... 602 */ 603 604 if (count > 1) 605 { 606 for (quote = 0; *sep; sep ++) 607 { 608 if (*sep == quote) 609 { 610 /* 611 * Finish quoted value... 612 */ 613 614 quote = 0; 615 } 616 else if (!quote && (*sep == '\'' || *sep == '\"')) 617 { 618 /* 619 * Handle quoted option value... 620 */ 621 622 quote = *sep; 623 } 624 else if (*sep == ',' && count > 1) 625 break; 626 else if (*sep == '\\' && sep[1]) 627 { 628 /* 629 * Skip quoted character... 630 */ 631 632 sep ++; 633 } 634 } 635 636 if (*sep == ',') 637 *sep++ = '\0'; 638 } 639 640 /* 641 * Copy the option value(s) over as needed by the type... 642 */ 643 644 switch (attr->value_tag) 645 { 646 case IPP_TAG_INTEGER : 647 case IPP_TAG_ENUM : 648 /* 649 * Integer/enumeration value... 650 */ 651 652 attr->values[j].integer = (int)strtol(val, &s, 10); 653 654 DEBUG_printf(("2cupsEncodeOptions2: Added integer option value " 655 "%d...", attr->values[j].integer)); 656 break; 657 658 case IPP_TAG_BOOLEAN : 659 if (!_cups_strcasecmp(val, "true") || 660 !_cups_strcasecmp(val, "on") || 661 !_cups_strcasecmp(val, "yes")) 662 { 663 /* 664 * Boolean value - true... 665 */ 666 667 attr->values[j].boolean = 1; 668 669 DEBUG_puts("2cupsEncodeOptions2: Added boolean true value..."); 670 } 671 else 672 { 673 /* 674 * Boolean value - false... 675 */ 676 677 attr->values[j].boolean = 0; 678 679 DEBUG_puts("2cupsEncodeOptions2: Added boolean false value..."); 680 } 681 break; 682 683 case IPP_TAG_RANGE : 684 /* 685 * Range... 686 */ 687 688 if (*val == '-') 689 { 690 attr->values[j].range.lower = 1; 691 s = val; 692 } 693 else 694 attr->values[j].range.lower = (int)strtol(val, &s, 10); 695 696 if (*s == '-') 697 { 698 if (s[1]) 699 attr->values[j].range.upper = (int)strtol(s + 1, NULL, 10); 700 else 701 attr->values[j].range.upper = 2147483647; 702 } 703 else 704 attr->values[j].range.upper = attr->values[j].range.lower; 705 706 DEBUG_printf(("2cupsEncodeOptions2: Added range option value " 707 "%d-%d...", attr->values[j].range.lower, 708 attr->values[j].range.upper)); 709 break; 710 711 case IPP_TAG_RESOLUTION : 712 /* 713 * Resolution... 714 */ 715 716 attr->values[j].resolution.xres = (int)strtol(val, &s, 10); 717 718 if (*s == 'x') 719 attr->values[j].resolution.yres = (int)strtol(s + 1, &s, 10); 720 else 721 attr->values[j].resolution.yres = attr->values[j].resolution.xres; 722 723 if (!_cups_strcasecmp(s, "dpc") || 724 !_cups_strcasecmp(s, "dpcm")) 725 attr->values[j].resolution.units = IPP_RES_PER_CM; 726 else 727 attr->values[j].resolution.units = IPP_RES_PER_INCH; 728 729 DEBUG_printf(("2cupsEncodeOptions2: Added resolution option value " 730 "%s...", val)); 731 break; 732 733 case IPP_TAG_STRING : 734 /* 735 * octet-string 736 */ 737 738 attr->values[j].unknown.length = (int)strlen(val); 739 attr->values[j].unknown.data = strdup(val); 740 741 DEBUG_printf(("2cupsEncodeOptions2: Added octet-string value " 742 "\"%s\"...", (char *)attr->values[j].unknown.data)); 743 break; 744 745 case IPP_TAG_BEGIN_COLLECTION : 746 /* 747 * Collection value 748 */ 749 750 num_cols = cupsParseOptions(val, 0, &cols); 751 if ((collection = ippNew()) == NULL) 752 { 753 cupsFreeOptions(num_cols, cols); 754 755 if (copy) 756 free(copy); 757 758 ippDeleteAttribute(ipp, attr); 759 return; 760 } 761 762 attr->values[j].collection = collection; 763 cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB); 764 cupsFreeOptions(num_cols, cols); 765 break; 766 767 default : 768 if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL) 769 { 770 /* 771 * Ran out of memory! 772 */ 773 774 DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for string!"); 775 776 if (copy) 777 free(copy); 778 779 ippDeleteAttribute(ipp, attr); 780 return; 781 } 782 783 DEBUG_printf(("2cupsEncodeOptions2: Added string value \"%s\"...", 784 val)); 785 break; 786 } 787 } 788 789 if (copy) 790 free(copy); 791 } 792} 793 794 795#ifdef DEBUG 796/* 797 * '_ippCheckOptions()' - Validate that the option array is sorted properly. 798 */ 799 800const char * /* O - First out-of-order option or NULL */ 801_ippCheckOptions(void) 802{ 803 int i; /* Looping var */ 804 805 806 for (i = 0; i < (int)(sizeof(ipp_options) / sizeof(ipp_options[0]) - 1); i ++) 807 if (strcmp(ipp_options[i].name, ipp_options[i + 1].name) >= 0) 808 return (ipp_options[i + 1].name); 809 810 return (NULL); 811} 812#endif /* DEBUG */ 813 814 815/* 816 * '_ippFindOption()' - Find the attribute information for an option. 817 */ 818 819_ipp_option_t * /* O - Attribute information */ 820_ippFindOption(const char *name) /* I - Option/attribute name */ 821{ 822 _ipp_option_t key; /* Search key */ 823 824 825 /* 826 * Lookup the proper value and group tags for this option... 827 */ 828 829 key.name = name; 830 831 return ((_ipp_option_t *)bsearch(&key, ipp_options, 832 sizeof(ipp_options) / sizeof(ipp_options[0]), 833 sizeof(ipp_options[0]), 834 (int (*)(const void *, const void *)) 835 compare_ipp_options)); 836} 837 838 839/* 840 * 'compare_ipp_options()' - Compare two IPP options. 841 */ 842 843static int /* O - Result of comparison */ 844compare_ipp_options(_ipp_option_t *a, /* I - First option */ 845 _ipp_option_t *b) /* I - Second option */ 846{ 847 return (strcmp(a->name, b->name)); 848} 849 850 851/* 852 * End of "$Id: encode.c 11742 2014-03-26 21:14:15Z msweet $". 853 */ 854