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