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