1 /* 2 * Internet Printing Protocol 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 #include <regex.h> 22 #ifdef WIN32 23 # include <io.h> 24 #endif /* WIN32 */ 25 26 27 /* 28 * Local functions... 29 */ 30 31 static ipp_attribute_t *ipp_add_attr(ipp_t *ipp, const char *name, 32 ipp_tag_t group_tag, ipp_tag_t value_tag, 33 int num_values); 34 static void ipp_free_values(ipp_attribute_t *attr, int element, 35 int count); 36 static char *ipp_get_code(const char *locale, char *buffer, 37 size_t bufsize) 38 __attribute__((nonnull(1,2))); 39 static char *ipp_lang_code(const char *locale, char *buffer, 40 size_t bufsize) 41 __attribute__((nonnull(1,2))); 42 static size_t ipp_length(ipp_t *ipp, int collection); 43 static ssize_t ipp_read_http(http_t *http, ipp_uchar_t *buffer, 44 size_t length); 45 static ssize_t ipp_read_file(int *fd, ipp_uchar_t *buffer, 46 size_t length); 47 static void ipp_set_error(ipp_status_t status, const char *format, 48 ...); 49 static _ipp_value_t *ipp_set_value(ipp_t *ipp, ipp_attribute_t **attr, 50 int element); 51 static ssize_t ipp_write_file(int *fd, ipp_uchar_t *buffer, 52 size_t length); 53 54 55 /* 56 * '_cupsBufferGet()' - Get a read/write buffer. 57 */ 58 59 char * /* O - Buffer */ 60 _cupsBufferGet(size_t size) /* I - Size required */ 61 { 62 _cups_buffer_t *buffer; /* Current buffer */ 63 _cups_globals_t *cg = _cupsGlobals(); 64 /* Global data */ 65 66 67 for (buffer = cg->cups_buffers; buffer; buffer = buffer->next) 68 if (!buffer->used && buffer->size >= size) 69 break; 70 71 if (!buffer) 72 { 73 if ((buffer = malloc(sizeof(_cups_buffer_t) + size - 1)) == NULL) 74 return (NULL); 75 76 buffer->next = cg->cups_buffers; 77 buffer->size = size; 78 cg->cups_buffers = buffer; 79 } 80 81 buffer->used = 1; 82 83 return (buffer->d); 84 } 85 86 87 /* 88 * '_cupsBufferRelease()' - Release a read/write buffer. 89 */ 90 91 void 92 _cupsBufferRelease(char *b) /* I - Buffer to release */ 93 { 94 _cups_buffer_t *buffer; /* Buffer */ 95 96 97 /* 98 * Mark this buffer as unused... 99 */ 100 101 buffer = (_cups_buffer_t *)(b - offsetof(_cups_buffer_t, d)); 102 buffer->used = 0; 103 } 104 105 106 /* 107 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message. 108 * 109 * The @code ipp@ parameter refers to an IPP message previously created using 110 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 111 * 112 * The @code group@ parameter specifies the IPP attribute group tag: none 113 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 114 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 115 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 116 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 117 */ 118 119 ipp_attribute_t * /* O - New attribute */ 120 ippAddBoolean(ipp_t *ipp, /* I - IPP message */ 121 ipp_tag_t group, /* I - IPP group */ 122 const char *name, /* I - Name of attribute */ 123 char value) /* I - Value of attribute */ 124 { 125 ipp_attribute_t *attr; /* New attribute */ 126 127 128 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)", (void *)ipp, group, ippTagString(group), name, value)); 129 130 /* 131 * Range check input... 132 */ 133 134 if (!ipp || !name || group < IPP_TAG_ZERO || 135 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) 136 return (NULL); 137 138 /* 139 * Create the attribute... 140 */ 141 142 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, 1)) == NULL) 143 return (NULL); 144 145 attr->values[0].boolean = value; 146 147 return (attr); 148 } 149 150 151 /* 152 * 'ippAddBooleans()' - Add an array of boolean values. 153 * 154 * The @code ipp@ parameter refers to an IPP message previously created using 155 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 156 * 157 * The @code group@ parameter specifies the IPP attribute group tag: none 158 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 159 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 160 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 161 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 162 */ 163 164 ipp_attribute_t * /* O - New attribute */ 165 ippAddBooleans(ipp_t *ipp, /* I - IPP message */ 166 ipp_tag_t group, /* I - IPP group */ 167 const char *name, /* I - Name of attribute */ 168 int num_values, /* I - Number of values */ 169 const char *values) /* I - Values */ 170 { 171 int i; /* Looping var */ 172 ipp_attribute_t *attr; /* New attribute */ 173 _ipp_value_t *value; /* Current value */ 174 175 176 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)values)); 177 178 /* 179 * Range check input... 180 */ 181 182 if (!ipp || !name || group < IPP_TAG_ZERO || 183 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 184 num_values < 1) 185 return (NULL); 186 187 /* 188 * Create the attribute... 189 */ 190 191 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, num_values)) == NULL) 192 return (NULL); 193 194 if (values) 195 { 196 for (i = num_values, value = attr->values; 197 i > 0; 198 i --, value ++) 199 value->boolean = *values++; 200 } 201 202 return (attr); 203 } 204 205 206 /* 207 * 'ippAddCollection()' - Add a collection value. 208 * 209 * The @code ipp@ parameter refers to an IPP message previously created using 210 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 211 * 212 * The @code group@ parameter specifies the IPP attribute group tag: none 213 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 214 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 215 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 216 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 217 * 218 * @since CUPS 1.1.19/macOS 10.3@ 219 */ 220 221 ipp_attribute_t * /* O - New attribute */ 222 ippAddCollection(ipp_t *ipp, /* I - IPP message */ 223 ipp_tag_t group, /* I - IPP group */ 224 const char *name, /* I - Name of attribute */ 225 ipp_t *value) /* I - Value */ 226 { 227 ipp_attribute_t *attr; /* New attribute */ 228 229 230 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)", (void *)ipp, group, ippTagString(group), name, (void *)value)); 231 232 /* 233 * Range check input... 234 */ 235 236 if (!ipp || !name || group < IPP_TAG_ZERO || 237 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) 238 return (NULL); 239 240 /* 241 * Create the attribute... 242 */ 243 244 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION, 1)) == NULL) 245 return (NULL); 246 247 attr->values[0].collection = value; 248 249 if (value) 250 value->use ++; 251 252 return (attr); 253 } 254 255 256 /* 257 * 'ippAddCollections()' - Add an array of collection values. 258 * 259 * The @code ipp@ parameter refers to an IPP message previously created using 260 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 261 * 262 * The @code group@ parameter specifies the IPP attribute group tag: none 263 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 264 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 265 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 266 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 267 * 268 * @since CUPS 1.1.19/macOS 10.3@ 269 */ 270 271 ipp_attribute_t * /* O - New attribute */ 272 ippAddCollections( 273 ipp_t *ipp, /* I - IPP message */ 274 ipp_tag_t group, /* I - IPP group */ 275 const char *name, /* I - Name of attribute */ 276 int num_values, /* I - Number of values */ 277 const ipp_t **values) /* I - Values */ 278 { 279 int i; /* Looping var */ 280 ipp_attribute_t *attr; /* New attribute */ 281 _ipp_value_t *value; /* Current value */ 282 283 284 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)values)); 285 286 /* 287 * Range check input... 288 */ 289 290 if (!ipp || !name || group < IPP_TAG_ZERO || 291 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 292 num_values < 1) 293 return (NULL); 294 295 /* 296 * Create the attribute... 297 */ 298 299 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION, 300 num_values)) == NULL) 301 return (NULL); 302 303 if (values) 304 { 305 for (i = num_values, value = attr->values; 306 i > 0; 307 i --, value ++) 308 { 309 value->collection = (ipp_t *)*values++; 310 value->collection->use ++; 311 } 312 } 313 314 return (attr); 315 } 316 317 318 /* 319 * 'ippAddDate()' - Add a dateTime attribute to an IPP message. 320 * 321 * The @code ipp@ parameter refers to an IPP message previously created using 322 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 323 * 324 * The @code group@ parameter specifies the IPP attribute group tag: none 325 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 326 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 327 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 328 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 329 */ 330 331 ipp_attribute_t * /* O - New attribute */ 332 ippAddDate(ipp_t *ipp, /* I - IPP message */ 333 ipp_tag_t group, /* I - IPP group */ 334 const char *name, /* I - Name of attribute */ 335 const ipp_uchar_t *value) /* I - Value */ 336 { 337 ipp_attribute_t *attr; /* New attribute */ 338 339 340 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)", (void *)ipp, group, ippTagString(group), name, (void *)value)); 341 342 /* 343 * Range check input... 344 */ 345 346 if (!ipp || !name || !value || group < IPP_TAG_ZERO || 347 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) 348 return (NULL); 349 350 /* 351 * Create the attribute... 352 */ 353 354 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_DATE, 1)) == NULL) 355 return (NULL); 356 357 memcpy(attr->values[0].date, value, 11); 358 359 return (attr); 360 } 361 362 363 /* 364 * 'ippAddInteger()' - Add a integer attribute to an IPP message. 365 * 366 * The @code ipp@ parameter refers to an IPP message previously created using 367 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 368 * 369 * The @code group@ parameter specifies the IPP attribute group tag: none 370 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 371 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 372 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 373 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 374 * 375 * Supported values include enum (@code IPP_TAG_ENUM@) and integer 376 * (@code IPP_TAG_INTEGER@). 377 */ 378 379 ipp_attribute_t * /* O - New attribute */ 380 ippAddInteger(ipp_t *ipp, /* I - IPP message */ 381 ipp_tag_t group, /* I - IPP group */ 382 ipp_tag_t value_tag, /* I - Type of attribute */ 383 const char *name, /* I - Name of attribute */ 384 int value) /* I - Value of attribute */ 385 { 386 ipp_attribute_t *attr; /* New attribute */ 387 388 389 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), name=\"%s\", value=%d)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, value)); 390 391 value_tag &= IPP_TAG_CUPS_MASK; 392 393 /* 394 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand 395 * function... 396 */ 397 398 if (value_tag >= IPP_TAG_UNSUPPORTED_VALUE && value_tag <= IPP_TAG_ADMINDEFINE) 399 return (ippAddOutOfBand(ipp, group, value_tag, name)); 400 401 /* 402 * Range check input... 403 */ 404 405 #if 0 406 if (!ipp || !name || group < IPP_TAG_ZERO || 407 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 408 (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM)) 409 return (NULL); 410 #else 411 if (!ipp || !name || group < IPP_TAG_ZERO || 412 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) 413 return (NULL); 414 #endif /* 0 */ 415 416 /* 417 * Create the attribute... 418 */ 419 420 if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL) 421 return (NULL); 422 423 attr->values[0].integer = value; 424 425 return (attr); 426 } 427 428 429 /* 430 * 'ippAddIntegers()' - Add an array of integer values. 431 * 432 * The @code ipp@ parameter refers to an IPP message previously created using 433 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 434 * 435 * The @code group@ parameter specifies the IPP attribute group tag: none 436 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 437 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 438 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 439 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 440 * 441 * Supported values include enum (@code IPP_TAG_ENUM@) and integer 442 * (@code IPP_TAG_INTEGER@). 443 */ 444 445 ipp_attribute_t * /* O - New attribute */ 446 ippAddIntegers(ipp_t *ipp, /* I - IPP message */ 447 ipp_tag_t group, /* I - IPP group */ 448 ipp_tag_t value_tag, /* I - Type of attribute */ 449 const char *name, /* I - Name of attribute */ 450 int num_values, /* I - Number of values */ 451 const int *values) /* I - Values */ 452 { 453 int i; /* Looping var */ 454 ipp_attribute_t *attr; /* New attribute */ 455 _ipp_value_t *value; /* Current value */ 456 457 458 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, num_values, (void *)values)); 459 460 value_tag &= IPP_TAG_CUPS_MASK; 461 462 /* 463 * Range check input... 464 */ 465 466 #if 0 467 if (!ipp || !name || group < IPP_TAG_ZERO || 468 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 469 (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM) || 470 num_values < 1) 471 return (NULL); 472 #else 473 if (!ipp || !name || group < IPP_TAG_ZERO || 474 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 475 num_values < 1) 476 return (NULL); 477 #endif /* 0 */ 478 479 /* 480 * Create the attribute... 481 */ 482 483 if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL) 484 return (NULL); 485 486 if (values) 487 { 488 for (i = num_values, value = attr->values; 489 i > 0; 490 i --, value ++) 491 value->integer = *values++; 492 } 493 494 return (attr); 495 } 496 497 498 /* 499 * 'ippAddOctetString()' - Add an octetString value to an IPP message. 500 * 501 * The @code ipp@ parameter refers to an IPP message previously created using 502 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 503 * 504 * The @code group@ parameter specifies the IPP attribute group tag: none 505 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 506 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 507 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 508 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 509 * 510 * @since CUPS 1.2/macOS 10.5@ 511 */ 512 513 ipp_attribute_t * /* O - New attribute */ 514 ippAddOctetString(ipp_t *ipp, /* I - IPP message */ 515 ipp_tag_t group, /* I - IPP group */ 516 const char *name, /* I - Name of attribute */ 517 const void *data, /* I - octetString data */ 518 int datalen) /* I - Length of data in bytes */ 519 { 520 ipp_attribute_t *attr; /* New attribute */ 521 522 523 if (!ipp || !name || group < IPP_TAG_ZERO || 524 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 525 datalen < 0 || datalen > IPP_MAX_LENGTH) 526 return (NULL); 527 528 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_STRING, 1)) == NULL) 529 return (NULL); 530 531 /* 532 * Initialize the attribute data... 533 */ 534 535 attr->values[0].unknown.length = datalen; 536 537 if (data) 538 { 539 if ((attr->values[0].unknown.data = malloc((size_t)datalen)) == NULL) 540 { 541 ippDeleteAttribute(ipp, attr); 542 return (NULL); 543 } 544 545 memcpy(attr->values[0].unknown.data, data, (size_t)datalen); 546 } 547 548 /* 549 * Return the new attribute... 550 */ 551 552 return (attr); 553 } 554 555 556 /* 557 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message. 558 * 559 * The @code ipp@ parameter refers to an IPP message previously created using 560 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 561 * 562 * The @code group@ parameter specifies the IPP attribute group tag: none 563 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 564 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 565 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 566 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 567 * 568 * Supported out-of-band values include unsupported-value 569 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown 570 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable 571 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and 572 * admin-define (@code IPP_TAG_ADMINDEFINE@). 573 * 574 * @since CUPS 1.6/macOS 10.8@ 575 */ 576 577 ipp_attribute_t * /* O - New attribute */ 578 ippAddOutOfBand(ipp_t *ipp, /* I - IPP message */ 579 ipp_tag_t group, /* I - IPP group */ 580 ipp_tag_t value_tag, /* I - Type of attribute */ 581 const char *name) /* I - Name of attribute */ 582 { 583 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\")", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name)); 584 585 value_tag &= IPP_TAG_CUPS_MASK; 586 587 /* 588 * Range check input... 589 */ 590 591 if (!ipp || !name || group < IPP_TAG_ZERO || 592 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 593 (value_tag != IPP_TAG_UNSUPPORTED_VALUE && 594 value_tag != IPP_TAG_DEFAULT && 595 value_tag != IPP_TAG_UNKNOWN && 596 value_tag != IPP_TAG_NOVALUE && 597 value_tag != IPP_TAG_NOTSETTABLE && 598 value_tag != IPP_TAG_DELETEATTR && 599 value_tag != IPP_TAG_ADMINDEFINE)) 600 return (NULL); 601 602 /* 603 * Create the attribute... 604 */ 605 606 return (ipp_add_attr(ipp, name, group, value_tag, 1)); 607 } 608 609 610 /* 611 * 'ippAddRange()' - Add a range of values to an IPP message. 612 * 613 * The @code ipp@ parameter refers to an IPP message previously created using 614 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 615 * 616 * The @code group@ parameter specifies the IPP attribute group tag: none 617 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 618 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 619 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 620 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 621 * 622 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter. 623 */ 624 625 ipp_attribute_t * /* O - New attribute */ 626 ippAddRange(ipp_t *ipp, /* I - IPP message */ 627 ipp_tag_t group, /* I - IPP group */ 628 const char *name, /* I - Name of attribute */ 629 int lower, /* I - Lower value */ 630 int upper) /* I - Upper value */ 631 { 632 ipp_attribute_t *attr; /* New attribute */ 633 634 635 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, upper=%d)", (void *)ipp, group, ippTagString(group), name, lower, upper)); 636 637 /* 638 * Range check input... 639 */ 640 641 if (!ipp || !name || group < IPP_TAG_ZERO || 642 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) 643 return (NULL); 644 645 /* 646 * Create the attribute... 647 */ 648 649 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, 1)) == NULL) 650 return (NULL); 651 652 attr->values[0].range.lower = lower; 653 attr->values[0].range.upper = upper; 654 655 return (attr); 656 } 657 658 659 /* 660 * 'ippAddRanges()' - Add ranges of values to an IPP message. 661 * 662 * The @code ipp@ parameter refers to an IPP message previously created using 663 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 664 * 665 * The @code group@ parameter specifies the IPP attribute group tag: none 666 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 667 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 668 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 669 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 670 */ 671 672 ipp_attribute_t * /* O - New attribute */ 673 ippAddRanges(ipp_t *ipp, /* I - IPP message */ 674 ipp_tag_t group, /* I - IPP group */ 675 const char *name, /* I - Name of attribute */ 676 int num_values, /* I - Number of values */ 677 const int *lower, /* I - Lower values */ 678 const int *upper) /* I - Upper values */ 679 { 680 int i; /* Looping var */ 681 ipp_attribute_t *attr; /* New attribute */ 682 _ipp_value_t *value; /* Current value */ 683 684 685 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, lower=%p, upper=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)lower, (void *)upper)); 686 687 /* 688 * Range check input... 689 */ 690 691 if (!ipp || !name || group < IPP_TAG_ZERO || 692 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 693 num_values < 1) 694 return (NULL); 695 696 /* 697 * Create the attribute... 698 */ 699 700 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, num_values)) == NULL) 701 return (NULL); 702 703 if (lower && upper) 704 { 705 for (i = num_values, value = attr->values; 706 i > 0; 707 i --, value ++) 708 { 709 value->range.lower = *lower++; 710 value->range.upper = *upper++; 711 } 712 } 713 714 return (attr); 715 } 716 717 718 /* 719 * 'ippAddResolution()' - Add a resolution value to an IPP message. 720 * 721 * The @code ipp@ parameter refers to an IPP message previously created using 722 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 723 * 724 * The @code group@ parameter specifies the IPP attribute group tag: none 725 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 726 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 727 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 728 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 729 */ 730 731 ipp_attribute_t * /* O - New attribute */ 732 ippAddResolution(ipp_t *ipp, /* I - IPP message */ 733 ipp_tag_t group, /* I - IPP group */ 734 const char *name, /* I - Name of attribute */ 735 ipp_res_t units, /* I - Units for resolution */ 736 int xres, /* I - X resolution */ 737 int yres) /* I - Y resolution */ 738 { 739 ipp_attribute_t *attr; /* New attribute */ 740 741 742 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", units=%d, xres=%d, yres=%d)", (void *)ipp, group, 743 ippTagString(group), name, units, xres, yres)); 744 745 /* 746 * Range check input... 747 */ 748 749 if (!ipp || !name || group < IPP_TAG_ZERO || 750 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 751 units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM || 752 xres < 0 || yres < 0) 753 return (NULL); 754 755 /* 756 * Create the attribute... 757 */ 758 759 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, 1)) == NULL) 760 return (NULL); 761 762 attr->values[0].resolution.xres = xres; 763 attr->values[0].resolution.yres = yres; 764 attr->values[0].resolution.units = units; 765 766 return (attr); 767 } 768 769 770 /* 771 * 'ippAddResolutions()' - Add resolution values to an IPP message. 772 * 773 * The @code ipp@ parameter refers to an IPP message previously created using 774 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 775 * 776 * The @code group@ parameter specifies the IPP attribute group tag: none 777 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 778 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 779 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 780 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 781 */ 782 783 ipp_attribute_t * /* O - New attribute */ 784 ippAddResolutions(ipp_t *ipp, /* I - IPP message */ 785 ipp_tag_t group, /* I - IPP group */ 786 const char *name, /* I - Name of attribute */ 787 int num_values,/* I - Number of values */ 788 ipp_res_t units, /* I - Units for resolution */ 789 const int *xres, /* I - X resolutions */ 790 const int *yres) /* I - Y resolutions */ 791 { 792 int i; /* Looping var */ 793 ipp_attribute_t *attr; /* New attribute */ 794 _ipp_value_t *value; /* Current value */ 795 796 797 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", num_value=%d, units=%d, xres=%p, yres=%p)", (void *)ipp, group, ippTagString(group), name, num_values, units, (void *)xres, (void *)yres)); 798 799 /* 800 * Range check input... 801 */ 802 803 if (!ipp || !name || group < IPP_TAG_ZERO || 804 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 805 num_values < 1 || 806 units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM) 807 return (NULL); 808 809 /* 810 * Create the attribute... 811 */ 812 813 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, num_values)) == NULL) 814 return (NULL); 815 816 if (xres && yres) 817 { 818 for (i = num_values, value = attr->values; 819 i > 0; 820 i --, value ++) 821 { 822 value->resolution.xres = *xres++; 823 value->resolution.yres = *yres++; 824 value->resolution.units = units; 825 } 826 } 827 828 return (attr); 829 } 830 831 832 /* 833 * 'ippAddSeparator()' - Add a group separator to an IPP message. 834 * 835 * The @code ipp@ parameter refers to an IPP message previously created using 836 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 837 */ 838 839 ipp_attribute_t * /* O - New attribute */ 840 ippAddSeparator(ipp_t *ipp) /* I - IPP message */ 841 { 842 DEBUG_printf(("ippAddSeparator(ipp=%p)", (void *)ipp)); 843 844 /* 845 * Range check input... 846 */ 847 848 if (!ipp) 849 return (NULL); 850 851 /* 852 * Create the attribute... 853 */ 854 855 return (ipp_add_attr(ipp, NULL, IPP_TAG_ZERO, IPP_TAG_ZERO, 0)); 856 } 857 858 859 /* 860 * 'ippAddString()' - Add a language-encoded string to an IPP message. 861 * 862 * The @code ipp@ parameter refers to an IPP message previously created using 863 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 864 * 865 * The @code group@ parameter specifies the IPP attribute group tag: none 866 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 867 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 868 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 869 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 870 * 871 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword 872 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType 873 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage 874 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage 875 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme 876 * (@code IPP_TAG_URISCHEME@). 877 * 878 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and 879 * textWithLanguage string values and must be @code NULL@ for all other string values. 880 */ 881 882 ipp_attribute_t * /* O - New attribute */ 883 ippAddString(ipp_t *ipp, /* I - IPP message */ 884 ipp_tag_t group, /* I - IPP group */ 885 ipp_tag_t value_tag, /* I - Type of attribute */ 886 const char *name, /* I - Name of attribute */ 887 const char *language, /* I - Language code */ 888 const char *value) /* I - Value */ 889 { 890 ipp_tag_t temp_tag; /* Temporary value tag (masked) */ 891 ipp_attribute_t *attr; /* New attribute */ 892 char code[IPP_MAX_LANGUAGE]; 893 /* Charset/language code buffer */ 894 895 896 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\", language=\"%s\", value=\"%s\")", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, language, value)); 897 898 /* 899 * Range check input... 900 */ 901 902 temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_CUPS_MASK); 903 904 #if 0 905 if (!ipp || !name || group < IPP_TAG_ZERO || 906 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 907 (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG && 908 temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE) 909 return (NULL); 910 911 if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG) 912 != (language != NULL)) 913 return (NULL); 914 #else 915 if (!ipp || !name || group < IPP_TAG_ZERO || 916 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE) 917 return (NULL); 918 #endif /* 0 */ 919 920 /* 921 * See if we need to map charset, language, or locale values... 922 */ 923 924 if (language && ((int)value_tag & IPP_TAG_CUPS_CONST) && 925 strcmp(language, ipp_lang_code(language, code, sizeof(code)))) 926 value_tag = temp_tag; /* Don't do a fast copy */ 927 else if (value && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_CUPS_CONST) && 928 strcmp(value, ipp_get_code(value, code, sizeof(code)))) 929 value_tag = temp_tag; /* Don't do a fast copy */ 930 else if (value && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_CUPS_CONST) && 931 strcmp(value, ipp_lang_code(value, code, sizeof(code)))) 932 value_tag = temp_tag; /* Don't do a fast copy */ 933 934 /* 935 * Create the attribute... 936 */ 937 938 if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL) 939 return (NULL); 940 941 /* 942 * Initialize the attribute data... 943 */ 944 945 if ((int)value_tag & IPP_TAG_CUPS_CONST) 946 { 947 attr->values[0].string.language = (char *)language; 948 attr->values[0].string.text = (char *)value; 949 } 950 else 951 { 952 if (language) 953 attr->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language, code, 954 sizeof(code))); 955 956 if (value) 957 { 958 if (value_tag == IPP_TAG_CHARSET) 959 attr->values[0].string.text = _cupsStrAlloc(ipp_get_code(value, code, 960 sizeof(code))); 961 else if (value_tag == IPP_TAG_LANGUAGE) 962 attr->values[0].string.text = _cupsStrAlloc(ipp_lang_code(value, code, 963 sizeof(code))); 964 else 965 attr->values[0].string.text = _cupsStrAlloc(value); 966 } 967 } 968 969 return (attr); 970 } 971 972 973 /* 974 * 'ippAddStringf()' - Add a formatted string to an IPP message. 975 * 976 * The @code ipp@ parameter refers to an IPP message previously created using 977 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 978 * 979 * The @code group@ parameter specifies the IPP attribute group tag: none 980 * (@code IPP_TAG_ZERO@, for member attributes), document 981 * (@code IPP_TAG_DOCUMENT@), event notification 982 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@), 983 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@), 984 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 985 * 986 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword 987 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType 988 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage 989 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage 990 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme 991 * (@code IPP_TAG_URISCHEME@). 992 * 993 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage 994 * and textWithLanguage string values and must be @code NULL@ for all other 995 * string values. 996 * 997 * The @code format@ parameter uses formatting characters compatible with the 998 * printf family of standard functions. Additional arguments follow it as 999 * needed. The formatted string is truncated as needed to the maximum length of 1000 * the corresponding value type. 1001 * 1002 * @since CUPS 1.7/macOS 10.9@ 1003 */ 1004 1005 ipp_attribute_t * /* O - New attribute */ 1006 ippAddStringf(ipp_t *ipp, /* I - IPP message */ 1007 ipp_tag_t group, /* I - IPP group */ 1008 ipp_tag_t value_tag, /* I - Type of attribute */ 1009 const char *name, /* I - Name of attribute */ 1010 const char *language, /* I - Language code (@code NULL@ for default) */ 1011 const char *format, /* I - Printf-style format string */ 1012 ...) /* I - Additional arguments as needed */ 1013 { 1014 ipp_attribute_t *attr; /* New attribute */ 1015 va_list ap; /* Argument pointer */ 1016 1017 1018 va_start(ap, format); 1019 attr = ippAddStringfv(ipp, group, value_tag, name, language, format, ap); 1020 va_end(ap); 1021 1022 return (attr); 1023 } 1024 1025 1026 /* 1027 * 'ippAddStringfv()' - Add a formatted string to an IPP message. 1028 * 1029 * The @code ipp@ parameter refers to an IPP message previously created using 1030 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 1031 * 1032 * The @code group@ parameter specifies the IPP attribute group tag: none 1033 * (@code IPP_TAG_ZERO@, for member attributes), document 1034 * (@code IPP_TAG_DOCUMENT@), event notification 1035 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@), 1036 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@), 1037 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 1038 * 1039 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword 1040 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType 1041 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage 1042 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage 1043 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme 1044 * (@code IPP_TAG_URISCHEME@). 1045 * 1046 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage 1047 * and textWithLanguage string values and must be @code NULL@ for all other 1048 * string values. 1049 * 1050 * The @code format@ parameter uses formatting characters compatible with the 1051 * printf family of standard functions. Additional arguments are passed in the 1052 * stdarg pointer @code ap@. The formatted string is truncated as needed to the 1053 * maximum length of the corresponding value type. 1054 * 1055 * @since CUPS 1.7/macOS 10.9@ 1056 */ 1057 1058 ipp_attribute_t * /* O - New attribute */ 1059 ippAddStringfv(ipp_t *ipp, /* I - IPP message */ 1060 ipp_tag_t group, /* I - IPP group */ 1061 ipp_tag_t value_tag, /* I - Type of attribute */ 1062 const char *name, /* I - Name of attribute */ 1063 const char *language, /* I - Language code (@code NULL@ for default) */ 1064 const char *format, /* I - Printf-style format string */ 1065 va_list ap) /* I - Additional arguments */ 1066 { 1067 char buffer[IPP_MAX_TEXT + 4]; 1068 /* Formatted text string */ 1069 ssize_t bytes, /* Length of formatted value */ 1070 max_bytes; /* Maximum number of bytes for value */ 1071 1072 1073 /* 1074 * Range check input... 1075 */ 1076 1077 if (!ipp || !name || group < IPP_TAG_ZERO || 1078 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 1079 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG && 1080 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE || 1081 !format) 1082 return (NULL); 1083 1084 if ((value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_NAMELANG) 1085 != (language != NULL)) 1086 return (NULL); 1087 1088 /* 1089 * Format the string... 1090 */ 1091 1092 if (!strcmp(format, "%s")) 1093 { 1094 /* 1095 * Optimize the simple case... 1096 */ 1097 1098 const char *s = va_arg(ap, char *); 1099 1100 if (!s) 1101 s = "(null)"; 1102 1103 bytes = (ssize_t)strlen(s); 1104 strlcpy(buffer, s, sizeof(buffer)); 1105 } 1106 else 1107 { 1108 /* 1109 * Do a full formatting of the message... 1110 */ 1111 1112 if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0) 1113 return (NULL); 1114 } 1115 1116 /* 1117 * Limit the length of the string... 1118 */ 1119 1120 switch (value_tag) 1121 { 1122 default : 1123 case IPP_TAG_TEXT : 1124 case IPP_TAG_TEXTLANG : 1125 max_bytes = IPP_MAX_TEXT; 1126 break; 1127 1128 case IPP_TAG_NAME : 1129 case IPP_TAG_NAMELANG : 1130 max_bytes = IPP_MAX_NAME; 1131 break; 1132 1133 case IPP_TAG_CHARSET : 1134 max_bytes = IPP_MAX_CHARSET; 1135 break; 1136 1137 case IPP_TAG_KEYWORD : 1138 max_bytes = IPP_MAX_KEYWORD; 1139 break; 1140 1141 case IPP_TAG_LANGUAGE : 1142 max_bytes = IPP_MAX_LANGUAGE; 1143 break; 1144 1145 case IPP_TAG_MIMETYPE : 1146 max_bytes = IPP_MAX_MIMETYPE; 1147 break; 1148 1149 case IPP_TAG_URI : 1150 max_bytes = IPP_MAX_URI; 1151 break; 1152 1153 case IPP_TAG_URISCHEME : 1154 max_bytes = IPP_MAX_URISCHEME; 1155 break; 1156 } 1157 1158 if (bytes >= max_bytes) 1159 { 1160 char *bufmax, /* Buffer at max_bytes */ 1161 *bufptr; /* Pointer into buffer */ 1162 1163 bufptr = buffer + strlen(buffer) - 1; 1164 bufmax = buffer + max_bytes - 1; 1165 1166 while (bufptr > bufmax) 1167 { 1168 if (*bufptr & 0x80) 1169 { 1170 while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer) 1171 bufptr --; 1172 } 1173 1174 bufptr --; 1175 } 1176 1177 *bufptr = '\0'; 1178 } 1179 1180 /* 1181 * Add the formatted string and return... 1182 */ 1183 1184 return (ippAddString(ipp, group, value_tag, name, language, buffer)); 1185 } 1186 1187 1188 /* 1189 * 'ippAddStrings()' - Add language-encoded strings to an IPP message. 1190 * 1191 * The @code ipp@ parameter refers to an IPP message previously created using 1192 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 1193 * 1194 * The @code group@ parameter specifies the IPP attribute group tag: none 1195 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 1196 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 1197 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 1198 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 1199 * 1200 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword 1201 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType 1202 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage 1203 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage 1204 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme 1205 * (@code IPP_TAG_URISCHEME@). 1206 * 1207 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and 1208 * textWithLanguage string values and must be @code NULL@ for all other string values. 1209 */ 1210 1211 ipp_attribute_t * /* O - New attribute */ 1212 ippAddStrings( 1213 ipp_t *ipp, /* I - IPP message */ 1214 ipp_tag_t group, /* I - IPP group */ 1215 ipp_tag_t value_tag, /* I - Type of attribute */ 1216 const char *name, /* I - Name of attribute */ 1217 int num_values, /* I - Number of values */ 1218 const char *language, /* I - Language code (@code NULL@ for default) */ 1219 const char * const *values) /* I - Values */ 1220 { 1221 int i; /* Looping var */ 1222 ipp_tag_t temp_tag; /* Temporary value tag (masked) */ 1223 ipp_attribute_t *attr; /* New attribute */ 1224 _ipp_value_t *value; /* Current value */ 1225 char code[32]; /* Language/charset value buffer */ 1226 1227 1228 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\", num_values=%d, language=\"%s\", values=%p)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, num_values, language, (void *)values)); 1229 1230 /* 1231 * Range check input... 1232 */ 1233 1234 temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_CUPS_MASK); 1235 1236 #if 0 1237 if (!ipp || !name || group < IPP_TAG_ZERO || 1238 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 1239 (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG && 1240 temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE || 1241 num_values < 1) 1242 return (NULL); 1243 1244 if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG) 1245 != (language != NULL)) 1246 return (NULL); 1247 #else 1248 if (!ipp || !name || group < IPP_TAG_ZERO || 1249 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE || 1250 num_values < 1) 1251 return (NULL); 1252 #endif /* 0 */ 1253 1254 /* 1255 * See if we need to map charset, language, or locale values... 1256 */ 1257 1258 if (language && ((int)value_tag & IPP_TAG_CUPS_CONST) && 1259 strcmp(language, ipp_lang_code(language, code, sizeof(code)))) 1260 value_tag = temp_tag; /* Don't do a fast copy */ 1261 else if (values && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_CUPS_CONST)) 1262 { 1263 for (i = 0; i < num_values; i ++) 1264 if (strcmp(values[i], ipp_get_code(values[i], code, sizeof(code)))) 1265 { 1266 value_tag = temp_tag; /* Don't do a fast copy */ 1267 break; 1268 } 1269 } 1270 else if (values && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_CUPS_CONST)) 1271 { 1272 for (i = 0; i < num_values; i ++) 1273 if (strcmp(values[i], ipp_lang_code(values[i], code, sizeof(code)))) 1274 { 1275 value_tag = temp_tag; /* Don't do a fast copy */ 1276 break; 1277 } 1278 } 1279 1280 /* 1281 * Create the attribute... 1282 */ 1283 1284 if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL) 1285 return (NULL); 1286 1287 /* 1288 * Initialize the attribute data... 1289 */ 1290 1291 for (i = num_values, value = attr->values; 1292 i > 0; 1293 i --, value ++) 1294 { 1295 if (language) 1296 { 1297 if (value == attr->values) 1298 { 1299 if ((int)value_tag & IPP_TAG_CUPS_CONST) 1300 value->string.language = (char *)language; 1301 else 1302 value->string.language = _cupsStrAlloc(ipp_lang_code(language, code, 1303 sizeof(code))); 1304 } 1305 else 1306 value->string.language = attr->values[0].string.language; 1307 } 1308 1309 if (values) 1310 { 1311 if ((int)value_tag & IPP_TAG_CUPS_CONST) 1312 value->string.text = (char *)*values++; 1313 else if (value_tag == IPP_TAG_CHARSET) 1314 value->string.text = _cupsStrAlloc(ipp_get_code(*values++, code, sizeof(code))); 1315 else if (value_tag == IPP_TAG_LANGUAGE) 1316 value->string.text = _cupsStrAlloc(ipp_lang_code(*values++, code, sizeof(code))); 1317 else 1318 value->string.text = _cupsStrAlloc(*values++); 1319 } 1320 } 1321 1322 return (attr); 1323 } 1324 1325 1326 /* 1327 * 'ippContainsInteger()' - Determine whether an attribute contains the 1328 * specified value or is within the list of ranges. 1329 * 1330 * Returns non-zero when the attribute contains either a matching integer or 1331 * enum value, or the value falls within one of the rangeOfInteger values for 1332 * the attribute. 1333 * 1334 * @since CUPS 1.7/macOS 10.9@ 1335 */ 1336 1337 int /* O - 1 on a match, 0 on no match */ 1338 ippContainsInteger( 1339 ipp_attribute_t *attr, /* I - Attribute */ 1340 int value) /* I - Integer/enum value */ 1341 { 1342 int i; /* Looping var */ 1343 _ipp_value_t *avalue; /* Current attribute value */ 1344 1345 1346 /* 1347 * Range check input... 1348 */ 1349 1350 if (!attr) 1351 return (0); 1352 1353 if (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM && 1354 attr->value_tag != IPP_TAG_RANGE) 1355 return (0); 1356 1357 /* 1358 * Compare... 1359 */ 1360 1361 if (attr->value_tag == IPP_TAG_RANGE) 1362 { 1363 for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++) 1364 if (value >= avalue->range.lower && value <= avalue->range.upper) 1365 return (1); 1366 } 1367 else 1368 { 1369 for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++) 1370 if (value == avalue->integer) 1371 return (1); 1372 } 1373 1374 return (0); 1375 } 1376 1377 1378 /* 1379 * 'ippContainsString()' - Determine whether an attribute contains the 1380 * specified string value. 1381 * 1382 * Returns non-zero when the attribute contains a matching charset, keyword, 1383 * naturalLanguage, mimeMediaType, name, text, uri, or uriScheme value. 1384 * 1385 * @since CUPS 1.7/macOS 10.9@ 1386 */ 1387 1388 int /* O - 1 on a match, 0 on no match */ 1389 ippContainsString( 1390 ipp_attribute_t *attr, /* I - Attribute */ 1391 const char *value) /* I - String value */ 1392 { 1393 int i; /* Looping var */ 1394 _ipp_value_t *avalue; /* Current attribute value */ 1395 1396 1397 DEBUG_printf(("ippContainsString(attr=%p, value=\"%s\")", (void *)attr, value)); 1398 1399 /* 1400 * Range check input... 1401 */ 1402 1403 if (!attr || !value) 1404 { 1405 DEBUG_puts("1ippContainsString: Returning 0 (bad input)"); 1406 return (0); 1407 } 1408 1409 /* 1410 * Compare... 1411 */ 1412 1413 DEBUG_printf(("1ippContainsString: attr %s, %s with %d values.", 1414 attr->name, ippTagString(attr->value_tag), 1415 attr->num_values)); 1416 1417 switch (attr->value_tag & IPP_TAG_CUPS_MASK) 1418 { 1419 case IPP_TAG_CHARSET : 1420 case IPP_TAG_KEYWORD : 1421 case IPP_TAG_LANGUAGE : 1422 case IPP_TAG_URI : 1423 case IPP_TAG_URISCHEME : 1424 for (i = attr->num_values, avalue = attr->values; 1425 i > 0; 1426 i --, avalue ++) 1427 { 1428 DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"", 1429 attr->num_values - i, avalue->string.text)); 1430 1431 if (!strcmp(value, avalue->string.text)) 1432 { 1433 DEBUG_puts("1ippContainsString: Returning 1 (match)"); 1434 return (1); 1435 } 1436 } 1437 1438 case IPP_TAG_MIMETYPE : 1439 case IPP_TAG_NAME : 1440 case IPP_TAG_NAMELANG : 1441 case IPP_TAG_TEXT : 1442 case IPP_TAG_TEXTLANG : 1443 for (i = attr->num_values, avalue = attr->values; 1444 i > 0; 1445 i --, avalue ++) 1446 { 1447 DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"", 1448 attr->num_values - i, avalue->string.text)); 1449 1450 if (!_cups_strcasecmp(value, avalue->string.text)) 1451 { 1452 DEBUG_puts("1ippContainsString: Returning 1 (match)"); 1453 return (1); 1454 } 1455 } 1456 1457 default : 1458 break; 1459 } 1460 1461 DEBUG_puts("1ippContainsString: Returning 0 (no match)"); 1462 1463 return (0); 1464 } 1465 1466 1467 /* 1468 * 'ippCopyAttribute()' - Copy an attribute. 1469 * 1470 * The specified attribute, @code attr@, is copied to the destination IPP message. 1471 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is 1472 * created - this should only be done as long as the original source IPP message will 1473 * not be freed for the life of the destination. 1474 * 1475 * @since CUPS 1.6/macOS 10.8@ 1476 */ 1477 1478 1479 ipp_attribute_t * /* O - New attribute */ 1480 ippCopyAttribute( 1481 ipp_t *dst, /* I - Destination IPP message */ 1482 ipp_attribute_t *srcattr, /* I - Attribute to copy */ 1483 int quickcopy) /* I - 1 for a referenced copy, 0 for normal */ 1484 { 1485 int i; /* Looping var */ 1486 ipp_attribute_t *dstattr; /* Destination attribute */ 1487 _ipp_value_t *srcval, /* Source value */ 1488 *dstval; /* Destination value */ 1489 1490 1491 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", (void *)dst, (void *)srcattr, quickcopy)); 1492 1493 /* 1494 * Range check input... 1495 */ 1496 1497 if (!dst || !srcattr) 1498 return (NULL); 1499 1500 /* 1501 * Copy it... 1502 */ 1503 1504 quickcopy = quickcopy ? IPP_TAG_CUPS_CONST : 0; 1505 1506 switch (srcattr->value_tag & ~IPP_TAG_CUPS_CONST) 1507 { 1508 case IPP_TAG_ZERO : 1509 dstattr = ippAddSeparator(dst); 1510 break; 1511 1512 case IPP_TAG_UNSUPPORTED_VALUE : 1513 case IPP_TAG_DEFAULT : 1514 case IPP_TAG_UNKNOWN : 1515 case IPP_TAG_NOVALUE : 1516 case IPP_TAG_NOTSETTABLE : 1517 case IPP_TAG_DELETEATTR : 1518 case IPP_TAG_ADMINDEFINE : 1519 dstattr = ippAddOutOfBand(dst, srcattr->group_tag, srcattr->value_tag & ~IPP_TAG_CUPS_CONST, srcattr->name); 1520 break; 1521 1522 case IPP_TAG_INTEGER : 1523 case IPP_TAG_ENUM : 1524 dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag, 1525 srcattr->name, srcattr->num_values, NULL); 1526 if (!dstattr) 1527 break; 1528 1529 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; 1530 i > 0; 1531 i --, srcval ++, dstval ++) 1532 dstval->integer = srcval->integer; 1533 break; 1534 1535 case IPP_TAG_BOOLEAN : 1536 dstattr = ippAddBooleans(dst, srcattr->group_tag, srcattr->name, 1537 srcattr->num_values, NULL); 1538 if (!dstattr) 1539 break; 1540 1541 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; 1542 i > 0; 1543 i --, srcval ++, dstval ++) 1544 dstval->boolean = srcval->boolean; 1545 break; 1546 1547 case IPP_TAG_TEXT : 1548 case IPP_TAG_NAME : 1549 case IPP_TAG_KEYWORD : 1550 case IPP_TAG_URI : 1551 case IPP_TAG_URISCHEME : 1552 case IPP_TAG_CHARSET : 1553 case IPP_TAG_LANGUAGE : 1554 case IPP_TAG_MIMETYPE : 1555 dstattr = ippAddStrings(dst, srcattr->group_tag, 1556 (ipp_tag_t)(srcattr->value_tag | quickcopy), 1557 srcattr->name, srcattr->num_values, NULL, NULL); 1558 if (!dstattr) 1559 break; 1560 1561 if (quickcopy) 1562 { 1563 for (i = srcattr->num_values, srcval = srcattr->values, 1564 dstval = dstattr->values; 1565 i > 0; 1566 i --, srcval ++, dstval ++) 1567 dstval->string.text = srcval->string.text; 1568 } 1569 else if (srcattr->value_tag & IPP_TAG_CUPS_CONST) 1570 { 1571 for (i = srcattr->num_values, srcval = srcattr->values, 1572 dstval = dstattr->values; 1573 i > 0; 1574 i --, srcval ++, dstval ++) 1575 dstval->string.text = _cupsStrAlloc(srcval->string.text); 1576 } 1577 else 1578 { 1579 for (i = srcattr->num_values, srcval = srcattr->values, 1580 dstval = dstattr->values; 1581 i > 0; 1582 i --, srcval ++, dstval ++) 1583 dstval->string.text = _cupsStrRetain(srcval->string.text); 1584 } 1585 break; 1586 1587 case IPP_TAG_DATE : 1588 if (srcattr->num_values != 1) 1589 return (NULL); 1590 1591 dstattr = ippAddDate(dst, srcattr->group_tag, srcattr->name, 1592 srcattr->values[0].date); 1593 break; 1594 1595 case IPP_TAG_RESOLUTION : 1596 dstattr = ippAddResolutions(dst, srcattr->group_tag, srcattr->name, 1597 srcattr->num_values, IPP_RES_PER_INCH, 1598 NULL, NULL); 1599 if (!dstattr) 1600 break; 1601 1602 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; 1603 i > 0; 1604 i --, srcval ++, dstval ++) 1605 { 1606 dstval->resolution.xres = srcval->resolution.xres; 1607 dstval->resolution.yres = srcval->resolution.yres; 1608 dstval->resolution.units = srcval->resolution.units; 1609 } 1610 break; 1611 1612 case IPP_TAG_RANGE : 1613 dstattr = ippAddRanges(dst, srcattr->group_tag, srcattr->name, 1614 srcattr->num_values, NULL, NULL); 1615 if (!dstattr) 1616 break; 1617 1618 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; 1619 i > 0; 1620 i --, srcval ++, dstval ++) 1621 { 1622 dstval->range.lower = srcval->range.lower; 1623 dstval->range.upper = srcval->range.upper; 1624 } 1625 break; 1626 1627 case IPP_TAG_TEXTLANG : 1628 case IPP_TAG_NAMELANG : 1629 dstattr = ippAddStrings(dst, srcattr->group_tag, 1630 (ipp_tag_t)(srcattr->value_tag | quickcopy), 1631 srcattr->name, srcattr->num_values, NULL, NULL); 1632 if (!dstattr) 1633 break; 1634 1635 if (quickcopy) 1636 { 1637 for (i = srcattr->num_values, srcval = srcattr->values, 1638 dstval = dstattr->values; 1639 i > 0; 1640 i --, srcval ++, dstval ++) 1641 { 1642 dstval->string.language = srcval->string.language; 1643 dstval->string.text = srcval->string.text; 1644 } 1645 } 1646 else if (srcattr->value_tag & IPP_TAG_CUPS_CONST) 1647 { 1648 for (i = srcattr->num_values, srcval = srcattr->values, 1649 dstval = dstattr->values; 1650 i > 0; 1651 i --, srcval ++, dstval ++) 1652 { 1653 if (srcval == srcattr->values) 1654 dstval->string.language = _cupsStrAlloc(srcval->string.language); 1655 else 1656 dstval->string.language = dstattr->values[0].string.language; 1657 1658 dstval->string.text = _cupsStrAlloc(srcval->string.text); 1659 } 1660 } 1661 else 1662 { 1663 for (i = srcattr->num_values, srcval = srcattr->values, 1664 dstval = dstattr->values; 1665 i > 0; 1666 i --, srcval ++, dstval ++) 1667 { 1668 if (srcval == srcattr->values) 1669 dstval->string.language = _cupsStrRetain(srcval->string.language); 1670 else 1671 dstval->string.language = dstattr->values[0].string.language; 1672 1673 dstval->string.text = _cupsStrRetain(srcval->string.text); 1674 } 1675 } 1676 break; 1677 1678 case IPP_TAG_BEGIN_COLLECTION : 1679 dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name, 1680 srcattr->num_values, NULL); 1681 if (!dstattr) 1682 break; 1683 1684 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; 1685 i > 0; 1686 i --, srcval ++, dstval ++) 1687 { 1688 dstval->collection = srcval->collection; 1689 srcval->collection->use ++; 1690 } 1691 break; 1692 1693 case IPP_TAG_STRING : 1694 default : 1695 /* TODO: Implement quick copy for unknown/octetString values */ 1696 dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag, 1697 srcattr->name, srcattr->num_values, NULL); 1698 if (!dstattr) 1699 break; 1700 1701 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; 1702 i > 0; 1703 i --, srcval ++, dstval ++) 1704 { 1705 dstval->unknown.length = srcval->unknown.length; 1706 1707 if (dstval->unknown.length > 0) 1708 { 1709 if ((dstval->unknown.data = malloc((size_t)dstval->unknown.length)) == NULL) 1710 dstval->unknown.length = 0; 1711 else 1712 memcpy(dstval->unknown.data, srcval->unknown.data, (size_t)dstval->unknown.length); 1713 } 1714 } 1715 break; /* anti-compiler-warning-code */ 1716 } 1717 1718 return (dstattr); 1719 } 1720 1721 1722 /* 1723 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another. 1724 * 1725 * Zero or more attributes are copied from the source IPP message, @code src@, to the 1726 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow" 1727 * reference copy of the attribute is created - this should only be done as long as the 1728 * original source IPP message will not be freed for the life of the destination. 1729 * 1730 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the 1731 * attributes that are copied - the function must return 1 to copy the attribute or 1732 * 0 to skip it. The function may also choose to do a partial copy of the source attribute 1733 * itself. 1734 * 1735 * @since CUPS 1.6/macOS 10.8@ 1736 */ 1737 1738 int /* O - 1 on success, 0 on error */ 1739 ippCopyAttributes( 1740 ipp_t *dst, /* I - Destination IPP message */ 1741 ipp_t *src, /* I - Source IPP message */ 1742 int quickcopy, /* I - 1 for a referenced copy, 0 for normal */ 1743 ipp_copycb_t cb, /* I - Copy callback or @code NULL@ for none */ 1744 void *context) /* I - Context pointer */ 1745 { 1746 ipp_attribute_t *srcattr; /* Source attribute */ 1747 1748 1749 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)", (void *)dst, (void *)src, quickcopy, (void *)cb, context)); 1750 1751 /* 1752 * Range check input... 1753 */ 1754 1755 if (!dst || !src) 1756 return (0); 1757 1758 /* 1759 * Loop through source attributes and copy as needed... 1760 */ 1761 1762 for (srcattr = src->attrs; srcattr; srcattr = srcattr->next) 1763 if (!cb || (*cb)(context, dst, srcattr)) 1764 if (!ippCopyAttribute(dst, srcattr, quickcopy)) 1765 return (0); 1766 1767 return (1); 1768 } 1769 1770 1771 /* 1772 * 'ippDateToTime()' - Convert from RFC 2579 Date/Time format to time in 1773 * seconds. 1774 */ 1775 1776 time_t /* O - UNIX time value */ 1777 ippDateToTime(const ipp_uchar_t *date) /* I - RFC 2579 date info */ 1778 { 1779 struct tm unixdate; /* UNIX date/time info */ 1780 time_t t; /* Computed time */ 1781 1782 1783 if (!date) 1784 return (0); 1785 1786 memset(&unixdate, 0, sizeof(unixdate)); 1787 1788 /* 1789 * RFC-2579 date/time format is: 1790 * 1791 * Byte(s) Description 1792 * ------- ----------- 1793 * 0-1 Year (0 to 65535) 1794 * 2 Month (1 to 12) 1795 * 3 Day (1 to 31) 1796 * 4 Hours (0 to 23) 1797 * 5 Minutes (0 to 59) 1798 * 6 Seconds (0 to 60, 60 = "leap second") 1799 * 7 Deciseconds (0 to 9) 1800 * 8 +/- UTC 1801 * 9 UTC hours (0 to 11) 1802 * 10 UTC minutes (0 to 59) 1803 */ 1804 1805 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900; 1806 unixdate.tm_mon = date[2] - 1; 1807 unixdate.tm_mday = date[3]; 1808 unixdate.tm_hour = date[4]; 1809 unixdate.tm_min = date[5]; 1810 unixdate.tm_sec = date[6]; 1811 1812 t = mktime(&unixdate); 1813 1814 if (date[8] == '-') 1815 t += date[9] * 3600 + date[10] * 60; 1816 else 1817 t -= date[9] * 3600 + date[10] * 60; 1818 1819 return (t); 1820 } 1821 1822 1823 /* 1824 * 'ippDelete()' - Delete an IPP message. 1825 */ 1826 1827 void 1828 ippDelete(ipp_t *ipp) /* I - IPP message */ 1829 { 1830 ipp_attribute_t *attr, /* Current attribute */ 1831 *next; /* Next attribute */ 1832 1833 1834 DEBUG_printf(("ippDelete(ipp=%p)", (void *)ipp)); 1835 1836 if (!ipp) 1837 return; 1838 1839 ipp->use --; 1840 if (ipp->use > 0) 1841 { 1842 DEBUG_printf(("4debug_retain: %p IPP message (use=%d)", (void *)ipp, ipp->use)); 1843 return; 1844 } 1845 1846 DEBUG_printf(("4debug_free: %p IPP message", (void *)ipp)); 1847 1848 for (attr = ipp->attrs; attr != NULL; attr = next) 1849 { 1850 next = attr->next; 1851 1852 DEBUG_printf(("4debug_free: %p %s %s%s (%d values)", (void *)attr, attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), attr->num_values)); 1853 1854 ipp_free_values(attr, 0, attr->num_values); 1855 1856 if (attr->name) 1857 _cupsStrFree(attr->name); 1858 1859 free(attr); 1860 } 1861 1862 free(ipp); 1863 } 1864 1865 1866 /* 1867 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message. 1868 * 1869 * @since CUPS 1.1.19/macOS 10.3@ 1870 */ 1871 1872 void 1873 ippDeleteAttribute( 1874 ipp_t *ipp, /* I - IPP message */ 1875 ipp_attribute_t *attr) /* I - Attribute to delete */ 1876 { 1877 ipp_attribute_t *current, /* Current attribute */ 1878 *prev; /* Previous attribute */ 1879 1880 1881 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", (void *)ipp, (void *)attr, attr ? attr->name : "(null)")); 1882 1883 /* 1884 * Range check input... 1885 */ 1886 1887 if (!attr) 1888 return; 1889 1890 DEBUG_printf(("4debug_free: %p %s %s%s (%d values)", (void *)attr, attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), attr->num_values)); 1891 1892 /* 1893 * Find the attribute in the list... 1894 */ 1895 1896 if (ipp) 1897 { 1898 for (current = ipp->attrs, prev = NULL; 1899 current; 1900 prev = current, current = current->next) 1901 if (current == attr) 1902 { 1903 /* 1904 * Found it, remove the attribute from the list... 1905 */ 1906 1907 if (prev) 1908 prev->next = current->next; 1909 else 1910 ipp->attrs = current->next; 1911 1912 if (current == ipp->last) 1913 ipp->last = prev; 1914 1915 break; 1916 } 1917 1918 if (!current) 1919 return; 1920 } 1921 1922 /* 1923 * Free memory used by the attribute... 1924 */ 1925 1926 ipp_free_values(attr, 0, attr->num_values); 1927 1928 if (attr->name) 1929 _cupsStrFree(attr->name); 1930 1931 free(attr); 1932 } 1933 1934 1935 /* 1936 * 'ippDeleteValues()' - Delete values in an attribute. 1937 * 1938 * The @code element@ parameter specifies the first value to delete, starting at 1939 * 0. It must be less than the number of values returned by @link ippGetCount@. 1940 * 1941 * The @code attr@ parameter may be modified as a result of setting the value. 1942 * 1943 * Deleting all values in an attribute deletes the attribute. 1944 * 1945 * @since CUPS 1.6/macOS 10.8@ 1946 */ 1947 1948 int /* O - 1 on success, 0 on failure */ 1949 ippDeleteValues( 1950 ipp_t *ipp, /* I - IPP message */ 1951 ipp_attribute_t **attr, /* IO - Attribute */ 1952 int element, /* I - Index of first value to delete (0-based) */ 1953 int count) /* I - Number of values to delete */ 1954 { 1955 /* 1956 * Range check input... 1957 */ 1958 1959 if (!ipp || !attr || !*attr || 1960 element < 0 || element >= (*attr)->num_values || count <= 0 || 1961 (element + count) >= (*attr)->num_values) 1962 return (0); 1963 1964 /* 1965 * If we are deleting all values, just delete the attribute entirely. 1966 */ 1967 1968 if (count == (*attr)->num_values) 1969 { 1970 ippDeleteAttribute(ipp, *attr); 1971 *attr = NULL; 1972 return (1); 1973 } 1974 1975 /* 1976 * Otherwise free the values in question and return. 1977 */ 1978 1979 ipp_free_values(*attr, element, count); 1980 1981 return (1); 1982 } 1983 1984 1985 /* 1986 * 'ippFindAttribute()' - Find a named attribute in a request. 1987 * 1988 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list 1989 * of attribute and member names separated by slashes, for example 1990 * "media-col/media-size". 1991 */ 1992 1993 ipp_attribute_t * /* O - Matching attribute */ 1994 ippFindAttribute(ipp_t *ipp, /* I - IPP message */ 1995 const char *name, /* I - Name of attribute */ 1996 ipp_tag_t type) /* I - Type of attribute */ 1997 { 1998 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type))); 1999 2000 if (!ipp || !name) 2001 return (NULL); 2002 2003 /* 2004 * Reset the current pointer... 2005 */ 2006 2007 ipp->current = NULL; 2008 ipp->atend = 0; 2009 2010 /* 2011 * Search for the attribute... 2012 */ 2013 2014 return (ippFindNextAttribute(ipp, name, type)); 2015 } 2016 2017 2018 /* 2019 * 'ippFindNextAttribute()' - Find the next named attribute in a request. 2020 * 2021 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list 2022 * of attribute and member names separated by slashes, for example 2023 * "media-col/media-size". 2024 */ 2025 2026 ipp_attribute_t * /* O - Matching attribute */ 2027 ippFindNextAttribute(ipp_t *ipp, /* I - IPP message */ 2028 const char *name, /* I - Name of attribute */ 2029 ipp_tag_t type) /* I - Type of attribute */ 2030 { 2031 ipp_attribute_t *attr, /* Current atttribute */ 2032 *childattr; /* Child attribute */ 2033 ipp_tag_t value_tag; /* Value tag */ 2034 char parent[1024], /* Parent attribute name */ 2035 *child = NULL; /* Child attribute name */ 2036 2037 2038 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type))); 2039 2040 if (!ipp || !name) 2041 return (NULL); 2042 2043 DEBUG_printf(("3ippFindNextAttribute: atend=%d", ipp->atend)); 2044 2045 if (ipp->atend) 2046 return (NULL); 2047 2048 if (strchr(name, '/')) 2049 { 2050 /* 2051 * Search for child attribute... 2052 */ 2053 2054 strlcpy(parent, name, sizeof(parent)); 2055 if ((child = strchr(parent, '/')) == NULL) 2056 { 2057 DEBUG_puts("3ippFindNextAttribute: Attribute name too long."); 2058 return (NULL); 2059 } 2060 2061 *child++ = '\0'; 2062 2063 if (ipp->current && ipp->current->name && ipp->current->value_tag == IPP_TAG_BEGIN_COLLECTION && !strcmp(parent, ipp->current->name)) 2064 { 2065 while (ipp->curindex < ipp->current->num_values) 2066 { 2067 if ((childattr = ippFindNextAttribute(ipp->current->values[ipp->curindex].collection, child, type)) != NULL) 2068 return (childattr); 2069 2070 ipp->curindex ++; 2071 if (ipp->curindex < ipp->current->num_values && ipp->current->values[ipp->curindex].collection) 2072 ipp->current->values[ipp->curindex].collection->current = NULL; 2073 } 2074 2075 ipp->prev = ipp->current; 2076 ipp->current = ipp->current->next; 2077 ipp->curindex = 0; 2078 2079 if (!ipp->current) 2080 { 2081 ipp->atend = 1; 2082 return (NULL); 2083 } 2084 } 2085 2086 if (!ipp->current) 2087 { 2088 ipp->prev = NULL; 2089 ipp->current = ipp->attrs; 2090 ipp->curindex = 0; 2091 } 2092 2093 name = parent; 2094 attr = ipp->current; 2095 } 2096 else if (ipp->current) 2097 { 2098 ipp->prev = ipp->current; 2099 attr = ipp->current->next; 2100 } 2101 else 2102 { 2103 ipp->prev = NULL; 2104 attr = ipp->attrs; 2105 } 2106 2107 for (; attr != NULL; ipp->prev = attr, attr = attr->next) 2108 { 2109 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", (void *)attr, attr->name)); 2110 2111 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK); 2112 2113 if (attr->name != NULL && _cups_strcasecmp(attr->name, name) == 0 && 2114 (value_tag == type || type == IPP_TAG_ZERO || name == parent || 2115 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) || 2116 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME))) 2117 { 2118 ipp->current = attr; 2119 2120 if (name == parent && attr->value_tag == IPP_TAG_BEGIN_COLLECTION) 2121 { 2122 int i; /* Looping var */ 2123 2124 for (i = 0; i < attr->num_values; i ++) 2125 { 2126 if ((childattr = ippFindAttribute(attr->values[i].collection, child, type)) != NULL) 2127 { 2128 attr->values[0].collection->curindex = i; 2129 return (childattr); 2130 } 2131 } 2132 } 2133 else 2134 return (attr); 2135 } 2136 } 2137 2138 ipp->current = NULL; 2139 ipp->prev = NULL; 2140 ipp->atend = 1; 2141 2142 return (NULL); 2143 } 2144 2145 2146 /* 2147 * 'ippFirstAttribute()' - Return the first attribute in the message. 2148 * 2149 * @since CUPS 1.6/macOS 10.8@ 2150 */ 2151 2152 ipp_attribute_t * /* O - First attribute or @code NULL@ if none */ 2153 ippFirstAttribute(ipp_t *ipp) /* I - IPP message */ 2154 { 2155 /* 2156 * Range check input... 2157 */ 2158 2159 if (!ipp) 2160 return (NULL); 2161 2162 /* 2163 * Return the first attribute... 2164 */ 2165 2166 return (ipp->current = ipp->attrs); 2167 } 2168 2169 2170 /* 2171 * 'ippGetBoolean()' - Get a boolean value for an attribute. 2172 * 2173 * The @code element@ parameter specifies which value to get from 0 to 2174 * @code ippGetCount(attr)@ - 1. 2175 * 2176 * @since CUPS 1.6/macOS 10.8@ 2177 */ 2178 2179 int /* O - Boolean value or 0 on error */ 2180 ippGetBoolean(ipp_attribute_t *attr, /* I - IPP attribute */ 2181 int element) /* I - Value number (0-based) */ 2182 { 2183 /* 2184 * Range check input... 2185 */ 2186 2187 if (!attr || attr->value_tag != IPP_TAG_BOOLEAN || 2188 element < 0 || element >= attr->num_values) 2189 return (0); 2190 2191 /* 2192 * Return the value... 2193 */ 2194 2195 return (attr->values[element].boolean); 2196 } 2197 2198 2199 /* 2200 * 'ippGetCollection()' - Get a collection value for an attribute. 2201 * 2202 * The @code element@ parameter specifies which value to get from 0 to 2203 * @code ippGetCount(attr)@ - 1. 2204 * 2205 * @since CUPS 1.6/macOS 10.8@ 2206 */ 2207 2208 ipp_t * /* O - Collection value or @code NULL@ on error */ 2209 ippGetCollection( 2210 ipp_attribute_t *attr, /* I - IPP attribute */ 2211 int element) /* I - Value number (0-based) */ 2212 { 2213 /* 2214 * Range check input... 2215 */ 2216 2217 if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION || 2218 element < 0 || element >= attr->num_values) 2219 return (NULL); 2220 2221 /* 2222 * Return the value... 2223 */ 2224 2225 return (attr->values[element].collection); 2226 } 2227 2228 2229 /* 2230 * 'ippGetCount()' - Get the number of values in an attribute. 2231 * 2232 * @since CUPS 1.6/macOS 10.8@ 2233 */ 2234 2235 int /* O - Number of values or 0 on error */ 2236 ippGetCount(ipp_attribute_t *attr) /* I - IPP attribute */ 2237 { 2238 /* 2239 * Range check input... 2240 */ 2241 2242 if (!attr) 2243 return (0); 2244 2245 /* 2246 * Return the number of values... 2247 */ 2248 2249 return (attr->num_values); 2250 } 2251 2252 2253 /* 2254 * 'ippGetDate()' - Get a dateTime value for an attribute. 2255 * 2256 * The @code element@ parameter specifies which value to get from 0 to 2257 * @code ippGetCount(attr)@ - 1. 2258 * 2259 * @since CUPS 1.6/macOS 10.8@ 2260 */ 2261 2262 const ipp_uchar_t * /* O - dateTime value or @code NULL@ */ 2263 ippGetDate(ipp_attribute_t *attr, /* I - IPP attribute */ 2264 int element) /* I - Value number (0-based) */ 2265 { 2266 /* 2267 * Range check input... 2268 */ 2269 2270 if (!attr || attr->value_tag != IPP_TAG_DATE || 2271 element < 0 || element >= attr->num_values) 2272 return (NULL); 2273 2274 /* 2275 * Return the value... 2276 */ 2277 2278 return (attr->values[element].date); 2279 } 2280 2281 2282 /* 2283 * 'ippGetGroupTag()' - Get the group associated with an attribute. 2284 * 2285 * @since CUPS 1.6/macOS 10.8@ 2286 */ 2287 2288 ipp_tag_t /* O - Group tag or @code IPP_TAG_ZERO@ on error */ 2289 ippGetGroupTag(ipp_attribute_t *attr) /* I - IPP attribute */ 2290 { 2291 /* 2292 * Range check input... 2293 */ 2294 2295 if (!attr) 2296 return (IPP_TAG_ZERO); 2297 2298 /* 2299 * Return the group... 2300 */ 2301 2302 return (attr->group_tag); 2303 } 2304 2305 2306 /* 2307 * 'ippGetInteger()' - Get the integer/enum value for an attribute. 2308 * 2309 * The @code element@ parameter specifies which value to get from 0 to 2310 * @code ippGetCount(attr)@ - 1. 2311 * 2312 * @since CUPS 1.6/macOS 10.8@ 2313 */ 2314 2315 int /* O - Value or 0 on error */ 2316 ippGetInteger(ipp_attribute_t *attr, /* I - IPP attribute */ 2317 int element) /* I - Value number (0-based) */ 2318 { 2319 /* 2320 * Range check input... 2321 */ 2322 2323 if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) || 2324 element < 0 || element >= attr->num_values) 2325 return (0); 2326 2327 /* 2328 * Return the value... 2329 */ 2330 2331 return (attr->values[element].integer); 2332 } 2333 2334 2335 /* 2336 * 'ippGetName()' - Get the attribute name. 2337 * 2338 * @since CUPS 1.6/macOS 10.8@ 2339 */ 2340 2341 const char * /* O - Attribute name or @code NULL@ for separators */ 2342 ippGetName(ipp_attribute_t *attr) /* I - IPP attribute */ 2343 { 2344 /* 2345 * Range check input... 2346 */ 2347 2348 if (!attr) 2349 return (NULL); 2350 2351 /* 2352 * Return the name... 2353 */ 2354 2355 return (attr->name); 2356 } 2357 2358 2359 /* 2360 * 'ippGetOctetString()' - Get an octetString value from an IPP attribute. 2361 * 2362 * The @code element@ parameter specifies which value to get from 0 to 2363 * @code ippGetCount(attr)@ - 1. 2364 * 2365 * @since CUPS 1.7/macOS 10.9@ 2366 */ 2367 2368 void * /* O - Pointer to octetString data */ 2369 ippGetOctetString( 2370 ipp_attribute_t *attr, /* I - IPP attribute */ 2371 int element, /* I - Value number (0-based) */ 2372 int *datalen) /* O - Length of octetString data */ 2373 { 2374 /* 2375 * Range check input... 2376 */ 2377 2378 if (!attr || attr->value_tag != IPP_TAG_STRING || 2379 element < 0 || element >= attr->num_values) 2380 { 2381 if (datalen) 2382 *datalen = 0; 2383 2384 return (NULL); 2385 } 2386 2387 /* 2388 * Return the values... 2389 */ 2390 2391 if (datalen) 2392 *datalen = attr->values[element].unknown.length; 2393 2394 return (attr->values[element].unknown.data); 2395 } 2396 2397 2398 /* 2399 * 'ippGetOperation()' - Get the operation ID in an IPP message. 2400 * 2401 * @since CUPS 1.6/macOS 10.8@ 2402 */ 2403 2404 ipp_op_t /* O - Operation ID or 0 on error */ 2405 ippGetOperation(ipp_t *ipp) /* I - IPP request message */ 2406 { 2407 /* 2408 * Range check input... 2409 */ 2410 2411 if (!ipp) 2412 return ((ipp_op_t)0); 2413 2414 /* 2415 * Return the value... 2416 */ 2417 2418 return (ipp->request.op.operation_id); 2419 } 2420 2421 2422 /* 2423 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute. 2424 * 2425 * The @code element@ parameter specifies which value to get from 0 to 2426 * @code ippGetCount(attr)@ - 1. 2427 * 2428 * @since CUPS 1.6/macOS 10.8@ 2429 */ 2430 2431 int /* O - Lower value of range or 0 */ 2432 ippGetRange(ipp_attribute_t *attr, /* I - IPP attribute */ 2433 int element, /* I - Value number (0-based) */ 2434 int *uppervalue)/* O - Upper value of range */ 2435 { 2436 /* 2437 * Range check input... 2438 */ 2439 2440 if (!attr || attr->value_tag != IPP_TAG_RANGE || 2441 element < 0 || element >= attr->num_values) 2442 { 2443 if (uppervalue) 2444 *uppervalue = 0; 2445 2446 return (0); 2447 } 2448 2449 /* 2450 * Return the values... 2451 */ 2452 2453 if (uppervalue) 2454 *uppervalue = attr->values[element].range.upper; 2455 2456 return (attr->values[element].range.lower); 2457 } 2458 2459 2460 /* 2461 * 'ippGetRequestId()' - Get the request ID from an IPP message. 2462 * 2463 * @since CUPS 1.6/macOS 10.8@ 2464 */ 2465 2466 int /* O - Request ID or 0 on error */ 2467 ippGetRequestId(ipp_t *ipp) /* I - IPP message */ 2468 { 2469 /* 2470 * Range check input... 2471 */ 2472 2473 if (!ipp) 2474 return (0); 2475 2476 /* 2477 * Return the request ID... 2478 */ 2479 2480 return (ipp->request.any.request_id); 2481 } 2482 2483 2484 /* 2485 * 'ippGetResolution()' - Get a resolution value for an attribute. 2486 * 2487 * The @code element@ parameter specifies which value to get from 0 to 2488 * @code ippGetCount(attr)@ - 1. 2489 * 2490 * @since CUPS 1.6/macOS 10.8@ 2491 */ 2492 2493 int /* O - Horizontal/cross feed resolution or 0 */ 2494 ippGetResolution( 2495 ipp_attribute_t *attr, /* I - IPP attribute */ 2496 int element, /* I - Value number (0-based) */ 2497 int *yres, /* O - Vertical/feed resolution */ 2498 ipp_res_t *units) /* O - Units for resolution */ 2499 { 2500 /* 2501 * Range check input... 2502 */ 2503 2504 if (!attr || attr->value_tag != IPP_TAG_RESOLUTION || 2505 element < 0 || element >= attr->num_values) 2506 { 2507 if (yres) 2508 *yres = 0; 2509 2510 if (units) 2511 *units = (ipp_res_t)0; 2512 2513 return (0); 2514 } 2515 2516 /* 2517 * Return the value... 2518 */ 2519 2520 if (yres) 2521 *yres = attr->values[element].resolution.yres; 2522 2523 if (units) 2524 *units = attr->values[element].resolution.units; 2525 2526 return (attr->values[element].resolution.xres); 2527 } 2528 2529 2530 /* 2531 * 'ippGetState()' - Get the IPP message state. 2532 * 2533 * @since CUPS 1.6/macOS 10.8@ 2534 */ 2535 2536 ipp_state_t /* O - IPP message state value */ 2537 ippGetState(ipp_t *ipp) /* I - IPP message */ 2538 { 2539 /* 2540 * Range check input... 2541 */ 2542 2543 if (!ipp) 2544 return (IPP_STATE_IDLE); 2545 2546 /* 2547 * Return the value... 2548 */ 2549 2550 return (ipp->state); 2551 } 2552 2553 2554 /* 2555 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message. 2556 * 2557 * @since CUPS 1.6/macOS 10.8@ 2558 */ 2559 2560 ipp_status_t /* O - Status code in IPP message */ 2561 ippGetStatusCode(ipp_t *ipp) /* I - IPP response or event message */ 2562 { 2563 /* 2564 * Range check input... 2565 */ 2566 2567 if (!ipp) 2568 return (IPP_STATUS_ERROR_INTERNAL); 2569 2570 /* 2571 * Return the value... 2572 */ 2573 2574 return (ipp->request.status.status_code); 2575 } 2576 2577 2578 /* 2579 * 'ippGetString()' - Get the string and optionally the language code for an attribute. 2580 * 2581 * The @code element@ parameter specifies which value to get from 0 to 2582 * @code ippGetCount(attr)@ - 1. 2583 * 2584 * @since CUPS 1.6/macOS 10.8@ 2585 */ 2586 2587 const char * 2588 ippGetString(ipp_attribute_t *attr, /* I - IPP attribute */ 2589 int element, /* I - Value number (0-based) */ 2590 const char **language)/* O - Language code (@code NULL@ for don't care) */ 2591 { 2592 ipp_tag_t tag; /* Value tag */ 2593 2594 2595 /* 2596 * Range check input... 2597 */ 2598 2599 tag = ippGetValueTag(attr); 2600 2601 if (!attr || element < 0 || element >= attr->num_values || (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE))) 2602 return (NULL); 2603 2604 /* 2605 * Return the value... 2606 */ 2607 2608 if (language) 2609 *language = attr->values[element].string.language; 2610 2611 return (attr->values[element].string.text); 2612 } 2613 2614 2615 /* 2616 * 'ippGetValueTag()' - Get the value tag for an attribute. 2617 * 2618 * @since CUPS 1.6/macOS 10.8@ 2619 */ 2620 2621 ipp_tag_t /* O - Value tag or @code IPP_TAG_ZERO@ on error */ 2622 ippGetValueTag(ipp_attribute_t *attr) /* I - IPP attribute */ 2623 { 2624 /* 2625 * Range check input... 2626 */ 2627 2628 if (!attr) 2629 return (IPP_TAG_ZERO); 2630 2631 /* 2632 * Return the value... 2633 */ 2634 2635 return (attr->value_tag & IPP_TAG_CUPS_MASK); 2636 } 2637 2638 2639 /* 2640 * 'ippGetVersion()' - Get the major and minor version number from an IPP message. 2641 * 2642 * @since CUPS 1.6/macOS 10.8@ 2643 */ 2644 2645 int /* O - Major version number or 0 on error */ 2646 ippGetVersion(ipp_t *ipp, /* I - IPP message */ 2647 int *minor) /* O - Minor version number or @code NULL@ for don't care */ 2648 { 2649 /* 2650 * Range check input... 2651 */ 2652 2653 if (!ipp) 2654 { 2655 if (minor) 2656 *minor = 0; 2657 2658 return (0); 2659 } 2660 2661 /* 2662 * Return the value... 2663 */ 2664 2665 if (minor) 2666 *minor = ipp->request.any.version[1]; 2667 2668 return (ipp->request.any.version[0]); 2669 } 2670 2671 2672 /* 2673 * 'ippLength()' - Compute the length of an IPP message. 2674 */ 2675 2676 size_t /* O - Size of IPP message */ 2677 ippLength(ipp_t *ipp) /* I - IPP message */ 2678 { 2679 return (ipp_length(ipp, 0)); 2680 } 2681 2682 2683 /* 2684 * 'ippNextAttribute()' - Return the next attribute in the message. 2685 * 2686 * @since CUPS 1.6/macOS 10.8@ 2687 */ 2688 2689 ipp_attribute_t * /* O - Next attribute or @code NULL@ if none */ 2690 ippNextAttribute(ipp_t *ipp) /* I - IPP message */ 2691 { 2692 /* 2693 * Range check input... 2694 */ 2695 2696 if (!ipp || !ipp->current) 2697 return (NULL); 2698 2699 /* 2700 * Return the next attribute... 2701 */ 2702 2703 return (ipp->current = ipp->current->next); 2704 } 2705 2706 2707 /* 2708 * 'ippNew()' - Allocate a new IPP message. 2709 */ 2710 2711 ipp_t * /* O - New IPP message */ 2712 ippNew(void) 2713 { 2714 ipp_t *temp; /* New IPP message */ 2715 _cups_globals_t *cg = _cupsGlobals(); 2716 /* Global data */ 2717 2718 2719 DEBUG_puts("ippNew()"); 2720 2721 if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL) 2722 { 2723 /* 2724 * Set default version - usually 2.0... 2725 */ 2726 2727 DEBUG_printf(("4debug_alloc: %p IPP message", (void *)temp)); 2728 2729 if (cg->server_version == 0) 2730 _cupsSetDefaults(); 2731 2732 temp->request.any.version[0] = (ipp_uchar_t)(cg->server_version / 10); 2733 temp->request.any.version[1] = (ipp_uchar_t)(cg->server_version % 10); 2734 temp->use = 1; 2735 } 2736 2737 DEBUG_printf(("1ippNew: Returning %p", (void *)temp)); 2738 2739 return (temp); 2740 } 2741 2742 2743 /* 2744 * 'ippNewRequest()' - Allocate a new IPP request message. 2745 * 2746 * The new request message is initialized with the "attributes-charset" and 2747 * "attributes-natural-language" attributes added. The 2748 * "attributes-natural-language" value is derived from the current locale. 2749 * 2750 * @since CUPS 1.2/macOS 10.5@ 2751 */ 2752 2753 ipp_t * /* O - IPP request message */ 2754 ippNewRequest(ipp_op_t op) /* I - Operation code */ 2755 { 2756 ipp_t *request; /* IPP request message */ 2757 cups_lang_t *language; /* Current language localization */ 2758 static int request_id = 0; /* Current request ID */ 2759 static _cups_mutex_t request_mutex = _CUPS_MUTEX_INITIALIZER; 2760 /* Mutex for request ID */ 2761 2762 2763 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op, ippOpString(op))); 2764 2765 /* 2766 * Create a new IPP message... 2767 */ 2768 2769 if ((request = ippNew()) == NULL) 2770 return (NULL); 2771 2772 /* 2773 * Set the operation and request ID... 2774 */ 2775 2776 _cupsMutexLock(&request_mutex); 2777 2778 request->request.op.operation_id = op; 2779 request->request.op.request_id = ++request_id; 2780 2781 _cupsMutexUnlock(&request_mutex); 2782 2783 /* 2784 * Use UTF-8 as the character set... 2785 */ 2786 2787 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 2788 "attributes-charset", NULL, "utf-8"); 2789 2790 /* 2791 * Get the language from the current locale... 2792 */ 2793 2794 language = cupsLangDefault(); 2795 2796 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 2797 "attributes-natural-language", NULL, language->language); 2798 2799 /* 2800 * Return the new request... 2801 */ 2802 2803 return (request); 2804 } 2805 2806 2807 /* 2808 * 'ippNewResponse()' - Allocate a new IPP response message. 2809 * 2810 * The new response message is initialized with the same "version-number", 2811 * "request-id", "attributes-charset", and "attributes-natural-language" as the 2812 * provided request message. If the "attributes-charset" or 2813 * "attributes-natural-language" attributes are missing from the request, 2814 * 'utf-8' and a value derived from the current locale are substituted, 2815 * respectively. 2816 * 2817 * @since CUPS 1.7/macOS 10.9@ 2818 */ 2819 2820 ipp_t * /* O - IPP response message */ 2821 ippNewResponse(ipp_t *request) /* I - IPP request message */ 2822 { 2823 ipp_t *response; /* IPP response message */ 2824 ipp_attribute_t *attr; /* Current attribute */ 2825 2826 2827 /* 2828 * Range check input... 2829 */ 2830 2831 if (!request) 2832 return (NULL); 2833 2834 /* 2835 * Create a new IPP message... 2836 */ 2837 2838 if ((response = ippNew()) == NULL) 2839 return (NULL); 2840 2841 /* 2842 * Copy the request values over to the response... 2843 */ 2844 2845 response->request.status.version[0] = request->request.op.version[0]; 2846 response->request.status.version[1] = request->request.op.version[1]; 2847 response->request.status.request_id = request->request.op.request_id; 2848 2849 /* 2850 * The first attribute MUST be attributes-charset... 2851 */ 2852 2853 attr = request->attrs; 2854 2855 if (attr && attr->name && !strcmp(attr->name, "attributes-charset") && 2856 attr->group_tag == IPP_TAG_OPERATION && 2857 attr->value_tag == IPP_TAG_CHARSET && 2858 attr->num_values == 1) 2859 { 2860 /* 2861 * Copy charset from request... 2862 */ 2863 2864 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 2865 "attributes-charset", NULL, attr->values[0].string.text); 2866 } 2867 else 2868 { 2869 /* 2870 * Use "utf-8" as the default... 2871 */ 2872 2873 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 2874 "attributes-charset", NULL, "utf-8"); 2875 } 2876 2877 /* 2878 * Then attributes-natural-language... 2879 */ 2880 2881 if (attr) 2882 attr = attr->next; 2883 2884 if (attr && attr->name && 2885 !strcmp(attr->name, "attributes-natural-language") && 2886 attr->group_tag == IPP_TAG_OPERATION && 2887 attr->value_tag == IPP_TAG_LANGUAGE && 2888 attr->num_values == 1) 2889 { 2890 /* 2891 * Copy language from request... 2892 */ 2893 2894 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 2895 "attributes-natural-language", NULL, 2896 attr->values[0].string.text); 2897 } 2898 else 2899 { 2900 /* 2901 * Use the language from the current locale... 2902 */ 2903 2904 cups_lang_t *language = cupsLangDefault(); 2905 /* Current locale */ 2906 2907 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 2908 "attributes-natural-language", NULL, language->language); 2909 } 2910 2911 return (response); 2912 } 2913 2914 2915 /* 2916 * 'ippRead()' - Read data for an IPP message from a HTTP connection. 2917 */ 2918 2919 ipp_state_t /* O - Current state */ 2920 ippRead(http_t *http, /* I - HTTP connection */ 2921 ipp_t *ipp) /* I - IPP data */ 2922 { 2923 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT, (void *)http, (void *)ipp, CUPS_LLCAST (http ? http->data_remaining : -1))); 2924 2925 if (!http) 2926 return (IPP_STATE_ERROR); 2927 2928 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http->state, http->used)); 2929 2930 return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL, 2931 ipp)); 2932 } 2933 2934 2935 /* 2936 * 'ippReadFile()' - Read data for an IPP message from a file. 2937 * 2938 * @since CUPS 1.1.19/macOS 10.3@ 2939 */ 2940 2941 ipp_state_t /* O - Current state */ 2942 ippReadFile(int fd, /* I - HTTP data */ 2943 ipp_t *ipp) /* I - IPP data */ 2944 { 2945 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd, (void *)ipp)); 2946 2947 return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp)); 2948 } 2949 2950 2951 /* 2952 * 'ippReadIO()' - Read data for an IPP message. 2953 * 2954 * @since CUPS 1.2/macOS 10.5@ 2955 */ 2956 2957 ipp_state_t /* O - Current state */ 2958 ippReadIO(void *src, /* I - Data source */ 2959 ipp_iocb_t cb, /* I - Read callback function */ 2960 int blocking, /* I - Use blocking IO? */ 2961 ipp_t *parent, /* I - Parent request, if any */ 2962 ipp_t *ipp) /* I - IPP data */ 2963 { 2964 int n; /* Length of data */ 2965 unsigned char *buffer, /* Data buffer */ 2966 string[IPP_MAX_TEXT], 2967 /* Small string buffer */ 2968 *bufptr; /* Pointer into buffer */ 2969 ipp_attribute_t *attr; /* Current attribute */ 2970 ipp_tag_t tag; /* Current tag */ 2971 ipp_tag_t value_tag; /* Current value tag */ 2972 _ipp_value_t *value; /* Current value */ 2973 2974 2975 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)src, (void *)cb, blocking, (void *)parent, (void *)ipp)); 2976 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_STATE_ERROR)); 2977 2978 if (!src || !ipp) 2979 return (IPP_STATE_ERROR); 2980 2981 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL) 2982 { 2983 DEBUG_puts("1ippReadIO: Unable to get read buffer."); 2984 return (IPP_STATE_ERROR); 2985 } 2986 2987 switch (ipp->state) 2988 { 2989 case IPP_STATE_IDLE : 2990 ipp->state ++; /* Avoid common problem... */ 2991 2992 case IPP_STATE_HEADER : 2993 if (parent == NULL) 2994 { 2995 /* 2996 * Get the request header... 2997 */ 2998 2999 if ((*cb)(src, buffer, 8) < 8) 3000 { 3001 DEBUG_puts("1ippReadIO: Unable to read header."); 3002 _cupsBufferRelease((char *)buffer); 3003 return (IPP_STATE_ERROR); 3004 } 3005 3006 /* 3007 * Then copy the request header over... 3008 */ 3009 3010 ipp->request.any.version[0] = buffer[0]; 3011 ipp->request.any.version[1] = buffer[1]; 3012 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3]; 3013 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) | 3014 buffer[6]) << 8) | buffer[7]; 3015 3016 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1])); 3017 DEBUG_printf(("2ippReadIO: op_status=%04x", 3018 ipp->request.any.op_status)); 3019 DEBUG_printf(("2ippReadIO: request_id=%d", 3020 ipp->request.any.request_id)); 3021 } 3022 3023 ipp->state = IPP_STATE_ATTRIBUTE; 3024 ipp->current = NULL; 3025 ipp->curtag = IPP_TAG_ZERO; 3026 ipp->prev = ipp->last; 3027 3028 /* 3029 * If blocking is disabled, stop here... 3030 */ 3031 3032 if (!blocking) 3033 break; 3034 3035 case IPP_STATE_ATTRIBUTE : 3036 for (;;) 3037 { 3038 if ((*cb)(src, buffer, 1) < 1) 3039 { 3040 DEBUG_puts("1ippReadIO: Callback returned EOF/error"); 3041 _cupsBufferRelease((char *)buffer); 3042 return (IPP_STATE_ERROR); 3043 } 3044 3045 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev)); 3046 3047 /* 3048 * Read this attribute... 3049 */ 3050 3051 tag = (ipp_tag_t)buffer[0]; 3052 if (tag == IPP_TAG_EXTENSION) 3053 { 3054 /* 3055 * Read 32-bit "extension" tag... 3056 */ 3057 3058 if ((*cb)(src, buffer, 4) < 1) 3059 { 3060 DEBUG_puts("1ippReadIO: Callback returned EOF/error"); 3061 _cupsBufferRelease((char *)buffer); 3062 return (IPP_STATE_ERROR); 3063 } 3064 3065 tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) | 3066 buffer[2]) << 8) | buffer[3]); 3067 3068 if (tag & IPP_TAG_CUPS_CONST) 3069 { 3070 /* 3071 * Fail if the high bit is set in the tag... 3072 */ 3073 3074 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1); 3075 DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag)); 3076 _cupsBufferRelease((char *)buffer); 3077 return (IPP_STATE_ERROR); 3078 } 3079 } 3080 3081 if (tag == IPP_TAG_END) 3082 { 3083 /* 3084 * No more attributes left... 3085 */ 3086 3087 DEBUG_puts("2ippReadIO: IPP_TAG_END."); 3088 3089 ipp->state = IPP_STATE_DATA; 3090 break; 3091 } 3092 else if (tag < IPP_TAG_UNSUPPORTED_VALUE) 3093 { 3094 /* 3095 * Group tag... Set the current group and continue... 3096 */ 3097 3098 if (ipp->curtag == tag) 3099 ipp->prev = ippAddSeparator(ipp); 3100 else if (ipp->current) 3101 ipp->prev = ipp->current; 3102 3103 ipp->curtag = tag; 3104 ipp->current = NULL; 3105 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev)); 3106 continue; 3107 } 3108 3109 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag, 3110 ippTagString(tag))); 3111 3112 /* 3113 * Get the name... 3114 */ 3115 3116 if ((*cb)(src, buffer, 2) < 2) 3117 { 3118 DEBUG_puts("1ippReadIO: unable to read name length."); 3119 _cupsBufferRelease((char *)buffer); 3120 return (IPP_STATE_ERROR); 3121 } 3122 3123 n = (buffer[0] << 8) | buffer[1]; 3124 3125 if (n >= IPP_BUF_SIZE) 3126 { 3127 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1); 3128 DEBUG_printf(("1ippReadIO: bad name length %d.", n)); 3129 _cupsBufferRelease((char *)buffer); 3130 return (IPP_STATE_ERROR); 3131 } 3132 3133 DEBUG_printf(("2ippReadIO: name length=%d", n)); 3134 3135 if (n == 0 && tag != IPP_TAG_MEMBERNAME && 3136 tag != IPP_TAG_END_COLLECTION) 3137 { 3138 /* 3139 * More values for current attribute... 3140 */ 3141 3142 if (ipp->current == NULL) 3143 { 3144 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1); 3145 DEBUG_puts("1ippReadIO: Attribute without name and no current."); 3146 _cupsBufferRelease((char *)buffer); 3147 return (IPP_STATE_ERROR); 3148 } 3149 3150 attr = ipp->current; 3151 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK); 3152 3153 /* 3154 * Make sure we aren't adding a new value of a different 3155 * type... 3156 */ 3157 3158 if (value_tag == IPP_TAG_ZERO) 3159 { 3160 /* 3161 * Setting the value of a collection member... 3162 */ 3163 3164 attr->value_tag = tag; 3165 } 3166 else if (value_tag == IPP_TAG_TEXTLANG || 3167 value_tag == IPP_TAG_NAMELANG || 3168 (value_tag >= IPP_TAG_TEXT && 3169 value_tag <= IPP_TAG_MIMETYPE)) 3170 { 3171 /* 3172 * String values can sometimes come across in different 3173 * forms; accept sets of differing values... 3174 */ 3175 3176 if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && 3177 (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) && 3178 tag != IPP_TAG_NOVALUE) 3179 { 3180 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3181 _("IPP 1setOf attribute with incompatible value " 3182 "tags."), 1); 3183 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)", 3184 value_tag, ippTagString(value_tag), tag, 3185 ippTagString(tag))); 3186 _cupsBufferRelease((char *)buffer); 3187 return (IPP_STATE_ERROR); 3188 } 3189 3190 if (value_tag != tag) 3191 { 3192 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.", 3193 attr->name, ippTagString(value_tag), ippTagString(tag))); 3194 ippSetValueTag(ipp, &attr, tag); 3195 } 3196 } 3197 else if (value_tag == IPP_TAG_INTEGER || 3198 value_tag == IPP_TAG_RANGE) 3199 { 3200 /* 3201 * Integer and rangeOfInteger values can sometimes be mixed; accept 3202 * sets of differing values... 3203 */ 3204 3205 if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE) 3206 { 3207 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3208 _("IPP 1setOf attribute with incompatible value " 3209 "tags."), 1); 3210 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)", 3211 value_tag, ippTagString(value_tag), tag, 3212 ippTagString(tag))); 3213 _cupsBufferRelease((char *)buffer); 3214 return (IPP_STATE_ERROR); 3215 } 3216 3217 if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE) 3218 { 3219 /* 3220 * Convert integer values to rangeOfInteger values... 3221 */ 3222 3223 DEBUG_printf(("1ippReadIO: Converting %s attribute to " 3224 "rangeOfInteger.", attr->name)); 3225 ippSetValueTag(ipp, &attr, IPP_TAG_RANGE); 3226 } 3227 } 3228 else if (value_tag != tag) 3229 { 3230 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3231 _("IPP 1setOf attribute with incompatible value " 3232 "tags."), 1); 3233 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)", 3234 value_tag, ippTagString(value_tag), tag, 3235 ippTagString(tag))); 3236 _cupsBufferRelease((char *)buffer); 3237 return (IPP_STATE_ERROR); 3238 } 3239 3240 /* 3241 * Finally, reallocate the attribute array as needed... 3242 */ 3243 3244 if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL) 3245 { 3246 _cupsBufferRelease((char *)buffer); 3247 return (IPP_STATE_ERROR); 3248 } 3249 } 3250 else if (tag == IPP_TAG_MEMBERNAME) 3251 { 3252 /* 3253 * Name must be length 0! 3254 */ 3255 3256 if (n) 3257 { 3258 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1); 3259 DEBUG_puts("1ippReadIO: member name not empty."); 3260 _cupsBufferRelease((char *)buffer); 3261 return (IPP_STATE_ERROR); 3262 } 3263 3264 if (ipp->current) 3265 ipp->prev = ipp->current; 3266 3267 attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1); 3268 if (!attr) 3269 { 3270 _cupsSetHTTPError(HTTP_STATUS_ERROR); 3271 DEBUG_puts("1ippReadIO: unable to allocate attribute."); 3272 _cupsBufferRelease((char *)buffer); 3273 return (IPP_STATE_ERROR); 3274 } 3275 3276 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev)); 3277 3278 value = attr->values; 3279 } 3280 else if (tag != IPP_TAG_END_COLLECTION) 3281 { 3282 /* 3283 * New attribute; read the name and add it... 3284 */ 3285 3286 if ((*cb)(src, buffer, (size_t)n) < n) 3287 { 3288 DEBUG_puts("1ippReadIO: unable to read name."); 3289 _cupsBufferRelease((char *)buffer); 3290 return (IPP_STATE_ERROR); 3291 } 3292 3293 buffer[n] = '\0'; 3294 3295 if (ipp->current) 3296 ipp->prev = ipp->current; 3297 3298 if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag, 3299 1)) == NULL) 3300 { 3301 _cupsSetHTTPError(HTTP_STATUS_ERROR); 3302 DEBUG_puts("1ippReadIO: unable to allocate attribute."); 3303 _cupsBufferRelease((char *)buffer); 3304 return (IPP_STATE_ERROR); 3305 } 3306 3307 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev)); 3308 3309 value = attr->values; 3310 } 3311 else 3312 { 3313 attr = NULL; 3314 value = NULL; 3315 } 3316 3317 if ((*cb)(src, buffer, 2) < 2) 3318 { 3319 DEBUG_puts("1ippReadIO: unable to read value length."); 3320 _cupsBufferRelease((char *)buffer); 3321 return (IPP_STATE_ERROR); 3322 } 3323 3324 n = (buffer[0] << 8) | buffer[1]; 3325 DEBUG_printf(("2ippReadIO: value length=%d", n)); 3326 3327 if (n >= IPP_BUF_SIZE) 3328 { 3329 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3330 _("IPP value larger than 32767 bytes."), 1); 3331 DEBUG_printf(("1ippReadIO: bad value length %d.", n)); 3332 _cupsBufferRelease((char *)buffer); 3333 return (IPP_STATE_ERROR); 3334 } 3335 3336 switch (tag) 3337 { 3338 case IPP_TAG_INTEGER : 3339 case IPP_TAG_ENUM : 3340 if (n != 4) 3341 { 3342 if (tag == IPP_TAG_INTEGER) 3343 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3344 _("IPP integer value not 4 bytes."), 1); 3345 else 3346 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3347 _("IPP enum value not 4 bytes."), 1); 3348 DEBUG_printf(("1ippReadIO: bad integer value length %d.", n)); 3349 _cupsBufferRelease((char *)buffer); 3350 return (IPP_STATE_ERROR); 3351 } 3352 3353 if ((*cb)(src, buffer, 4) < 4) 3354 { 3355 DEBUG_puts("1ippReadIO: Unable to read integer value."); 3356 _cupsBufferRelease((char *)buffer); 3357 return (IPP_STATE_ERROR); 3358 } 3359 3360 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | 3361 buffer[3]; 3362 3363 if (attr->value_tag == IPP_TAG_RANGE) 3364 value->range.lower = value->range.upper = n; 3365 else 3366 value->integer = n; 3367 break; 3368 3369 case IPP_TAG_BOOLEAN : 3370 if (n != 1) 3371 { 3372 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."), 3373 1); 3374 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n)); 3375 _cupsBufferRelease((char *)buffer); 3376 return (IPP_STATE_ERROR); 3377 } 3378 3379 if ((*cb)(src, buffer, 1) < 1) 3380 { 3381 DEBUG_puts("1ippReadIO: Unable to read boolean value."); 3382 _cupsBufferRelease((char *)buffer); 3383 return (IPP_STATE_ERROR); 3384 } 3385 3386 value->boolean = (char)buffer[0]; 3387 break; 3388 3389 case IPP_TAG_NOVALUE : 3390 case IPP_TAG_NOTSETTABLE : 3391 case IPP_TAG_DELETEATTR : 3392 case IPP_TAG_ADMINDEFINE : 3393 /* 3394 * These value types are not supposed to have values, however 3395 * some vendors (Brother) do not implement IPP correctly and so 3396 * we need to map non-empty values to text... 3397 */ 3398 3399 if (attr->value_tag == tag) 3400 { 3401 if (n == 0) 3402 break; 3403 3404 attr->value_tag = IPP_TAG_TEXT; 3405 } 3406 3407 case IPP_TAG_TEXT : 3408 case IPP_TAG_NAME : 3409 case IPP_TAG_KEYWORD : 3410 case IPP_TAG_URI : 3411 case IPP_TAG_URISCHEME : 3412 case IPP_TAG_CHARSET : 3413 case IPP_TAG_LANGUAGE : 3414 case IPP_TAG_MIMETYPE : 3415 if (n > 0) 3416 { 3417 if ((*cb)(src, buffer, (size_t)n) < n) 3418 { 3419 DEBUG_puts("1ippReadIO: unable to read string value."); 3420 _cupsBufferRelease((char *)buffer); 3421 return (IPP_STATE_ERROR); 3422 } 3423 } 3424 3425 buffer[n] = '\0'; 3426 value->string.text = _cupsStrAlloc((char *)buffer); 3427 DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text)); 3428 break; 3429 3430 case IPP_TAG_DATE : 3431 if (n != 11) 3432 { 3433 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1); 3434 DEBUG_printf(("1ippReadIO: bad date value length %d.", n)); 3435 _cupsBufferRelease((char *)buffer); 3436 return (IPP_STATE_ERROR); 3437 } 3438 3439 if ((*cb)(src, value->date, 11) < 11) 3440 { 3441 DEBUG_puts("1ippReadIO: Unable to read date value."); 3442 _cupsBufferRelease((char *)buffer); 3443 return (IPP_STATE_ERROR); 3444 } 3445 break; 3446 3447 case IPP_TAG_RESOLUTION : 3448 if (n != 9) 3449 { 3450 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3451 _("IPP resolution value not 9 bytes."), 1); 3452 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n)); 3453 _cupsBufferRelease((char *)buffer); 3454 return (IPP_STATE_ERROR); 3455 } 3456 3457 if ((*cb)(src, buffer, 9) < 9) 3458 { 3459 DEBUG_puts("1ippReadIO: Unable to read resolution value."); 3460 _cupsBufferRelease((char *)buffer); 3461 return (IPP_STATE_ERROR); 3462 } 3463 3464 value->resolution.xres = 3465 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | 3466 buffer[3]; 3467 value->resolution.yres = 3468 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | 3469 buffer[7]; 3470 value->resolution.units = 3471 (ipp_res_t)buffer[8]; 3472 break; 3473 3474 case IPP_TAG_RANGE : 3475 if (n != 8) 3476 { 3477 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3478 _("IPP rangeOfInteger value not 8 bytes."), 1); 3479 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length " 3480 "%d.", n)); 3481 _cupsBufferRelease((char *)buffer); 3482 return (IPP_STATE_ERROR); 3483 } 3484 3485 if ((*cb)(src, buffer, 8) < 8) 3486 { 3487 DEBUG_puts("1ippReadIO: Unable to read range value."); 3488 _cupsBufferRelease((char *)buffer); 3489 return (IPP_STATE_ERROR); 3490 } 3491 3492 value->range.lower = 3493 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | 3494 buffer[3]; 3495 value->range.upper = 3496 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) | 3497 buffer[7]; 3498 break; 3499 3500 case IPP_TAG_TEXTLANG : 3501 case IPP_TAG_NAMELANG : 3502 if (n < 4) 3503 { 3504 if (tag == IPP_TAG_TEXTLANG) 3505 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3506 _("IPP textWithLanguage value less than " 3507 "minimum 4 bytes."), 1); 3508 else 3509 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3510 _("IPP nameWithLanguage value less than " 3511 "minimum 4 bytes."), 1); 3512 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value " 3513 "length %d.", n)); 3514 _cupsBufferRelease((char *)buffer); 3515 return (IPP_STATE_ERROR); 3516 } 3517 3518 if ((*cb)(src, buffer, (size_t)n) < n) 3519 { 3520 DEBUG_puts("1ippReadIO: Unable to read string w/language " 3521 "value."); 3522 _cupsBufferRelease((char *)buffer); 3523 return (IPP_STATE_ERROR); 3524 } 3525 3526 bufptr = buffer; 3527 3528 /* 3529 * text-with-language and name-with-language are composite 3530 * values: 3531 * 3532 * language-length 3533 * language 3534 * text-length 3535 * text 3536 */ 3537 3538 n = (bufptr[0] << 8) | bufptr[1]; 3539 3540 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string)) 3541 { 3542 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3543 _("IPP language length overflows value."), 1); 3544 DEBUG_printf(("1ippReadIO: bad language value length %d.", 3545 n)); 3546 _cupsBufferRelease((char *)buffer); 3547 return (IPP_STATE_ERROR); 3548 } 3549 else if (n >= IPP_MAX_LANGUAGE) 3550 { 3551 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3552 _("IPP language length too large."), 1); 3553 DEBUG_printf(("1ippReadIO: bad language value length %d.", 3554 n)); 3555 _cupsBufferRelease((char *)buffer); 3556 return (IPP_STATE_ERROR); 3557 } 3558 3559 memcpy(string, bufptr + 2, (size_t)n); 3560 string[n] = '\0'; 3561 3562 value->string.language = _cupsStrAlloc((char *)string); 3563 3564 bufptr += 2 + n; 3565 n = (bufptr[0] << 8) | bufptr[1]; 3566 3567 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE)) 3568 { 3569 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3570 _("IPP string length overflows value."), 1); 3571 DEBUG_printf(("1ippReadIO: bad string value length %d.", n)); 3572 _cupsBufferRelease((char *)buffer); 3573 return (IPP_STATE_ERROR); 3574 } 3575 3576 bufptr[2 + n] = '\0'; 3577 value->string.text = _cupsStrAlloc((char *)bufptr + 2); 3578 break; 3579 3580 case IPP_TAG_BEGIN_COLLECTION : 3581 /* 3582 * Oh, boy, here comes a collection value, so read it... 3583 */ 3584 3585 value->collection = ippNew(); 3586 3587 if (n > 0) 3588 { 3589 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3590 _("IPP begCollection value not 0 bytes."), 1); 3591 DEBUG_puts("1ippReadIO: begCollection tag with value length " 3592 "> 0."); 3593 _cupsBufferRelease((char *)buffer); 3594 return (IPP_STATE_ERROR); 3595 } 3596 3597 if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR) 3598 { 3599 DEBUG_puts("1ippReadIO: Unable to read collection value."); 3600 _cupsBufferRelease((char *)buffer); 3601 return (IPP_STATE_ERROR); 3602 } 3603 break; 3604 3605 case IPP_TAG_END_COLLECTION : 3606 _cupsBufferRelease((char *)buffer); 3607 3608 if (n > 0) 3609 { 3610 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3611 _("IPP endCollection value not 0 bytes."), 1); 3612 DEBUG_puts("1ippReadIO: endCollection tag with value length " 3613 "> 0."); 3614 return (IPP_STATE_ERROR); 3615 } 3616 3617 DEBUG_puts("1ippReadIO: endCollection tag..."); 3618 return (ipp->state = IPP_STATE_DATA); 3619 3620 case IPP_TAG_MEMBERNAME : 3621 /* 3622 * The value the name of the member in the collection, which 3623 * we need to carry over... 3624 */ 3625 3626 if (!attr) 3627 { 3628 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3629 _("IPP memberName with no attribute."), 1); 3630 DEBUG_puts("1ippReadIO: Member name without attribute."); 3631 _cupsBufferRelease((char *)buffer); 3632 return (IPP_STATE_ERROR); 3633 } 3634 else if (n == 0) 3635 { 3636 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3637 _("IPP memberName value is empty."), 1); 3638 DEBUG_puts("1ippReadIO: Empty member name value."); 3639 _cupsBufferRelease((char *)buffer); 3640 return (IPP_STATE_ERROR); 3641 } 3642 else if ((*cb)(src, buffer, (size_t)n) < n) 3643 { 3644 DEBUG_puts("1ippReadIO: Unable to read member name value."); 3645 _cupsBufferRelease((char *)buffer); 3646 return (IPP_STATE_ERROR); 3647 } 3648 3649 buffer[n] = '\0'; 3650 attr->name = _cupsStrAlloc((char *)buffer); 3651 3652 /* 3653 * Since collection members are encoded differently than 3654 * regular attributes, make sure we don't start with an 3655 * empty value... 3656 */ 3657 3658 attr->num_values --; 3659 3660 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name)); 3661 break; 3662 3663 default : /* Other unsupported values */ 3664 if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH) 3665 { 3666 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 3667 _("IPP octetString length too large."), 1); 3668 DEBUG_printf(("1ippReadIO: bad octetString value length %d.", 3669 n)); 3670 _cupsBufferRelease((char *)buffer); 3671 return (IPP_STATE_ERROR); 3672 } 3673 3674 value->unknown.length = n; 3675 3676 if (n > 0) 3677 { 3678 if ((value->unknown.data = malloc((size_t)n)) == NULL) 3679 { 3680 _cupsSetHTTPError(HTTP_STATUS_ERROR); 3681 DEBUG_puts("1ippReadIO: Unable to allocate value"); 3682 _cupsBufferRelease((char *)buffer); 3683 return (IPP_STATE_ERROR); 3684 } 3685 3686 if ((*cb)(src, value->unknown.data, (size_t)n) < n) 3687 { 3688 DEBUG_puts("1ippReadIO: Unable to read unsupported value."); 3689 _cupsBufferRelease((char *)buffer); 3690 return (IPP_STATE_ERROR); 3691 } 3692 } 3693 else 3694 value->unknown.data = NULL; 3695 break; 3696 } 3697 3698 /* 3699 * If blocking is disabled, stop here... 3700 */ 3701 3702 if (!blocking) 3703 break; 3704 } 3705 break; 3706 3707 case IPP_STATE_DATA : 3708 break; 3709 3710 default : 3711 break; /* anti-compiler-warning-code */ 3712 } 3713 3714 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state)); 3715 _cupsBufferRelease((char *)buffer); 3716 3717 return (ipp->state); 3718 } 3719 3720 3721 /* 3722 * 'ippSetBoolean()' - Set a boolean value in an attribute. 3723 * 3724 * The @code ipp@ parameter refers to an IPP message previously created using 3725 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 3726 * 3727 * The @code attr@ parameter may be modified as a result of setting the value. 3728 * 3729 * The @code element@ parameter specifies which value to set from 0 to 3730 * @code ippGetCount(attr)@. 3731 * 3732 * @since CUPS 1.6/macOS 10.8@ 3733 */ 3734 3735 int /* O - 1 on success, 0 on failure */ 3736 ippSetBoolean(ipp_t *ipp, /* I - IPP message */ 3737 ipp_attribute_t **attr, /* IO - IPP attribute */ 3738 int element, /* I - Value number (0-based) */ 3739 int boolvalue)/* I - Boolean value */ 3740 { 3741 _ipp_value_t *value; /* Current value */ 3742 3743 3744 /* 3745 * Range check input... 3746 */ 3747 3748 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BOOLEAN || 3749 element < 0 || element > (*attr)->num_values) 3750 return (0); 3751 3752 /* 3753 * Set the value and return... 3754 */ 3755 3756 if ((value = ipp_set_value(ipp, attr, element)) != NULL) 3757 value->boolean = (char)boolvalue; 3758 3759 return (value != NULL); 3760 } 3761 3762 3763 /* 3764 * 'ippSetCollection()' - Set a collection value in an attribute. 3765 * 3766 * The @code ipp@ parameter refers to an IPP message previously created using 3767 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 3768 * 3769 * The @code attr@ parameter may be modified as a result of setting the value. 3770 * 3771 * The @code element@ parameter specifies which value to set from 0 to 3772 * @code ippGetCount(attr)@. 3773 * 3774 * @since CUPS 1.6/macOS 10.8@ 3775 */ 3776 3777 int /* O - 1 on success, 0 on failure */ 3778 ippSetCollection( 3779 ipp_t *ipp, /* I - IPP message */ 3780 ipp_attribute_t **attr, /* IO - IPP attribute */ 3781 int element, /* I - Value number (0-based) */ 3782 ipp_t *colvalue) /* I - Collection value */ 3783 { 3784 _ipp_value_t *value; /* Current value */ 3785 3786 3787 /* 3788 * Range check input... 3789 */ 3790 3791 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION || 3792 element < 0 || element > (*attr)->num_values || !colvalue) 3793 return (0); 3794 3795 /* 3796 * Set the value and return... 3797 */ 3798 3799 if ((value = ipp_set_value(ipp, attr, element)) != NULL) 3800 { 3801 if (value->collection) 3802 ippDelete(value->collection); 3803 3804 value->collection = colvalue; 3805 colvalue->use ++; 3806 } 3807 3808 return (value != NULL); 3809 } 3810 3811 3812 /* 3813 * 'ippSetDate()' - Set a dateTime value in an attribute. 3814 * 3815 * The @code ipp@ parameter refers to an IPP message previously created using 3816 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 3817 * 3818 * The @code attr@ parameter may be modified as a result of setting the value. 3819 * 3820 * The @code element@ parameter specifies which value to set from 0 to 3821 * @code ippGetCount(attr)@. 3822 * 3823 * @since CUPS 1.6/macOS 10.8@ 3824 */ 3825 3826 int /* O - 1 on success, 0 on failure */ 3827 ippSetDate(ipp_t *ipp, /* I - IPP message */ 3828 ipp_attribute_t **attr, /* IO - IPP attribute */ 3829 int element, /* I - Value number (0-based) */ 3830 const ipp_uchar_t *datevalue)/* I - dateTime value */ 3831 { 3832 _ipp_value_t *value; /* Current value */ 3833 3834 3835 /* 3836 * Range check input... 3837 */ 3838 3839 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_DATE || 3840 element < 0 || element > (*attr)->num_values || !datevalue) 3841 return (0); 3842 3843 /* 3844 * Set the value and return... 3845 */ 3846 3847 if ((value = ipp_set_value(ipp, attr, element)) != NULL) 3848 memcpy(value->date, datevalue, sizeof(value->date)); 3849 3850 return (value != NULL); 3851 } 3852 3853 3854 /* 3855 * 'ippSetGroupTag()' - Set the group tag of an attribute. 3856 * 3857 * The @code ipp@ parameter refers to an IPP message previously created using 3858 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 3859 * 3860 * The @code attr@ parameter may be modified as a result of setting the value. 3861 * 3862 * The @code group@ parameter specifies the IPP attribute group tag: none 3863 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@), 3864 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation 3865 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription 3866 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@). 3867 * 3868 * @since CUPS 1.6/macOS 10.8@ 3869 */ 3870 3871 int /* O - 1 on success, 0 on failure */ 3872 ippSetGroupTag( 3873 ipp_t *ipp, /* I - IPP message */ 3874 ipp_attribute_t **attr, /* IO - Attribute */ 3875 ipp_tag_t group_tag) /* I - Group tag */ 3876 { 3877 /* 3878 * Range check input - group tag must be 0x01 to 0x0F, per RFC 8011... 3879 */ 3880 3881 if (!ipp || !attr || !*attr || 3882 group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END || 3883 group_tag >= IPP_TAG_UNSUPPORTED_VALUE) 3884 return (0); 3885 3886 /* 3887 * Set the group tag and return... 3888 */ 3889 3890 (*attr)->group_tag = group_tag; 3891 3892 return (1); 3893 } 3894 3895 3896 /* 3897 * 'ippSetInteger()' - Set an integer or enum value in an attribute. 3898 * 3899 * The @code ipp@ parameter refers to an IPP message previously created using 3900 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 3901 * 3902 * The @code attr@ parameter may be modified as a result of setting the value. 3903 * 3904 * The @code element@ parameter specifies which value to set from 0 to 3905 * @code ippGetCount(attr)@. 3906 * 3907 * @since CUPS 1.6/macOS 10.8@ 3908 */ 3909 3910 int /* O - 1 on success, 0 on failure */ 3911 ippSetInteger(ipp_t *ipp, /* I - IPP message */ 3912 ipp_attribute_t **attr, /* IO - IPP attribute */ 3913 int element, /* I - Value number (0-based) */ 3914 int intvalue) /* I - Integer/enum value */ 3915 { 3916 _ipp_value_t *value; /* Current value */ 3917 3918 3919 /* 3920 * Range check input... 3921 */ 3922 3923 if (!ipp || !attr || !*attr || 3924 ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM) || 3925 element < 0 || element > (*attr)->num_values) 3926 return (0); 3927 3928 /* 3929 * Set the value and return... 3930 */ 3931 3932 if ((value = ipp_set_value(ipp, attr, element)) != NULL) 3933 value->integer = intvalue; 3934 3935 return (value != NULL); 3936 } 3937 3938 3939 /* 3940 * 'ippSetName()' - Set the name of an attribute. 3941 * 3942 * The @code ipp@ parameter refers to an IPP message previously created using 3943 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 3944 * 3945 * The @code attr@ parameter may be modified as a result of setting the value. 3946 * 3947 * @since CUPS 1.6/macOS 10.8@ 3948 */ 3949 3950 int /* O - 1 on success, 0 on failure */ 3951 ippSetName(ipp_t *ipp, /* I - IPP message */ 3952 ipp_attribute_t **attr, /* IO - IPP attribute */ 3953 const char *name) /* I - Attribute name */ 3954 { 3955 char *temp; /* Temporary name value */ 3956 3957 3958 /* 3959 * Range check input... 3960 */ 3961 3962 if (!ipp || !attr || !*attr) 3963 return (0); 3964 3965 /* 3966 * Set the value and return... 3967 */ 3968 3969 if ((temp = _cupsStrAlloc(name)) != NULL) 3970 { 3971 if ((*attr)->name) 3972 _cupsStrFree((*attr)->name); 3973 3974 (*attr)->name = temp; 3975 } 3976 3977 return (temp != NULL); 3978 } 3979 3980 3981 /* 3982 * 'ippSetOctetString()' - Set an octetString value in an IPP attribute. 3983 * 3984 * The @code ipp@ parameter refers to an IPP message previously created using 3985 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 3986 * 3987 * The @code attr@ parameter may be modified as a result of setting the value. 3988 * 3989 * The @code element@ parameter specifies which value to set from 0 to 3990 * @code ippGetCount(attr)@. 3991 * 3992 * @since CUPS 1.7/macOS 10.9@ 3993 */ 3994 3995 int /* O - 1 on success, 0 on failure */ 3996 ippSetOctetString( 3997 ipp_t *ipp, /* I - IPP message */ 3998 ipp_attribute_t **attr, /* IO - IPP attribute */ 3999 int element, /* I - Value number (0-based) */ 4000 const void *data, /* I - Pointer to octetString data */ 4001 int datalen) /* I - Length of octetString data */ 4002 { 4003 _ipp_value_t *value; /* Current value */ 4004 4005 4006 /* 4007 * Range check input... 4008 */ 4009 4010 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_STRING || 4011 element < 0 || element > (*attr)->num_values || 4012 datalen < 0 || datalen > IPP_MAX_LENGTH) 4013 return (0); 4014 4015 /* 4016 * Set the value and return... 4017 */ 4018 4019 if ((value = ipp_set_value(ipp, attr, element)) != NULL) 4020 { 4021 if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST) 4022 { 4023 /* 4024 * Just copy the pointer... 4025 */ 4026 4027 value->unknown.data = (void *)data; 4028 value->unknown.length = datalen; 4029 } 4030 else 4031 { 4032 /* 4033 * Copy the data... 4034 */ 4035 4036 if (value->unknown.data) 4037 { 4038 /* 4039 * Free previous data... 4040 */ 4041 4042 free(value->unknown.data); 4043 4044 value->unknown.data = NULL; 4045 value->unknown.length = 0; 4046 } 4047 4048 if (datalen > 0) 4049 { 4050 void *temp; /* Temporary data pointer */ 4051 4052 if ((temp = malloc((size_t)datalen)) != NULL) 4053 { 4054 memcpy(temp, data, (size_t)datalen); 4055 4056 value->unknown.data = temp; 4057 value->unknown.length = datalen; 4058 } 4059 else 4060 return (0); 4061 } 4062 } 4063 } 4064 4065 return (value != NULL); 4066 } 4067 4068 4069 /* 4070 * 'ippSetOperation()' - Set the operation ID in an IPP request message. 4071 * 4072 * The @code ipp@ parameter refers to an IPP message previously created using 4073 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4074 * 4075 * @since CUPS 1.6/macOS 10.8@ 4076 */ 4077 4078 int /* O - 1 on success, 0 on failure */ 4079 ippSetOperation(ipp_t *ipp, /* I - IPP request message */ 4080 ipp_op_t op) /* I - Operation ID */ 4081 { 4082 /* 4083 * Range check input... 4084 */ 4085 4086 if (!ipp) 4087 return (0); 4088 4089 /* 4090 * Set the operation and return... 4091 */ 4092 4093 ipp->request.op.operation_id = op; 4094 4095 return (1); 4096 } 4097 4098 4099 /* 4100 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute. 4101 * 4102 * The @code ipp@ parameter refers to an IPP message previously created using 4103 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4104 * 4105 * The @code attr@ parameter may be modified as a result of setting the value. 4106 * 4107 * The @code element@ parameter specifies which value to set from 0 to 4108 * @code ippGetCount(attr)@. 4109 * 4110 * @since CUPS 1.6/macOS 10.8@ 4111 */ 4112 4113 int /* O - 1 on success, 0 on failure */ 4114 ippSetRange(ipp_t *ipp, /* I - IPP message */ 4115 ipp_attribute_t **attr, /* IO - IPP attribute */ 4116 int element, /* I - Value number (0-based) */ 4117 int lowervalue, /* I - Lower bound for range */ 4118 int uppervalue) /* I - Upper bound for range */ 4119 { 4120 _ipp_value_t *value; /* Current value */ 4121 4122 4123 /* 4124 * Range check input... 4125 */ 4126 4127 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RANGE || 4128 element < 0 || element > (*attr)->num_values || lowervalue > uppervalue) 4129 return (0); 4130 4131 /* 4132 * Set the value and return... 4133 */ 4134 4135 if ((value = ipp_set_value(ipp, attr, element)) != NULL) 4136 { 4137 value->range.lower = lowervalue; 4138 value->range.upper = uppervalue; 4139 } 4140 4141 return (value != NULL); 4142 } 4143 4144 4145 /* 4146 * 'ippSetRequestId()' - Set the request ID in an IPP message. 4147 * 4148 * The @code ipp@ parameter refers to an IPP message previously created using 4149 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4150 * 4151 * The @code request_id@ parameter must be greater than 0. 4152 * 4153 * @since CUPS 1.6/macOS 10.8@ 4154 */ 4155 4156 int /* O - 1 on success, 0 on failure */ 4157 ippSetRequestId(ipp_t *ipp, /* I - IPP message */ 4158 int request_id) /* I - Request ID */ 4159 { 4160 /* 4161 * Range check input; not checking request_id values since ipptool wants to send 4162 * invalid values for conformance testing and a bad request_id does not affect the 4163 * encoding of a message... 4164 */ 4165 4166 if (!ipp) 4167 return (0); 4168 4169 /* 4170 * Set the request ID and return... 4171 */ 4172 4173 ipp->request.any.request_id = request_id; 4174 4175 return (1); 4176 } 4177 4178 4179 /* 4180 * 'ippSetResolution()' - Set a resolution value in an attribute. 4181 * 4182 * The @code ipp@ parameter refers to an IPP message previously created using 4183 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4184 * 4185 * The @code attr@ parameter may be modified as a result of setting the value. 4186 * 4187 * The @code element@ parameter specifies which value to set from 0 to 4188 * @code ippGetCount(attr)@. 4189 * 4190 * @since CUPS 1.6/macOS 10.8@ 4191 */ 4192 4193 int /* O - 1 on success, 0 on failure */ 4194 ippSetResolution( 4195 ipp_t *ipp, /* I - IPP message */ 4196 ipp_attribute_t **attr, /* IO - IPP attribute */ 4197 int element, /* I - Value number (0-based) */ 4198 ipp_res_t unitsvalue, /* I - Resolution units */ 4199 int xresvalue, /* I - Horizontal/cross feed resolution */ 4200 int yresvalue) /* I - Vertical/feed resolution */ 4201 { 4202 _ipp_value_t *value; /* Current value */ 4203 4204 4205 /* 4206 * Range check input... 4207 */ 4208 4209 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RESOLUTION || 4210 element < 0 || element > (*attr)->num_values || xresvalue <= 0 || yresvalue <= 0 || 4211 unitsvalue < IPP_RES_PER_INCH || unitsvalue > IPP_RES_PER_CM) 4212 return (0); 4213 4214 /* 4215 * Set the value and return... 4216 */ 4217 4218 if ((value = ipp_set_value(ipp, attr, element)) != NULL) 4219 { 4220 value->resolution.units = unitsvalue; 4221 value->resolution.xres = xresvalue; 4222 value->resolution.yres = yresvalue; 4223 } 4224 4225 return (value != NULL); 4226 } 4227 4228 4229 /* 4230 * 'ippSetState()' - Set the current state of the IPP message. 4231 * 4232 * @since CUPS 1.6/macOS 10.8@ 4233 */ 4234 4235 int /* O - 1 on success, 0 on failure */ 4236 ippSetState(ipp_t *ipp, /* I - IPP message */ 4237 ipp_state_t state) /* I - IPP state value */ 4238 { 4239 /* 4240 * Range check input... 4241 */ 4242 4243 if (!ipp) 4244 return (0); 4245 4246 /* 4247 * Set the state and return... 4248 */ 4249 4250 ipp->state = state; 4251 ipp->current = NULL; 4252 4253 return (1); 4254 } 4255 4256 4257 /* 4258 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message. 4259 * 4260 * The @code ipp@ parameter refers to an IPP message previously created using 4261 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4262 * 4263 * @since CUPS 1.6/macOS 10.8@ 4264 */ 4265 4266 int /* O - 1 on success, 0 on failure */ 4267 ippSetStatusCode(ipp_t *ipp, /* I - IPP response or event message */ 4268 ipp_status_t status) /* I - Status code */ 4269 { 4270 /* 4271 * Range check input... 4272 */ 4273 4274 if (!ipp) 4275 return (0); 4276 4277 /* 4278 * Set the status code and return... 4279 */ 4280 4281 ipp->request.status.status_code = status; 4282 4283 return (1); 4284 } 4285 4286 4287 /* 4288 * 'ippSetString()' - Set a string value in an attribute. 4289 * 4290 * The @code ipp@ parameter refers to an IPP message previously created using 4291 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4292 * 4293 * The @code attr@ parameter may be modified as a result of setting the value. 4294 * 4295 * The @code element@ parameter specifies which value to set from 0 to 4296 * @code ippGetCount(attr)@. 4297 * 4298 * @since CUPS 1.6/macOS 10.8@ 4299 */ 4300 4301 int /* O - 1 on success, 0 on failure */ 4302 ippSetString(ipp_t *ipp, /* I - IPP message */ 4303 ipp_attribute_t **attr, /* IO - IPP attribute */ 4304 int element, /* I - Value number (0-based) */ 4305 const char *strvalue) /* I - String value */ 4306 { 4307 char *temp; /* Temporary string */ 4308 _ipp_value_t *value; /* Current value */ 4309 4310 4311 /* 4312 * Range check input... 4313 */ 4314 4315 if (!ipp || !attr || !*attr || 4316 ((*attr)->value_tag != IPP_TAG_TEXTLANG && 4317 (*attr)->value_tag != IPP_TAG_NAMELANG && 4318 ((*attr)->value_tag < IPP_TAG_TEXT || 4319 (*attr)->value_tag > IPP_TAG_MIMETYPE)) || 4320 element < 0 || element > (*attr)->num_values || !strvalue) 4321 return (0); 4322 4323 /* 4324 * Set the value and return... 4325 */ 4326 4327 if ((value = ipp_set_value(ipp, attr, element)) != NULL) 4328 { 4329 if (element > 0) 4330 value->string.language = (*attr)->values[0].string.language; 4331 4332 if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST) 4333 value->string.text = (char *)strvalue; 4334 else if ((temp = _cupsStrAlloc(strvalue)) != NULL) 4335 { 4336 if (value->string.text) 4337 _cupsStrFree(value->string.text); 4338 4339 value->string.text = temp; 4340 } 4341 else 4342 return (0); 4343 } 4344 4345 return (value != NULL); 4346 } 4347 4348 4349 /* 4350 * 'ippSetStringf()' - Set a formatted string value of an attribute. 4351 * 4352 * The @code ipp@ parameter refers to an IPP message previously created using 4353 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4354 * 4355 * The @code attr@ parameter may be modified as a result of setting the value. 4356 * 4357 * The @code element@ parameter specifies which value to set from 0 to 4358 * @code ippGetCount(attr)@. 4359 * 4360 * The @code format@ parameter uses formatting characters compatible with the 4361 * printf family of standard functions. Additional arguments follow it as 4362 * needed. The formatted string is truncated as needed to the maximum length of 4363 * the corresponding value type. 4364 * 4365 * @since CUPS 1.7/macOS 10.9@ 4366 */ 4367 4368 int /* O - 1 on success, 0 on failure */ 4369 ippSetStringf(ipp_t *ipp, /* I - IPP message */ 4370 ipp_attribute_t **attr, /* IO - IPP attribute */ 4371 int element, /* I - Value number (0-based) */ 4372 const char *format, /* I - Printf-style format string */ 4373 ...) /* I - Additional arguments as needed */ 4374 { 4375 int ret; /* Return value */ 4376 va_list ap; /* Pointer to additional arguments */ 4377 4378 4379 va_start(ap, format); 4380 ret = ippSetStringfv(ipp, attr, element, format, ap); 4381 va_end(ap); 4382 4383 return (ret); 4384 } 4385 4386 4387 /* 4388 * 'ippSetStringf()' - Set a formatted string value of an attribute. 4389 * 4390 * The @code ipp@ parameter refers to an IPP message previously created using 4391 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4392 * 4393 * The @code attr@ parameter may be modified as a result of setting the value. 4394 * 4395 * The @code element@ parameter specifies which value to set from 0 to 4396 * @code ippGetCount(attr)@. 4397 * 4398 * The @code format@ parameter uses formatting characters compatible with the 4399 * printf family of standard functions. Additional arguments follow it as 4400 * needed. The formatted string is truncated as needed to the maximum length of 4401 * the corresponding value type. 4402 * 4403 * @since CUPS 1.7/macOS 10.9@ 4404 */ 4405 4406 int /* O - 1 on success, 0 on failure */ 4407 ippSetStringfv(ipp_t *ipp, /* I - IPP message */ 4408 ipp_attribute_t **attr, /* IO - IPP attribute */ 4409 int element, /* I - Value number (0-based) */ 4410 const char *format, /* I - Printf-style format string */ 4411 va_list ap) /* I - Pointer to additional arguments */ 4412 { 4413 ipp_tag_t value_tag; /* Value tag */ 4414 char buffer[IPP_MAX_TEXT + 4]; 4415 /* Formatted text string */ 4416 ssize_t bytes, /* Length of formatted value */ 4417 max_bytes; /* Maximum number of bytes for value */ 4418 4419 4420 /* 4421 * Range check input... 4422 */ 4423 4424 if (attr && *attr) 4425 value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK; 4426 else 4427 value_tag = IPP_TAG_ZERO; 4428 4429 if (!ipp || !attr || !*attr || 4430 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG && 4431 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE || 4432 !format) 4433 return (0); 4434 4435 /* 4436 * Format the string... 4437 */ 4438 4439 if (!strcmp(format, "%s")) 4440 { 4441 /* 4442 * Optimize the simple case... 4443 */ 4444 4445 const char *s = va_arg(ap, char *); 4446 4447 if (!s) 4448 s = "(null)"; 4449 4450 bytes = (ssize_t)strlen(s); 4451 strlcpy(buffer, s, sizeof(buffer)); 4452 } 4453 else 4454 { 4455 /* 4456 * Do a full formatting of the message... 4457 */ 4458 4459 if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0) 4460 return (0); 4461 } 4462 4463 /* 4464 * Limit the length of the string... 4465 */ 4466 4467 switch (value_tag) 4468 { 4469 default : 4470 case IPP_TAG_TEXT : 4471 case IPP_TAG_TEXTLANG : 4472 max_bytes = IPP_MAX_TEXT; 4473 break; 4474 4475 case IPP_TAG_NAME : 4476 case IPP_TAG_NAMELANG : 4477 max_bytes = IPP_MAX_NAME; 4478 break; 4479 4480 case IPP_TAG_CHARSET : 4481 max_bytes = IPP_MAX_CHARSET; 4482 break; 4483 4484 case IPP_TAG_KEYWORD : 4485 max_bytes = IPP_MAX_KEYWORD; 4486 break; 4487 4488 case IPP_TAG_LANGUAGE : 4489 max_bytes = IPP_MAX_LANGUAGE; 4490 break; 4491 4492 case IPP_TAG_MIMETYPE : 4493 max_bytes = IPP_MAX_MIMETYPE; 4494 break; 4495 4496 case IPP_TAG_URI : 4497 max_bytes = IPP_MAX_URI; 4498 break; 4499 4500 case IPP_TAG_URISCHEME : 4501 max_bytes = IPP_MAX_URISCHEME; 4502 break; 4503 } 4504 4505 if (bytes >= max_bytes) 4506 { 4507 char *bufmax, /* Buffer at max_bytes */ 4508 *bufptr; /* Pointer into buffer */ 4509 4510 bufptr = buffer + strlen(buffer) - 1; 4511 bufmax = buffer + max_bytes - 1; 4512 4513 while (bufptr > bufmax) 4514 { 4515 if (*bufptr & 0x80) 4516 { 4517 while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer) 4518 bufptr --; 4519 } 4520 4521 bufptr --; 4522 } 4523 4524 *bufptr = '\0'; 4525 } 4526 4527 /* 4528 * Set the formatted string and return... 4529 */ 4530 4531 return (ippSetString(ipp, attr, element, buffer)); 4532 } 4533 4534 4535 /* 4536 * 'ippSetValueTag()' - Set the value tag of an attribute. 4537 * 4538 * The @code ipp@ parameter refers to an IPP message previously created using 4539 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4540 * 4541 * The @code attr@ parameter may be modified as a result of setting the value. 4542 * 4543 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger 4544 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name 4545 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text 4546 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage 4547 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various 4548 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes 4549 * will be rejected. 4550 * 4551 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language 4552 * code in the "attributes-natural-language" attribute or, if not present, the language 4553 * code for the current locale. 4554 * 4555 * @since CUPS 1.6/macOS 10.8@ 4556 */ 4557 4558 int /* O - 1 on success, 0 on failure */ 4559 ippSetValueTag( 4560 ipp_t *ipp, /* I - IPP message */ 4561 ipp_attribute_t **attr, /* IO - IPP attribute */ 4562 ipp_tag_t value_tag) /* I - Value tag */ 4563 { 4564 int i; /* Looping var */ 4565 _ipp_value_t *value; /* Current value */ 4566 int integer; /* Current integer value */ 4567 cups_lang_t *language; /* Current language */ 4568 char code[32]; /* Language code */ 4569 ipp_tag_t temp_tag; /* Temporary value tag */ 4570 4571 4572 /* 4573 * Range check input... 4574 */ 4575 4576 if (!ipp || !attr || !*attr) 4577 return (0); 4578 4579 /* 4580 * If there is no change, return immediately... 4581 */ 4582 4583 if (value_tag == (*attr)->value_tag) 4584 return (1); 4585 4586 /* 4587 * Otherwise implement changes as needed... 4588 */ 4589 4590 temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_CUPS_MASK); 4591 4592 switch (value_tag) 4593 { 4594 case IPP_TAG_UNSUPPORTED_VALUE : 4595 case IPP_TAG_DEFAULT : 4596 case IPP_TAG_UNKNOWN : 4597 case IPP_TAG_NOVALUE : 4598 case IPP_TAG_NOTSETTABLE : 4599 case IPP_TAG_DELETEATTR : 4600 case IPP_TAG_ADMINDEFINE : 4601 /* 4602 * Free any existing values... 4603 */ 4604 4605 if ((*attr)->num_values > 0) 4606 ipp_free_values(*attr, 0, (*attr)->num_values); 4607 4608 /* 4609 * Set out-of-band value... 4610 */ 4611 4612 (*attr)->value_tag = value_tag; 4613 break; 4614 4615 case IPP_TAG_RANGE : 4616 if (temp_tag != IPP_TAG_INTEGER) 4617 return (0); 4618 4619 for (i = (*attr)->num_values, value = (*attr)->values; 4620 i > 0; 4621 i --, value ++) 4622 { 4623 integer = value->integer; 4624 value->range.lower = value->range.upper = integer; 4625 } 4626 4627 (*attr)->value_tag = IPP_TAG_RANGE; 4628 break; 4629 4630 case IPP_TAG_NAME : 4631 if (temp_tag != IPP_TAG_KEYWORD && temp_tag != IPP_TAG_URI && 4632 temp_tag != IPP_TAG_URISCHEME && temp_tag != IPP_TAG_LANGUAGE && 4633 temp_tag != IPP_TAG_MIMETYPE) 4634 return (0); 4635 4636 (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST)); 4637 break; 4638 4639 case IPP_TAG_NAMELANG : 4640 case IPP_TAG_TEXTLANG : 4641 if (value_tag == IPP_TAG_NAMELANG && 4642 (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD && 4643 temp_tag != IPP_TAG_URI && temp_tag != IPP_TAG_URISCHEME && 4644 temp_tag != IPP_TAG_LANGUAGE && temp_tag != IPP_TAG_MIMETYPE)) 4645 return (0); 4646 4647 if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT) 4648 return (0); 4649 4650 if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name && 4651 !strcmp(ipp->attrs->next->name, "attributes-natural-language")) 4652 { 4653 /* 4654 * Use the language code from the IPP message... 4655 */ 4656 4657 (*attr)->values[0].string.language = 4658 _cupsStrAlloc(ipp->attrs->next->values[0].string.text); 4659 } 4660 else 4661 { 4662 /* 4663 * Otherwise, use the language code corresponding to the locale... 4664 */ 4665 4666 language = cupsLangDefault(); 4667 (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language, 4668 code, 4669 sizeof(code))); 4670 } 4671 4672 for (i = (*attr)->num_values - 1, value = (*attr)->values + 1; 4673 i > 0; 4674 i --, value ++) 4675 value->string.language = (*attr)->values[0].string.language; 4676 4677 if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST) 4678 { 4679 /* 4680 * Make copies of all values... 4681 */ 4682 4683 for (i = (*attr)->num_values, value = (*attr)->values; 4684 i > 0; 4685 i --, value ++) 4686 value->string.text = _cupsStrAlloc(value->string.text); 4687 } 4688 4689 (*attr)->value_tag = IPP_TAG_NAMELANG; 4690 break; 4691 4692 case IPP_TAG_KEYWORD : 4693 if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG) 4694 break; /* Silently "allow" name -> keyword */ 4695 4696 default : 4697 return (0); 4698 } 4699 4700 return (1); 4701 } 4702 4703 4704 /* 4705 * 'ippSetVersion()' - Set the version number in an IPP message. 4706 * 4707 * The @code ipp@ parameter refers to an IPP message previously created using 4708 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. 4709 * 4710 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2. 4711 * 4712 * @since CUPS 1.6/macOS 10.8@ 4713 */ 4714 4715 int /* O - 1 on success, 0 on failure */ 4716 ippSetVersion(ipp_t *ipp, /* I - IPP message */ 4717 int major, /* I - Major version number (major.minor) */ 4718 int minor) /* I - Minor version number (major.minor) */ 4719 { 4720 /* 4721 * Range check input... 4722 */ 4723 4724 if (!ipp || major < 0 || minor < 0) 4725 return (0); 4726 4727 /* 4728 * Set the version number... 4729 */ 4730 4731 ipp->request.any.version[0] = (ipp_uchar_t)major; 4732 ipp->request.any.version[1] = (ipp_uchar_t)minor; 4733 4734 return (1); 4735 } 4736 4737 4738 /* 4739 * 'ippTimeToDate()' - Convert from time in seconds to RFC 2579 format. 4740 */ 4741 4742 const ipp_uchar_t * /* O - RFC-2579 date/time data */ 4743 ippTimeToDate(time_t t) /* I - Time in seconds */ 4744 { 4745 struct tm *unixdate; /* UNIX unixdate/time info */ 4746 ipp_uchar_t *date = _cupsGlobals()->ipp_date; 4747 /* RFC-2579 date/time data */ 4748 4749 4750 /* 4751 * RFC-2579 date/time format is: 4752 * 4753 * Byte(s) Description 4754 * ------- ----------- 4755 * 0-1 Year (0 to 65535) 4756 * 2 Month (1 to 12) 4757 * 3 Day (1 to 31) 4758 * 4 Hours (0 to 23) 4759 * 5 Minutes (0 to 59) 4760 * 6 Seconds (0 to 60, 60 = "leap second") 4761 * 7 Deciseconds (0 to 9) 4762 * 8 +/- UTC 4763 * 9 UTC hours (0 to 11) 4764 * 10 UTC minutes (0 to 59) 4765 */ 4766 4767 unixdate = gmtime(&t); 4768 unixdate->tm_year += 1900; 4769 4770 date[0] = (ipp_uchar_t)(unixdate->tm_year >> 8); 4771 date[1] = (ipp_uchar_t)(unixdate->tm_year); 4772 date[2] = (ipp_uchar_t)(unixdate->tm_mon + 1); 4773 date[3] = (ipp_uchar_t)unixdate->tm_mday; 4774 date[4] = (ipp_uchar_t)unixdate->tm_hour; 4775 date[5] = (ipp_uchar_t)unixdate->tm_min; 4776 date[6] = (ipp_uchar_t)unixdate->tm_sec; 4777 date[7] = 0; 4778 date[8] = '+'; 4779 date[9] = 0; 4780 date[10] = 0; 4781 4782 return (date); 4783 } 4784 4785 4786 /* 4787 * 'ippValidateAttribute()' - Validate the contents of an attribute. 4788 * 4789 * This function validates the contents of an attribute based on the name and 4790 * value tag. 1 is returned if the attribute is valid, 0 otherwise. On 4791 * failure, @link cupsLastErrorString@ is set to a human-readable message. 4792 * 4793 * @since CUPS 1.7/macOS 10.9@ 4794 */ 4795 4796 int /* O - 1 if valid, 0 otherwise */ 4797 ippValidateAttribute( 4798 ipp_attribute_t *attr) /* I - Attribute */ 4799 { 4800 int i; /* Looping var */ 4801 char scheme[64], /* Scheme from URI */ 4802 userpass[256], /* Username/password from URI */ 4803 hostname[256], /* Hostname from URI */ 4804 resource[1024]; /* Resource from URI */ 4805 int port, /* Port number from URI */ 4806 uri_status; /* URI separation status */ 4807 const char *ptr; /* Pointer into string */ 4808 ipp_attribute_t *colattr; /* Collection attribute */ 4809 regex_t re; /* Regular expression */ 4810 ipp_uchar_t *date; /* Current date value */ 4811 static const char * const uri_status_strings[] = 4812 { /* URI status strings */ 4813 "URI too large", 4814 "Bad arguments to function", 4815 "Bad resource in URI", 4816 "Bad port number in URI", 4817 "Bad hostname/address in URI", 4818 "Bad username in URI", 4819 "Bad scheme in URI", 4820 "Bad/empty URI", 4821 "OK", 4822 "Missing scheme in URI", 4823 "Unknown scheme in URI", 4824 "Missing resource in URI" 4825 }; 4826 4827 4828 /* 4829 * Skip separators. 4830 */ 4831 4832 if (!attr->name) 4833 return (1); 4834 4835 /* 4836 * Validate the attribute name. 4837 */ 4838 4839 for (ptr = attr->name; *ptr; ptr ++) 4840 if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_') 4841 break; 4842 4843 if (*ptr || ptr == attr->name) 4844 { 4845 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4846 _("\"%s\": Bad attribute name - invalid character " 4847 "(RFC 8011 section 5.1.4)."), attr->name); 4848 return (0); 4849 } 4850 4851 if ((ptr - attr->name) > 255) 4852 { 4853 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4854 _("\"%s\": Bad attribute name - bad length %d " 4855 "(RFC 8011 section 5.1.4)."), attr->name, 4856 (int)(ptr - attr->name)); 4857 return (0); 4858 } 4859 4860 switch (attr->value_tag) 4861 { 4862 case IPP_TAG_INTEGER : 4863 break; 4864 4865 case IPP_TAG_BOOLEAN : 4866 for (i = 0; i < attr->num_values; i ++) 4867 { 4868 if (attr->values[i].boolean != 0 && 4869 attr->values[i].boolean != 1) 4870 { 4871 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4872 _("\"%s\": Bad boolen value %d " 4873 "(RFC 8011 section 5.1.21)."), attr->name, 4874 attr->values[i].boolean); 4875 return (0); 4876 } 4877 } 4878 break; 4879 4880 case IPP_TAG_ENUM : 4881 for (i = 0; i < attr->num_values; i ++) 4882 { 4883 if (attr->values[i].integer < 1) 4884 { 4885 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4886 _("\"%s\": Bad enum value %d - out of range " 4887 "(RFC 8011 section 5.1.5)."), attr->name, 4888 attr->values[i].integer); 4889 return (0); 4890 } 4891 } 4892 break; 4893 4894 case IPP_TAG_STRING : 4895 for (i = 0; i < attr->num_values; i ++) 4896 { 4897 if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING) 4898 { 4899 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4900 _("\"%s\": Bad octetString value - bad length %d " 4901 "(RFC 8011 section 5.1.20)."), attr->name, 4902 attr->values[i].unknown.length); 4903 return (0); 4904 } 4905 } 4906 break; 4907 4908 case IPP_TAG_DATE : 4909 for (i = 0; i < attr->num_values; i ++) 4910 { 4911 date = attr->values[i].date; 4912 4913 if (date[2] < 1 || date[2] > 12) 4914 { 4915 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4916 _("\"%s\": Bad dateTime month %u " 4917 "(RFC 8011 section 5.1.15)."), attr->name, date[2]); 4918 return (0); 4919 } 4920 4921 if (date[3] < 1 || date[3] > 31) 4922 { 4923 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4924 _("\"%s\": Bad dateTime day %u " 4925 "(RFC 8011 section 5.1.15)."), attr->name, date[3]); 4926 return (0); 4927 } 4928 4929 if (date[4] > 23) 4930 { 4931 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4932 _("\"%s\": Bad dateTime hours %u " 4933 "(RFC 8011 section 5.1.15)."), attr->name, date[4]); 4934 return (0); 4935 } 4936 4937 if (date[5] > 59) 4938 { 4939 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4940 _("\"%s\": Bad dateTime minutes %u " 4941 "(RFC 8011 section 5.1.15)."), attr->name, date[5]); 4942 return (0); 4943 } 4944 4945 if (date[6] > 60) 4946 { 4947 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4948 _("\"%s\": Bad dateTime seconds %u " 4949 "(RFC 8011 section 5.1.15)."), attr->name, date[6]); 4950 return (0); 4951 } 4952 4953 if (date[7] > 9) 4954 { 4955 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4956 _("\"%s\": Bad dateTime deciseconds %u " 4957 "(RFC 8011 section 5.1.15)."), attr->name, date[7]); 4958 return (0); 4959 } 4960 4961 if (date[8] != '-' && date[8] != '+') 4962 { 4963 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4964 _("\"%s\": Bad dateTime UTC sign '%c' " 4965 "(RFC 8011 section 5.1.15)."), attr->name, date[8]); 4966 return (0); 4967 } 4968 4969 if (date[9] > 11) 4970 { 4971 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4972 _("\"%s\": Bad dateTime UTC hours %u " 4973 "(RFC 8011 section 5.1.15)."), attr->name, date[9]); 4974 return (0); 4975 } 4976 4977 if (date[10] > 59) 4978 { 4979 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4980 _("\"%s\": Bad dateTime UTC minutes %u " 4981 "(RFC 8011 section 5.1.15)."), attr->name, date[10]); 4982 return (0); 4983 } 4984 } 4985 break; 4986 4987 case IPP_TAG_RESOLUTION : 4988 for (i = 0; i < attr->num_values; i ++) 4989 { 4990 if (attr->values[i].resolution.xres <= 0) 4991 { 4992 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 4993 _("\"%s\": Bad resolution value %dx%d%s - cross " 4994 "feed resolution must be positive " 4995 "(RFC 8011 section 5.1.16)."), attr->name, 4996 attr->values[i].resolution.xres, 4997 attr->values[i].resolution.yres, 4998 attr->values[i].resolution.units == 4999 IPP_RES_PER_INCH ? "dpi" : 5000 attr->values[i].resolution.units == 5001 IPP_RES_PER_CM ? "dpcm" : "unknown"); 5002 return (0); 5003 } 5004 5005 if (attr->values[i].resolution.yres <= 0) 5006 { 5007 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5008 _("\"%s\": Bad resolution value %dx%d%s - feed " 5009 "resolution must be positive " 5010 "(RFC 8011 section 5.1.16)."), attr->name, 5011 attr->values[i].resolution.xres, 5012 attr->values[i].resolution.yres, 5013 attr->values[i].resolution.units == 5014 IPP_RES_PER_INCH ? "dpi" : 5015 attr->values[i].resolution.units == 5016 IPP_RES_PER_CM ? "dpcm" : "unknown"); 5017 return (0); 5018 } 5019 5020 if (attr->values[i].resolution.units != IPP_RES_PER_INCH && 5021 attr->values[i].resolution.units != IPP_RES_PER_CM) 5022 { 5023 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5024 _("\"%s\": Bad resolution value %dx%d%s - bad " 5025 "units value (RFC 8011 section 5.1.16)."), 5026 attr->name, attr->values[i].resolution.xres, 5027 attr->values[i].resolution.yres, 5028 attr->values[i].resolution.units == 5029 IPP_RES_PER_INCH ? "dpi" : 5030 attr->values[i].resolution.units == 5031 IPP_RES_PER_CM ? "dpcm" : "unknown"); 5032 return (0); 5033 } 5034 } 5035 break; 5036 5037 case IPP_TAG_RANGE : 5038 for (i = 0; i < attr->num_values; i ++) 5039 { 5040 if (attr->values[i].range.lower > attr->values[i].range.upper) 5041 { 5042 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5043 _("\"%s\": Bad rangeOfInteger value %d-%d - lower " 5044 "greater than upper (RFC 8011 section 5.1.14)."), 5045 attr->name, attr->values[i].range.lower, 5046 attr->values[i].range.upper); 5047 return (0); 5048 } 5049 } 5050 break; 5051 5052 case IPP_TAG_BEGIN_COLLECTION : 5053 for (i = 0; i < attr->num_values; i ++) 5054 { 5055 for (colattr = attr->values[i].collection->attrs; 5056 colattr; 5057 colattr = colattr->next) 5058 { 5059 if (!ippValidateAttribute(colattr)) 5060 return (0); 5061 } 5062 } 5063 break; 5064 5065 case IPP_TAG_TEXT : 5066 case IPP_TAG_TEXTLANG : 5067 for (i = 0; i < attr->num_values; i ++) 5068 { 5069 for (ptr = attr->values[i].string.text; *ptr; ptr ++) 5070 { 5071 if ((*ptr & 0xe0) == 0xc0) 5072 { 5073 ptr ++; 5074 if ((*ptr & 0xc0) != 0x80) 5075 break; 5076 } 5077 else if ((*ptr & 0xf0) == 0xe0) 5078 { 5079 ptr ++; 5080 if ((*ptr & 0xc0) != 0x80) 5081 break; 5082 ptr ++; 5083 if ((*ptr & 0xc0) != 0x80) 5084 break; 5085 } 5086 else if ((*ptr & 0xf8) == 0xf0) 5087 { 5088 ptr ++; 5089 if ((*ptr & 0xc0) != 0x80) 5090 break; 5091 ptr ++; 5092 if ((*ptr & 0xc0) != 0x80) 5093 break; 5094 ptr ++; 5095 if ((*ptr & 0xc0) != 0x80) 5096 break; 5097 } 5098 else if (*ptr & 0x80) 5099 break; 5100 } 5101 5102 if (*ptr) 5103 { 5104 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5105 _("\"%s\": Bad text value \"%s\" - bad UTF-8 " 5106 "sequence (RFC 8011 section 5.1.2)."), attr->name, 5107 attr->values[i].string.text); 5108 return (0); 5109 } 5110 5111 if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1)) 5112 { 5113 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5114 _("\"%s\": Bad text value \"%s\" - bad length %d " 5115 "(RFC 8011 section 5.1.2)."), attr->name, 5116 attr->values[i].string.text, 5117 (int)(ptr - attr->values[i].string.text)); 5118 return (0); 5119 } 5120 } 5121 break; 5122 5123 case IPP_TAG_NAME : 5124 case IPP_TAG_NAMELANG : 5125 for (i = 0; i < attr->num_values; i ++) 5126 { 5127 for (ptr = attr->values[i].string.text; *ptr; ptr ++) 5128 { 5129 if ((*ptr & 0xe0) == 0xc0) 5130 { 5131 ptr ++; 5132 if ((*ptr & 0xc0) != 0x80) 5133 break; 5134 } 5135 else if ((*ptr & 0xf0) == 0xe0) 5136 { 5137 ptr ++; 5138 if ((*ptr & 0xc0) != 0x80) 5139 break; 5140 ptr ++; 5141 if ((*ptr & 0xc0) != 0x80) 5142 break; 5143 } 5144 else if ((*ptr & 0xf8) == 0xf0) 5145 { 5146 ptr ++; 5147 if ((*ptr & 0xc0) != 0x80) 5148 break; 5149 ptr ++; 5150 if ((*ptr & 0xc0) != 0x80) 5151 break; 5152 ptr ++; 5153 if ((*ptr & 0xc0) != 0x80) 5154 break; 5155 } 5156 else if (*ptr & 0x80) 5157 break; 5158 } 5159 5160 if (*ptr) 5161 { 5162 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5163 _("\"%s\": Bad name value \"%s\" - bad UTF-8 " 5164 "sequence (RFC 8011 section 5.1.3)."), attr->name, 5165 attr->values[i].string.text); 5166 return (0); 5167 } 5168 5169 if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1)) 5170 { 5171 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5172 _("\"%s\": Bad name value \"%s\" - bad length %d " 5173 "(RFC 8011 section 5.1.3)."), attr->name, 5174 attr->values[i].string.text, 5175 (int)(ptr - attr->values[i].string.text)); 5176 return (0); 5177 } 5178 } 5179 break; 5180 5181 case IPP_TAG_KEYWORD : 5182 for (i = 0; i < attr->num_values; i ++) 5183 { 5184 for (ptr = attr->values[i].string.text; *ptr; ptr ++) 5185 if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && 5186 *ptr != '_') 5187 break; 5188 5189 if (*ptr || ptr == attr->values[i].string.text) 5190 { 5191 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5192 _("\"%s\": Bad keyword value \"%s\" - invalid " 5193 "character (RFC 8011 section 5.1.4)."), 5194 attr->name, attr->values[i].string.text); 5195 return (0); 5196 } 5197 5198 if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1)) 5199 { 5200 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5201 _("\"%s\": Bad keyword value \"%s\" - bad " 5202 "length %d (RFC 8011 section 5.1.4)."), 5203 attr->name, attr->values[i].string.text, 5204 (int)(ptr - attr->values[i].string.text)); 5205 return (0); 5206 } 5207 } 5208 break; 5209 5210 case IPP_TAG_URI : 5211 for (i = 0; i < attr->num_values; i ++) 5212 { 5213 uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, 5214 attr->values[i].string.text, 5215 scheme, sizeof(scheme), 5216 userpass, sizeof(userpass), 5217 hostname, sizeof(hostname), 5218 &port, resource, sizeof(resource)); 5219 5220 if (uri_status < HTTP_URI_STATUS_OK) 5221 { 5222 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5223 _("\"%s\": Bad URI value \"%s\" - %s " 5224 "(RFC 8011 section 5.1.6)."), attr->name, 5225 attr->values[i].string.text, 5226 uri_status_strings[uri_status - 5227 HTTP_URI_STATUS_OVERFLOW]); 5228 return (0); 5229 } 5230 5231 if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1)) 5232 { 5233 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5234 _("\"%s\": Bad URI value \"%s\" - bad length %d " 5235 "(RFC 8011 section 5.1.6)."), attr->name, 5236 attr->values[i].string.text, 5237 (int)strlen(attr->values[i].string.text)); 5238 } 5239 } 5240 break; 5241 5242 case IPP_TAG_URISCHEME : 5243 for (i = 0; i < attr->num_values; i ++) 5244 { 5245 ptr = attr->values[i].string.text; 5246 if (islower(*ptr & 255)) 5247 { 5248 for (ptr ++; *ptr; ptr ++) 5249 if (!islower(*ptr & 255) && !isdigit(*ptr & 255) && 5250 *ptr != '+' && *ptr != '-' && *ptr != '.') 5251 break; 5252 } 5253 5254 if (*ptr || ptr == attr->values[i].string.text) 5255 { 5256 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5257 _("\"%s\": Bad uriScheme value \"%s\" - bad " 5258 "characters (RFC 8011 section 5.1.7)."), 5259 attr->name, attr->values[i].string.text); 5260 return (0); 5261 } 5262 5263 if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1)) 5264 { 5265 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5266 _("\"%s\": Bad uriScheme value \"%s\" - bad " 5267 "length %d (RFC 8011 section 5.1.7)."), 5268 attr->name, attr->values[i].string.text, 5269 (int)(ptr - attr->values[i].string.text)); 5270 return (0); 5271 } 5272 } 5273 break; 5274 5275 case IPP_TAG_CHARSET : 5276 for (i = 0; i < attr->num_values; i ++) 5277 { 5278 for (ptr = attr->values[i].string.text; *ptr; ptr ++) 5279 if (!isprint(*ptr & 255) || isupper(*ptr & 255) || 5280 isspace(*ptr & 255)) 5281 break; 5282 5283 if (*ptr || ptr == attr->values[i].string.text) 5284 { 5285 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5286 _("\"%s\": Bad charset value \"%s\" - bad " 5287 "characters (RFC 8011 section 5.1.8)."), 5288 attr->name, attr->values[i].string.text); 5289 return (0); 5290 } 5291 5292 if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1)) 5293 { 5294 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5295 _("\"%s\": Bad charset value \"%s\" - bad " 5296 "length %d (RFC 8011 section 5.1.8)."), 5297 attr->name, attr->values[i].string.text, 5298 (int)(ptr - attr->values[i].string.text)); 5299 return (0); 5300 } 5301 } 5302 break; 5303 5304 case IPP_TAG_LANGUAGE : 5305 /* 5306 * The following regular expression is derived from the ABNF for 5307 * language tags in RFC 4646. All I can say is that this is the 5308 * easiest way to check the values... 5309 */ 5310 5311 if ((i = regcomp(&re, 5312 "^(" 5313 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})" 5314 /* language */ 5315 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */ 5316 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */ 5317 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */ 5318 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */ 5319 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */ 5320 "|" 5321 "x(-[a-z0-9]{1,8})+" /* privateuse */ 5322 "|" 5323 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */ 5324 ")$", 5325 REG_NOSUB | REG_EXTENDED)) != 0) 5326 { 5327 char temp[256]; /* Temporary error string */ 5328 5329 regerror(i, &re, temp, sizeof(temp)); 5330 ipp_set_error(IPP_STATUS_ERROR_INTERNAL, 5331 _("Unable to compile naturalLanguage regular " 5332 "expression: %s."), temp); 5333 return (0); 5334 } 5335 5336 for (i = 0; i < attr->num_values; i ++) 5337 { 5338 if (regexec(&re, attr->values[i].string.text, 0, NULL, 0)) 5339 { 5340 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5341 _("\"%s\": Bad naturalLanguage value \"%s\" - bad " 5342 "characters (RFC 8011 section 5.1.9)."), 5343 attr->name, attr->values[i].string.text); 5344 regfree(&re); 5345 return (0); 5346 } 5347 5348 if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1)) 5349 { 5350 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5351 _("\"%s\": Bad naturalLanguage value \"%s\" - bad " 5352 "length %d (RFC 8011 section 5.1.9)."), 5353 attr->name, attr->values[i].string.text, 5354 (int)strlen(attr->values[i].string.text)); 5355 regfree(&re); 5356 return (0); 5357 } 5358 } 5359 5360 regfree(&re); 5361 break; 5362 5363 case IPP_TAG_MIMETYPE : 5364 /* 5365 * The following regular expression is derived from the ABNF for 5366 * MIME media types in RFC 2045 and 4288. All I can say is that this is 5367 * the easiest way to check the values... 5368 */ 5369 5370 if ((i = regcomp(&re, 5371 "^" 5372 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */ 5373 "/" 5374 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */ 5375 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */ 5376 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*" 5377 /* value */ 5378 "$", 5379 REG_NOSUB | REG_EXTENDED)) != 0) 5380 { 5381 char temp[256]; /* Temporary error string */ 5382 5383 regerror(i, &re, temp, sizeof(temp)); 5384 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5385 _("Unable to compile mimeMediaType regular " 5386 "expression: %s."), temp); 5387 return (0); 5388 } 5389 5390 for (i = 0; i < attr->num_values; i ++) 5391 { 5392 if (regexec(&re, attr->values[i].string.text, 0, NULL, 0)) 5393 { 5394 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5395 _("\"%s\": Bad mimeMediaType value \"%s\" - bad " 5396 "characters (RFC 8011 section 5.1.10)."), 5397 attr->name, attr->values[i].string.text); 5398 regfree(&re); 5399 return (0); 5400 } 5401 5402 if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1)) 5403 { 5404 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, 5405 _("\"%s\": Bad mimeMediaType value \"%s\" - bad " 5406 "length %d (RFC 8011 section 5.1.10)."), 5407 attr->name, attr->values[i].string.text, 5408 (int)strlen(attr->values[i].string.text)); 5409 regfree(&re); 5410 return (0); 5411 } 5412 } 5413 5414 regfree(&re); 5415 break; 5416 5417 default : 5418 break; 5419 } 5420 5421 return (1); 5422 } 5423 5424 5425 /* 5426 * 'ippValidateAttributes()' - Validate all attributes in an IPP message. 5427 * 5428 * This function validates the contents of the IPP message, including each 5429 * attribute. Like @link ippValidateAttribute@, @link cupsLastErrorString@ is 5430 * set to a human-readable message on failure. 5431 * 5432 * @since CUPS 1.7/macOS 10.9@ 5433 */ 5434 5435 int /* O - 1 if valid, 0 otherwise */ 5436 ippValidateAttributes(ipp_t *ipp) /* I - IPP message */ 5437 { 5438 ipp_attribute_t *attr; /* Current attribute */ 5439 5440 5441 if (!ipp) 5442 return (1); 5443 5444 for (attr = ipp->attrs; attr; attr = attr->next) 5445 if (!ippValidateAttribute(attr)) 5446 return (0); 5447 5448 return (1); 5449 } 5450 5451 5452 /* 5453 * 'ippWrite()' - Write data for an IPP message to a HTTP connection. 5454 */ 5455 5456 ipp_state_t /* O - Current state */ 5457 ippWrite(http_t *http, /* I - HTTP connection */ 5458 ipp_t *ipp) /* I - IPP data */ 5459 { 5460 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", (void *)http, (void *)ipp)); 5461 5462 if (!http) 5463 return (IPP_STATE_ERROR); 5464 5465 return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp)); 5466 } 5467 5468 5469 /* 5470 * 'ippWriteFile()' - Write data for an IPP message to a file. 5471 * 5472 * @since CUPS 1.1.19/macOS 10.3@ 5473 */ 5474 5475 ipp_state_t /* O - Current state */ 5476 ippWriteFile(int fd, /* I - HTTP data */ 5477 ipp_t *ipp) /* I - IPP data */ 5478 { 5479 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp)); 5480 5481 ipp->state = IPP_STATE_IDLE; 5482 5483 return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp)); 5484 } 5485 5486 5487 /* 5488 * 'ippWriteIO()' - Write data for an IPP message. 5489 * 5490 * @since CUPS 1.2/macOS 10.5@ 5491 */ 5492 5493 ipp_state_t /* O - Current state */ 5494 ippWriteIO(void *dst, /* I - Destination */ 5495 ipp_iocb_t cb, /* I - Write callback function */ 5496 int blocking, /* I - Use blocking IO? */ 5497 ipp_t *parent, /* I - Parent IPP message */ 5498 ipp_t *ipp) /* I - IPP data */ 5499 { 5500 int i; /* Looping var */ 5501 int n; /* Length of data */ 5502 unsigned char *buffer, /* Data buffer */ 5503 *bufptr; /* Pointer into buffer */ 5504 ipp_attribute_t *attr; /* Current attribute */ 5505 _ipp_value_t *value; /* Current value */ 5506 5507 5508 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp)); 5509 5510 if (!dst || !ipp) 5511 return (IPP_STATE_ERROR); 5512 5513 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL) 5514 { 5515 DEBUG_puts("1ippWriteIO: Unable to get write buffer"); 5516 return (IPP_STATE_ERROR); 5517 } 5518 5519 switch (ipp->state) 5520 { 5521 case IPP_STATE_IDLE : 5522 ipp->state ++; /* Avoid common problem... */ 5523 5524 case IPP_STATE_HEADER : 5525 if (parent == NULL) 5526 { 5527 /* 5528 * Send the request header: 5529 * 5530 * Version = 2 bytes 5531 * Operation/Status Code = 2 bytes 5532 * Request ID = 4 bytes 5533 * Total = 8 bytes 5534 */ 5535 5536 bufptr = buffer; 5537 5538 *bufptr++ = ipp->request.any.version[0]; 5539 *bufptr++ = ipp->request.any.version[1]; 5540 *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8); 5541 *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status; 5542 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24); 5543 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16); 5544 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8); 5545 *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id; 5546 5547 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1])); 5548 DEBUG_printf(("2ippWriteIO: op_status=%04x", 5549 ipp->request.any.op_status)); 5550 DEBUG_printf(("2ippWriteIO: request_id=%d", 5551 ipp->request.any.request_id)); 5552 5553 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 5554 { 5555 DEBUG_puts("1ippWriteIO: Could not write IPP header..."); 5556 _cupsBufferRelease((char *)buffer); 5557 return (IPP_STATE_ERROR); 5558 } 5559 } 5560 5561 /* 5562 * Reset the state engine to point to the first attribute 5563 * in the request/response, with no current group. 5564 */ 5565 5566 ipp->state = IPP_STATE_ATTRIBUTE; 5567 ipp->current = ipp->attrs; 5568 ipp->curtag = IPP_TAG_ZERO; 5569 5570 DEBUG_printf(("1ippWriteIO: ipp->current=%p", (void *)ipp->current)); 5571 5572 /* 5573 * If blocking is disabled, stop here... 5574 */ 5575 5576 if (!blocking) 5577 break; 5578 5579 case IPP_STATE_ATTRIBUTE : 5580 while (ipp->current != NULL) 5581 { 5582 /* 5583 * Write this attribute... 5584 */ 5585 5586 bufptr = buffer; 5587 attr = ipp->current; 5588 5589 ipp->current = ipp->current->next; 5590 5591 if (!parent) 5592 { 5593 if (ipp->curtag != attr->group_tag) 5594 { 5595 /* 5596 * Send a group tag byte... 5597 */ 5598 5599 ipp->curtag = attr->group_tag; 5600 5601 if (attr->group_tag == IPP_TAG_ZERO) 5602 continue; 5603 5604 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)", 5605 attr->group_tag, ippTagString(attr->group_tag))); 5606 *bufptr++ = (ipp_uchar_t)attr->group_tag; 5607 } 5608 else if (attr->group_tag == IPP_TAG_ZERO) 5609 continue; 5610 } 5611 5612 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name, 5613 attr->num_values > 1 ? "1setOf " : "", 5614 ippTagString(attr->value_tag))); 5615 5616 /* 5617 * Write the attribute tag and name. 5618 * 5619 * The attribute name length does not include the trailing nul 5620 * character in the source string. 5621 * 5622 * Collection values (parent != NULL) are written differently... 5623 */ 5624 5625 if (parent == NULL) 5626 { 5627 /* 5628 * Get the length of the attribute name, and make sure it won't 5629 * overflow the buffer... 5630 */ 5631 5632 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8)) 5633 { 5634 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n)); 5635 _cupsBufferRelease((char *)buffer); 5636 return (IPP_STATE_ERROR); 5637 } 5638 5639 /* 5640 * Write the value tag, name length, and name string... 5641 */ 5642 5643 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)", 5644 attr->value_tag, ippTagString(attr->value_tag))); 5645 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n, 5646 attr->name)); 5647 5648 if (attr->value_tag > 0xff) 5649 { 5650 *bufptr++ = IPP_TAG_EXTENSION; 5651 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24); 5652 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16); 5653 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8); 5654 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5655 } 5656 else 5657 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5658 5659 *bufptr++ = (ipp_uchar_t)(n >> 8); 5660 *bufptr++ = (ipp_uchar_t)n; 5661 memcpy(bufptr, attr->name, (size_t)n); 5662 bufptr += n; 5663 } 5664 else 5665 { 5666 /* 5667 * Get the length of the attribute name, and make sure it won't 5668 * overflow the buffer... 5669 */ 5670 5671 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12)) 5672 { 5673 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n)); 5674 _cupsBufferRelease((char *)buffer); 5675 return (IPP_STATE_ERROR); 5676 } 5677 5678 /* 5679 * Write the member name tag, name length, name string, value tag, 5680 * and empty name for the collection member attribute... 5681 */ 5682 5683 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)", 5684 IPP_TAG_MEMBERNAME)); 5685 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n, 5686 attr->name)); 5687 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)", 5688 attr->value_tag, ippTagString(attr->value_tag))); 5689 DEBUG_puts("2ippWriteIO: writing name=0,\"\""); 5690 5691 *bufptr++ = IPP_TAG_MEMBERNAME; 5692 *bufptr++ = 0; 5693 *bufptr++ = 0; 5694 *bufptr++ = (ipp_uchar_t)(n >> 8); 5695 *bufptr++ = (ipp_uchar_t)n; 5696 memcpy(bufptr, attr->name, (size_t)n); 5697 bufptr += n; 5698 5699 if (attr->value_tag > 0xff) 5700 { 5701 *bufptr++ = IPP_TAG_EXTENSION; 5702 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24); 5703 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16); 5704 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8); 5705 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5706 } 5707 else 5708 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5709 5710 *bufptr++ = 0; 5711 *bufptr++ = 0; 5712 } 5713 5714 /* 5715 * Now write the attribute value(s)... 5716 */ 5717 5718 switch (attr->value_tag & ~IPP_TAG_CUPS_CONST) 5719 { 5720 case IPP_TAG_UNSUPPORTED_VALUE : 5721 case IPP_TAG_DEFAULT : 5722 case IPP_TAG_UNKNOWN : 5723 case IPP_TAG_NOVALUE : 5724 case IPP_TAG_NOTSETTABLE : 5725 case IPP_TAG_DELETEATTR : 5726 case IPP_TAG_ADMINDEFINE : 5727 *bufptr++ = 0; 5728 *bufptr++ = 0; 5729 break; 5730 5731 case IPP_TAG_INTEGER : 5732 case IPP_TAG_ENUM : 5733 for (i = 0, value = attr->values; 5734 i < attr->num_values; 5735 i ++, value ++) 5736 { 5737 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9) 5738 { 5739 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 5740 { 5741 DEBUG_puts("1ippWriteIO: Could not write IPP " 5742 "attribute..."); 5743 _cupsBufferRelease((char *)buffer); 5744 return (IPP_STATE_ERROR); 5745 } 5746 5747 bufptr = buffer; 5748 } 5749 5750 if (i) 5751 { 5752 /* 5753 * Arrays and sets are done by sending additional 5754 * values with a zero-length name... 5755 */ 5756 5757 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5758 *bufptr++ = 0; 5759 *bufptr++ = 0; 5760 } 5761 5762 /* 5763 * Integers and enumerations are both 4-byte signed 5764 * (twos-complement) values. 5765 * 5766 * Put the 2-byte length and 4-byte value into the buffer... 5767 */ 5768 5769 *bufptr++ = 0; 5770 *bufptr++ = 4; 5771 *bufptr++ = (ipp_uchar_t)(value->integer >> 24); 5772 *bufptr++ = (ipp_uchar_t)(value->integer >> 16); 5773 *bufptr++ = (ipp_uchar_t)(value->integer >> 8); 5774 *bufptr++ = (ipp_uchar_t)value->integer; 5775 } 5776 break; 5777 5778 case IPP_TAG_BOOLEAN : 5779 for (i = 0, value = attr->values; 5780 i < attr->num_values; 5781 i ++, value ++) 5782 { 5783 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6) 5784 { 5785 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 5786 { 5787 DEBUG_puts("1ippWriteIO: Could not write IPP " 5788 "attribute..."); 5789 _cupsBufferRelease((char *)buffer); 5790 return (IPP_STATE_ERROR); 5791 } 5792 5793 bufptr = buffer; 5794 } 5795 5796 if (i) 5797 { 5798 /* 5799 * Arrays and sets are done by sending additional 5800 * values with a zero-length name... 5801 */ 5802 5803 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5804 *bufptr++ = 0; 5805 *bufptr++ = 0; 5806 } 5807 5808 /* 5809 * Boolean values are 1-byte; 0 = false, 1 = true. 5810 * 5811 * Put the 2-byte length and 1-byte value into the buffer... 5812 */ 5813 5814 *bufptr++ = 0; 5815 *bufptr++ = 1; 5816 *bufptr++ = (ipp_uchar_t)value->boolean; 5817 } 5818 break; 5819 5820 case IPP_TAG_TEXT : 5821 case IPP_TAG_NAME : 5822 case IPP_TAG_KEYWORD : 5823 case IPP_TAG_URI : 5824 case IPP_TAG_URISCHEME : 5825 case IPP_TAG_CHARSET : 5826 case IPP_TAG_LANGUAGE : 5827 case IPP_TAG_MIMETYPE : 5828 for (i = 0, value = attr->values; 5829 i < attr->num_values; 5830 i ++, value ++) 5831 { 5832 if (i) 5833 { 5834 /* 5835 * Arrays and sets are done by sending additional 5836 * values with a zero-length name... 5837 */ 5838 5839 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)", 5840 attr->value_tag, 5841 ippTagString(attr->value_tag))); 5842 DEBUG_printf(("2ippWriteIO: writing name=0,\"\"")); 5843 5844 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3) 5845 { 5846 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 5847 { 5848 DEBUG_puts("1ippWriteIO: Could not write IPP " 5849 "attribute..."); 5850 _cupsBufferRelease((char *)buffer); 5851 return (IPP_STATE_ERROR); 5852 } 5853 5854 bufptr = buffer; 5855 } 5856 5857 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5858 *bufptr++ = 0; 5859 *bufptr++ = 0; 5860 } 5861 5862 if (value->string.text != NULL) 5863 n = (int)strlen(value->string.text); 5864 else 5865 n = 0; 5866 5867 if (n > (IPP_BUF_SIZE - 2)) 5868 { 5869 DEBUG_printf(("1ippWriteIO: String too long (%d)", n)); 5870 _cupsBufferRelease((char *)buffer); 5871 return (IPP_STATE_ERROR); 5872 } 5873 5874 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n, 5875 value->string.text)); 5876 5877 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2)) 5878 { 5879 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 5880 { 5881 DEBUG_puts("1ippWriteIO: Could not write IPP " 5882 "attribute..."); 5883 _cupsBufferRelease((char *)buffer); 5884 return (IPP_STATE_ERROR); 5885 } 5886 5887 bufptr = buffer; 5888 } 5889 5890 /* 5891 * All simple strings consist of the 2-byte length and 5892 * character data without the trailing nul normally found 5893 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH 5894 * bytes since the 2-byte length is a signed (twos-complement) 5895 * value. 5896 * 5897 * Put the 2-byte length and string characters in the buffer. 5898 */ 5899 5900 *bufptr++ = (ipp_uchar_t)(n >> 8); 5901 *bufptr++ = (ipp_uchar_t)n; 5902 5903 if (n > 0) 5904 { 5905 memcpy(bufptr, value->string.text, (size_t)n); 5906 bufptr += n; 5907 } 5908 } 5909 break; 5910 5911 case IPP_TAG_DATE : 5912 for (i = 0, value = attr->values; 5913 i < attr->num_values; 5914 i ++, value ++) 5915 { 5916 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16) 5917 { 5918 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 5919 { 5920 DEBUG_puts("1ippWriteIO: Could not write IPP " 5921 "attribute..."); 5922 _cupsBufferRelease((char *)buffer); 5923 return (IPP_STATE_ERROR); 5924 } 5925 5926 bufptr = buffer; 5927 } 5928 5929 if (i) 5930 { 5931 /* 5932 * Arrays and sets are done by sending additional 5933 * values with a zero-length name... 5934 */ 5935 5936 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5937 *bufptr++ = 0; 5938 *bufptr++ = 0; 5939 } 5940 5941 /* 5942 * Date values consist of a 2-byte length and an 5943 * 11-byte date/time structure defined by RFC 1903. 5944 * 5945 * Put the 2-byte length and 11-byte date/time 5946 * structure in the buffer. 5947 */ 5948 5949 *bufptr++ = 0; 5950 *bufptr++ = 11; 5951 memcpy(bufptr, value->date, 11); 5952 bufptr += 11; 5953 } 5954 break; 5955 5956 case IPP_TAG_RESOLUTION : 5957 for (i = 0, value = attr->values; 5958 i < attr->num_values; 5959 i ++, value ++) 5960 { 5961 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14) 5962 { 5963 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 5964 { 5965 DEBUG_puts("1ippWriteIO: Could not write IPP " 5966 "attribute..."); 5967 _cupsBufferRelease((char *)buffer); 5968 return (IPP_STATE_ERROR); 5969 } 5970 5971 bufptr = buffer; 5972 } 5973 5974 if (i) 5975 { 5976 /* 5977 * Arrays and sets are done by sending additional 5978 * values with a zero-length name... 5979 */ 5980 5981 *bufptr++ = (ipp_uchar_t)attr->value_tag; 5982 *bufptr++ = 0; 5983 *bufptr++ = 0; 5984 } 5985 5986 /* 5987 * Resolution values consist of a 2-byte length, 5988 * 4-byte horizontal resolution value, 4-byte vertical 5989 * resolution value, and a 1-byte units value. 5990 * 5991 * Put the 2-byte length and resolution value data 5992 * into the buffer. 5993 */ 5994 5995 *bufptr++ = 0; 5996 *bufptr++ = 9; 5997 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24); 5998 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16); 5999 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8); 6000 *bufptr++ = (ipp_uchar_t)value->resolution.xres; 6001 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24); 6002 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16); 6003 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8); 6004 *bufptr++ = (ipp_uchar_t)value->resolution.yres; 6005 *bufptr++ = (ipp_uchar_t)value->resolution.units; 6006 } 6007 break; 6008 6009 case IPP_TAG_RANGE : 6010 for (i = 0, value = attr->values; 6011 i < attr->num_values; 6012 i ++, value ++) 6013 { 6014 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13) 6015 { 6016 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 6017 { 6018 DEBUG_puts("1ippWriteIO: Could not write IPP " 6019 "attribute..."); 6020 _cupsBufferRelease((char *)buffer); 6021 return (IPP_STATE_ERROR); 6022 } 6023 6024 bufptr = buffer; 6025 } 6026 6027 if (i) 6028 { 6029 /* 6030 * Arrays and sets are done by sending additional 6031 * values with a zero-length name... 6032 */ 6033 6034 *bufptr++ = (ipp_uchar_t)attr->value_tag; 6035 *bufptr++ = 0; 6036 *bufptr++ = 0; 6037 } 6038 6039 /* 6040 * Range values consist of a 2-byte length, 6041 * 4-byte lower value, and 4-byte upper value. 6042 * 6043 * Put the 2-byte length and range value data 6044 * into the buffer. 6045 */ 6046 6047 *bufptr++ = 0; 6048 *bufptr++ = 8; 6049 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24); 6050 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16); 6051 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8); 6052 *bufptr++ = (ipp_uchar_t)value->range.lower; 6053 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24); 6054 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16); 6055 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8); 6056 *bufptr++ = (ipp_uchar_t)value->range.upper; 6057 } 6058 break; 6059 6060 case IPP_TAG_TEXTLANG : 6061 case IPP_TAG_NAMELANG : 6062 for (i = 0, value = attr->values; 6063 i < attr->num_values; 6064 i ++, value ++) 6065 { 6066 if (i) 6067 { 6068 /* 6069 * Arrays and sets are done by sending additional 6070 * values with a zero-length name... 6071 */ 6072 6073 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3) 6074 { 6075 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 6076 { 6077 DEBUG_puts("1ippWriteIO: Could not write IPP " 6078 "attribute..."); 6079 _cupsBufferRelease((char *)buffer); 6080 return (IPP_STATE_ERROR); 6081 } 6082 6083 bufptr = buffer; 6084 } 6085 6086 *bufptr++ = (ipp_uchar_t)attr->value_tag; 6087 *bufptr++ = 0; 6088 *bufptr++ = 0; 6089 } 6090 6091 /* 6092 * textWithLanguage and nameWithLanguage values consist 6093 * of a 2-byte length for both strings and their 6094 * individual lengths, a 2-byte length for the 6095 * character string, the character string without the 6096 * trailing nul, a 2-byte length for the character 6097 * set string, and the character set string without 6098 * the trailing nul. 6099 */ 6100 6101 n = 4; 6102 6103 if (value->string.language != NULL) 6104 n += (int)strlen(value->string.language); 6105 6106 if (value->string.text != NULL) 6107 n += (int)strlen(value->string.text); 6108 6109 if (n > (IPP_BUF_SIZE - 2)) 6110 { 6111 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value " 6112 "too long (%d)", n)); 6113 _cupsBufferRelease((char *)buffer); 6114 return (IPP_STATE_ERROR); 6115 } 6116 6117 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2)) 6118 { 6119 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 6120 { 6121 DEBUG_puts("1ippWriteIO: Could not write IPP " 6122 "attribute..."); 6123 _cupsBufferRelease((char *)buffer); 6124 return (IPP_STATE_ERROR); 6125 } 6126 6127 bufptr = buffer; 6128 } 6129 6130 /* Length of entire value */ 6131 *bufptr++ = (ipp_uchar_t)(n >> 8); 6132 *bufptr++ = (ipp_uchar_t)n; 6133 6134 /* Length of language */ 6135 if (value->string.language != NULL) 6136 n = (int)strlen(value->string.language); 6137 else 6138 n = 0; 6139 6140 *bufptr++ = (ipp_uchar_t)(n >> 8); 6141 *bufptr++ = (ipp_uchar_t)n; 6142 6143 /* Language */ 6144 if (n > 0) 6145 { 6146 memcpy(bufptr, value->string.language, (size_t)n); 6147 bufptr += n; 6148 } 6149 6150 /* Length of text */ 6151 if (value->string.text != NULL) 6152 n = (int)strlen(value->string.text); 6153 else 6154 n = 0; 6155 6156 *bufptr++ = (ipp_uchar_t)(n >> 8); 6157 *bufptr++ = (ipp_uchar_t)n; 6158 6159 /* Text */ 6160 if (n > 0) 6161 { 6162 memcpy(bufptr, value->string.text, (size_t)n); 6163 bufptr += n; 6164 } 6165 } 6166 break; 6167 6168 case IPP_TAG_BEGIN_COLLECTION : 6169 for (i = 0, value = attr->values; 6170 i < attr->num_values; 6171 i ++, value ++) 6172 { 6173 /* 6174 * Collections are written with the begin-collection 6175 * tag first with a value of 0 length, followed by the 6176 * attributes in the collection, then the end-collection 6177 * value... 6178 */ 6179 6180 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5) 6181 { 6182 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 6183 { 6184 DEBUG_puts("1ippWriteIO: Could not write IPP " 6185 "attribute..."); 6186 _cupsBufferRelease((char *)buffer); 6187 return (IPP_STATE_ERROR); 6188 } 6189 6190 bufptr = buffer; 6191 } 6192 6193 if (i) 6194 { 6195 /* 6196 * Arrays and sets are done by sending additional 6197 * values with a zero-length name... 6198 */ 6199 6200 *bufptr++ = (ipp_uchar_t)attr->value_tag; 6201 *bufptr++ = 0; 6202 *bufptr++ = 0; 6203 } 6204 6205 /* 6206 * Write a data length of 0 and flush the buffer... 6207 */ 6208 6209 *bufptr++ = 0; 6210 *bufptr++ = 0; 6211 6212 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 6213 { 6214 DEBUG_puts("1ippWriteIO: Could not write IPP " 6215 "attribute..."); 6216 _cupsBufferRelease((char *)buffer); 6217 return (IPP_STATE_ERROR); 6218 } 6219 6220 bufptr = buffer; 6221 6222 /* 6223 * Then write the collection attribute... 6224 */ 6225 6226 value->collection->state = IPP_STATE_IDLE; 6227 6228 if (ippWriteIO(dst, cb, 1, ipp, 6229 value->collection) == IPP_STATE_ERROR) 6230 { 6231 DEBUG_puts("1ippWriteIO: Unable to write collection value"); 6232 _cupsBufferRelease((char *)buffer); 6233 return (IPP_STATE_ERROR); 6234 } 6235 } 6236 break; 6237 6238 default : 6239 for (i = 0, value = attr->values; 6240 i < attr->num_values; 6241 i ++, value ++) 6242 { 6243 if (i) 6244 { 6245 /* 6246 * Arrays and sets are done by sending additional 6247 * values with a zero-length name... 6248 */ 6249 6250 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3) 6251 { 6252 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 6253 { 6254 DEBUG_puts("1ippWriteIO: Could not write IPP " 6255 "attribute..."); 6256 _cupsBufferRelease((char *)buffer); 6257 return (IPP_STATE_ERROR); 6258 } 6259 6260 bufptr = buffer; 6261 } 6262 6263 *bufptr++ = (ipp_uchar_t)attr->value_tag; 6264 *bufptr++ = 0; 6265 *bufptr++ = 0; 6266 } 6267 6268 /* 6269 * An unknown value might some new value that a 6270 * vendor has come up with. It consists of a 6271 * 2-byte length and the bytes in the unknown 6272 * value buffer. 6273 */ 6274 6275 n = value->unknown.length; 6276 6277 if (n > (IPP_BUF_SIZE - 2)) 6278 { 6279 DEBUG_printf(("1ippWriteIO: Data length too long (%d)", 6280 n)); 6281 _cupsBufferRelease((char *)buffer); 6282 return (IPP_STATE_ERROR); 6283 } 6284 6285 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2)) 6286 { 6287 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 6288 { 6289 DEBUG_puts("1ippWriteIO: Could not write IPP " 6290 "attribute..."); 6291 _cupsBufferRelease((char *)buffer); 6292 return (IPP_STATE_ERROR); 6293 } 6294 6295 bufptr = buffer; 6296 } 6297 6298 /* Length of unknown value */ 6299 *bufptr++ = (ipp_uchar_t)(n >> 8); 6300 *bufptr++ = (ipp_uchar_t)n; 6301 6302 /* Value */ 6303 if (n > 0) 6304 { 6305 memcpy(bufptr, value->unknown.data, (size_t)n); 6306 bufptr += n; 6307 } 6308 } 6309 break; 6310 } 6311 6312 /* 6313 * Write the data out... 6314 */ 6315 6316 if (bufptr > buffer) 6317 { 6318 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0) 6319 { 6320 DEBUG_puts("1ippWriteIO: Could not write IPP attribute..."); 6321 _cupsBufferRelease((char *)buffer); 6322 return (IPP_STATE_ERROR); 6323 } 6324 6325 DEBUG_printf(("2ippWriteIO: wrote %d bytes", 6326 (int)(bufptr - buffer))); 6327 } 6328 6329 /* 6330 * If blocking is disabled and we aren't at the end of the attribute 6331 * list, stop here... 6332 */ 6333 6334 if (!blocking && ipp->current) 6335 break; 6336 } 6337 6338 if (ipp->current == NULL) 6339 { 6340 /* 6341 * Done with all of the attributes; add the end-of-attributes 6342 * tag or end-collection attribute... 6343 */ 6344 6345 if (parent == NULL) 6346 { 6347 buffer[0] = IPP_TAG_END; 6348 n = 1; 6349 } 6350 else 6351 { 6352 buffer[0] = IPP_TAG_END_COLLECTION; 6353 buffer[1] = 0; /* empty name */ 6354 buffer[2] = 0; 6355 buffer[3] = 0; /* empty value */ 6356 buffer[4] = 0; 6357 n = 5; 6358 } 6359 6360 if ((*cb)(dst, buffer, (size_t)n) < 0) 6361 { 6362 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag..."); 6363 _cupsBufferRelease((char *)buffer); 6364 return (IPP_STATE_ERROR); 6365 } 6366 6367 ipp->state = IPP_STATE_DATA; 6368 } 6369 break; 6370 6371 case IPP_STATE_DATA : 6372 break; 6373 6374 default : 6375 break; /* anti-compiler-warning-code */ 6376 } 6377 6378 _cupsBufferRelease((char *)buffer); 6379 6380 return (ipp->state); 6381 } 6382 6383 6384 /* 6385 * 'ipp_add_attr()' - Add a new attribute to the message. 6386 */ 6387 6388 static ipp_attribute_t * /* O - New attribute */ 6389 ipp_add_attr(ipp_t *ipp, /* I - IPP message */ 6390 const char *name, /* I - Attribute name or NULL */ 6391 ipp_tag_t group_tag, /* I - Group tag or IPP_TAG_ZERO */ 6392 ipp_tag_t value_tag, /* I - Value tag or IPP_TAG_ZERO */ 6393 int num_values) /* I - Number of values */ 6394 { 6395 int alloc_values; /* Number of values to allocate */ 6396 ipp_attribute_t *attr; /* New attribute */ 6397 6398 6399 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, num_values=%d)", (void *)ipp, name, group_tag, value_tag, num_values)); 6400 6401 /* 6402 * Range check input... 6403 */ 6404 6405 if (!ipp || num_values < 0) 6406 return (NULL); 6407 6408 /* 6409 * Allocate memory, rounding the allocation up as needed... 6410 */ 6411 6412 if (num_values <= 1) 6413 alloc_values = 1; 6414 else 6415 alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1); 6416 6417 attr = calloc(sizeof(ipp_attribute_t) + 6418 (size_t)(alloc_values - 1) * sizeof(_ipp_value_t), 1); 6419 6420 if (attr) 6421 { 6422 /* 6423 * Initialize attribute... 6424 */ 6425 6426 DEBUG_printf(("4debug_alloc: %p %s %s%s (%d values)", (void *)attr, name, num_values > 1 ? "1setOf " : "", ippTagString(value_tag), num_values)); 6427 6428 if (name) 6429 attr->name = _cupsStrAlloc(name); 6430 6431 attr->group_tag = group_tag; 6432 attr->value_tag = value_tag; 6433 attr->num_values = num_values; 6434 6435 /* 6436 * Add it to the end of the linked list... 6437 */ 6438 6439 if (ipp->last) 6440 ipp->last->next = attr; 6441 else 6442 ipp->attrs = attr; 6443 6444 ipp->prev = ipp->last; 6445 ipp->last = ipp->current = attr; 6446 } 6447 6448 DEBUG_printf(("5ipp_add_attr: Returning %p", (void *)attr)); 6449 6450 return (attr); 6451 } 6452 6453 6454 /* 6455 * 'ipp_free_values()' - Free attribute values. 6456 */ 6457 6458 static void 6459 ipp_free_values(ipp_attribute_t *attr, /* I - Attribute to free values from */ 6460 int element,/* I - First value to free */ 6461 int count) /* I - Number of values to free */ 6462 { 6463 int i; /* Looping var */ 6464 _ipp_value_t *value; /* Current value */ 6465 6466 6467 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count)); 6468 6469 if (!(attr->value_tag & IPP_TAG_CUPS_CONST)) 6470 { 6471 /* 6472 * Free values as needed... 6473 */ 6474 6475 switch (attr->value_tag) 6476 { 6477 case IPP_TAG_TEXTLANG : 6478 case IPP_TAG_NAMELANG : 6479 if (element == 0 && count == attr->num_values && 6480 attr->values[0].string.language) 6481 { 6482 _cupsStrFree(attr->values[0].string.language); 6483 attr->values[0].string.language = NULL; 6484 } 6485 /* Fall through to other string values */ 6486 6487 case IPP_TAG_TEXT : 6488 case IPP_TAG_NAME : 6489 case IPP_TAG_RESERVED_STRING : 6490 case IPP_TAG_KEYWORD : 6491 case IPP_TAG_URI : 6492 case IPP_TAG_URISCHEME : 6493 case IPP_TAG_CHARSET : 6494 case IPP_TAG_LANGUAGE : 6495 case IPP_TAG_MIMETYPE : 6496 for (i = count, value = attr->values + element; 6497 i > 0; 6498 i --, value ++) 6499 { 6500 _cupsStrFree(value->string.text); 6501 value->string.text = NULL; 6502 } 6503 break; 6504 6505 case IPP_TAG_DEFAULT : 6506 case IPP_TAG_UNKNOWN : 6507 case IPP_TAG_NOVALUE : 6508 case IPP_TAG_NOTSETTABLE : 6509 case IPP_TAG_DELETEATTR : 6510 case IPP_TAG_ADMINDEFINE : 6511 case IPP_TAG_INTEGER : 6512 case IPP_TAG_ENUM : 6513 case IPP_TAG_BOOLEAN : 6514 case IPP_TAG_DATE : 6515 case IPP_TAG_RESOLUTION : 6516 case IPP_TAG_RANGE : 6517 break; 6518 6519 case IPP_TAG_BEGIN_COLLECTION : 6520 for (i = count, value = attr->values + element; 6521 i > 0; 6522 i --, value ++) 6523 { 6524 ippDelete(value->collection); 6525 value->collection = NULL; 6526 } 6527 break; 6528 6529 case IPP_TAG_STRING : 6530 default : 6531 for (i = count, value = attr->values + element; 6532 i > 0; 6533 i --, value ++) 6534 { 6535 if (value->unknown.data) 6536 { 6537 free(value->unknown.data); 6538 value->unknown.data = NULL; 6539 } 6540 } 6541 break; 6542 } 6543 } 6544 6545 /* 6546 * If we are not freeing values from the end, move the remaining values up... 6547 */ 6548 6549 if ((element + count) < attr->num_values) 6550 memmove(attr->values + element, attr->values + element + count, 6551 (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t)); 6552 6553 attr->num_values -= count; 6554 } 6555 6556 6557 /* 6558 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code. 6559 * 6560 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER" 6561 * to "ll-cc", "ll-region", and "charset-number", respectively. 6562 */ 6563 6564 static char * /* O - Language code string */ 6565 ipp_get_code(const char *value, /* I - Locale/charset string */ 6566 char *buffer, /* I - String buffer */ 6567 size_t bufsize) /* I - Size of string buffer */ 6568 { 6569 char *bufptr, /* Pointer into buffer */ 6570 *bufend; /* End of buffer */ 6571 6572 6573 /* 6574 * Convert values to lowercase and change _ to - as needed... 6575 */ 6576 6577 for (bufptr = buffer, bufend = buffer + bufsize - 1; 6578 *value && bufptr < bufend; 6579 value ++) 6580 if (*value == '_') 6581 *bufptr++ = '-'; 6582 else 6583 *bufptr++ = (char)_cups_tolower(*value); 6584 6585 *bufptr = '\0'; 6586 6587 /* 6588 * Return the converted string... 6589 */ 6590 6591 return (buffer); 6592 } 6593 6594 6595 /* 6596 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code. 6597 * 6598 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and 6599 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en". 6600 */ 6601 6602 static char * /* O - Language code string */ 6603 ipp_lang_code(const char *locale, /* I - Locale string */ 6604 char *buffer, /* I - String buffer */ 6605 size_t bufsize) /* I - Size of string buffer */ 6606 { 6607 /* 6608 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is. 6609 */ 6610 6611 if (!_cups_strcasecmp(locale, "c")) 6612 { 6613 strlcpy(buffer, "en", bufsize); 6614 return (buffer); 6615 } 6616 else 6617 return (ipp_get_code(locale, buffer, bufsize)); 6618 } 6619 6620 6621 /* 6622 * 'ipp_length()' - Compute the length of an IPP message or collection value. 6623 */ 6624 6625 static size_t /* O - Size of IPP message */ 6626 ipp_length(ipp_t *ipp, /* I - IPP message or collection */ 6627 int collection) /* I - 1 if a collection, 0 otherwise */ 6628 { 6629 int i; /* Looping var */ 6630 size_t bytes; /* Number of bytes */ 6631 ipp_attribute_t *attr; /* Current attribute */ 6632 ipp_tag_t group; /* Current group */ 6633 _ipp_value_t *value; /* Current value */ 6634 6635 6636 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", (void *)ipp, collection)); 6637 6638 if (!ipp) 6639 { 6640 DEBUG_puts("4ipp_length: Returning 0 bytes"); 6641 return (0); 6642 } 6643 6644 /* 6645 * Start with 8 bytes for the IPP message header... 6646 */ 6647 6648 bytes = collection ? 0 : 8; 6649 6650 /* 6651 * Then add the lengths of each attribute... 6652 */ 6653 6654 group = IPP_TAG_ZERO; 6655 6656 for (attr = ipp->attrs; attr != NULL; attr = attr->next) 6657 { 6658 if (attr->group_tag != group && !collection) 6659 { 6660 group = attr->group_tag; 6661 if (group == IPP_TAG_ZERO) 6662 continue; 6663 6664 bytes ++; /* Group tag */ 6665 } 6666 6667 if (!attr->name) 6668 continue; 6669 6670 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, " 6671 "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes)); 6672 6673 if ((attr->value_tag & ~IPP_TAG_CUPS_CONST) < IPP_TAG_EXTENSION) 6674 bytes += (size_t)attr->num_values;/* Value tag for each value */ 6675 else 6676 bytes += (size_t)(5 * attr->num_values); 6677 /* Value tag for each value */ 6678 bytes += (size_t)(2 * attr->num_values); 6679 /* Name lengths */ 6680 bytes += strlen(attr->name); /* Name */ 6681 bytes += (size_t)(2 * attr->num_values); 6682 /* Value lengths */ 6683 6684 if (collection) 6685 bytes += 5; /* Add membername overhead */ 6686 6687 switch (attr->value_tag & ~IPP_TAG_CUPS_CONST) 6688 { 6689 case IPP_TAG_UNSUPPORTED_VALUE : 6690 case IPP_TAG_DEFAULT : 6691 case IPP_TAG_UNKNOWN : 6692 case IPP_TAG_NOVALUE : 6693 case IPP_TAG_NOTSETTABLE : 6694 case IPP_TAG_DELETEATTR : 6695 case IPP_TAG_ADMINDEFINE : 6696 break; 6697 6698 case IPP_TAG_INTEGER : 6699 case IPP_TAG_ENUM : 6700 bytes += (size_t)(4 * attr->num_values); 6701 break; 6702 6703 case IPP_TAG_BOOLEAN : 6704 bytes += (size_t)attr->num_values; 6705 break; 6706 6707 case IPP_TAG_TEXT : 6708 case IPP_TAG_NAME : 6709 case IPP_TAG_KEYWORD : 6710 case IPP_TAG_URI : 6711 case IPP_TAG_URISCHEME : 6712 case IPP_TAG_CHARSET : 6713 case IPP_TAG_LANGUAGE : 6714 case IPP_TAG_MIMETYPE : 6715 for (i = 0, value = attr->values; 6716 i < attr->num_values; 6717 i ++, value ++) 6718 if (value->string.text) 6719 bytes += strlen(value->string.text); 6720 break; 6721 6722 case IPP_TAG_DATE : 6723 bytes += (size_t)(11 * attr->num_values); 6724 break; 6725 6726 case IPP_TAG_RESOLUTION : 6727 bytes += (size_t)(9 * attr->num_values); 6728 break; 6729 6730 case IPP_TAG_RANGE : 6731 bytes += (size_t)(8 * attr->num_values); 6732 break; 6733 6734 case IPP_TAG_TEXTLANG : 6735 case IPP_TAG_NAMELANG : 6736 bytes += (size_t)(4 * attr->num_values); 6737 /* Charset + text length */ 6738 6739 for (i = 0, value = attr->values; 6740 i < attr->num_values; 6741 i ++, value ++) 6742 { 6743 if (value->string.language) 6744 bytes += strlen(value->string.language); 6745 6746 if (value->string.text) 6747 bytes += strlen(value->string.text); 6748 } 6749 break; 6750 6751 case IPP_TAG_BEGIN_COLLECTION : 6752 for (i = 0, value = attr->values; 6753 i < attr->num_values; 6754 i ++, value ++) 6755 bytes += ipp_length(value->collection, 1); 6756 break; 6757 6758 default : 6759 for (i = 0, value = attr->values; 6760 i < attr->num_values; 6761 i ++, value ++) 6762 bytes += (size_t)value->unknown.length; 6763 break; 6764 } 6765 } 6766 6767 /* 6768 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes 6769 * for the "end of collection" tag and return... 6770 */ 6771 6772 if (collection) 6773 bytes += 5; 6774 else 6775 bytes ++; 6776 6777 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes)); 6778 6779 return (bytes); 6780 } 6781 6782 6783 /* 6784 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection... 6785 */ 6786 6787 static ssize_t /* O - Number of bytes read */ 6788 ipp_read_http(http_t *http, /* I - Client connection */ 6789 ipp_uchar_t *buffer, /* O - Buffer for data */ 6790 size_t length) /* I - Total length */ 6791 { 6792 ssize_t tbytes, /* Total bytes read */ 6793 bytes; /* Bytes read this pass */ 6794 6795 6796 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length)); 6797 6798 /* 6799 * Loop until all bytes are read... 6800 */ 6801 6802 for (tbytes = 0, bytes = 0; 6803 tbytes < (int)length; 6804 tbytes += bytes, buffer += bytes) 6805 { 6806 DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state)); 6807 6808 if (http->state == HTTP_STATE_WAITING) 6809 break; 6810 6811 if (http->used == 0 && !http->blocking) 6812 { 6813 /* 6814 * Wait up to 10 seconds for more data on non-blocking sockets... 6815 */ 6816 6817 if (!httpWait(http, 10000)) 6818 { 6819 /* 6820 * Signal no data... 6821 */ 6822 6823 bytes = -1; 6824 break; 6825 } 6826 } 6827 else if (http->used == 0 && http->timeout_value > 0) 6828 { 6829 /* 6830 * Wait up to timeout seconds for more data on blocking sockets... 6831 */ 6832 6833 if (!httpWait(http, (int)(1000 * http->timeout_value))) 6834 { 6835 /* 6836 * Signal no data... 6837 */ 6838 6839 bytes = -1; 6840 break; 6841 } 6842 } 6843 6844 if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0) 6845 { 6846 #ifdef WIN32 6847 break; 6848 #else 6849 if (errno != EAGAIN && errno != EINTR) 6850 break; 6851 6852 bytes = 0; 6853 #endif /* WIN32 */ 6854 } 6855 else if (bytes == 0) 6856 break; 6857 } 6858 6859 /* 6860 * Return the number of bytes read... 6861 */ 6862 6863 if (tbytes == 0 && bytes < 0) 6864 tbytes = -1; 6865 6866 DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes)); 6867 6868 return (tbytes); 6869 } 6870 6871 6872 /* 6873 * 'ipp_read_file()' - Read IPP data from a file. 6874 */ 6875 6876 static ssize_t /* O - Number of bytes read */ 6877 ipp_read_file(int *fd, /* I - File descriptor */ 6878 ipp_uchar_t *buffer, /* O - Read buffer */ 6879 size_t length) /* I - Number of bytes to read */ 6880 { 6881 #ifdef WIN32 6882 return ((ssize_t)read(*fd, buffer, (unsigned)length)); 6883 #else 6884 return (read(*fd, buffer, length)); 6885 #endif /* WIN32 */ 6886 } 6887 6888 6889 /* 6890 * 'ipp_set_error()' - Set a formatted, localized error string. 6891 */ 6892 6893 static void 6894 ipp_set_error(ipp_status_t status, /* I - Status code */ 6895 const char *format, /* I - Printf-style error string */ 6896 ...) /* I - Additional arguments as needed */ 6897 { 6898 va_list ap; /* Pointer to additional args */ 6899 char buffer[2048]; /* Message buffer */ 6900 cups_lang_t *lang = cupsLangDefault(); 6901 /* Current language */ 6902 6903 6904 va_start(ap, format); 6905 vsnprintf(buffer, sizeof(buffer), _cupsLangString(lang, format), ap); 6906 va_end(ap); 6907 6908 _cupsSetError(status, buffer, 0); 6909 } 6910 6911 6912 /* 6913 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as 6914 * needed. 6915 */ 6916 6917 static _ipp_value_t * /* O - IPP value element or NULL on error */ 6918 ipp_set_value(ipp_t *ipp, /* IO - IPP message */ 6919 ipp_attribute_t **attr, /* IO - IPP attribute */ 6920 int element) /* I - Value number (0-based) */ 6921 { 6922 ipp_attribute_t *temp, /* New attribute pointer */ 6923 *current, /* Current attribute in list */ 6924 *prev; /* Previous attribute in list */ 6925 int alloc_values; /* Allocated values */ 6926 6927 6928 /* 6929 * If we are setting an existing value element, return it... 6930 */ 6931 6932 temp = *attr; 6933 6934 if (temp->num_values <= 1) 6935 alloc_values = 1; 6936 else 6937 alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) & 6938 ~(IPP_MAX_VALUES - 1); 6939 6940 if (element < alloc_values) 6941 { 6942 if (element >= temp->num_values) 6943 temp->num_values = element + 1; 6944 6945 return (temp->values + element); 6946 } 6947 6948 /* 6949 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE 6950 * values when num_values > 1. 6951 */ 6952 6953 if (alloc_values < IPP_MAX_VALUES) 6954 alloc_values = IPP_MAX_VALUES; 6955 else 6956 alloc_values += IPP_MAX_VALUES; 6957 6958 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.", 6959 alloc_values)); 6960 6961 /* 6962 * Reallocate memory... 6963 */ 6964 6965 if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL) 6966 { 6967 _cupsSetHTTPError(HTTP_STATUS_ERROR); 6968 DEBUG_puts("4ipp_set_value: Unable to resize attribute."); 6969 return (NULL); 6970 } 6971 6972 /* 6973 * Zero the new memory... 6974 */ 6975 6976 memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t)); 6977 6978 if (temp != *attr) 6979 { 6980 /* 6981 * Reset pointers in the list... 6982 */ 6983 6984 DEBUG_printf(("4debug_free: %p %s", (void *)*attr, temp->name)); 6985 DEBUG_printf(("4debug_alloc: %p %s %s%s (%d)", (void *)temp, temp->name, temp->num_values > 1 ? "1setOf " : "", ippTagString(temp->value_tag), temp->num_values)); 6986 6987 if (ipp->current == *attr && ipp->prev) 6988 { 6989 /* 6990 * Use current "previous" pointer... 6991 */ 6992 6993 prev = ipp->prev; 6994 } 6995 else 6996 { 6997 /* 6998 * Find this attribute in the linked list... 6999 */ 7000 7001 for (prev = NULL, current = ipp->attrs; 7002 current && current != *attr; 7003 prev = current, current = current->next); 7004 7005 if (!current) 7006 { 7007 /* 7008 * This is a serious error! 7009 */ 7010 7011 *attr = temp; 7012 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, 7013 _("IPP attribute is not a member of the message."), 1); 7014 DEBUG_puts("4ipp_set_value: Unable to find attribute in message."); 7015 return (NULL); 7016 } 7017 } 7018 7019 if (prev) 7020 prev->next = temp; 7021 else 7022 ipp->attrs = temp; 7023 7024 ipp->current = temp; 7025 ipp->prev = prev; 7026 7027 if (ipp->last == *attr) 7028 ipp->last = temp; 7029 7030 *attr = temp; 7031 } 7032 7033 /* 7034 * Return the value element... 7035 */ 7036 7037 if (element >= temp->num_values) 7038 temp->num_values = element + 1; 7039 7040 return (temp->values + element); 7041 } 7042 7043 7044 /* 7045 * 'ipp_write_file()' - Write IPP data to a file. 7046 */ 7047 7048 static ssize_t /* O - Number of bytes written */ 7049 ipp_write_file(int *fd, /* I - File descriptor */ 7050 ipp_uchar_t *buffer, /* I - Data to write */ 7051 size_t length) /* I - Number of bytes to write */ 7052 { 7053 #ifdef WIN32 7054 return ((ssize_t)write(*fd, buffer, (unsigned)length)); 7055 #else 7056 return (write(*fd, buffer, length)); 7057 #endif /* WIN32 */ 7058 } 7059