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