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