]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ipp.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / cups / ipp.c
CommitLineData
dec2f757 1/*
64bbab09 2 * "$Id: ipp.c,v 1.55.2.39 2004/02/25 16:58:32 mike Exp $"
dec2f757 3 *
3a193f5e 4 * Internet Printing Protocol support functions for the Common UNIX
5 * Printing System (CUPS).
dec2f757 6 *
1d9595ab 7 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
dec2f757 8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Easy Software Products and are protected by Federal
11 * copyright law. Distribution and use rights are outlined in the file
12 * "LICENSE.txt" which should have been included with this file. If this
13 * file is missing or damaged please contact Easy Software Products
14 * at:
15 *
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
58ec2a95 18 * 44141 Airport View Drive, Suite 204
dec2f757 19 * Hollywood, Maryland 20636-3111 USA
20 *
21 * Voice: (301) 373-9603
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
24 *
dab1a4d8 25 * This file is subject to the Apple OS-Developed Software exception.
26 *
dec2f757 27 * Contents:
28 *
7db52463 29 * ippAddBoolean() - Add a boolean attribute to an IPP request.
30 * ippAddBooleans() - Add an array of boolean values.
31 * ippAddDate() - Add a date attribute to an IPP request.
32 * ippAddInteger() - Add a integer attribute to an IPP request.
33 * ippAddIntegers() - Add an array of integer values.
34 * ippAddString() - Add a language-encoded string to an IPP request.
35 * ippAddStrings() - Add language-encoded strings to an IPP request.
36 * ippAddRange() - Add a range of values to an IPP request.
37 * ippAddRanges() - Add ranges of values to an IPP request.
38 * ippAddResolution() - Add a resolution value to an IPP request.
39 * ippAddResolutions() - Add resolution values to an IPP request.
40 * ippAddSeparator() - Add a group separator to an IPP request.
b070f93d 41 * ippDateToTime() - Convert from RFC 1903 Date/Time format to
42 * UNIX time in seconds.
7db52463 43 * ippDelete() - Delete an IPP request.
b0757135 44 * ippDeleteAttribute() - Delete a single attribute in an IPP request.
7db52463 45 * ippFindAttribute() - Find a named attribute in a request...
46 * ippFindNextAttribute() - Find the next named attribute in a request...
47 * ippLength() - Compute the length of an IPP request.
48 * ippNew() - Allocate a new IPP request.
b070f93d 49 * ippRead() - Read data for an IPP request from a HTTP
50 * connection.
51 * ippReadFile() - Read data for an IPP request from a file.
52 * ippReadIO() - Read data for an IPP request.
53 * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
54 * ippWrite() - Write data for an IPP request to a HTTP
55 * connection.
56 * ippWriteFile() - Write data for an IPP request to a file.
57 * ippWriteIO() - Write data for an IPP request.
7db52463 58 * _ipp_add_attr() - Add a new attribute to the request.
59 * _ipp_free_attr() - Free an attribute.
b0757135 60 * ipp_length() - Compute the length of an IPP request or
61 * collection value.
b070f93d 62 * ipp_read_http() - Semi-blocking read on a HTTP connection...
63 * ipp_read_file() - Read IPP data from a file.
b070f93d 64 * ipp_write_file() - Write IPP data to a file.
dec2f757 65 */
66
67/*
68 * Include necessary headers...
69 */
70
3b960317 71#include <stdio.h>
72#include <stdlib.h>
977acbd3 73#include "string.h"
3b960317 74
50146867 75#include "ipp.h"
4a73831b 76#include "debug.h"
b03923b8 77#include <ctype.h>
3955a26e 78#include <errno.h>
dec2f757 79
80
81/*
3a193f5e 82 * Local functions...
83 */
84
b0757135 85static size_t ipp_length(ipp_t *ipp, int collection);
86static int ipp_read_http(http_t *http, ipp_uchar_t *buffer, int length);
87static int ipp_read_file(int *fd, ipp_uchar_t *buffer, int length);
b0757135 88static int ipp_write_file(int *fd, ipp_uchar_t *buffer, int length);
3a193f5e 89
90
50146867 91/*
92 * 'ippAddBoolean()' - Add a boolean attribute to an IPP request.
93 */
94
b0757135 95ipp_attribute_t * /* O - New attribute */
96ippAddBoolean(ipp_t *ipp, /* I - IPP request */
97 ipp_tag_t group, /* I - IPP group */
98 const char *name, /* I - Name of attribute */
99 char value) /* I - Value of attribute */
3a193f5e 100{
b0757135 101 ipp_attribute_t *attr; /* New attribute */
3a193f5e 102
103
27d555e8 104 DEBUG_printf(("ippAddBoolean(%p, %02x, \'%s\', %d)\n", ipp, group, name, value));
aeabf506 105
50146867 106 if (ipp == NULL || name == NULL)
107 return (NULL);
3a193f5e 108
e09246c8 109 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 110 return (NULL);
3a193f5e 111
50146867 112 attr->name = strdup(name);
113 attr->group_tag = group;
114 attr->value_tag = IPP_TAG_BOOLEAN;
115 attr->values[0].boolean = value;
116
117 return (attr);
3a193f5e 118}
119
120
50146867 121/*
122 * 'ippAddBooleans()' - Add an array of boolean values.
123 */
124
b0757135 125ipp_attribute_t * /* O - New attribute */
126ippAddBooleans(ipp_t *ipp, /* I - IPP request */
127 ipp_tag_t group, /* I - IPP group */
128 const char *name, /* I - Name of attribute */
129 int num_values, /* I - Number of values */
130 const char *values) /* I - Values */
3a193f5e 131{
b0757135 132 int i; /* Looping var */
133 ipp_attribute_t *attr; /* New attribute */
134 ipp_value_t *value; /* Current value */
50146867 135
136
27d555e8 137 DEBUG_printf(("ippAddBooleans(%p, %02x, \'%s\', %d, %p)\n", ipp,
5356dc5a 138 group, name, num_values, values));
aeabf506 139
2d850885 140 if (ipp == NULL || name == NULL || num_values < 1)
50146867 141 return (NULL);
142
e09246c8 143 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
50146867 144 return (NULL);
145
146 attr->name = strdup(name);
147 attr->group_tag = group;
148 attr->value_tag = IPP_TAG_BOOLEAN;
149
5356dc5a 150 if (values != NULL)
753453e4 151 for (i = 0, value = attr->values;
152 i < num_values;
153 i ++, value ++)
154 value->boolean = values[i];
50146867 155
156 return (attr);
3a193f5e 157}
158
159
b0757135 160/*
161 * 'ippAddCollection()' - Add a collection value.
162 */
163
164ipp_attribute_t * /* O - New attribute */
165ippAddCollection(ipp_t *ipp, /* I - IPP request */
166 ipp_tag_t group, /* I - IPP group */
167 const char *name, /* I - Name of attribute */
168 ipp_t *value) /* I - Value */
169{
170 ipp_attribute_t *attr; /* New attribute */
171
172
173 DEBUG_printf(("ippAddCollection(%p, %02x, \'%s\', %p)\n", ipp, group, name,
174 value));
175
176 if (ipp == NULL || name == NULL)
177 return (NULL);
178
179 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
180 return (NULL);
181
182 attr->name = strdup(name);
183 attr->group_tag = group;
184 attr->value_tag = IPP_TAG_BEGIN_COLLECTION;
185 attr->values[0].collection = value;
186
187 return (attr);
188}
189
190
191/*
192 * 'ippAddCollections()' - Add an array of collection values.
193 */
194
195ipp_attribute_t * /* O - New attribute */
196ippAddCollections(ipp_t *ipp, /* I - IPP request */
197 ipp_tag_t group, /* I - IPP group */
198 const char *name, /* I - Name of attribute */
199 int num_values, /* I - Number of values */
200 const ipp_t **values) /* I - Values */
201{
202 int i; /* Looping var */
203 ipp_attribute_t *attr; /* New attribute */
204 ipp_value_t *value; /* Current value */
205
206
207 DEBUG_printf(("ippAddCollections(%p, %02x, \'%s\', %d, %p)\n", ipp,
208 group, name, num_values, values));
209
210 if (ipp == NULL || name == NULL || num_values < 1)
211 return (NULL);
212
213 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
214 return (NULL);
215
216 attr->name = strdup(name);
217 attr->group_tag = group;
218 attr->value_tag = IPP_TAG_BEGIN_COLLECTION;
219
220 if (values != NULL)
221 for (i = 0, value = attr->values;
222 i < num_values;
223 i ++, value ++)
224 value->collection = (ipp_t *)values[i];
225
226 return (attr);
227}
228
229
50146867 230/*
231 * 'ippAddDate()' - Add a date attribute to an IPP request.
232 */
233
b0757135 234ipp_attribute_t * /* O - New attribute */
235ippAddDate(ipp_t *ipp, /* I - IPP request */
236 ipp_tag_t group, /* I - IPP group */
237 const char *name, /* I - Name of attribute */
238 const ipp_uchar_t *value) /* I - Value */
3a193f5e 239{
b0757135 240 ipp_attribute_t *attr; /* New attribute */
50146867 241
242
27d555e8 243 DEBUG_printf(("ippAddDate(%p, %02x, \'%s\', %p)\n", ipp, group, name,
aeabf506 244 value));
245
50146867 246 if (ipp == NULL || name == NULL || value == NULL)
247 return (NULL);
248
e09246c8 249 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 250 return (NULL);
251
252 attr->name = strdup(name);
253 attr->group_tag = group;
254 attr->value_tag = IPP_TAG_DATE;
255 memcpy(attr->values[0].date, value, 11);
256
257 return (attr);
3a193f5e 258}
259
260
50146867 261/*
262 * 'ippAddInteger()' - Add a integer attribute to an IPP request.
263 */
264
b0757135 265ipp_attribute_t * /* O - New attribute */
266ippAddInteger(ipp_t *ipp, /* I - IPP request */
267 ipp_tag_t group, /* I - IPP group */
268 ipp_tag_t type, /* I - Type of attribute */
269 const char *name, /* I - Name of attribute */
270 int value) /* I - Value of attribute */
3a193f5e 271{
b0757135 272 ipp_attribute_t *attr; /* New attribute */
50146867 273
274
27d555e8 275 DEBUG_printf(("ippAddInteger(%p, %d, \'%s\', %d)\n", ipp, group, name,
4a73831b 276 value));
277
50146867 278 if (ipp == NULL || name == NULL)
279 return (NULL);
280
e09246c8 281 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 282 return (NULL);
283
284 attr->name = strdup(name);
285 attr->group_tag = group;
58ec2a95 286 attr->value_tag = type;
50146867 287 attr->values[0].integer = value;
288
289 return (attr);
3a193f5e 290}
291
292
50146867 293/*
294 * 'ippAddIntegers()' - Add an array of integer values.
295 */
296
b0757135 297ipp_attribute_t * /* O - New attribute */
298ippAddIntegers(ipp_t *ipp, /* I - IPP request */
299 ipp_tag_t group, /* I - IPP group */
300 ipp_tag_t type, /* I - Type of attribute */
301 const char *name, /* I - Name of attribute */
302 int num_values, /* I - Number of values */
303 const int *values) /* I - Values */
3a193f5e 304{
b0757135 305 int i; /* Looping var */
306 ipp_attribute_t *attr; /* New attribute */
307 ipp_value_t *value; /* Current value */
50146867 308
309
2d850885 310 if (ipp == NULL || name == NULL || num_values < 1)
50146867 311 return (NULL);
312
e09246c8 313 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
50146867 314 return (NULL);
315
316 attr->name = strdup(name);
317 attr->group_tag = group;
58ec2a95 318 attr->value_tag = type;
50146867 319
5356dc5a 320 if (values != NULL)
753453e4 321 for (i = 0, value = attr->values;
322 i < num_values;
323 i ++, value ++)
324 value->integer = values[i];
50146867 325
326 return (attr);
3a193f5e 327}
328
329
50146867 330/*
58ec2a95 331 * 'ippAddString()' - Add a language-encoded string to an IPP request.
50146867 332 */
333
b0757135 334ipp_attribute_t * /* O - New attribute */
335ippAddString(ipp_t *ipp, /* I - IPP request */
336 ipp_tag_t group, /* I - IPP group */
337 ipp_tag_t type, /* I - Type of attribute */
338 const char *name, /* I - Name of attribute */
339 const char *charset, /* I - Character set */
340 const char *value) /* I - Value */
3a193f5e 341{
b0757135 342 ipp_attribute_t *attr; /* New attribute */
50146867 343
344
345 if (ipp == NULL || name == NULL)
346 return (NULL);
347
e09246c8 348 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 349 return (NULL);
350
746265a5 351 /*
352 * Force value to be English for the POSIX locale...
353 */
354
355 if (type == IPP_TAG_LANGUAGE && strcasecmp(value, "C") == 0)
356 value = "en";
357
358 /*
359 * Initialize the attribute data...
360 */
361
50146867 362 attr->name = strdup(name);
363 attr->group_tag = group;
58ec2a95 364 attr->value_tag = type;
753453e4 365 attr->values[0].string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
366 charset ? strdup(charset) : NULL;
367 attr->values[0].string.text = ((int)type & IPP_TAG_COPY) ? (char *)value :
368 value ? strdup(value) : NULL;
50146867 369
746265a5 370 /*
371 * Convert language values to lowercase and change _ to - as needed...
372 */
373
b54e35d5 374 if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) &&
375 attr->values[0].string.text)
c9061d17 376 {
c9061d17 377 char *p;
378
379
5a2c7855 380 for (p = attr->values[0].string.text; *p; p ++)
c9061d17 381 if (*p == '_')
5a2c7855 382 *p = '-';
c9061d17 383 else
64bbab09 384 *p = tolower(*p & 255);
c9061d17 385 }
386
50146867 387 return (attr);
3a193f5e 388}
389
390
50146867 391/*
58ec2a95 392 * 'ippAddStrings()' - Add language-encoded strings to an IPP request.
50146867 393 */
394
b0757135 395ipp_attribute_t * /* O - New attribute */
6db7190f 396ippAddStrings(ipp_t *ipp, /* I - IPP request */
397 ipp_tag_t group, /* I - IPP group */
398 ipp_tag_t type, /* I - Type of attribute */
399 const char *name, /* I - Name of attribute */
400 int num_values, /* I - Number of values */
401 const char *charset, /* I - Character set */
402 const char * const *values) /* I - Values */
3a193f5e 403{
b0757135 404 int i; /* Looping var */
405 ipp_attribute_t *attr; /* New attribute */
406 ipp_value_t *value; /* Current value */
50146867 407
408
2d850885 409 if (ipp == NULL || name == NULL || num_values < 1)
50146867 410 return (NULL);
411
e09246c8 412 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
50146867 413 return (NULL);
414
746265a5 415 /*
416 * Initialize the attribute data...
417 */
418
50146867 419 attr->name = strdup(name);
420 attr->group_tag = group;
58ec2a95 421 attr->value_tag = type;
50146867 422
753453e4 423 for (i = 0, value = attr->values;
424 i < num_values;
425 i ++, value ++)
426 {
427 if (i == 0)
428 value->string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
429 charset ? strdup(charset) : NULL;
430 else
431 value->string.charset = attr->values[0].string.charset;
432
433 if (values != NULL)
746265a5 434 {
435 /*
436 * Force language to be English for the POSIX locale...
437 */
438
439 if (type == IPP_TAG_LANGUAGE && strcasecmp(values[i], "C") == 0)
440 value->string.text = ((int)type & IPP_TAG_COPY) ? "en" :
441 strdup("en");
442 else
443 value->string.text = ((int)type & IPP_TAG_COPY) ? (char *)values[i] :
444 strdup(values[i]);
445 }
753453e4 446 }
50146867 447
448 return (attr);
3a193f5e 449}
450
451
50146867 452/*
453 * 'ippAddRange()' - Add a range of values to an IPP request.
454 */
3a193f5e 455
b0757135 456ipp_attribute_t * /* O - New attribute */
457ippAddRange(ipp_t *ipp, /* I - IPP request */
458 ipp_tag_t group, /* I - IPP group */
459 const char *name, /* I - Name of attribute */
460 int lower, /* I - Lower value */
461 int upper) /* I - Upper value */
3a193f5e 462{
b0757135 463 ipp_attribute_t *attr; /* New attribute */
50146867 464
465
e455ef57 466 if (ipp == NULL || name == NULL)
50146867 467 return (NULL);
468
e09246c8 469 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 470 return (NULL);
471
472 attr->name = strdup(name);
473 attr->group_tag = group;
474 attr->value_tag = IPP_TAG_RANGE;
475 attr->values[0].range.lower = lower;
476 attr->values[0].range.upper = upper;
477
478 return (attr);
3a193f5e 479}
480
481
5356dc5a 482/*
483 * 'ippAddRanges()' - Add ranges of values to an IPP request.
484 */
485
b0757135 486ipp_attribute_t * /* O - New attribute */
487ippAddRanges(ipp_t *ipp, /* I - IPP request */
488 ipp_tag_t group, /* I - IPP group */
489 const char *name, /* I - Name of attribute */
490 int num_values, /* I - Number of values */
491 const int *lower, /* I - Lower values */
492 const int *upper) /* I - Upper values */
5356dc5a 493{
b0757135 494 int i; /* Looping var */
495 ipp_attribute_t *attr; /* New attribute */
496 ipp_value_t *value; /* Current value */
5356dc5a 497
498
2d850885 499 if (ipp == NULL || name == NULL || num_values < 1)
5356dc5a 500 return (NULL);
501
e09246c8 502 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
5356dc5a 503 return (NULL);
504
b0757135 505 attr->name = strdup(name);
506 attr->group_tag = group;
507 attr->value_tag = IPP_TAG_RANGE;
5356dc5a 508
509 if (lower != NULL && upper != NULL)
753453e4 510 for (i = 0, value = attr->values;
511 i < num_values;
512 i ++, value ++)
5356dc5a 513 {
753453e4 514 value->range.lower = lower[i];
515 value->range.upper = upper[i];
5356dc5a 516 }
517
518 return (attr);
519}
520
521
50146867 522/*
523 * 'ippAddResolution()' - Add a resolution value to an IPP request.
524 */
525
b0757135 526ipp_attribute_t * /* O - New attribute */
527ippAddResolution(ipp_t *ipp, /* I - IPP request */
528 ipp_tag_t group, /* I - IPP group */
529 const char *name, /* I - Name of attribute */
530 ipp_res_t units, /* I - Units for resolution */
531 int xres, /* I - X resolution */
532 int yres) /* I - Y resolution */
3a193f5e 533{
b0757135 534 ipp_attribute_t *attr; /* New attribute */
50146867 535
536
537 if (ipp == NULL || name == NULL)
538 return (NULL);
539
e09246c8 540 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 541 return (NULL);
542
543 attr->name = strdup(name);
544 attr->group_tag = group;
545 attr->value_tag = IPP_TAG_RESOLUTION;
546 attr->values[0].resolution.xres = xres;
547 attr->values[0].resolution.yres = yres;
548 attr->values[0].resolution.units = units;
549
550 return (attr);
3a193f5e 551}
552
553
5356dc5a 554/*
555 * 'ippAddResolutions()' - Add resolution values to an IPP request.
556 */
557
b0757135 558ipp_attribute_t * /* O - New attribute */
559ippAddResolutions(ipp_t *ipp, /* I - IPP request */
560 ipp_tag_t group, /* I - IPP group */
561 const char *name, /* I - Name of attribute */
562 int num_values, /* I - Number of values */
563 ipp_res_t units, /* I - Units for resolution */
564 const int *xres, /* I - X resolutions */
565 const int *yres) /* I - Y resolutions */
5356dc5a 566{
b0757135 567 int i; /* Looping var */
568 ipp_attribute_t *attr; /* New attribute */
569 ipp_value_t *value; /* Current value */
5356dc5a 570
571
e455ef57 572 if (ipp == NULL || name == NULL || num_values < 1)
5356dc5a 573 return (NULL);
574
e09246c8 575 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
5356dc5a 576 return (NULL);
577
b0757135 578 attr->name = strdup(name);
579 attr->group_tag = group;
580 attr->value_tag = IPP_TAG_RESOLUTION;
5356dc5a 581
582 if (xres != NULL && yres != NULL)
753453e4 583 for (i = 0, value = attr->values;
584 i < num_values;
585 i ++, value ++)
5356dc5a 586 {
753453e4 587 value->resolution.xres = xres[i];
588 value->resolution.yres = yres[i];
589 value->resolution.units = units;
5356dc5a 590 }
591
592 return (attr);
593}
594
595
596/*
597 * 'ippAddSeparator()' - Add a group separator to an IPP request.
598 */
599
b0757135 600ipp_attribute_t * /* O - New attribute */
601ippAddSeparator(ipp_t *ipp) /* I - IPP request */
5356dc5a 602{
b0757135 603 ipp_attribute_t *attr; /* New attribute */
5356dc5a 604
605
27d555e8 606 DEBUG_printf(("ippAddSeparator(%p)\n", ipp));
5356dc5a 607
608 if (ipp == NULL)
609 return (NULL);
610
e09246c8 611 if ((attr = _ipp_add_attr(ipp, 0)) == NULL)
5356dc5a 612 return (NULL);
613
614 attr->group_tag = IPP_TAG_ZERO;
615 attr->value_tag = IPP_TAG_ZERO;
616
617 return (attr);
618}
619
620
3a193f5e 621/*
50146867 622 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
7db52463 623 * in seconds.
3a193f5e 624 */
625
b0757135 626time_t /* O - UNIX time value */
627ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */
3a193f5e 628{
b0757135 629 struct tm unixdate; /* UNIX date/time info */
630 time_t t; /* Computed time */
3a193f5e 631
632
633 memset(&unixdate, 0, sizeof(unixdate));
634
635 /*
636 * RFC-1903 date/time format is:
637 *
638 * Byte(s) Description
639 * ------- -----------
640 * 0-1 Year (0 to 65535)
641 * 2 Month (1 to 12)
642 * 3 Day (1 to 31)
643 * 4 Hours (0 to 23)
644 * 5 Minutes (0 to 59)
645 * 6 Seconds (0 to 60, 60 = "leap second")
646 * 7 Deciseconds (0 to 9)
647 * 8 +/- UTC
648 * 9 UTC hours (0 to 11)
649 * 10 UTC minutes (0 to 59)
650 */
651
652 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
653 unixdate.tm_mon = date[2] - 1;
654 unixdate.tm_mday = date[3];
655 unixdate.tm_hour = date[4];
656 unixdate.tm_min = date[5];
657 unixdate.tm_sec = date[6];
658
659 t = mktime(&unixdate);
660
661 if (date[8] == '-')
662 t += date[9] * 3600 + date[10] * 60;
663 else
664 t -= date[9] * 3600 + date[10] * 60;
665
666 return (t);
667}
668
669
50146867 670/*
671 * 'ippDelete()' - Delete an IPP request.
672 */
673
3a193f5e 674void
b0757135 675ippDelete(ipp_t *ipp) /* I - IPP request */
3a193f5e 676{
b0757135 677 ipp_attribute_t *attr, /* Current attribute */
678 *next; /* Next attribute */
50146867 679
680
753453e4 681 DEBUG_printf(("ippDelete(): %p\n", ipp));
ccf243ee 682
50146867 683 if (ipp == NULL)
684 return;
685
686 for (attr = ipp->attrs; attr != NULL; attr = next)
687 {
50146867 688 next = attr->next;
a3e17a89 689 _ipp_free_attr(attr);
50146867 690 }
691
692 free(ipp);
3a193f5e 693}
694
695
b0757135 696/*
697 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP request.
698 */
699
700void
701ippDeleteAttribute(ipp_t *ipp, /* I - IPP request */
702 ipp_attribute_t *attr) /* I - Attribute to delete */
703{
704}
705
706
50146867 707/*
708 * 'ippFindAttribute()' - Find a named attribute in a request...
709 */
710
b0757135 711ipp_attribute_t * /* O - Matching attribute */
712ippFindAttribute(ipp_t *ipp, /* I - IPP request */
713 const char *name, /* I - Name of attribute */
714 ipp_tag_t type) /* I - Type of attribute */
7db52463 715{
716 DEBUG_printf(("ippFindAttribute(%p, \'%s\')\n", ipp, name));
717
718 if (ipp == NULL || name == NULL)
719 return (NULL);
720
721 /*
722 * Reset the current pointer...
723 */
724
725 ipp->current = NULL;
726
727 /*
728 * Search for the attribute...
729 */
730
731 return (ippFindNextAttribute(ipp, name, type));
732}
733
734
735/*
736 * 'ippFindNextAttribute()' - Find the next named attribute in a request...
737 */
738
b0757135 739ipp_attribute_t * /* O - Matching attribute */
740ippFindNextAttribute(ipp_t *ipp, /* I - IPP request */
741 const char *name, /* I - Name of attribute */
742 ipp_tag_t type) /* I - Type of attribute */
3a193f5e 743{
b0757135 744 ipp_attribute_t *attr; /* Current atttribute */
745 ipp_tag_t value_tag; /* Value tag */
50146867 746
747
7db52463 748 DEBUG_printf(("ippFindNextAttribute(%p, \'%s\')\n", ipp, name));
5356dc5a 749
50146867 750 if (ipp == NULL || name == NULL)
751 return (NULL);
752
7db52463 753 if (ipp->current)
754 attr = ipp->current->next;
755 else
756 attr = ipp->attrs;
757
758 for (; attr != NULL; attr = attr->next)
5356dc5a 759 {
27d555e8 760 DEBUG_printf(("ippFindAttribute: attr = %p, name = \'%s\'\n", attr,
5356dc5a 761 attr->name));
762
b5cb0608 763 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
b6ea8f29 764
a7b3e92e 765 if (attr->name != NULL && strcasecmp(attr->name, name) == 0 &&
b6ea8f29 766 (value_tag == type || type == IPP_TAG_ZERO ||
767 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
768 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
7db52463 769 {
770 ipp->current = attr;
771
50146867 772 return (attr);
7db52463 773 }
5356dc5a 774 }
50146867 775
7db52463 776 ipp->current = NULL;
777
50146867 778 return (NULL);
3a193f5e 779}
780
781
782/*
50146867 783 * 'ippLength()' - Compute the length of an IPP request.
3a193f5e 784 */
785
b0757135 786size_t /* O - Size of IPP request */
787ippLength(ipp_t *ipp) /* I - IPP request */
3a193f5e 788{
b0757135 789 return (ipp_length(ipp, 0));
50146867 790}
3a193f5e 791
50146867 792
7ebf3a09 793/*
794 * 'ippNew()' - Allocate a new IPP request.
795 */
796
b0757135 797ipp_t * /* O - New IPP request */
50146867 798ippNew(void)
799{
b0757135 800 ipp_t *temp; /* New IPP request */
7ebf3a09 801
802
d2e58bfa 803 if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
7ebf3a09 804 {
805 /*
806 * Default to IPP 1.1...
807 */
808
0a3ac972 809 temp->request.any.version[0] = 1;
810 temp->request.any.version[1] = 1;
7ebf3a09 811 }
812
ccf243ee 813 DEBUG_printf(("ippNew(): %p\n", temp));
814
7ebf3a09 815 return (temp);
3a193f5e 816}
817
818
819/*
b070f93d 820 * 'ippRead()' - Read data for an IPP request from a HTTP connection.
3a193f5e 821 */
822
b0757135 823ipp_state_t /* O - Current state */
824ippRead(http_t *http, /* I - HTTP connection */
825 ipp_t *ipp) /* I - IPP data */
b070f93d 826{
dd63ebe2 827 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=%d\n", http, ipp,
828 http ? http->data_remaining : -1));
b070f93d 829
830 if (http == NULL)
831 return (IPP_ERROR);
832
dd63ebe2 833 DEBUG_printf(("http->state = %d\n", http->state));
834
ed093015 835 return (ippReadIO(http, (ipp_iocb_t)ipp_read_http,
b070f93d 836 http->blocking || http->used != 0, NULL, ipp));
837}
838
839
840/*
841 * 'ippReadFile()' - Read data for an IPP request from a file.
842 */
843
b0757135 844ipp_state_t /* O - Current state */
845ippReadFile(int fd, /* I - HTTP data */
846 ipp_t *ipp) /* I - IPP data */
b070f93d 847{
848 DEBUG_printf(("ippReadFile(%d, %p)\n", fd, ipp));
849
ed093015 850 return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp));
b070f93d 851}
852
853
854/*
855 * 'ippReadIO()' - Read data for an IPP request.
856 */
857
b0757135 858ipp_state_t /* O - Current state */
859ippReadIO(void *src, /* I - Data source */
860 ipp_iocb_t cb, /* I - Read callback function */
861 int blocking, /* I - Use blocking IO? */
862 ipp_t *parent, /* I - Parent request, if any */
863 ipp_t *ipp) /* I - IPP data */
3a193f5e 864{
b0757135 865 int n; /* Length of data */
866 unsigned char buffer[32768], /* Data buffer */
867 *bufptr; /* Pointer into buffer */
868 ipp_attribute_t *attr; /* Current attribute */
869 ipp_tag_t tag; /* Current tag */
870 ipp_value_t *value; /* Current value */
3b960317 871
872
ed093015 873 DEBUG_printf(("ippReadIO(%p, %p, %d, %p, %p)\n", src, cb, blocking,
874 parent, ipp));
4a73831b 875
b070f93d 876 if (src == NULL || ipp == NULL)
3b960317 877 return (IPP_ERROR);
878
879 switch (ipp->state)
880 {
881 case IPP_IDLE :
4a73831b 882 ipp->state ++; /* Avoid common problem... */
3b960317 883
884 case IPP_HEADER :
b0757135 885 if (parent == NULL)
4a73831b 886 {
b0757135 887 /*
888 * Get the request header...
889 */
3b960317 890
b0757135 891 if ((n = (*cb)(src, buffer, 8)) < 8)
892 {
893 DEBUG_printf(("ippReadIO: Unable to read header (%d bytes read)!\n", n));
894 return (n == 0 ? IPP_IDLE : IPP_ERROR);
895 }
3b960317 896
b0757135 897 /*
898 * Verify the major version number...
899 */
3b960317 900
b0757135 901 if (buffer[0] != 1)
902 {
903 DEBUG_printf(("ippReadIO: version number (%d.%d) is bad.\n", buffer[0],
904 buffer[1]));
905 return (IPP_ERROR);
906 }
907
908 /*
909 * Then copy the request header over...
910 */
3b960317 911
b0757135 912 ipp->request.any.version[0] = buffer[0];
913 ipp->request.any.version[1] = buffer[1];
914 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
915 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
916 buffer[6]) << 8) | buffer[7];
917 }
3b960317 918
919 ipp->state = IPP_ATTRIBUTE;
920 ipp->current = NULL;
921 ipp->curtag = IPP_TAG_ZERO;
922
b070f93d 923 DEBUG_printf(("ippReadIO: version=%d.%d\n", buffer[0], buffer[1]));
0a3ac972 924 DEBUG_printf(("ippReadIO: op_status=%04x\n", ipp->request.any.op_status));
925 DEBUG_printf(("ippReadIO: request_id=%d\n", ipp->request.any.request_id));
27d555e8 926
3b960317 927 /*
928 * If blocking is disabled, stop here...
929 */
930
b070f93d 931 if (!blocking)
3b960317 932 break;
933
934 case IPP_ATTRIBUTE :
b070f93d 935 while ((*cb)(src, buffer, 1) > 0)
3b960317 936 {
937 /*
938 * Read this attribute...
939 */
940
941 tag = (ipp_tag_t)buffer[0];
942
943 if (tag == IPP_TAG_END)
944 {
945 /*
946 * No more attributes left...
947 */
948
b070f93d 949 DEBUG_puts("ippReadIO: IPP_TAG_END!");
4a73831b 950
3b960317 951 ipp->state = IPP_DATA;
952 break;
953 }
714294b4 954 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
3b960317 955 {
956 /*
957 * Group tag... Set the current group and continue...
958 */
959
5356dc5a 960 if (ipp->curtag == tag)
961 ippAddSeparator(ipp);
962
3b960317 963 ipp->curtag = tag;
964 ipp->current = NULL;
b070f93d 965 DEBUG_printf(("ippReadIO: group tag = %x\n", tag));
3b960317 966 continue;
967 }
968
b070f93d 969 DEBUG_printf(("ippReadIO: value tag = %x\n", tag));
5356dc5a 970
3b960317 971 /*
972 * Get the name...
973 */
974
b070f93d 975 if ((*cb)(src, buffer, 2) < 2)
4a73831b 976 {
b070f93d 977 DEBUG_puts("ippReadIO: unable to read name length!");
3b960317 978 return (IPP_ERROR);
4a73831b 979 }
3b960317 980
981 n = (buffer[0] << 8) | buffer[1];
982
843779ef 983 if (n > (sizeof(buffer) - 1))
984 {
985 DEBUG_printf(("ippReadIO: bad name length %d!\n", n));
986 return (IPP_ERROR);
987 }
988
b070f93d 989 DEBUG_printf(("ippReadIO: name length = %d\n", n));
4a73831b 990
1f90dbaa 991 if (n == 0 && tag != IPP_TAG_MEMBERNAME)
3b960317 992 {
993 /*
994 * More values for current attribute...
995 */
996
997 if (ipp->current == NULL)
998 return (IPP_ERROR);
999
1000 attr = ipp->current;
1001
7e9dc5e9 1002 /*
1003 * Make sure we aren't adding a new value of a different
1004 * type...
1005 */
1006
1f90dbaa 1007 if (attr->value_tag == IPP_TAG_ZERO)
1008 {
1009 attr->value_tag = tag;
1010 }
1011 else if (attr->value_tag == IPP_TAG_STRING ||
1012 (attr->value_tag >= IPP_TAG_TEXTLANG &&
1013 attr->value_tag <= IPP_TAG_MIMETYPE))
7e9dc5e9 1014 {
1015 /*
1016 * String values can sometimes come across in different
1017 * forms; accept sets of differing values...
1018 */
1019
1020 if (tag != IPP_TAG_STRING &&
1021 (tag < IPP_TAG_TEXTLANG || tag > IPP_TAG_MIMETYPE))
1022 return (IPP_ERROR);
1023 }
b0757135 1024 else if (attr->value_tag != tag &&
b0757135 1025 tag != IPP_TAG_END_COLLECTION)
7e9dc5e9 1026 return (IPP_ERROR);
1027
1028 /*
753453e4 1029 * Finally, reallocate the attribute array as needed...
7e9dc5e9 1030 */
1031
1f90dbaa 1032 if ((attr->num_values % IPP_MAX_VALUES) == 0 &&
1033 attr->num_values > 0)
753453e4 1034 {
1035 ipp_attribute_t *temp, /* Pointer to new buffer */
1036 *ptr; /* Pointer in attribute list */
1037
1038
1039 /*
1040 * Reallocate memory...
1041 */
1042
1043 if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
1044 (attr->num_values + IPP_MAX_VALUES - 1) *
1045 sizeof(ipp_value_t))) == NULL)
1046 return (IPP_ERROR);
1047
1048 /*
1049 * Reset pointers in the list...
1050 */
1051
1052 for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next);
1053
1054 if (ptr)
1055 ptr->next = temp;
1056 else
1057 ipp->attrs = temp;
1058
1059 attr = ipp->current = ipp->last = temp;
1060 }
3b960317 1061 }
1f90dbaa 1062 else if (tag == IPP_TAG_MEMBERNAME)
1063 {
1064 /*
1065 * Name must be length 0!
1066 */
1067
1068 if (n)
1069 {
1070 DEBUG_puts("ippReadIO: member name not empty!");
1071 return (IPP_ERROR);
1072 }
1073
1074 attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES);
1075
1076 attr->group_tag = ipp->curtag;
1077 attr->value_tag = IPP_TAG_ZERO;
1078 attr->num_values = 0;
1079 }
3b960317 1080 else
1081 {
1082 /*
1083 * New attribute; read the name and add it...
1084 */
1085
b070f93d 1086 if ((*cb)(src, buffer, n) < n)
4a73831b 1087 {
b070f93d 1088 DEBUG_puts("ippReadIO: unable to read name!");
3b960317 1089 return (IPP_ERROR);
4a73831b 1090 }
3b960317 1091
1092 buffer[n] = '\0';
b070f93d 1093 DEBUG_printf(("ippReadIO: name = \'%s\'\n", buffer));
4a73831b 1094
e09246c8 1095 attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES);
3b960317 1096
4a73831b 1097 attr->group_tag = ipp->curtag;
1098 attr->value_tag = tag;
15749ff9 1099 attr->name = strdup((char *)buffer);
4a73831b 1100 attr->num_values = 0;
3b960317 1101 }
1102
753453e4 1103 value = attr->values + attr->num_values;
1104
b070f93d 1105 if ((*cb)(src, buffer, 2) < 2)
4a73831b 1106 {
b070f93d 1107 DEBUG_puts("ippReadIO: unable to read value length!");
4a73831b 1108 return (IPP_ERROR);
1109 }
1110
1111 n = (buffer[0] << 8) | buffer[1];
b070f93d 1112 DEBUG_printf(("ippReadIO: value length = %d\n", n));
4a73831b 1113
3b960317 1114 switch (tag)
1115 {
1116 case IPP_TAG_INTEGER :
1117 case IPP_TAG_ENUM :
b070f93d 1118 if ((*cb)(src, buffer, 4) < 4)
dd63ebe2 1119 {
1120 DEBUG_puts("ippReadIO: Unable to read integer value!");
3b960317 1121 return (IPP_ERROR);
dd63ebe2 1122 }
3b960317 1123
1124 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1125 buffer[3];
1126
753453e4 1127 value->integer = n;
3b960317 1128 break;
1129 case IPP_TAG_BOOLEAN :
b070f93d 1130 if ((*cb)(src, buffer, 1) < 1)
dd63ebe2 1131 {
1132 DEBUG_puts("ippReadIO: Unable to read boolean value!");
3b960317 1133 return (IPP_ERROR);
dd63ebe2 1134 }
3b960317 1135
753453e4 1136 value->boolean = buffer[0];
3b960317 1137 break;
1138 case IPP_TAG_TEXT :
1139 case IPP_TAG_NAME :
1140 case IPP_TAG_KEYWORD :
1141 case IPP_TAG_STRING :
1142 case IPP_TAG_URI :
1143 case IPP_TAG_URISCHEME :
1144 case IPP_TAG_CHARSET :
1145 case IPP_TAG_LANGUAGE :
7db52463 1146 case IPP_TAG_MIMETYPE :
1147 value->string.text = calloc(n + 1, 1);
cb1f28d6 1148
fc562d94 1149 if ((*cb)(src, (ipp_uchar_t *)value->string.text, n) < n)
dd63ebe2 1150 {
1151 DEBUG_puts("ippReadIO: Unable to read string value!");
7db52463 1152 return (IPP_ERROR);
dd63ebe2 1153 }
cb1f28d6 1154
b070f93d 1155 DEBUG_printf(("ippReadIO: value = \'%s\'\n",
7db52463 1156 value->string.text));
1157 break;
1158 case IPP_TAG_DATE :
b070f93d 1159 if ((*cb)(src, value->date, 11) < 11)
dd63ebe2 1160 {
1161 DEBUG_puts("ippReadIO: Unable to date integer value!");
7db52463 1162 return (IPP_ERROR);
dd63ebe2 1163 }
7db52463 1164 break;
1165 case IPP_TAG_RESOLUTION :
b070f93d 1166 if ((*cb)(src, buffer, 9) < 9)
dd63ebe2 1167 {
1168 DEBUG_puts("ippReadIO: Unable to read resolution value!");
7db52463 1169 return (IPP_ERROR);
dd63ebe2 1170 }
d2e58bfa 1171
7db52463 1172 value->resolution.xres =
1173 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1174 buffer[3];
1175 value->resolution.yres =
1176 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
1177 buffer[7];
1178 value->resolution.units =
1179 (ipp_res_t)buffer[8];
1180 break;
1181 case IPP_TAG_RANGE :
b070f93d 1182 if ((*cb)(src, buffer, 8) < 8)
dd63ebe2 1183 {
1184 DEBUG_puts("ippReadIO: Unable to read range value!");
7db52463 1185 return (IPP_ERROR);
dd63ebe2 1186 }
d2e58bfa 1187
7db52463 1188 value->range.lower =
1189 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1190 buffer[3];
1191 value->range.upper =
1192 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
1193 buffer[7];
1194 break;
1195 case IPP_TAG_TEXTLANG :
1196 case IPP_TAG_NAMELANG :
ba31b514 1197 if (n > sizeof(buffer) || n < 4)
a4834236 1198 {
1199 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1200 return (IPP_ERROR);
1201 }
1202
b070f93d 1203 if ((*cb)(src, buffer, n) < n)
dd63ebe2 1204 {
1205 DEBUG_puts("ippReadIO: Unable to read string w/language value!");
7db52463 1206 return (IPP_ERROR);
dd63ebe2 1207 }
cb1f28d6 1208
7db52463 1209 bufptr = buffer;
bd84e0d1 1210
7db52463 1211 /*
1212 * text-with-language and name-with-language are composite
1213 * values:
1214 *
1215 * charset-length
1216 * charset
1217 * text-length
1218 * text
1219 */
d2e58bfa 1220
7db52463 1221 n = (bufptr[0] << 8) | bufptr[1];
bd84e0d1 1222
7db52463 1223 value->string.charset = calloc(n + 1, 1);
bd84e0d1 1224
7db52463 1225 memcpy(value->string.charset,
1226 bufptr + 2, n);
f63a2256 1227
7db52463 1228 bufptr += 2 + n;
1229 n = (bufptr[0] << 8) | bufptr[1];
3b960317 1230
7db52463 1231 value->string.text = calloc(n + 1, 1);
3b960317 1232
7db52463 1233 memcpy(value->string.text,
1234 bufptr + 2, n);
1235 break;
1236
b0757135 1237 case IPP_TAG_BEGIN_COLLECTION :
1238 /*
1239 * Oh, boy, here comes a collection value, so read it...
1240 */
1241
1242 value->collection = ippNew();
1243
1244 if (n > 0)
dd63ebe2 1245 {
1246 DEBUG_puts("ippReadIO: begCollection tag with value length > 0!");
b0757135 1247 return (IPP_ERROR);
dd63ebe2 1248 }
b0757135 1249
1250 if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_ERROR)
dd63ebe2 1251 {
1252 DEBUG_puts("ippReadIO: Unable to read collection value!");
b0757135 1253 return (IPP_ERROR);
dd63ebe2 1254 }
b0757135 1255 break;
1256
1257 case IPP_TAG_END_COLLECTION :
1258 if (n > 0)
dd63ebe2 1259 {
1260 DEBUG_puts("ippReadIO: endCollection tag with value length > 0!");
b0757135 1261 return (IPP_ERROR);
dd63ebe2 1262 }
1263
1264 DEBUG_puts("ippReadIO: endCollection tag...");
b0757135 1265
1f90dbaa 1266 return (ipp->state = IPP_DATA);
b0757135 1267
1268 case IPP_TAG_MEMBERNAME :
1269 /*
1270 * The value the name of the member in the collection, which
1271 * we need to carry over...
1272 */
1273
1f90dbaa 1274 attr->name = calloc(n + 1, 1);
b0757135 1275
1276 if ((*cb)(src, (ipp_uchar_t *)attr->name, n) < n)
dd63ebe2 1277 {
1278 DEBUG_puts("ippReadIO: Unable to read member name value!");
b0757135 1279 return (IPP_ERROR);
dd63ebe2 1280 }
1281
1282 DEBUG_printf(("ippReadIO: member name = \"%s\"\n", attr->name));
b0757135 1283 break;
1284
7db52463 1285 default : /* Other unsupported values */
1286 value->unknown.length = n;
1287 if (n > 0)
1288 {
1289 value->unknown.data = malloc(n);
b070f93d 1290 if ((*cb)(src, value->unknown.data, n) < n)
dd63ebe2 1291 {
1292 DEBUG_puts("ippReadIO: Unable to read unsupported value!");
7db52463 1293 return (IPP_ERROR);
dd63ebe2 1294 }
7db52463 1295 }
1296 else
1297 value->unknown.data = NULL;
1298 break;
4a73831b 1299 }
3b960317 1300
7db52463 1301 attr->num_values ++;
5356dc5a 1302
3b960317 1303 /*
1304 * If blocking is disabled, stop here...
1305 */
1306
b070f93d 1307 if (!blocking)
3b960317 1308 break;
1309 }
3b960317 1310 break;
1311
1312 case IPP_DATA :
1313 break;
d21a7597 1314
1315 default :
1316 break; /* anti-compiler-warning-code */
3b960317 1317 }
1318
1319 return (ipp->state);
3a193f5e 1320}
1321
1322
99de6da0 1323/*
7db52463 1324 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
1325 */
1326
b0757135 1327const ipp_uchar_t * /* O - RFC-1903 date/time data */
1328ippTimeToDate(time_t t) /* I - UNIX time value */
7db52463 1329{
b0757135 1330 struct tm *unixdate; /* UNIX unixdate/time info */
1331 static ipp_uchar_t date[11]; /* RFC-1903 date/time data */
7db52463 1332
1333
1334 /*
1335 * RFC-1903 date/time format is:
1336 *
1337 * Byte(s) Description
1338 * ------- -----------
1339 * 0-1 Year (0 to 65535)
1340 * 2 Month (1 to 12)
1341 * 3 Day (1 to 31)
1342 * 4 Hours (0 to 23)
1343 * 5 Minutes (0 to 59)
1344 * 6 Seconds (0 to 60, 60 = "leap second")
1345 * 7 Deciseconds (0 to 9)
1346 * 8 +/- UTC
1347 * 9 UTC hours (0 to 11)
1348 * 10 UTC minutes (0 to 59)
1349 */
1350
1351 unixdate = gmtime(&t);
1352 unixdate->tm_year += 1900;
1353
1354 date[0] = unixdate->tm_year >> 8;
1355 date[1] = unixdate->tm_year;
1356 date[2] = unixdate->tm_mon + 1;
1357 date[3] = unixdate->tm_mday;
1358 date[4] = unixdate->tm_hour;
1359 date[5] = unixdate->tm_min;
1360 date[6] = unixdate->tm_sec;
1361 date[7] = 0;
1362 date[8] = '+';
1363 date[9] = 0;
1364 date[10] = 0;
1365
1366 return (date);
1367}
1368
1369
1370/*
b070f93d 1371 * 'ippWrite()' - Write data for an IPP request to a HTTP connection.
99de6da0 1372 */
1373
b0757135 1374ipp_state_t /* O - Current state */
1375ippWrite(http_t *http, /* I - HTTP connection */
1376 ipp_t *ipp) /* I - IPP data */
b070f93d 1377{
1378 DEBUG_printf(("ippWrite(%p, %p)\n", http, ipp));
1379
1380 if (http == NULL)
1381 return (IPP_ERROR);
1382
ed093015 1383 return (ippWriteIO(http, (ipp_iocb_t)httpWrite,
b070f93d 1384 http->blocking, NULL, ipp));
1385}
1386
1387
1388/*
1389 * 'ippWriteFile()' - Write data for an IPP request to a file.
1390 */
1391
b0757135 1392ipp_state_t /* O - Current state */
1393ippWriteFile(int fd, /* I - HTTP data */
1394 ipp_t *ipp) /* I - IPP data */
b070f93d 1395{
1396 DEBUG_printf(("ippWriteFile(%d, %p)\n", fd, ipp));
1397
b01791df 1398 ipp->state = IPP_IDLE;
1399
ed093015 1400 return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
b070f93d 1401}
1402
1403
1404/*
1405 * 'ippWriteIO()' - Write data for an IPP request.
1406 */
1407
b0757135 1408ipp_state_t /* O - Current state */
1409ippWriteIO(void *dst, /* I - Destination */
1410 ipp_iocb_t cb, /* I - Write callback function */
1411 int blocking, /* I - Use blocking IO? */
1412 ipp_t *parent, /* I - Parent IPP request */
1413 ipp_t *ipp) /* I - IPP data */
99de6da0 1414{
b0757135 1415 int i; /* Looping var */
1416 int n; /* Length of data */
1417 unsigned char buffer[32768], /* Data buffer */
1418 *bufptr; /* Pointer into buffer */
1419 ipp_attribute_t *attr; /* Current attribute */
1420 ipp_value_t *value; /* Current value */
99de6da0 1421
1422
ed093015 1423 DEBUG_printf(("ippWriteIO(%p, %p, %d, %p, %p)\n", dst, cb, blocking,
1424 parent, ipp));
1425
b070f93d 1426 if (dst == NULL || ipp == NULL)
99de6da0 1427 return (IPP_ERROR);
1428
99de6da0 1429 switch (ipp->state)
1430 {
99de6da0 1431 case IPP_IDLE :
1432 ipp->state ++; /* Avoid common problem... */
1433
1434 case IPP_HEADER :
b0757135 1435 if (parent == NULL)
1436 {
1437 /*
1438 * Send the request header:
1439 *
1440 * Version = 2 bytes
1441 * Operation/Status Code = 2 bytes
1442 * Request ID = 4 bytes
1443 * Total = 8 bytes
1444 */
99de6da0 1445
b0757135 1446 bufptr = buffer;
99de6da0 1447
b0757135 1448 *bufptr++ = ipp->request.any.version[0];
1449 *bufptr++ = ipp->request.any.version[1];
1450 *bufptr++ = ipp->request.any.op_status >> 8;
1451 *bufptr++ = ipp->request.any.op_status;
1452 *bufptr++ = ipp->request.any.request_id >> 24;
1453 *bufptr++ = ipp->request.any.request_id >> 16;
1454 *bufptr++ = ipp->request.any.request_id >> 8;
1455 *bufptr++ = ipp->request.any.request_id;
99de6da0 1456
b0757135 1457 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
1458 {
1459 DEBUG_puts("ippWrite: Could not write IPP header...");
1460 return (IPP_ERROR);
1461 }
99de6da0 1462 }
1463
375a0ad5 1464 /*
1465 * Reset the state engine to point to the first attribute
1466 * in the request/response, with no current group.
1467 */
1468
99de6da0 1469 ipp->state = IPP_ATTRIBUTE;
1470 ipp->current = ipp->attrs;
1471 ipp->curtag = IPP_TAG_ZERO;
1472
7db52463 1473 DEBUG_printf(("ippWrite: version=%d.%d\n", buffer[0], buffer[1]));
0a3ac972 1474 DEBUG_printf(("ippWrite: op_status=%04x\n", ipp->request.any.op_status));
1475 DEBUG_printf(("ippWrite: request_id=%d\n", ipp->request.any.request_id));
7db52463 1476
1477 /*
1478 * If blocking is disabled, stop here...
1479 */
1480
b070f93d 1481 if (!blocking)
7db52463 1482 break;
1483
99de6da0 1484 case IPP_ATTRIBUTE :
1485 while (ipp->current != NULL)
1486 {
1487 /*
1488 * Write this attribute...
1489 */
1490
1491 bufptr = buffer;
1492 attr = ipp->current;
1493
1494 ipp->current = ipp->current->next;
1495
b0757135 1496 if (ipp->curtag != attr->group_tag && parent == NULL)
99de6da0 1497 {
1498 /*
375a0ad5 1499 * Send a group tag byte...
99de6da0 1500 */
1501
1502 ipp->curtag = attr->group_tag;
1503
1504 if (attr->group_tag == IPP_TAG_ZERO)
1505 continue;
1506
7db52463 1507 DEBUG_printf(("ippWrite: wrote group tag = %x\n", attr->group_tag));
99de6da0 1508 *bufptr++ = attr->group_tag;
1509 }
1510
375a0ad5 1511 /*
1512 * Write the attribute tag and name. The current implementation
1513 * does not support the extension value tags above 0x7f, so all
1514 * value tags are 1 byte.
1515 *
1516 * The attribute name length does not include the trailing nul
1517 * character in the source string.
b0757135 1518 *
1519 * Collection values (parent != NULL) are written differently...
375a0ad5 1520 */
1521
b0757135 1522 if (parent == NULL)
1523 {
1524 /*
1525 * Get the length of the attribute name, and make sure it won't
1526 * overflow the buffer...
1527 */
1528
1529 if ((n = strlen(attr->name)) > (sizeof(buffer) - 4))
1530 return (IPP_ERROR);
1531
1532 /*
1533 * Write the value tag, name length, and name string...
1534 */
1535
1536 DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag));
1537 DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n, attr->name));
1538
1539 *bufptr++ = attr->value_tag;
1540 *bufptr++ = n >> 8;
1541 *bufptr++ = n;
1542 memcpy(bufptr, attr->name, n);
1543 bufptr += n;
1544 }
1545 else
1546 {
1547 /*
1548 * Get the length of the attribute name, and make sure it won't
1549 * overflow the buffer...
1550 */
1551
1552 if ((n = strlen(attr->name)) > (sizeof(buffer) - 7))
1553 return (IPP_ERROR);
1554
1555 /*
1556 * Write the member name tag, name length, name string, value tag,
1557 * and empty name for the collection member attribute...
1558 */
1559
1560 DEBUG_printf(("ippWrite: writing value tag = %x\n",
1561 IPP_TAG_MEMBERNAME));
1562 DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n, attr->name));
1563 DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag));
1564 DEBUG_puts("ippWrite: writing name = 0, \'\'\n");
1565
1566 *bufptr++ = IPP_TAG_MEMBERNAME;
1f90dbaa 1567 *bufptr++ = 0;
1568 *bufptr++ = 0;
b0757135 1569 *bufptr++ = n >> 8;
1570 *bufptr++ = n;
1571 memcpy(bufptr, attr->name, n);
1572 bufptr += n;
1573
1574 *bufptr++ = attr->value_tag;
1575 *bufptr++ = 0;
1576 *bufptr++ = 0;
1577 }
99de6da0 1578
375a0ad5 1579 /*
1580 * Now write the attribute value(s)...
1581 */
1582
7db52463 1583 switch (attr->value_tag & ~IPP_TAG_COPY)
99de6da0 1584 {
1585 case IPP_TAG_INTEGER :
1586 case IPP_TAG_ENUM :
7db52463 1587 for (i = 0, value = attr->values;
1588 i < attr->num_values;
1589 i ++, value ++)
99de6da0 1590 {
1591 if ((sizeof(buffer) - (bufptr - buffer)) < 9)
1592 {
b070f93d 1593 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1594 {
1595 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1596 return (IPP_ERROR);
1597 }
1598
1599 bufptr = buffer;
1600 }
1601
1602 if (i)
1603 {
1604 /*
1605 * Arrays and sets are done by sending additional
1606 * values with a zero-length name...
1607 */
1608
1609 *bufptr++ = attr->value_tag;
1610 *bufptr++ = 0;
1611 *bufptr++ = 0;
1612 }
1613
375a0ad5 1614 /*
1615 * Integers and enumerations are both 4-byte signed
1616 * (twos-complement) values.
1617 *
1618 * Put the 2-byte length and 4-byte value into the buffer...
1619 */
1620
99de6da0 1621 *bufptr++ = 0;
1622 *bufptr++ = 4;
7db52463 1623 *bufptr++ = value->integer >> 24;
1624 *bufptr++ = value->integer >> 16;
1625 *bufptr++ = value->integer >> 8;
1626 *bufptr++ = value->integer;
99de6da0 1627 }
1628 break;
1629
1630 case IPP_TAG_BOOLEAN :
753453e4 1631 for (i = 0, value = attr->values;
1632 i < attr->num_values;
1633 i ++, value ++)
99de6da0 1634 {
1635 if ((sizeof(buffer) - (bufptr - buffer)) < 6)
1636 {
b070f93d 1637 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1638 {
1639 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1640 return (IPP_ERROR);
1641 }
1642
1643 bufptr = buffer;
1644 }
1645
1646 if (i)
1647 {
1648 /*
1649 * Arrays and sets are done by sending additional
1650 * values with a zero-length name...
1651 */
1652
1653 *bufptr++ = attr->value_tag;
1654 *bufptr++ = 0;
1655 *bufptr++ = 0;
1656 }
1657
375a0ad5 1658 /*
1659 * Boolean values are 1-byte; 0 = false, 1 = true.
1660 *
1661 * Put the 2-byte length and 1-byte value into the buffer...
1662 */
1663
99de6da0 1664 *bufptr++ = 0;
1665 *bufptr++ = 1;
753453e4 1666 *bufptr++ = value->boolean;
99de6da0 1667 }
1668 break;
1669
1670 case IPP_TAG_TEXT :
1671 case IPP_TAG_NAME :
1672 case IPP_TAG_KEYWORD :
1673 case IPP_TAG_STRING :
1674 case IPP_TAG_URI :
1675 case IPP_TAG_URISCHEME :
1676 case IPP_TAG_CHARSET :
1677 case IPP_TAG_LANGUAGE :
1678 case IPP_TAG_MIMETYPE :
753453e4 1679 for (i = 0, value = attr->values;
1680 i < attr->num_values;
1681 i ++, value ++)
99de6da0 1682 {
1683 if (i)
1684 {
1685 /*
1686 * Arrays and sets are done by sending additional
1687 * values with a zero-length name...
1688 */
1689
7db52463 1690 DEBUG_printf(("ippWrite: writing value tag = %x\n",
99de6da0 1691 attr->value_tag));
7db52463 1692 DEBUG_printf(("ippWrite: writing name = 0, \'\'\n"));
99de6da0 1693
1694 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
1695 {
b070f93d 1696 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1697 {
1698 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1699 return (IPP_ERROR);
1700 }
1701
1702 bufptr = buffer;
1703 }
1704
1705 *bufptr++ = attr->value_tag;
1706 *bufptr++ = 0;
1707 *bufptr++ = 0;
1708 }
1709
01460d2b 1710 if (value->string.text != NULL)
1711 n = strlen(value->string.text);
1712 else
1713 n = 0;
99de6da0 1714
375a0ad5 1715 if (n > (sizeof(buffer) - 2))
99de6da0 1716 return (IPP_ERROR);
1717
7db52463 1718 DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n,
1719 value->string.text));
99de6da0 1720
1721 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
1722 {
b070f93d 1723 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1724 {
7db52463 1725 DEBUG_puts("ippWrite: Could not write IPP attribute...");
99de6da0 1726 return (IPP_ERROR);
1727 }
1728
1729 bufptr = buffer;
1730 }
1731
375a0ad5 1732 /*
1733 * All simple strings consist of the 2-byte length and
1734 * character data without the trailing nul normally found
1735 * in C strings. Also, strings cannot be longer than 32767
1736 * bytes since the 2-byte length is a signed (twos-complement)
1737 * value.
1738 *
1739 * Put the 2-byte length and string characters in the buffer.
1740 */
1741
99de6da0 1742 *bufptr++ = n >> 8;
1743 *bufptr++ = n;
01460d2b 1744
1745 if (n > 0)
1746 {
1747 memcpy(bufptr, value->string.text, n);
1748 bufptr += n;
1749 }
99de6da0 1750 }
1751 break;
1752
1753 case IPP_TAG_DATE :
753453e4 1754 for (i = 0, value = attr->values;
1755 i < attr->num_values;
1756 i ++, value ++)
99de6da0 1757 {
1758 if ((sizeof(buffer) - (bufptr - buffer)) < 16)
1759 {
b070f93d 1760 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1761 {
1762 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1763 return (IPP_ERROR);
1764 }
1765
1766 bufptr = buffer;
1767 }
1768
1769 if (i)
1770 {
1771 /*
1772 * Arrays and sets are done by sending additional
1773 * values with a zero-length name...
1774 */
1775
1776 *bufptr++ = attr->value_tag;
1777 *bufptr++ = 0;
1778 *bufptr++ = 0;
1779 }
1780
375a0ad5 1781 /*
1782 * Date values consist of a 2-byte length and an
1783 * 11-byte date/time structure defined by RFC 1903.
1784 *
1785 * Put the 2-byte length and 11-byte date/time
1786 * structure in the buffer.
1787 */
1788
99de6da0 1789 *bufptr++ = 0;
1790 *bufptr++ = 11;
753453e4 1791 memcpy(bufptr, value->date, 11);
99de6da0 1792 bufptr += 11;
1793 }
1794 break;
1795
1796 case IPP_TAG_RESOLUTION :
753453e4 1797 for (i = 0, value = attr->values;
1798 i < attr->num_values;
1799 i ++, value ++)
99de6da0 1800 {
1801 if ((sizeof(buffer) - (bufptr - buffer)) < 14)
1802 {
b070f93d 1803 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1804 {
1805 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1806 return (IPP_ERROR);
1807 }
1808
1809 bufptr = buffer;
1810 }
1811
1812 if (i)
1813 {
1814 /*
1815 * Arrays and sets are done by sending additional
1816 * values with a zero-length name...
1817 */
1818
1819 *bufptr++ = attr->value_tag;
1820 *bufptr++ = 0;
1821 *bufptr++ = 0;
1822 }
1823
375a0ad5 1824 /*
1825 * Resolution values consist of a 2-byte length,
1826 * 4-byte horizontal resolution value, 4-byte vertical
1827 * resolution value, and a 1-byte units value.
1828 *
1829 * Put the 2-byte length and resolution value data
1830 * into the buffer.
1831 */
1832
99de6da0 1833 *bufptr++ = 0;
1834 *bufptr++ = 9;
753453e4 1835 *bufptr++ = value->resolution.xres >> 24;
1836 *bufptr++ = value->resolution.xres >> 16;
1837 *bufptr++ = value->resolution.xres >> 8;
1838 *bufptr++ = value->resolution.xres;
1839 *bufptr++ = value->resolution.yres >> 24;
1840 *bufptr++ = value->resolution.yres >> 16;
1841 *bufptr++ = value->resolution.yres >> 8;
1842 *bufptr++ = value->resolution.yres;
1843 *bufptr++ = value->resolution.units;
99de6da0 1844 }
1845 break;
1846
1847 case IPP_TAG_RANGE :
753453e4 1848 for (i = 0, value = attr->values;
1849 i < attr->num_values;
1850 i ++, value ++)
99de6da0 1851 {
1852 if ((sizeof(buffer) - (bufptr - buffer)) < 13)
1853 {
b070f93d 1854 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1855 {
1856 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1857 return (IPP_ERROR);
1858 }
1859
1860 bufptr = buffer;
1861 }
1862
1863 if (i)
1864 {
1865 /*
1866 * Arrays and sets are done by sending additional
1867 * values with a zero-length name...
1868 */
1869
1870 *bufptr++ = attr->value_tag;
1871 *bufptr++ = 0;
1872 *bufptr++ = 0;
1873 }
1874
375a0ad5 1875 /*
1876 * Range values consist of a 2-byte length,
1877 * 4-byte lower value, and 4-byte upper value.
1878 *
1879 * Put the 2-byte length and range value data
1880 * into the buffer.
1881 */
1882
99de6da0 1883 *bufptr++ = 0;
1884 *bufptr++ = 8;
753453e4 1885 *bufptr++ = value->range.lower >> 24;
1886 *bufptr++ = value->range.lower >> 16;
1887 *bufptr++ = value->range.lower >> 8;
1888 *bufptr++ = value->range.lower;
1889 *bufptr++ = value->range.upper >> 24;
1890 *bufptr++ = value->range.upper >> 16;
1891 *bufptr++ = value->range.upper >> 8;
1892 *bufptr++ = value->range.upper;
99de6da0 1893 }
1894 break;
1895
1896 case IPP_TAG_TEXTLANG :
1897 case IPP_TAG_NAMELANG :
753453e4 1898 for (i = 0, value = attr->values;
1899 i < attr->num_values;
1900 i ++, value ++)
99de6da0 1901 {
1902 if (i)
1903 {
1904 /*
1905 * Arrays and sets are done by sending additional
1906 * values with a zero-length name...
1907 */
1908
1909 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
1910 {
b070f93d 1911 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1912 {
1913 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1914 return (IPP_ERROR);
1915 }
1916
1917 bufptr = buffer;
1918 }
1919
1920 *bufptr++ = attr->value_tag;
1921 *bufptr++ = 0;
1922 *bufptr++ = 0;
1923 }
1924
375a0ad5 1925 /*
1926 * textWithLanguage and nameWithLanguage values consist
1927 * of a 2-byte length for both strings and their
1928 * individual lengths, a 2-byte length for the
1929 * character string, the character string without the
1930 * trailing nul, a 2-byte length for the character
1931 * set string, and the character set string without
1932 * the trailing nul.
1933 */
99de6da0 1934
01460d2b 1935 n = 4;
1936
1937 if (value->string.charset != NULL)
1938 n += strlen(value->string.charset);
1939
1940 if (value->string.text != NULL)
1941 n += strlen(value->string.text);
375a0ad5 1942
1943 if (n > (sizeof(buffer) - 2))
99de6da0 1944 return (IPP_ERROR);
1945
1946 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
1947 {
b070f93d 1948 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 1949 {
7db52463 1950 DEBUG_puts("ippWrite: Could not write IPP attribute...");
99de6da0 1951 return (IPP_ERROR);
1952 }
1953
1954 bufptr = buffer;
1955 }
1956
1957 /* Length of entire value */
1958 *bufptr++ = n >> 8;
1959 *bufptr++ = n;
1960
1961 /* Length of charset */
01460d2b 1962 if (value->string.charset != NULL)
1963 n = strlen(value->string.charset);
1964 else
1965 n = 0;
1966
99de6da0 1967 *bufptr++ = n >> 8;
1968 *bufptr++ = n;
1969
1970 /* Charset */
01460d2b 1971 if (n > 0)
1972 {
1973 memcpy(bufptr, value->string.charset, n);
1974 bufptr += n;
1975 }
99de6da0 1976
1977 /* Length of text */
01460d2b 1978 if (value->string.text != NULL)
1979 n = strlen(value->string.text);
1980 else
1981 n = 0;
1982
99de6da0 1983 *bufptr++ = n >> 8;
1984 *bufptr++ = n;
1985
1986 /* Text */
01460d2b 1987 if (n > 0)
1988 {
1989 memcpy(bufptr, value->string.text, n);
1990 bufptr += n;
1991 }
99de6da0 1992 }
1993 break;
1994
b0757135 1995 case IPP_TAG_BEGIN_COLLECTION :
1996 for (i = 0, value = attr->values;
1997 i < attr->num_values;
1998 i ++, value ++)
1999 {
2000 /*
2001 * Collections are written with the begin-collection
2002 * tag first with a value of 0 length, followed by the
2003 * attributes in the collection, then the end-collection
2004 * value...
2005 */
2006
2007 if ((sizeof(buffer) - (bufptr - buffer)) < 5)
2008 {
2009 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
2010 {
2011 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2012 return (IPP_ERROR);
2013 }
2014
2015 bufptr = buffer;
2016 }
2017
2018 if (i)
2019 {
2020 /*
2021 * Arrays and sets are done by sending additional
2022 * values with a zero-length name...
2023 */
2024
2025 *bufptr++ = attr->value_tag;
2026 *bufptr++ = 0;
2027 *bufptr++ = 0;
2028 }
2029
2030 /*
2031 * Write a data length of 0 and flush the buffer...
2032 */
2033
2034 *bufptr++ = 0;
2035 *bufptr++ = 0;
2036
2037 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
2038 {
2039 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2040 return (IPP_ERROR);
2041 }
2042
2043 bufptr = buffer;
2044
2045 /*
2046 * Then write the collection attribute...
2047 */
2048
2049 value->collection->state = IPP_IDLE;
2050
2051 if (ippWriteIO(dst, cb, 1, ipp, value->collection) == IPP_ERROR)
2052 return (IPP_ERROR);
2053 }
2054 break;
2055
99de6da0 2056 default :
753453e4 2057 for (i = 0, value = attr->values;
2058 i < attr->num_values;
2059 i ++, value ++)
99de6da0 2060 {
2061 if (i)
2062 {
2063 /*
2064 * Arrays and sets are done by sending additional
2065 * values with a zero-length name...
2066 */
2067
2068 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
2069 {
b070f93d 2070 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 2071 {
2072 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2073 return (IPP_ERROR);
2074 }
2075
2076 bufptr = buffer;
2077 }
2078
2079 *bufptr++ = attr->value_tag;
2080 *bufptr++ = 0;
2081 *bufptr++ = 0;
2082 }
2083
375a0ad5 2084 /*
2085 * An unknown value might some new value that a
2086 * vendor has come up with. It consists of a
2087 * 2-byte length and the bytes in the unknown
2088 * value buffer.
2089 */
2090
753453e4 2091 n = value->unknown.length;
99de6da0 2092
375a0ad5 2093 if (n > (sizeof(buffer) - 2))
99de6da0 2094 return (IPP_ERROR);
2095
2096 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
2097 {
b070f93d 2098 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 2099 {
7db52463 2100 DEBUG_puts("ippWrite: Could not write IPP attribute...");
99de6da0 2101 return (IPP_ERROR);
2102 }
2103
2104 bufptr = buffer;
2105 }
2106
2107 /* Length of unknown value */
2108 *bufptr++ = n >> 8;
2109 *bufptr++ = n;
2110
2111 /* Value */
2112 if (n > 0)
2113 {
753453e4 2114 memcpy(bufptr, value->unknown.data, n);
99de6da0 2115 bufptr += n;
2116 }
2117 }
2118 break;
2119 }
2120
2121 /*
2122 * Write the data out...
2123 */
2124
b070f93d 2125 if ((*cb)(dst, buffer, bufptr - buffer) < 0)
99de6da0 2126 {
7db52463 2127 DEBUG_puts("ippWrite: Could not write IPP attribute...");
99de6da0 2128 return (IPP_ERROR);
2129 }
2130
7db52463 2131 DEBUG_printf(("ippWrite: wrote %d bytes\n", bufptr - buffer));
2132
2133 /*
2134 * If blocking is disabled, stop here...
2135 */
2136
b070f93d 2137 if (!blocking)
7db52463 2138 break;
99de6da0 2139 }
2140
2141 if (ipp->current == NULL)
2142 {
2143 /*
b0757135 2144 * Done with all of the attributes; add the end-of-attributes
2145 * tag or end-collection attribute...
99de6da0 2146 */
2147
b0757135 2148 if (parent == NULL)
2149 {
2150 buffer[0] = IPP_TAG_END;
2151 n = 1;
2152 }
2153 else
2154 {
2155 buffer[0] = IPP_TAG_END_COLLECTION;
2156 buffer[1] = 0; /* empty name */
2157 buffer[2] = 0;
2158 buffer[3] = 0; /* empty value */
2159 buffer[4] = 0;
2160 n = 5;
2161 }
2162
2163 if ((*cb)(dst, buffer, n) < 0)
99de6da0 2164 {
7db52463 2165 DEBUG_puts("ippWrite: Could not write IPP end-tag...");
99de6da0 2166 return (IPP_ERROR);
2167 }
2168
2169 ipp->state = IPP_DATA;
2170 }
2171 break;
2172
2173 case IPP_DATA :
2174 break;
99de6da0 2175
7db52463 2176 default :
2177 break; /* anti-compiler-warning-code */
2178 }
99de6da0 2179
2180 return (ipp->state);
2181}
2182
2183
50146867 2184/*
e09246c8 2185 * '_ipp_add_attr()' - Add a new attribute to the request.
50146867 2186 */
2187
b0757135 2188ipp_attribute_t * /* O - New attribute */
2189_ipp_add_attr(ipp_t *ipp, /* I - IPP request */
2190 int num_values) /* I - Number of values */
3a193f5e 2191{
b0757135 2192 ipp_attribute_t *attr; /* New attribute */
50146867 2193
2194
27d555e8 2195 DEBUG_printf(("_ipp_add_attr(%p, %d)\n", ipp, num_values));
4a73831b 2196
c775e1a3 2197 if (ipp == NULL || num_values < 0)
50146867 2198 return (NULL);
2199
2200 attr = calloc(sizeof(ipp_attribute_t) +
2201 (num_values - 1) * sizeof(ipp_value_t), 1);
2202
4a73831b 2203 attr->num_values = num_values;
2204
50146867 2205 if (attr == NULL)
2206 return (NULL);
2207
2208 if (ipp->last == NULL)
2209 ipp->attrs = attr;
2210 else
2211 ipp->last->next = attr;
2212
2213 ipp->last = attr;
2214
ccf243ee 2215 DEBUG_printf(("_ipp_add_attr(): %p\n", attr));
2216
50146867 2217 return (attr);
3a193f5e 2218}
2219
2220
a3e17a89 2221/*
2222 * '_ipp_free_attr()' - Free an attribute.
2223 */
2224
2225void
b0757135 2226_ipp_free_attr(ipp_attribute_t *attr) /* I - Attribute to free */
a3e17a89 2227{
b0757135 2228 int i; /* Looping var */
2229 ipp_value_t *value; /* Current value */
a3e17a89 2230
2231
ccf243ee 2232 DEBUG_printf(("_ipp_free_attr(): %p\n", attr));
2233
a3e17a89 2234 switch (attr->value_tag)
2235 {
2236 case IPP_TAG_TEXT :
2237 case IPP_TAG_NAME :
2238 case IPP_TAG_KEYWORD :
2239 case IPP_TAG_STRING :
2240 case IPP_TAG_URI :
2241 case IPP_TAG_URISCHEME :
2242 case IPP_TAG_CHARSET :
2243 case IPP_TAG_LANGUAGE :
2244 case IPP_TAG_MIMETYPE :
753453e4 2245 for (i = 0, value = attr->values;
2246 i < attr->num_values;
2247 i ++, value ++)
2248 free(value->string.text);
a3e17a89 2249 break;
2250
2251 case IPP_TAG_TEXTLANG :
2252 case IPP_TAG_NAMELANG :
753453e4 2253 for (i = 0, value = attr->values;
2254 i < attr->num_values;
2255 i ++, value ++)
a3e17a89 2256 {
753453e4 2257 if (value->string.charset && i == 0)
2258 free(value->string.charset);
2259 free(value->string.text);
a3e17a89 2260 }
2261 break;
2262
2263 default :
2264 break; /* anti-compiler-warning-code */
2265 }
2266
2267 if (attr->name != NULL)
2268 free(attr->name);
2269
2270 free(attr);
2271}
2272
2273
b0757135 2274/*
2275 * 'ipp_length()' - Compute the length of an IPP request or collection value.
2276 */
2277
2278static size_t /* O - Size of IPP request */
2279ipp_length(ipp_t *ipp, /* I - IPP request or collection */
2280 int collection) /* I - 1 if a collection, 0 otherwise */
2281{
2282 int i; /* Looping var */
2283 int bytes; /* Number of bytes */
2284 ipp_attribute_t *attr; /* Current attribute */
2285 ipp_tag_t group; /* Current group */
2286 ipp_value_t *value; /* Current value */
2287
2288
2289 if (ipp == NULL)
2290 return (0);
2291
2292 /*
2293 * Start with 8 bytes for the IPP request or status header...
2294 */
2295
2296 bytes = collection ? 0 : 8;
2297
2298 /*
2299 * Then add the lengths of each attribute...
2300 */
2301
2302 group = IPP_TAG_ZERO;
2303
2304 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
2305 {
2306 if (attr->group_tag != group && !collection)
2307 {
2308 group = attr->group_tag;
2309 if (group == IPP_TAG_ZERO)
2310 continue;
2311
2312 bytes ++; /* Group tag */
2313 }
2314
2315 DEBUG_printf(("attr->name = %s, attr->num_values = %d, bytes = %d\n",
2316 attr->name, attr->num_values, bytes));
2317
2318 bytes += strlen(attr->name); /* Name */
2319 bytes += attr->num_values; /* Value tag for each value */
2320 bytes += 2 * attr->num_values; /* Name lengths */
2321 bytes += 2 * attr->num_values; /* Value lengths */
2322
dd63ebe2 2323 if (collection)
2324 bytes += 5; /* Add membername overhead */
2325
b0757135 2326 switch (attr->value_tag & ~IPP_TAG_COPY)
2327 {
2328 case IPP_TAG_INTEGER :
2329 case IPP_TAG_ENUM :
2330 bytes += 4 * attr->num_values;
2331 break;
2332
2333 case IPP_TAG_BOOLEAN :
2334 bytes += attr->num_values;
2335 break;
2336
2337 case IPP_TAG_TEXT :
2338 case IPP_TAG_NAME :
2339 case IPP_TAG_KEYWORD :
2340 case IPP_TAG_STRING :
2341 case IPP_TAG_URI :
2342 case IPP_TAG_URISCHEME :
2343 case IPP_TAG_CHARSET :
2344 case IPP_TAG_LANGUAGE :
2345 case IPP_TAG_MIMETYPE :
2346 for (i = 0, value = attr->values;
2347 i < attr->num_values;
2348 i ++, value ++)
2349 if (value->string.text != NULL)
2350 bytes += strlen(value->string.text);
2351 break;
2352
2353 case IPP_TAG_DATE :
2354 bytes += 11 * attr->num_values;
2355 break;
2356
2357 case IPP_TAG_RESOLUTION :
2358 bytes += 9 * attr->num_values;
2359 break;
2360
2361 case IPP_TAG_RANGE :
2362 bytes += 8 * attr->num_values;
2363 break;
2364
2365 case IPP_TAG_TEXTLANG :
2366 case IPP_TAG_NAMELANG :
2367 bytes += 4 * attr->num_values;/* Charset + text length */
2368
2369 for (i = 0, value = attr->values;
2370 i < attr->num_values;
2371 i ++, value ++)
2372 {
2373 if (value->string.charset != NULL)
2374 bytes += strlen(value->string.charset);
2375
2376 if (value->string.text != NULL)
2377 bytes += strlen(value->string.text);
2378 }
2379 break;
2380
2381 case IPP_TAG_BEGIN_COLLECTION :
2382 for (i = 0, value = attr->values;
2383 i < attr->num_values;
2384 i ++, value ++)
0fda5681 2385 {
dd63ebe2 2386/* bytes += 5;*/ /* Overhead of begCollection */
b0757135 2387 bytes += ipp_length(attr->values[i].collection, 1);
dd63ebe2 2388/* bytes += 5;*/ /* Overhead of endCollection */
0fda5681 2389 }
b0757135 2390 break;
2391
2392 default :
2393 for (i = 0, value = attr->values;
2394 i < attr->num_values;
2395 i ++, value ++)
2396 bytes += attr->values[0].unknown.length;
2397 break;
2398 }
2399 }
2400
2401 /*
dd63ebe2 2402 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
2403 * for the "end of collection" tag and return...
b0757135 2404 */
2405
dd63ebe2 2406 if (collection)
2407 bytes += 5;
2408 else
9cc4a1c4 2409 bytes ++;
b0757135 2410
9cc4a1c4 2411 DEBUG_printf(("bytes = %d\n", bytes));
2412
2413 return (bytes);
b0757135 2414}
2415
2416
3a193f5e 2417/*
b070f93d 2418 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
d23a857a 2419 */
2420
b0757135 2421static int /* O - Number of bytes read */
2422ipp_read_http(http_t *http, /* I - Client connection */
2423 ipp_uchar_t *buffer, /* O - Buffer for data */
2424 int length) /* I - Total length */
d23a857a 2425{
aea6601a 2426 int tbytes, /* Total bytes read */
2427 bytes; /* Bytes read this pass */
2428 char len[32]; /* Length string */
7db52463 2429
d23a857a 2430
dd63ebe2 2431 DEBUG_printf(("ipp_read_http(http=%p, buffer=%p, length=%d)\n",
2432 http, buffer, length));
2433
d23a857a 2434 /*
2435 * Loop until all bytes are read...
2436 */
2437
41e45833 2438 for (tbytes = 0, bytes = 0; tbytes < length; tbytes += bytes, buffer += bytes)
753453e4 2439 {
dd63ebe2 2440 DEBUG_printf(("tbytes = %d, http->state = %d\n", tbytes, http->state));
2441
2442 if (http->state == HTTP_WAITING)
2443 break;
2444
2445 if (http->used > 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
753453e4 2446 {
2447 /*
2448 * Do "fast read" from HTTP buffer directly...
2449 */
2450
2451 if (http->used > (length - tbytes))
2452 bytes = length - tbytes;
2453 else
2454 bytes = http->used;
2455
2456 if (bytes == 1)
2457 buffer[0] = http->buffer[0];
2458 else
2459 memcpy(buffer, http->buffer, bytes);
2460
2461 http->used -= bytes;
2462 http->data_remaining -= bytes;
2463
2464 if (http->used > 0)
dfac1292 2465 memmove(http->buffer, http->buffer + bytes, http->used);
753453e4 2466
2467 if (http->data_remaining == 0)
2468 {
2469 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
92e48f04 2470 {
2471 /*
2472 * Get the trailing CR LF after the chunk...
2473 */
2474
2475 if (!httpGets(len, sizeof(len), http))
2476 return (-1);
2477 }
753453e4 2478
2479 if (http->data_encoding != HTTP_ENCODE_CHUNKED)
2480 {
2481 if (http->state == HTTP_POST_RECV)
2482 http->state ++;
2483 else
2484 http->state = HTTP_WAITING;
2485 }
2486 }
2487 }
aea6601a 2488 else
2489 {
2490 /*
2e32fcdb 2491 * Wait a maximum of 1 second for data...
aea6601a 2492 */
2493
d68320d4 2494 if (!http->blocking)
3955a26e 2495 {
2496 /*
d68320d4 2497 * Wait up to 1 second for more data on non-blocking sockets...
3955a26e 2498 */
2499
d68320d4 2500 if (!httpWait(http, 1000))
2501 {
2502 /*
2503 * Signal no data...
2504 */
2505
2506 bytes = -1;
2507 break;
2508 }
3955a26e 2509 }
d68320d4 2510
2511 if ((bytes = httpRead(http, (char *)buffer, length - tbytes)) <= 0)
aea6601a 2512 break;
2513 }
753453e4 2514 }
d23a857a 2515
2516 /*
2517 * Return the number of bytes read...
2518 */
2519
74464516 2520 if (tbytes == 0 && bytes < 0)
3955a26e 2521 tbytes = -1;
2522
dd63ebe2 2523 DEBUG_printf(("returning %d bytes...\n", tbytes));
2524
3955a26e 2525 return (tbytes);
d23a857a 2526}
2527
2528
d23a857a 2529/*
b070f93d 2530 * 'ipp_read_file()' - Read IPP data from a file.
2531 */
2532
b0757135 2533static int /* O - Number of bytes read */
2534ipp_read_file(int *fd, /* I - File descriptor */
2535 ipp_uchar_t *buffer, /* O - Read buffer */
2536 int length) /* I - Number of bytes to read */
b070f93d 2537{
2538 return (read(*fd, buffer, length));
2539}
2540
2541
b070f93d 2542/*
2543 * 'ipp_write_file()' - Write IPP data to a file.
2544 */
2545
b0757135 2546static int /* O - Number of bytes written */
2547ipp_write_file(int *fd, /* I - File descriptor */
2548 ipp_uchar_t *buffer, /* I - Data to write */
2549 int length) /* I - Number of bytes to write */
b070f93d 2550{
2551 return (write(*fd, buffer, length));
2552}
2553
2554
2555/*
64bbab09 2556 * End of "$Id: ipp.c,v 1.55.2.39 2004/02/25 16:58:32 mike Exp $".
dec2f757 2557 */