]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ipp.c
Copyright update...
[thirdparty/cups.git] / cups / ipp.c
CommitLineData
dec2f757 1/*
efb2f309 2 * "$Id: ipp.c,v 1.65 2002/01/02 17:58:39 mike Exp $"
dec2f757 3 *
3a193f5e 4 * Internet Printing Protocol support functions for the Common UNIX
5 * Printing System (CUPS).
dec2f757 6 *
efb2f309 7 * Copyright 1997-2002 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 *
25 * Contents:
26 *
fbd4fc3f 27 * ippAddBoolean() - Add a boolean attribute to an IPP request.
28 * ippAddBooleans() - Add an array of boolean values.
29 * ippAddDate() - Add a date attribute to an IPP request.
30 * ippAddInteger() - Add a integer attribute to an IPP request.
31 * ippAddIntegers() - Add an array of integer values.
32 * ippAddString() - Add a language-encoded string to an IPP request.
33 * ippAddStrings() - Add language-encoded strings to an IPP request.
34 * ippAddRange() - Add a range of values to an IPP request.
35 * ippAddRanges() - Add ranges of values to an IPP request.
36 * ippAddResolution() - Add a resolution value to an IPP request.
37 * ippAddResolutions() - Add resolution values to an IPP request.
38 * ippAddSeparator() - Add a group separator to an IPP request.
39 * ippDateToTime() - Convert from RFC 1903 Date/Time format to UNIX
40 * time in seconds.
41 * ippDelete() - Delete an IPP request.
42 * ippErrorString() - Return a textual message for the given error
43 * message.
44 * ippFindAttribute() - Find a named attribute in a request...
45 * ippFindNextAttribute() - Find the next named attribute in a request...
46 * ippLength() - Compute the length of an IPP request.
47 * ippNew() - Allocate a new IPP request.
48 * ippPort() - Return the default IPP port number.
49 * ippRead() - Read data for an IPP request.
50 * ippSetPort() - Set the default port number.
51 * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
52 * ippWrite() - Write data for an IPP request.
53 * _ipp_add_attr() - Add a new attribute to the request.
54 * _ipp_free_attr() - Free an attribute.
55 * ipp_read() - Semi-blocking read on a HTTP connection...
dec2f757 56 */
57
58/*
59 * Include necessary headers...
60 */
61
3b960317 62#include <stdio.h>
63#include <stdlib.h>
977acbd3 64#include "string.h"
9aebebc3 65#include "language.h"
3b960317 66
50146867 67#include "ipp.h"
4a73831b 68#include "debug.h"
b03923b8 69#include <ctype.h>
dec2f757 70
71
c68b6ae8 72/*
73 * Local globals...
74 */
75
76static int ipp_port = 0;
77
78
dec2f757 79/*
3a193f5e 80 * Local functions...
81 */
82
e09246c8 83static int ipp_read(http_t *http, unsigned char *buffer, int length);
3a193f5e 84
85
50146867 86/*
87 * 'ippAddBoolean()' - Add a boolean attribute to an IPP request.
88 */
89
90ipp_attribute_t * /* O - New attribute */
063e1ac7 91ippAddBoolean(ipp_t *ipp, /* I - IPP request */
92 ipp_tag_t group, /* I - IPP group */
93 const char *name, /* I - Name of attribute */
94 char value) /* I - Value of attribute */
3a193f5e 95{
50146867 96 ipp_attribute_t *attr; /* New attribute */
3a193f5e 97
98
27d555e8 99 DEBUG_printf(("ippAddBoolean(%p, %02x, \'%s\', %d)\n", ipp, group, name, value));
aeabf506 100
50146867 101 if (ipp == NULL || name == NULL)
102 return (NULL);
3a193f5e 103
e09246c8 104 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 105 return (NULL);
3a193f5e 106
50146867 107 attr->name = strdup(name);
108 attr->group_tag = group;
109 attr->value_tag = IPP_TAG_BOOLEAN;
110 attr->values[0].boolean = value;
111
112 return (attr);
3a193f5e 113}
114
115
50146867 116/*
117 * 'ippAddBooleans()' - Add an array of boolean values.
118 */
119
120ipp_attribute_t * /* O - New attribute */
063e1ac7 121ippAddBooleans(ipp_t *ipp, /* I - IPP request */
122 ipp_tag_t group, /* I - IPP group */
123 const char *name, /* I - Name of attribute */
124 int num_values, /* I - Number of values */
125 const char *values) /* I - Values */
3a193f5e 126{
50146867 127 int i; /* Looping var */
128 ipp_attribute_t *attr; /* New attribute */
0893e2bb 129 ipp_value_t *value; /* Current value */
50146867 130
131
27d555e8 132 DEBUG_printf(("ippAddBooleans(%p, %02x, \'%s\', %d, %p)\n", ipp,
5356dc5a 133 group, name, num_values, values));
aeabf506 134
5356dc5a 135 if (ipp == NULL || name == NULL)
50146867 136 return (NULL);
137
e09246c8 138 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
50146867 139 return (NULL);
140
141 attr->name = strdup(name);
142 attr->group_tag = group;
143 attr->value_tag = IPP_TAG_BOOLEAN;
144
5356dc5a 145 if (values != NULL)
0893e2bb 146 for (i = 0, value = attr->values;
147 i < num_values;
148 i ++, value ++)
149 value->boolean = values[i];
50146867 150
151 return (attr);
3a193f5e 152}
153
154
50146867 155/*
156 * 'ippAddDate()' - Add a date attribute to an IPP request.
157 */
158
159ipp_attribute_t * /* O - New attribute */
3dab5e3b 160ippAddDate(ipp_t *ipp, /* I - IPP request */
161 ipp_tag_t group, /* I - IPP group */
162 const char *name, /* I - Name of attribute */
163 const ipp_uchar_t *value) /* I - Value */
3a193f5e 164{
50146867 165 ipp_attribute_t *attr; /* New attribute */
166
167
27d555e8 168 DEBUG_printf(("ippAddDate(%p, %02x, \'%s\', %p)\n", ipp, group, name,
aeabf506 169 value));
170
50146867 171 if (ipp == NULL || name == NULL || value == NULL)
172 return (NULL);
173
e09246c8 174 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 175 return (NULL);
176
177 attr->name = strdup(name);
178 attr->group_tag = group;
179 attr->value_tag = IPP_TAG_DATE;
180 memcpy(attr->values[0].date, value, 11);
181
182 return (attr);
3a193f5e 183}
184
185
50146867 186/*
187 * 'ippAddInteger()' - Add a integer attribute to an IPP request.
188 */
189
190ipp_attribute_t * /* O - New attribute */
063e1ac7 191ippAddInteger(ipp_t *ipp, /* I - IPP request */
192 ipp_tag_t group, /* I - IPP group */
193 ipp_tag_t type, /* I - Type of attribute */
194 const char *name, /* I - Name of attribute */
195 int value) /* I - Value of attribute */
3a193f5e 196{
50146867 197 ipp_attribute_t *attr; /* New attribute */
198
199
27d555e8 200 DEBUG_printf(("ippAddInteger(%p, %d, \'%s\', %d)\n", ipp, group, name,
4a73831b 201 value));
202
50146867 203 if (ipp == NULL || name == NULL)
204 return (NULL);
205
e09246c8 206 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 207 return (NULL);
208
209 attr->name = strdup(name);
210 attr->group_tag = group;
58ec2a95 211 attr->value_tag = type;
50146867 212 attr->values[0].integer = value;
213
214 return (attr);
3a193f5e 215}
216
217
50146867 218/*
219 * 'ippAddIntegers()' - Add an array of integer values.
220 */
221
222ipp_attribute_t * /* O - New attribute */
063e1ac7 223ippAddIntegers(ipp_t *ipp, /* I - IPP request */
224 ipp_tag_t group, /* I - IPP group */
225 ipp_tag_t type, /* I - Type of attribute */
226 const char *name, /* I - Name of attribute */
227 int num_values, /* I - Number of values */
228 const int *values) /* I - Values */
3a193f5e 229{
50146867 230 int i; /* Looping var */
231 ipp_attribute_t *attr; /* New attribute */
0893e2bb 232 ipp_value_t *value; /* Current value */
50146867 233
234
5356dc5a 235 if (ipp == NULL || name == NULL)
50146867 236 return (NULL);
237
e09246c8 238 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
50146867 239 return (NULL);
240
241 attr->name = strdup(name);
242 attr->group_tag = group;
58ec2a95 243 attr->value_tag = type;
50146867 244
5356dc5a 245 if (values != NULL)
0893e2bb 246 for (i = 0, value = attr->values;
247 i < num_values;
248 i ++, value ++)
249 value->integer = values[i];
50146867 250
251 return (attr);
3a193f5e 252}
253
254
50146867 255/*
58ec2a95 256 * 'ippAddString()' - Add a language-encoded string to an IPP request.
50146867 257 */
258
259ipp_attribute_t * /* O - New attribute */
063e1ac7 260ippAddString(ipp_t *ipp, /* I - IPP request */
261 ipp_tag_t group, /* I - IPP group */
262 ipp_tag_t type, /* I - Type of attribute */
263 const char *name, /* I - Name of attribute */
264 const char *charset, /* I - Character set */
265 const char *value) /* I - Value */
3a193f5e 266{
50146867 267 ipp_attribute_t *attr; /* New attribute */
268
269
270 if (ipp == NULL || name == NULL)
271 return (NULL);
272
e09246c8 273 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 274 return (NULL);
275
276 attr->name = strdup(name);
277 attr->group_tag = group;
58ec2a95 278 attr->value_tag = type;
74c5d458 279 attr->values[0].string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
280 charset ? strdup(charset) : NULL;
281 attr->values[0].string.text = ((int)type & IPP_TAG_COPY) ? (char *)value :
282 value ? strdup(value) : NULL;
50146867 283
b54e35d5 284 if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) &&
285 attr->values[0].string.text)
c9061d17 286 {
287 /*
288 * Convert to lowercase and change _ to - as needed...
289 */
290
291 char *p;
292
293
5a2c7855 294 for (p = attr->values[0].string.text; *p; p ++)
c9061d17 295 if (*p == '_')
5a2c7855 296 *p = '-';
c9061d17 297 else
5a2c7855 298 *p = tolower(*p);
c9061d17 299 }
300
50146867 301 return (attr);
3a193f5e 302}
303
304
50146867 305/*
58ec2a95 306 * 'ippAddStrings()' - Add language-encoded strings to an IPP request.
50146867 307 */
308
309ipp_attribute_t * /* O - New attribute */
063e1ac7 310ippAddStrings(ipp_t *ipp, /* I - IPP request */
311 ipp_tag_t group, /* I - IPP group */
312 ipp_tag_t type, /* I - Type of attribute */
313 const char *name, /* I - Name of attribute */
314 int num_values, /* I - Number of values */
315 const char *charset, /* I - Character set */
316 const char **values) /* I - Values */
3a193f5e 317{
50146867 318 int i; /* Looping var */
319 ipp_attribute_t *attr; /* New attribute */
0893e2bb 320 ipp_value_t *value; /* Current value */
50146867 321
322
323 if (ipp == NULL || name == NULL)
324 return (NULL);
325
e09246c8 326 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
50146867 327 return (NULL);
328
329 attr->name = strdup(name);
330 attr->group_tag = group;
58ec2a95 331 attr->value_tag = type;
50146867 332
0893e2bb 333 for (i = 0, value = attr->values;
334 i < num_values;
335 i ++, value ++)
74c5d458 336 {
337 if (i == 0)
0893e2bb 338 value->string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
339 charset ? strdup(charset) : NULL;
74c5d458 340 else
0893e2bb 341 value->string.charset = attr->values[0].string.charset;
74c5d458 342
343 if (values != NULL)
0893e2bb 344 value->string.text = ((int)type & IPP_TAG_COPY) ? (char *)values[i] :
74c5d458 345 strdup(values[i]);
346 }
50146867 347
348 return (attr);
3a193f5e 349}
350
351
50146867 352/*
353 * 'ippAddRange()' - Add a range of values to an IPP request.
354 */
3a193f5e 355
50146867 356ipp_attribute_t * /* O - New attribute */
063e1ac7 357ippAddRange(ipp_t *ipp, /* I - IPP request */
358 ipp_tag_t group, /* I - IPP group */
359 const char *name, /* I - Name of attribute */
360 int lower, /* I - Lower value */
361 int upper) /* I - Upper value */
3a193f5e 362{
50146867 363 ipp_attribute_t *attr; /* New attribute */
364
365
366 if (ipp == NULL || name == NULL)
367 return (NULL);
368
e09246c8 369 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 370 return (NULL);
371
372 attr->name = strdup(name);
373 attr->group_tag = group;
374 attr->value_tag = IPP_TAG_RANGE;
375 attr->values[0].range.lower = lower;
376 attr->values[0].range.upper = upper;
377
378 return (attr);
3a193f5e 379}
380
381
5356dc5a 382/*
383 * 'ippAddRanges()' - Add ranges of values to an IPP request.
384 */
385
386ipp_attribute_t * /* O - New attribute */
063e1ac7 387ippAddRanges(ipp_t *ipp, /* I - IPP request */
388 ipp_tag_t group, /* I - IPP group */
389 const char *name, /* I - Name of attribute */
390 int num_values, /* I - Number of values */
391 const int *lower, /* I - Lower values */
392 const int *upper) /* I - Upper values */
5356dc5a 393{
394 int i; /* Looping var */
395 ipp_attribute_t *attr; /* New attribute */
0893e2bb 396 ipp_value_t *value; /* Current value */
5356dc5a 397
398
399 if (ipp == NULL || name == NULL)
400 return (NULL);
401
e09246c8 402 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
5356dc5a 403 return (NULL);
404
405 attr->name = strdup(name);
406 attr->group_tag = group;
407 attr->value_tag = IPP_TAG_RANGE;
408
409 if (lower != NULL && upper != NULL)
0893e2bb 410 for (i = 0, value = attr->values;
411 i < num_values;
412 i ++, value ++)
5356dc5a 413 {
0893e2bb 414 value->range.lower = lower[i];
415 value->range.upper = upper[i];
5356dc5a 416 }
417
418 return (attr);
419}
420
421
50146867 422/*
423 * 'ippAddResolution()' - Add a resolution value to an IPP request.
424 */
425
426ipp_attribute_t * /* O - New attribute */
063e1ac7 427ippAddResolution(ipp_t *ipp, /* I - IPP request */
428 ipp_tag_t group, /* I - IPP group */
429 const char *name, /* I - Name of attribute */
430 ipp_res_t units, /* I - Units for resolution */
431 int xres, /* I - X resolution */
432 int yres) /* I - Y resolution */
3a193f5e 433{
50146867 434 ipp_attribute_t *attr; /* New attribute */
435
436
437 if (ipp == NULL || name == NULL)
438 return (NULL);
439
e09246c8 440 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
50146867 441 return (NULL);
442
443 attr->name = strdup(name);
444 attr->group_tag = group;
445 attr->value_tag = IPP_TAG_RESOLUTION;
446 attr->values[0].resolution.xres = xres;
447 attr->values[0].resolution.yres = yres;
448 attr->values[0].resolution.units = units;
449
450 return (attr);
3a193f5e 451}
452
453
5356dc5a 454/*
455 * 'ippAddResolutions()' - Add resolution values to an IPP request.
456 */
457
458ipp_attribute_t * /* O - New attribute */
063e1ac7 459ippAddResolutions(ipp_t *ipp, /* I - IPP request */
460 ipp_tag_t group, /* I - IPP group */
461 const char *name, /* I - Name of attribute */
462 int num_values,/* I - Number of values */
463 ipp_res_t units, /* I - Units for resolution */
464 const int *xres, /* I - X resolutions */
465 const int *yres) /* I - Y resolutions */
5356dc5a 466{
467 int i; /* Looping var */
468 ipp_attribute_t *attr; /* New attribute */
0893e2bb 469 ipp_value_t *value; /* Current value */
5356dc5a 470
471
472 if (ipp == NULL || name == NULL)
473 return (NULL);
474
e09246c8 475 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
5356dc5a 476 return (NULL);
477
478 attr->name = strdup(name);
479 attr->group_tag = group;
480 attr->value_tag = IPP_TAG_RESOLUTION;
481
482 if (xres != NULL && yres != NULL)
0893e2bb 483 for (i = 0, value = attr->values;
484 i < num_values;
485 i ++, value ++)
5356dc5a 486 {
0893e2bb 487 value->resolution.xres = xres[i];
488 value->resolution.yres = yres[i];
489 value->resolution.units = units;
5356dc5a 490 }
491
492 return (attr);
493}
494
495
496/*
497 * 'ippAddSeparator()' - Add a group separator to an IPP request.
498 */
499
500ipp_attribute_t * /* O - New attribute */
501ippAddSeparator(ipp_t *ipp) /* I - IPP request */
502{
503 ipp_attribute_t *attr; /* New attribute */
504
505
27d555e8 506 DEBUG_printf(("ippAddSeparator(%p)\n", ipp));
5356dc5a 507
508 if (ipp == NULL)
509 return (NULL);
510
e09246c8 511 if ((attr = _ipp_add_attr(ipp, 0)) == NULL)
5356dc5a 512 return (NULL);
513
514 attr->group_tag = IPP_TAG_ZERO;
515 attr->value_tag = IPP_TAG_ZERO;
516
517 return (attr);
518}
519
520
3a193f5e 521/*
50146867 522 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
fbd4fc3f 523 * in seconds.
3a193f5e 524 */
525
063e1ac7 526time_t /* O - UNIX time value */
527ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */
3a193f5e 528{
529 struct tm unixdate; /* UNIX date/time info */
530 time_t t; /* Computed time */
531
532
533 memset(&unixdate, 0, sizeof(unixdate));
534
535 /*
536 * RFC-1903 date/time format is:
537 *
538 * Byte(s) Description
539 * ------- -----------
540 * 0-1 Year (0 to 65535)
541 * 2 Month (1 to 12)
542 * 3 Day (1 to 31)
543 * 4 Hours (0 to 23)
544 * 5 Minutes (0 to 59)
545 * 6 Seconds (0 to 60, 60 = "leap second")
546 * 7 Deciseconds (0 to 9)
547 * 8 +/- UTC
548 * 9 UTC hours (0 to 11)
549 * 10 UTC minutes (0 to 59)
550 */
551
552 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
553 unixdate.tm_mon = date[2] - 1;
554 unixdate.tm_mday = date[3];
555 unixdate.tm_hour = date[4];
556 unixdate.tm_min = date[5];
557 unixdate.tm_sec = date[6];
558
559 t = mktime(&unixdate);
560
561 if (date[8] == '-')
562 t += date[9] * 3600 + date[10] * 60;
563 else
564 t -= date[9] * 3600 + date[10] * 60;
565
566 return (t);
567}
568
569
50146867 570/*
571 * 'ippDelete()' - Delete an IPP request.
572 */
573
3a193f5e 574void
50146867 575ippDelete(ipp_t *ipp) /* I - IPP request */
3a193f5e 576{
50146867 577 ipp_attribute_t *attr, /* Current attribute */
578 *next; /* Next attribute */
579
580
de7ce5a1 581 DEBUG_printf(("ippDelete(): %p\n", ipp));
ccf243ee 582
50146867 583 if (ipp == NULL)
584 return;
585
586 for (attr = ipp->attrs; attr != NULL; attr = next)
587 {
50146867 588 next = attr->next;
a3e17a89 589 _ipp_free_attr(attr);
50146867 590 }
591
592 free(ipp);
3a193f5e 593}
594
595
9aebebc3 596/*
597 * 'ippErrorString()' - Return a textual message for the given error message.
598 */
599
600const char * /* O - Text string */
601ippErrorString(ipp_status_t error) /* I - Error status */
602{
a61a2be6 603 static char unknown[255]; /* Unknown error statuses */
604 static const char *status_oks[] = /* "OK" status codes */
605 {
606 "successful-ok",
607 "successful-ok-ignored-or-substituted-attributes",
7b1b1c6e 608 "successful-ok-conflicting-attributes",
609 "successful-ok-ignored-subscriptions",
610 "successful-ok-ignored-notifications",
611 "successful-ok-too-many-events",
612 "successful-ok-but-cancel-subscription"
a61a2be6 613 },
614 *status_400s[] = /* Client errors */
615 {
616 "client-error-bad-request",
617 "client-error-forbidden",
618 "client-error-not-authenticated",
619 "client-error-not-authorized",
620 "client-error-not-possible",
621 "client-error-timeout",
622 "client-error-not-found",
623 "client-error-gone",
624 "client-error-request-entity-too-large",
625 "client-error-request-value-too-long",
626 "client-error-document-format-not-supported",
627 "client-error-attributes-or-values-not-supported",
628 "client-error-uri-scheme-not-supported",
629 "client-error-charset-not-supported",
630 "client-error-conflicting-attributes",
631 "client-error-compression-not-supported",
632 "client-error-compression-error",
633 "client-error-document-format-error",
7b1b1c6e 634 "client-error-document-access-error",
635 "client-error-attributes-not-settable",
636 "client-error-ignored-all-subscriptions",
637 "client-error-too-many-subscriptions",
638 "client-error-ignored-all-notifications",
639 "client-error-print-support-file-not-found"
a61a2be6 640 },
641 *status_500s[] = /* Server errors */
642 {
643 "server-error-internal-error",
644 "server-error-operation-not-supported",
645 "server-error-service-unavailable",
646 "server-error-version-not-supported",
647 "server-error-device-error",
648 "server-error-temporary-error",
649 "server-error-not-accepting-jobs",
650 "server-error-busy",
651 "server-error-job-canceled",
7b1b1c6e 652 "server-error-multiple-document-jobs-not-supported",
653 "server-error-printer-is-deactivated"
a61a2be6 654 };
9aebebc3 655
656
657 /*
a61a2be6 658 * See if the error code is a known value...
9aebebc3 659 */
660
7b1b1c6e 661 if (error >= IPP_OK && error <= IPP_OK_BUT_CANCEL_SUBSCRIPTION)
a61a2be6 662 return (status_oks[error]);
d2dd6522 663 else if (error == IPP_REDIRECTION_OTHER_SITE)
664 return ("redirection-other-site");
7b1b1c6e 665 else if (error >= IPP_BAD_REQUEST && error <= IPP_PRINT_SUPPORT_FILE_NOT_FOUND)
a61a2be6 666 return (status_400s[error - IPP_BAD_REQUEST]);
7b1b1c6e 667 else if (error >= IPP_INTERNAL_ERROR && error <= IPP_PRINTER_IS_DEACTIVATED)
a61a2be6 668 return (status_500s[error - IPP_INTERNAL_ERROR]);
9aebebc3 669
670 /*
a61a2be6 671 * No, build an "unknown-xxxx" error string...
9aebebc3 672 */
673
a61a2be6 674 sprintf(unknown, "unknown-%04x", error);
9aebebc3 675
a61a2be6 676 return (unknown);
9aebebc3 677}
678
679
50146867 680/*
681 * 'ippFindAttribute()' - Find a named attribute in a request...
682 */
683
58ec2a95 684ipp_attribute_t * /* O - Matching attribute */
063e1ac7 685ippFindAttribute(ipp_t *ipp, /* I - IPP request */
686 const char *name, /* I - Name of attribute */
687 ipp_tag_t type) /* I - Type of attribute */
fbd4fc3f 688{
689 DEBUG_printf(("ippFindAttribute(%p, \'%s\')\n", ipp, name));
690
691 if (ipp == NULL || name == NULL)
692 return (NULL);
693
694 /*
695 * Reset the current pointer...
696 */
697
698 ipp->current = NULL;
699
700 /*
701 * Search for the attribute...
702 */
703
704 return (ippFindNextAttribute(ipp, name, type));
705}
706
707
708/*
709 * 'ippFindNextAttribute()' - Find the next named attribute in a request...
710 */
711
712ipp_attribute_t * /* O - Matching attribute */
713ippFindNextAttribute(ipp_t *ipp, /* I - IPP request */
714 const char *name, /* I - Name of attribute */
715 ipp_tag_t type) /* I - Type of attribute */
3a193f5e 716{
b6ea8f29 717 ipp_attribute_t *attr; /* Current atttribute */
718 ipp_tag_t value_tag; /* Value tag */
50146867 719
720
fbd4fc3f 721 DEBUG_printf(("ippFindNextAttribute(%p, \'%s\')\n", ipp, name));
5356dc5a 722
50146867 723 if (ipp == NULL || name == NULL)
724 return (NULL);
725
fbd4fc3f 726 if (ipp->current)
fbd4fc3f 727 attr = ipp->current->next;
06bd7599 728 else
729 attr = ipp->attrs;
fbd4fc3f 730
731 for (; attr != NULL; attr = attr->next)
5356dc5a 732 {
27d555e8 733 DEBUG_printf(("ippFindAttribute: attr = %p, name = \'%s\'\n", attr,
5356dc5a 734 attr->name));
735
a5f8b9e7 736 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
b6ea8f29 737
a7b3e92e 738 if (attr->name != NULL && strcasecmp(attr->name, name) == 0 &&
b6ea8f29 739 (value_tag == type || type == IPP_TAG_ZERO ||
740 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
741 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
fbd4fc3f 742 {
743 ipp->current = attr;
744
50146867 745 return (attr);
fbd4fc3f 746 }
5356dc5a 747 }
50146867 748
fbd4fc3f 749 ipp->current = NULL;
750
50146867 751 return (NULL);
3a193f5e 752}
753
754
755/*
50146867 756 * 'ippLength()' - Compute the length of an IPP request.
3a193f5e 757 */
758
50146867 759size_t /* O - Size of IPP request */
760ippLength(ipp_t *ipp) /* I - IPP request */
3a193f5e 761{
50146867 762 int i; /* Looping var */
763 int bytes; /* Number of bytes */
764 ipp_attribute_t *attr; /* Current attribute */
765 ipp_tag_t group; /* Current group */
0893e2bb 766 ipp_value_t *value; /* Current value */
50146867 767
768
769 if (ipp == NULL)
770 return (0);
771
772 /*
773 * Start with 8 bytes for the IPP request or status header...
774 */
775
776 bytes = 8;
777
778 /*
779 * Then add the lengths of each attribute...
780 */
781
782 group = IPP_TAG_ZERO;
783
784 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
785 {
786 if (attr->group_tag != group)
787 {
50146867 788 group = attr->group_tag;
5356dc5a 789 if (group == IPP_TAG_ZERO)
790 continue;
791
792 bytes ++; /* Group tag */
e8fda7b9 793 }
50146867 794
4a73831b 795 DEBUG_printf(("attr->name = %s, attr->num_values = %d, bytes = %d\n",
796 attr->name, attr->num_values, bytes));
797
50146867 798 bytes += strlen(attr->name); /* Name */
4a73831b 799 bytes += attr->num_values; /* Value tag for each value */
800 bytes += 2 * attr->num_values; /* Name lengths */
801 bytes += 2 * attr->num_values; /* Value lengths */
50146867 802
27d555e8 803 switch (attr->value_tag & ~IPP_TAG_COPY)
50146867 804 {
805 case IPP_TAG_INTEGER :
806 case IPP_TAG_ENUM :
807 bytes += 4 * attr->num_values;
808 break;
809
810 case IPP_TAG_BOOLEAN :
811 bytes += attr->num_values;
812 break;
813
814 case IPP_TAG_TEXT :
815 case IPP_TAG_NAME :
816 case IPP_TAG_KEYWORD :
817 case IPP_TAG_STRING :
818 case IPP_TAG_URI :
819 case IPP_TAG_URISCHEME :
820 case IPP_TAG_CHARSET :
821 case IPP_TAG_LANGUAGE :
822 case IPP_TAG_MIMETYPE :
0893e2bb 823 for (i = 0, value = attr->values;
824 i < attr->num_values;
825 i ++, value ++)
826 bytes += strlen(value->string.text);
50146867 827 break;
828
829 case IPP_TAG_DATE :
830 bytes += 11 * attr->num_values;
831 break;
832
833 case IPP_TAG_RESOLUTION :
834 bytes += 9 * attr->num_values;
835 break;
836
837 case IPP_TAG_RANGE :
838 bytes += 8 * attr->num_values;
839 break;
840
841 case IPP_TAG_TEXTLANG :
842 case IPP_TAG_NAMELANG :
cb1f28d6 843 bytes += 4 * attr->num_values;/* Charset + text length */
0893e2bb 844 for (i = 0, value = attr->values;
845 i < attr->num_values;
846 i ++, value ++)
847 bytes += strlen(value->string.charset) +
848 strlen(value->string.text);
50146867 849 break;
cb1f28d6 850
851 default :
0893e2bb 852 for (i = 0, value = attr->values;
853 i < attr->num_values;
854 i ++, value ++)
cb1f28d6 855 bytes += attr->values[0].unknown.length;
856 break;
50146867 857 }
858 }
859
860 /*
861 * Finally, add 1 byte for the "end of attributes" tag and return...
862 */
863
4a73831b 864 DEBUG_printf(("bytes = %d\n", bytes + 1));
865
50146867 866 return (bytes + 1);
867}
3a193f5e 868
50146867 869
7ebf3a09 870/*
871 * 'ippNew()' - Allocate a new IPP request.
872 */
873
50146867 874ipp_t * /* O - New IPP request */
875ippNew(void)
876{
7ebf3a09 877 ipp_t *temp; /* New IPP request */
878
879
d2e58bfa 880 if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
7ebf3a09 881 {
882 /*
883 * Default to IPP 1.1...
884 */
885
886 temp->request.any.version[0] = 1;
887 temp->request.any.version[1] = 1;
888 }
889
ccf243ee 890 DEBUG_printf(("ippNew(): %p\n", temp));
891
7ebf3a09 892 return (temp);
3a193f5e 893}
894
895
896/*
50146867 897 * 'ippRead()' - Read data for an IPP request.
3a193f5e 898 */
899
3b960317 900ipp_state_t /* O - Current state */
901ippRead(http_t *http, /* I - HTTP data */
902 ipp_t *ipp) /* I - IPP data */
3a193f5e 903{
3b960317 904 int n; /* Length of data */
cb1f28d6 905 unsigned char buffer[8192], /* Data buffer */
906 *bufptr; /* Pointer into buffer */
3b960317 907 ipp_attribute_t *attr; /* Current attribute */
908 ipp_tag_t tag; /* Current tag */
0893e2bb 909 ipp_value_t *value; /* Current value */
3b960317 910
911
27d555e8 912 DEBUG_printf(("ippRead(%p, %p)\n", http, ipp));
4a73831b 913
3b960317 914 if (http == NULL || ipp == NULL)
915 return (IPP_ERROR);
916
917 switch (ipp->state)
918 {
919 case IPP_IDLE :
4a73831b 920 ipp->state ++; /* Avoid common problem... */
3b960317 921
922 case IPP_HEADER :
923 /*
924 * Get the request header...
925 */
926
d23a857a 927 if ((n = ipp_read(http, buffer, 8)) < 8)
4a73831b 928 {
929 DEBUG_printf(("ippRead: Unable to read header (%d bytes read)!\n", n));
930 return (n == 0 ? IPP_IDLE : IPP_ERROR);
931 }
3b960317 932
933 /*
934 * Verify the major version number...
935 */
936
937 if (buffer[0] != 1)
4a73831b 938 {
939 DEBUG_printf(("ippRead: version number (%d.%d) is bad.\n", buffer[0],
940 buffer[1]));
3b960317 941 return (IPP_ERROR);
4a73831b 942 }
3b960317 943
944 /*
945 * Then copy the request header over...
946 */
947
948 ipp->request.any.version[0] = buffer[0];
949 ipp->request.any.version[1] = buffer[1];
950 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
951 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
952 buffer[6]) << 8) | buffer[7];
953
954 ipp->state = IPP_ATTRIBUTE;
955 ipp->current = NULL;
956 ipp->curtag = IPP_TAG_ZERO;
957
27d555e8 958 DEBUG_printf(("ippRead: version=%d.%d\n", buffer[0], buffer[1]));
959 DEBUG_printf(("ippRead: op_status=%04x\n", ipp->request.any.op_status));
960 DEBUG_printf(("ippRead: request_id=%d\n", ipp->request.any.request_id));
961
3b960317 962 /*
963 * If blocking is disabled, stop here...
964 */
965
61c341bf 966 if (!http->blocking && http->used == 0)
3b960317 967 break;
968
969 case IPP_ATTRIBUTE :
d23a857a 970 while (ipp_read(http, buffer, 1) > 0)
3b960317 971 {
972 /*
973 * Read this attribute...
974 */
975
976 tag = (ipp_tag_t)buffer[0];
977
978 if (tag == IPP_TAG_END)
979 {
980 /*
981 * No more attributes left...
982 */
983
4a73831b 984 DEBUG_puts("ippRead: IPP_TAG_END!");
985
3b960317 986 ipp->state = IPP_DATA;
987 break;
988 }
714294b4 989 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
3b960317 990 {
991 /*
992 * Group tag... Set the current group and continue...
993 */
994
5356dc5a 995 if (ipp->curtag == tag)
996 ippAddSeparator(ipp);
997
3b960317 998 ipp->curtag = tag;
999 ipp->current = NULL;
5356dc5a 1000 DEBUG_printf(("ippRead: group tag = %x\n", tag));
3b960317 1001 continue;
1002 }
1003
5356dc5a 1004 DEBUG_printf(("ippRead: value tag = %x\n", tag));
1005
3b960317 1006 /*
1007 * Get the name...
1008 */
1009
d23a857a 1010 if (ipp_read(http, buffer, 2) < 2)
4a73831b 1011 {
1012 DEBUG_puts("ippRead: unable to read name length!");
3b960317 1013 return (IPP_ERROR);
4a73831b 1014 }
3b960317 1015
1016 n = (buffer[0] << 8) | buffer[1];
1017
4a73831b 1018 DEBUG_printf(("ippRead: name length = %d\n", n));
1019
3b960317 1020 if (n == 0)
1021 {
1022 /*
1023 * More values for current attribute...
1024 */
1025
1026 if (ipp->current == NULL)
1027 return (IPP_ERROR);
1028
1029 attr = ipp->current;
1030
7e9dc5e9 1031 /*
1032 * Make sure we aren't adding a new value of a different
1033 * type...
1034 */
1035
1036 if (attr->value_tag == IPP_TAG_STRING ||
1037 (attr->value_tag >= IPP_TAG_TEXTLANG &&
1038 attr->value_tag <= IPP_TAG_MIMETYPE))
1039 {
1040 /*
1041 * String values can sometimes come across in different
1042 * forms; accept sets of differing values...
1043 */
1044
1045 if (tag != IPP_TAG_STRING &&
1046 (tag < IPP_TAG_TEXTLANG || tag > IPP_TAG_MIMETYPE))
1047 return (IPP_ERROR);
1048 }
1049 else if (attr->value_tag != tag)
1050 return (IPP_ERROR);
1051
1052 /*
acf4f738 1053 * Finally, reallocate the attribute array as needed...
7e9dc5e9 1054 */
1055
acf4f738 1056 if ((attr->num_values % IPP_MAX_VALUES) == 0)
1057 {
1058 ipp_attribute_t *temp, /* Pointer to new buffer */
1059 *ptr; /* Pointer in attribute list */
1060
1061
1062 /*
1063 * Reallocate memory...
1064 */
1065
1066 if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
1067 (attr->num_values + IPP_MAX_VALUES - 1) *
1068 sizeof(ipp_value_t))) == NULL)
1069 return (IPP_ERROR);
1070
1071 /*
1072 * Reset pointers in the list...
1073 */
1074
484c2d6b 1075 for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next);
acf4f738 1076
1077 if (ptr)
1078 ptr->next = temp;
484c2d6b 1079 else
acf4f738 1080 ipp->attrs = temp;
1081
484c2d6b 1082 attr = ipp->current = ipp->last = temp;
acf4f738 1083 }
3b960317 1084 }
1085 else
1086 {
1087 /*
1088 * New attribute; read the name and add it...
1089 */
1090
d23a857a 1091 if (ipp_read(http, buffer, n) < n)
4a73831b 1092 {
1093 DEBUG_puts("ippRead: unable to read name!");
3b960317 1094 return (IPP_ERROR);
4a73831b 1095 }
3b960317 1096
1097 buffer[n] = '\0';
4a73831b 1098 DEBUG_printf(("ippRead: name = \'%s\'\n", buffer));
1099
e09246c8 1100 attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES);
3b960317 1101
4a73831b 1102 attr->group_tag = ipp->curtag;
1103 attr->value_tag = tag;
15749ff9 1104 attr->name = strdup((char *)buffer);
4a73831b 1105 attr->num_values = 0;
3b960317 1106 }
1107
0893e2bb 1108 value = attr->values + attr->num_values;
1109
d23a857a 1110 if (ipp_read(http, buffer, 2) < 2)
4a73831b 1111 {
1112 DEBUG_puts("ippRead: unable to read value length!");
1113 return (IPP_ERROR);
1114 }
1115
1116 n = (buffer[0] << 8) | buffer[1];
1117 DEBUG_printf(("ippRead: value length = %d\n", n));
1118
3b960317 1119 switch (tag)
1120 {
1121 case IPP_TAG_INTEGER :
1122 case IPP_TAG_ENUM :
d23a857a 1123 if (ipp_read(http, buffer, 4) < 4)
3b960317 1124 return (IPP_ERROR);
1125
1126 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1127 buffer[3];
1128
0893e2bb 1129 value->integer = n;
3b960317 1130 break;
1131 case IPP_TAG_BOOLEAN :
d23a857a 1132 if (ipp_read(http, buffer, 1) < 1)
3b960317 1133 return (IPP_ERROR);
1134
0893e2bb 1135 value->boolean = buffer[0];
3b960317 1136 break;
1137 case IPP_TAG_TEXT :
1138 case IPP_TAG_NAME :
1139 case IPP_TAG_KEYWORD :
1140 case IPP_TAG_STRING :
1141 case IPP_TAG_URI :
1142 case IPP_TAG_URISCHEME :
1143 case IPP_TAG_CHARSET :
1144 case IPP_TAG_LANGUAGE :
1145 case IPP_TAG_MIMETYPE :
0893e2bb 1146 value->string.text = calloc(n + 1, 1);
3b960317 1147
0893e2bb 1148 if (ipp_read(http, value->string.text, n) < n)
1149 return (IPP_ERROR);
3b960317 1150
0893e2bb 1151 DEBUG_printf(("ippRead: value = \'%s\'\n",
1152 value->string.text));
3b960317 1153 break;
1154 case IPP_TAG_DATE :
0893e2bb 1155 if (ipp_read(http, value->date, 11) < 11)
3b960317 1156 return (IPP_ERROR);
3b960317 1157 break;
1158 case IPP_TAG_RESOLUTION :
d23a857a 1159 if (ipp_read(http, buffer, 9) < 9)
3b960317 1160 return (IPP_ERROR);
1161
0893e2bb 1162 value->resolution.xres =
3b960317 1163 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1164 buffer[3];
0893e2bb 1165 value->resolution.yres =
3b960317 1166 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
1167 buffer[7];
0893e2bb 1168 value->resolution.units =
3b960317 1169 (ipp_res_t)buffer[8];
1170 break;
1171 case IPP_TAG_RANGE :
d23a857a 1172 if (ipp_read(http, buffer, 8) < 8)
3b960317 1173 return (IPP_ERROR);
1174
0893e2bb 1175 value->range.lower =
3b960317 1176 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1177 buffer[3];
0893e2bb 1178 value->range.upper =
3b960317 1179 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
1180 buffer[7];
1181 break;
1182 case IPP_TAG_TEXTLANG :
1183 case IPP_TAG_NAMELANG :
d23a857a 1184 if (ipp_read(http, buffer, n) < n)
3b960317 1185 return (IPP_ERROR);
1186
cb1f28d6 1187 bufptr = buffer;
3b960317 1188
cb1f28d6 1189 /*
1190 * text-with-language and name-with-language are composite
1191 * values:
1192 *
1193 * charset-length
1194 * charset
1195 * text-length
1196 * text
1197 */
3b960317 1198
cb1f28d6 1199 n = (bufptr[0] << 8) | bufptr[1];
3b960317 1200
0893e2bb 1201 value->string.charset = calloc(n + 1, 1);
3b960317 1202
0893e2bb 1203 memcpy(value->string.charset,
cb1f28d6 1204 bufptr + 2, n);
3b960317 1205
cb1f28d6 1206 bufptr += 2 + n;
1207 n = (bufptr[0] << 8) | bufptr[1];
1208
0893e2bb 1209 value->string.text = calloc(n + 1, 1);
cb1f28d6 1210
0893e2bb 1211 memcpy(value->string.text,
cb1f28d6 1212 bufptr + 2, n);
cb1f28d6 1213 break;
1214
1215 default : /* Other unsupported values */
0893e2bb 1216 value->unknown.length = n;
cb1f28d6 1217 if (n > 0)
1218 {
0893e2bb 1219 value->unknown.data = malloc(n);
1220 if (ipp_read(http, value->unknown.data, n) < n)
cb1f28d6 1221 return (IPP_ERROR);
1222 }
1223 else
0893e2bb 1224 value->unknown.data = NULL;
3b960317 1225 break;
1226 }
1227
1228 attr->num_values ++;
1229
1230 /*
1231 * If blocking is disabled, stop here...
1232 */
1233
61c341bf 1234 if (!http->blocking && http->used == 0)
3b960317 1235 break;
1236 }
1237 break;
1238
1239 case IPP_DATA :
1240 break;
d21a7597 1241
1242 default :
1243 break; /* anti-compiler-warning-code */
3b960317 1244 }
1245
1246 return (ipp->state);
3a193f5e 1247}
1248
1249
1250/*
3b960317 1251 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
3a193f5e 1252 */
1253
063e1ac7 1254const ipp_uchar_t * /* O - RFC-1903 date/time data */
7551914d 1255ippTimeToDate(time_t t) /* I - UNIX time value */
3a193f5e 1256{
7551914d 1257 struct tm *unixdate; /* UNIX unixdate/time info */
1258 static ipp_uchar_t date[11]; /* RFC-1903 date/time data */
3a193f5e 1259
1260
1261 /*
1262 * RFC-1903 date/time format is:
1263 *
1264 * Byte(s) Description
1265 * ------- -----------
1266 * 0-1 Year (0 to 65535)
1267 * 2 Month (1 to 12)
1268 * 3 Day (1 to 31)
1269 * 4 Hours (0 to 23)
1270 * 5 Minutes (0 to 59)
1271 * 6 Seconds (0 to 60, 60 = "leap second")
1272 * 7 Deciseconds (0 to 9)
1273 * 8 +/- UTC
1274 * 9 UTC hours (0 to 11)
1275 * 10 UTC minutes (0 to 59)
1276 */
1277
1278 unixdate = gmtime(&t);
1279 unixdate->tm_year += 1900;
1280
1281 date[0] = unixdate->tm_year >> 8;
1282 date[1] = unixdate->tm_year;
1283 date[2] = unixdate->tm_mon + 1;
1284 date[3] = unixdate->tm_mday;
1285 date[4] = unixdate->tm_hour;
1286 date[5] = unixdate->tm_min;
1287 date[6] = unixdate->tm_sec;
1288 date[7] = 0;
1289 date[8] = '+';
1290 date[9] = 0;
1291 date[10] = 0;
1292
1293 return (date);
1294}
1295
1296
1297/*
50146867 1298 * 'ippWrite()' - Write data for an IPP request.
3a193f5e 1299 */
1300
3b960317 1301ipp_state_t /* O - Current state */
1302ippWrite(http_t *http, /* I - HTTP data */
1303 ipp_t *ipp) /* I - IPP data */
3a193f5e 1304{
58ec2a95 1305 int i; /* Looping var */
1306 int n; /* Length of data */
9abe28e7 1307 unsigned char buffer[8192], /* Data buffer */
58ec2a95 1308 *bufptr; /* Pointer into buffer */
1309 ipp_attribute_t *attr; /* Current attribute */
0893e2bb 1310 ipp_value_t *value; /* Current value */
3b960317 1311
1312
1313 if (http == NULL || ipp == NULL)
1314 return (IPP_ERROR);
1315
1316 switch (ipp->state)
1317 {
1318 case IPP_IDLE :
4a73831b 1319 ipp->state ++; /* Avoid common problem... */
3b960317 1320
1321 case IPP_HEADER :
1322 /*
1323 * Send the request header...
1324 */
1325
1326 bufptr = buffer;
1327
7ebf3a09 1328 *bufptr++ = ipp->request.any.version[0];
1329 *bufptr++ = ipp->request.any.version[1];
3b960317 1330 *bufptr++ = ipp->request.any.op_status >> 8;
1331 *bufptr++ = ipp->request.any.op_status;
1332 *bufptr++ = ipp->request.any.request_id >> 24;
1333 *bufptr++ = ipp->request.any.request_id >> 16;
1334 *bufptr++ = ipp->request.any.request_id >> 8;
1335 *bufptr++ = ipp->request.any.request_id;
1336
15749ff9 1337 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
4a73831b 1338 {
1339 DEBUG_puts("ippWrite: Could not write IPP header...");
3b960317 1340 return (IPP_ERROR);
4a73831b 1341 }
3b960317 1342
1343 ipp->state = IPP_ATTRIBUTE;
1344 ipp->current = ipp->attrs;
1345 ipp->curtag = IPP_TAG_ZERO;
1346
27d555e8 1347 DEBUG_printf(("ippWrite: version=%d.%d\n", buffer[0], buffer[1]));
1348 DEBUG_printf(("ippWrite: op_status=%04x\n", ipp->request.any.op_status));
1349 DEBUG_printf(("ippWrite: request_id=%d\n", ipp->request.any.request_id));
1350
3b960317 1351 /*
1352 * If blocking is disabled, stop here...
1353 */
1354
1355 if (!http->blocking)
1356 break;
1357
1358 case IPP_ATTRIBUTE :
1359 while (ipp->current != NULL)
1360 {
1361 /*
1362 * Write this attribute...
1363 */
1364
1365 bufptr = buffer;
1366 attr = ipp->current;
1367
1368 ipp->current = ipp->current->next;
1369
1370 if (ipp->curtag != attr->group_tag)
1371 {
1372 /*
1373 * Send a group operation tag...
1374 */
1375
3b960317 1376 ipp->curtag = attr->group_tag;
5356dc5a 1377
1378 if (attr->group_tag == IPP_TAG_ZERO)
1379 continue;
1380
1381 DEBUG_printf(("ippWrite: wrote group tag = %x\n", attr->group_tag));
1382 *bufptr++ = attr->group_tag;
3b960317 1383 }
1384
d2e58bfa 1385 if ((n = strlen(attr->name)) > (sizeof(buffer) - 3))
1386 return (IPP_ERROR);
5356dc5a 1387
1388 DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag));
1389 DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n, attr->name));
1390
3b960317 1391 *bufptr++ = attr->value_tag;
1392 *bufptr++ = n >> 8;
1393 *bufptr++ = n;
1394 memcpy(bufptr, attr->name, n);
1395 bufptr += n;
1396
27d555e8 1397 switch (attr->value_tag & ~IPP_TAG_COPY)
3b960317 1398 {
1399 case IPP_TAG_INTEGER :
1400 case IPP_TAG_ENUM :
0893e2bb 1401 for (i = 0, value = attr->values;
1402 i < attr->num_values;
1403 i ++, value ++)
3b960317 1404 {
d2e58bfa 1405 if ((sizeof(buffer) - (bufptr - buffer)) < 9)
1406 {
1407 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1408 {
1409 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1410 return (IPP_ERROR);
1411 }
1412
1413 bufptr = buffer;
1414 }
1415
3b960317 1416 if (i)
1417 {
1418 /*
1419 * Arrays and sets are done by sending additional
1420 * values with a zero-length name...
1421 */
1422
1423 *bufptr++ = attr->value_tag;
1424 *bufptr++ = 0;
1425 *bufptr++ = 0;
1426 }
1427
1428 *bufptr++ = 0;
1429 *bufptr++ = 4;
0893e2bb 1430 *bufptr++ = value->integer >> 24;
1431 *bufptr++ = value->integer >> 16;
1432 *bufptr++ = value->integer >> 8;
1433 *bufptr++ = value->integer;
3b960317 1434 }
1435 break;
1436
1437 case IPP_TAG_BOOLEAN :
0893e2bb 1438 for (i = 0, value = attr->values;
1439 i < attr->num_values;
1440 i ++, value ++)
3b960317 1441 {
d2e58bfa 1442 if ((sizeof(buffer) - (bufptr - buffer)) < 6)
1443 {
1444 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1445 {
1446 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1447 return (IPP_ERROR);
1448 }
1449
1450 bufptr = buffer;
1451 }
1452
3b960317 1453 if (i)
1454 {
1455 /*
1456 * Arrays and sets are done by sending additional
1457 * values with a zero-length name...
1458 */
1459
1460 *bufptr++ = attr->value_tag;
1461 *bufptr++ = 0;
1462 *bufptr++ = 0;
1463 }
1464
1465 *bufptr++ = 0;
1466 *bufptr++ = 1;
0893e2bb 1467 *bufptr++ = value->boolean;
3b960317 1468 }
1469 break;
1470
1471 case IPP_TAG_TEXT :
1472 case IPP_TAG_NAME :
1473 case IPP_TAG_KEYWORD :
1474 case IPP_TAG_STRING :
1475 case IPP_TAG_URI :
1476 case IPP_TAG_URISCHEME :
1477 case IPP_TAG_CHARSET :
1478 case IPP_TAG_LANGUAGE :
1479 case IPP_TAG_MIMETYPE :
0893e2bb 1480 for (i = 0, value = attr->values;
1481 i < attr->num_values;
1482 i ++, value ++)
3b960317 1483 {
1484 if (i)
1485 {
1486 /*
1487 * Arrays and sets are done by sending additional
1488 * values with a zero-length name...
1489 */
1490
5356dc5a 1491 DEBUG_printf(("ippWrite: writing value tag = %x\n",
1492 attr->value_tag));
1493 DEBUG_printf(("ippWrite: writing name = 0, \'\'\n"));
1494
d2e58bfa 1495 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
1496 {
1497 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1498 {
1499 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1500 return (IPP_ERROR);
1501 }
1502
1503 bufptr = buffer;
1504 }
1505
3b960317 1506 *bufptr++ = attr->value_tag;
1507 *bufptr++ = 0;
1508 *bufptr++ = 0;
1509 }
1510
0893e2bb 1511 n = strlen(value->string.text);
5356dc5a 1512
d2e58bfa 1513 if (n > sizeof(buffer))
1514 return (IPP_ERROR);
1515
5356dc5a 1516 DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n,
0893e2bb 1517 value->string.text));
5356dc5a 1518
e09246c8 1519 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
bd84e0d1 1520 {
1521 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1522 {
1523 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1524 return (IPP_ERROR);
1525 }
1526
1527 bufptr = buffer;
1528 }
1529
3b960317 1530 *bufptr++ = n >> 8;
1531 *bufptr++ = n;
0893e2bb 1532 memcpy(bufptr, value->string.text, n);
3b960317 1533 bufptr += n;
1534 }
1535 break;
1536
1537 case IPP_TAG_DATE :
0893e2bb 1538 for (i = 0, value = attr->values;
1539 i < attr->num_values;
1540 i ++, value ++)
3b960317 1541 {
d2e58bfa 1542 if ((sizeof(buffer) - (bufptr - buffer)) < 16)
1543 {
1544 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1545 {
1546 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1547 return (IPP_ERROR);
1548 }
1549
1550 bufptr = buffer;
1551 }
1552
3b960317 1553 if (i)
1554 {
1555 /*
1556 * Arrays and sets are done by sending additional
1557 * values with a zero-length name...
1558 */
1559
1560 *bufptr++ = attr->value_tag;
1561 *bufptr++ = 0;
1562 *bufptr++ = 0;
1563 }
1564
1565 *bufptr++ = 0;
1566 *bufptr++ = 11;
0893e2bb 1567 memcpy(bufptr, value->date, 11);
3b960317 1568 bufptr += 11;
1569 }
1570 break;
1571
1572 case IPP_TAG_RESOLUTION :
0893e2bb 1573 for (i = 0, value = attr->values;
1574 i < attr->num_values;
1575 i ++, value ++)
3b960317 1576 {
d2e58bfa 1577 if ((sizeof(buffer) - (bufptr - buffer)) < 14)
1578 {
1579 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1580 {
1581 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1582 return (IPP_ERROR);
1583 }
1584
1585 bufptr = buffer;
1586 }
1587
3b960317 1588 if (i)
1589 {
1590 /*
1591 * Arrays and sets are done by sending additional
1592 * values with a zero-length name...
1593 */
1594
1595 *bufptr++ = attr->value_tag;
1596 *bufptr++ = 0;
1597 *bufptr++ = 0;
1598 }
1599
1600 *bufptr++ = 0;
1601 *bufptr++ = 9;
0893e2bb 1602 *bufptr++ = value->resolution.xres >> 24;
1603 *bufptr++ = value->resolution.xres >> 16;
1604 *bufptr++ = value->resolution.xres >> 8;
1605 *bufptr++ = value->resolution.xres;
1606 *bufptr++ = value->resolution.yres >> 24;
1607 *bufptr++ = value->resolution.yres >> 16;
1608 *bufptr++ = value->resolution.yres >> 8;
1609 *bufptr++ = value->resolution.yres;
1610 *bufptr++ = value->resolution.units;
3b960317 1611 }
1612 break;
1613
1614 case IPP_TAG_RANGE :
0893e2bb 1615 for (i = 0, value = attr->values;
1616 i < attr->num_values;
1617 i ++, value ++)
3b960317 1618 {
d2e58bfa 1619 if ((sizeof(buffer) - (bufptr - buffer)) < 13)
1620 {
1621 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1622 {
1623 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1624 return (IPP_ERROR);
1625 }
1626
1627 bufptr = buffer;
1628 }
1629
3b960317 1630 if (i)
1631 {
1632 /*
1633 * Arrays and sets are done by sending additional
1634 * values with a zero-length name...
1635 */
1636
1637 *bufptr++ = attr->value_tag;
1638 *bufptr++ = 0;
1639 *bufptr++ = 0;
1640 }
1641
1642 *bufptr++ = 0;
1643 *bufptr++ = 8;
0893e2bb 1644 *bufptr++ = value->range.lower >> 24;
1645 *bufptr++ = value->range.lower >> 16;
1646 *bufptr++ = value->range.lower >> 8;
1647 *bufptr++ = value->range.lower;
1648 *bufptr++ = value->range.upper >> 24;
1649 *bufptr++ = value->range.upper >> 16;
1650 *bufptr++ = value->range.upper >> 8;
1651 *bufptr++ = value->range.upper;
3b960317 1652 }
1653 break;
1654
1655 case IPP_TAG_TEXTLANG :
1656 case IPP_TAG_NAMELANG :
0893e2bb 1657 for (i = 0, value = attr->values;
1658 i < attr->num_values;
1659 i ++, value ++)
3b960317 1660 {
1661 if (i)
1662 {
1663 /*
1664 * Arrays and sets are done by sending additional
1665 * values with a zero-length name...
1666 */
1667
d2e58bfa 1668 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
1669 {
1670 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1671 {
1672 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1673 return (IPP_ERROR);
1674 }
1675
1676 bufptr = buffer;
1677 }
1678
3b960317 1679 *bufptr++ = attr->value_tag;
1680 *bufptr++ = 0;
1681 *bufptr++ = 0;
1682 }
1683
0893e2bb 1684 n = strlen(value->string.charset) +
1685 strlen(value->string.text) +
9ba214bc 1686 4;
bd84e0d1 1687
d2e58bfa 1688 if (n > sizeof(buffer))
1689 return (IPP_ERROR);
1690
e09246c8 1691 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
bd84e0d1 1692 {
1693 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1694 {
1695 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1696 return (IPP_ERROR);
1697 }
1698
1699 bufptr = buffer;
1700 }
1701
cb1f28d6 1702 /* Length of entire value */
3b960317 1703 *bufptr++ = n >> 8;
1704 *bufptr++ = n;
cb1f28d6 1705
1706 /* Length of charset */
0893e2bb 1707 n = strlen(value->string.charset);
cb1f28d6 1708 *bufptr++ = n >> 8;
1709 *bufptr++ = n;
1710
1711 /* Charset */
0893e2bb 1712 memcpy(bufptr, value->string.charset, n);
3b960317 1713 bufptr += n;
1714
cb1f28d6 1715 /* Length of text */
0893e2bb 1716 n = strlen(value->string.text);
cb1f28d6 1717 *bufptr++ = n >> 8;
1718 *bufptr++ = n;
1719
1720 /* Text */
0893e2bb 1721 memcpy(bufptr, value->string.text, n);
cb1f28d6 1722 bufptr += n;
1723 }
1724 break;
1725
1726 default :
0893e2bb 1727 for (i = 0, value = attr->values;
1728 i < attr->num_values;
1729 i ++, value ++)
cb1f28d6 1730 {
1731 if (i)
1732 {
1733 /*
1734 * Arrays and sets are done by sending additional
1735 * values with a zero-length name...
1736 */
1737
d2e58bfa 1738 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
1739 {
1740 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1741 {
1742 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1743 return (IPP_ERROR);
1744 }
1745
1746 bufptr = buffer;
1747 }
1748
cb1f28d6 1749 *bufptr++ = attr->value_tag;
1750 *bufptr++ = 0;
1751 *bufptr++ = 0;
1752 }
1753
0893e2bb 1754 n = value->unknown.length;
bd84e0d1 1755
d2e58bfa 1756 if (n > sizeof(buffer))
1757 return (IPP_ERROR);
1758
e09246c8 1759 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
bd84e0d1 1760 {
1761 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1762 {
1763 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1764 return (IPP_ERROR);
1765 }
1766
1767 bufptr = buffer;
1768 }
1769
cb1f28d6 1770 /* Length of unknown value */
3b960317 1771 *bufptr++ = n >> 8;
1772 *bufptr++ = n;
f63a2256 1773
cb1f28d6 1774 /* Value */
1775 if (n > 0)
1776 {
0893e2bb 1777 memcpy(bufptr, value->unknown.data, n);
cb1f28d6 1778 bufptr += n;
1779 }
1780 }
f63a2256 1781 break;
3b960317 1782 }
1783
1784 /*
1785 * Write the data out...
1786 */
1787
15749ff9 1788 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
4a73831b 1789 {
1790 DEBUG_puts("ippWrite: Could not write IPP attribute...");
3b960317 1791 return (IPP_ERROR);
4a73831b 1792 }
3b960317 1793
5356dc5a 1794 DEBUG_printf(("ippWrite: wrote %d bytes\n", bufptr - buffer));
1795
3b960317 1796 /*
1797 * If blocking is disabled, stop here...
1798 */
1799
1800 if (!http->blocking)
1801 break;
1802 }
1803
1804 if (ipp->current == NULL)
1805 {
1806 /*
1807 * Done with all of the attributes; add the end-of-attributes tag...
1808 */
1809
1810 buffer[0] = IPP_TAG_END;
15749ff9 1811 if (httpWrite(http, (char *)buffer, 1) < 0)
4a73831b 1812 {
1813 DEBUG_puts("ippWrite: Could not write IPP end-tag...");
3b960317 1814 return (IPP_ERROR);
4a73831b 1815 }
3b960317 1816
1817 ipp->state = IPP_DATA;
1818 }
1819 break;
1820
1821 case IPP_DATA :
1822 break;
d21a7597 1823
1824 default :
1825 break; /* anti-compiler-warning-code */
3b960317 1826 }
1827
1828 return (ipp->state);
3a193f5e 1829}
1830
1831
4a73831b 1832/*
1833 * 'ippPort()' - Return the default IPP port number.
1834 */
1835
ff3758e3 1836int /* O - Port number */
4a73831b 1837ippPort(void)
1838{
063e1ac7 1839 const char *server_port; /* SERVER_PORT environment variable */
ff3758e3 1840 struct servent *port; /* Port number info */
4a73831b 1841
1842
c68b6ae8 1843 if (ipp_port)
1844 return (ipp_port);
1845 else if ((server_port = getenv("IPP_PORT")) != NULL)
1846 return (ipp_port = atoi(server_port));
ff3758e3 1847 else if ((port = getservbyname("ipp", NULL)) == NULL)
c68b6ae8 1848 return (ipp_port = IPP_PORT);
4a73831b 1849 else
c68b6ae8 1850 return (ipp_port = ntohs(port->s_port));
1851}
1852
1853
1854/*
1855 * 'ippSetPort()' - Set the default port number.
1856 */
1857
1858void
1859ippSetPort(int p) /* I - Port number to use */
1860{
1861 ipp_port = p;
4a73831b 1862}
1863
1864
50146867 1865/*
e09246c8 1866 * '_ipp_add_attr()' - Add a new attribute to the request.
50146867 1867 */
1868
e09246c8 1869ipp_attribute_t * /* O - New attribute */
1870_ipp_add_attr(ipp_t *ipp, /* I - IPP request */
1871 int num_values) /* I - Number of values */
3a193f5e 1872{
e09246c8 1873 ipp_attribute_t *attr; /* New attribute */
50146867 1874
1875
27d555e8 1876 DEBUG_printf(("_ipp_add_attr(%p, %d)\n", ipp, num_values));
4a73831b 1877
5356dc5a 1878 if (ipp == NULL || num_values < 0)
50146867 1879 return (NULL);
1880
1881 attr = calloc(sizeof(ipp_attribute_t) +
1882 (num_values - 1) * sizeof(ipp_value_t), 1);
1883
4a73831b 1884 attr->num_values = num_values;
1885
50146867 1886 if (attr == NULL)
1887 return (NULL);
1888
1889 if (ipp->last == NULL)
1890 ipp->attrs = attr;
1891 else
1892 ipp->last->next = attr;
1893
1894 ipp->last = attr;
1895
ccf243ee 1896 DEBUG_printf(("_ipp_add_attr(): %p\n", attr));
1897
50146867 1898 return (attr);
3a193f5e 1899}
1900
1901
a3e17a89 1902/*
1903 * '_ipp_free_attr()' - Free an attribute.
1904 */
1905
1906void
1907_ipp_free_attr(ipp_attribute_t *attr) /* I - Attribute to free */
1908{
0893e2bb 1909 int i; /* Looping var */
1910 ipp_value_t *value; /* Current value */
a3e17a89 1911
1912
ccf243ee 1913 DEBUG_printf(("_ipp_free_attr(): %p\n", attr));
1914
a3e17a89 1915 switch (attr->value_tag)
1916 {
1917 case IPP_TAG_TEXT :
1918 case IPP_TAG_NAME :
1919 case IPP_TAG_KEYWORD :
1920 case IPP_TAG_STRING :
1921 case IPP_TAG_URI :
1922 case IPP_TAG_URISCHEME :
1923 case IPP_TAG_CHARSET :
1924 case IPP_TAG_LANGUAGE :
1925 case IPP_TAG_MIMETYPE :
0893e2bb 1926 for (i = 0, value = attr->values;
1927 i < attr->num_values;
1928 i ++, value ++)
1929 free(value->string.text);
a3e17a89 1930 break;
1931
1932 case IPP_TAG_TEXTLANG :
1933 case IPP_TAG_NAMELANG :
0893e2bb 1934 for (i = 0, value = attr->values;
1935 i < attr->num_values;
1936 i ++, value ++)
a3e17a89 1937 {
0893e2bb 1938 if (value->string.charset && i == 0)
1939 free(value->string.charset);
1940 free(value->string.text);
a3e17a89 1941 }
1942 break;
1943
1944 default :
1945 break; /* anti-compiler-warning-code */
1946 }
1947
1948 if (attr->name != NULL)
1949 free(attr->name);
1950
1951 free(attr);
1952}
1953
1954
3a193f5e 1955/*
d23a857a 1956 * 'ipp_read()' - Semi-blocking read on a HTTP connection...
1957 */
1958
15749ff9 1959static int /* O - Number of bytes read */
1960ipp_read(http_t *http, /* I - Client connection */
1961 unsigned char *buffer, /* O - Buffer for data */
1962 int length) /* I - Total length */
d23a857a 1963{
15749ff9 1964 int tbytes, /* Total bytes read */
1965 bytes; /* Bytes read this pass */
c0a0a784 1966 char len[32]; /* Length string */
1967
d23a857a 1968
1969 /*
1970 * Loop until all bytes are read...
1971 */
1972
41e45833 1973 for (tbytes = 0, bytes = 0; tbytes < length; tbytes += bytes, buffer += bytes)
c0a0a784 1974 {
1975 if (http->used > 0)
1976 {
1977 /*
1978 * Do "fast read" from HTTP buffer directly...
1979 */
1980
1981 if (http->used > (length - tbytes))
1982 bytes = length - tbytes;
1983 else
1984 bytes = http->used;
1985
1986 if (bytes == 1)
1987 buffer[0] = http->buffer[0];
1988 else
1989 memcpy(buffer, http->buffer, bytes);
1990
1991 http->used -= bytes;
1992 http->data_remaining -= bytes;
1993
1994 if (http->used > 0)
1995 memcpy(http->buffer, http->buffer + bytes, http->used);
1996
1997 if (http->data_remaining == 0)
1998 {
1999 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
2000 httpGets(len, sizeof(len), http);
2001
2002 if (http->data_encoding != HTTP_ENCODE_CHUNKED)
2003 {
2004 if (http->state == HTTP_POST_RECV)
2005 http->state ++;
2006 else
2007 http->state = HTTP_WAITING;
2008 }
2009 }
2010 }
2011 else if ((bytes = httpRead(http, (char *)buffer, length - tbytes)) <= 0)
d23a857a 2012 break;
c0a0a784 2013 }
d23a857a 2014
2015 /*
2016 * Return the number of bytes read...
2017 */
2018
74464516 2019 if (tbytes == 0 && bytes < 0)
2020 return (-1);
2021 else
2022 return (tbytes);
d23a857a 2023}
2024
2025
d23a857a 2026/*
efb2f309 2027 * End of "$Id: ipp.c,v 1.65 2002/01/02 17:58:39 mike Exp $".
dec2f757 2028 */