]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ipp.c
Y2k copyright changes.
[thirdparty/cups.git] / cups / ipp.c
1 /*
2 * "$Id: ipp.c,v 1.30 2000/01/04 13:45:35 mike Exp $"
3 *
4 * Internet Printing Protocol support functions for the Common UNIX
5 * Printing System (CUPS).
6 *
7 * Copyright 1997-2000 by Easy Software Products, all rights reserved.
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
18 * 44141 Airport View Drive, Suite 204
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 *
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 time
40 * ippDelete() - Delete an IPP request.
41 * ippFindAttribute() - Find a named attribute in a request...
42 * ippLength() - Compute the length of an IPP request.
43 * ippPort() - Return the default IPP port number.
44 * ippRead() - Read data for an IPP request.
45 * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
46 * ippWrite() - Write data for an IPP request.
47 * _ipp_add_attr() - Add a new attribute to the request.
48 * ipp_read() - Semi-blocking read on a HTTP connection...
49 */
50
51 /*
52 * Include necessary headers...
53 */
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include "string.h"
58
59 #include "ipp.h"
60 #include "debug.h"
61
62
63 /*
64 * Local functions...
65 */
66
67 static int ipp_read(http_t *http, unsigned char *buffer, int length);
68
69
70 /*
71 * 'ippAddBoolean()' - Add a boolean attribute to an IPP request.
72 */
73
74 ipp_attribute_t * /* O - New attribute */
75 ippAddBoolean(ipp_t *ipp, /* I - IPP request */
76 ipp_tag_t group, /* I - IPP group */
77 const char *name, /* I - Name of attribute */
78 char value) /* I - Value of attribute */
79 {
80 ipp_attribute_t *attr; /* New attribute */
81
82
83 DEBUG_printf(("ippAddBoolean(%08x, %02x, \'%s\', %d)\n", ipp, group, name, value));
84
85 if (ipp == NULL || name == NULL)
86 return (NULL);
87
88 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
89 return (NULL);
90
91 attr->name = strdup(name);
92 attr->group_tag = group;
93 attr->value_tag = IPP_TAG_BOOLEAN;
94 attr->values[0].boolean = value;
95
96 return (attr);
97 }
98
99
100 /*
101 * 'ippAddBooleans()' - Add an array of boolean values.
102 */
103
104 ipp_attribute_t * /* O - New attribute */
105 ippAddBooleans(ipp_t *ipp, /* I - IPP request */
106 ipp_tag_t group, /* I - IPP group */
107 const char *name, /* I - Name of attribute */
108 int num_values, /* I - Number of values */
109 const char *values) /* I - Values */
110 {
111 int i; /* Looping var */
112 ipp_attribute_t *attr; /* New attribute */
113
114
115 DEBUG_printf(("ippAddBooleans(%08x, %02x, \'%s\', %d, %08x)\n", ipp,
116 group, name, num_values, values));
117
118 if (ipp == NULL || name == NULL)
119 return (NULL);
120
121 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
122 return (NULL);
123
124 attr->name = strdup(name);
125 attr->group_tag = group;
126 attr->value_tag = IPP_TAG_BOOLEAN;
127
128 if (values != NULL)
129 for (i = 0; i < num_values; i ++)
130 attr->values[i].boolean = values[i];
131
132 return (attr);
133 }
134
135
136 /*
137 * 'ippAddDate()' - Add a date attribute to an IPP request.
138 */
139
140 ipp_attribute_t * /* O - New attribute */
141 ippAddDate(ipp_t *ipp, /* I - IPP request */
142 ipp_tag_t group, /* I - IPP group */
143 const char *name, /* I - Name of attribute */
144 const ipp_uchar_t *value) /* I - Value */
145 {
146 ipp_attribute_t *attr; /* New attribute */
147
148
149 DEBUG_printf(("ippAddDate(%08x, %02x, \'%s\', %08x)\n", ipp, group, name,
150 value));
151
152 if (ipp == NULL || name == NULL || value == NULL)
153 return (NULL);
154
155 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
156 return (NULL);
157
158 attr->name = strdup(name);
159 attr->group_tag = group;
160 attr->value_tag = IPP_TAG_DATE;
161 memcpy(attr->values[0].date, value, 11);
162
163 return (attr);
164 }
165
166
167 /*
168 * 'ippAddInteger()' - Add a integer attribute to an IPP request.
169 */
170
171 ipp_attribute_t * /* O - New attribute */
172 ippAddInteger(ipp_t *ipp, /* I - IPP request */
173 ipp_tag_t group, /* I - IPP group */
174 ipp_tag_t type, /* I - Type of attribute */
175 const char *name, /* I - Name of attribute */
176 int value) /* I - Value of attribute */
177 {
178 ipp_attribute_t *attr; /* New attribute */
179
180
181 DEBUG_printf(("ippAddInteger(%08x, %d, \'%s\', %d)\n", ipp, group, name,
182 value));
183
184 if (ipp == NULL || name == NULL)
185 return (NULL);
186
187 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
188 return (NULL);
189
190 attr->name = strdup(name);
191 attr->group_tag = group;
192 attr->value_tag = type;
193 attr->values[0].integer = value;
194
195 return (attr);
196 }
197
198
199 /*
200 * 'ippAddIntegers()' - Add an array of integer values.
201 */
202
203 ipp_attribute_t * /* O - New attribute */
204 ippAddIntegers(ipp_t *ipp, /* I - IPP request */
205 ipp_tag_t group, /* I - IPP group */
206 ipp_tag_t type, /* I - Type of attribute */
207 const char *name, /* I - Name of attribute */
208 int num_values, /* I - Number of values */
209 const int *values) /* I - Values */
210 {
211 int i; /* Looping var */
212 ipp_attribute_t *attr; /* New attribute */
213
214
215 if (ipp == NULL || name == NULL)
216 return (NULL);
217
218 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
219 return (NULL);
220
221 attr->name = strdup(name);
222 attr->group_tag = group;
223 attr->value_tag = type;
224
225 if (values != NULL)
226 for (i = 0; i < num_values; i ++)
227 attr->values[i].integer = values[i];
228
229 return (attr);
230 }
231
232
233 /*
234 * 'ippAddString()' - Add a language-encoded string to an IPP request.
235 */
236
237 ipp_attribute_t * /* O - New attribute */
238 ippAddString(ipp_t *ipp, /* I - IPP request */
239 ipp_tag_t group, /* I - IPP group */
240 ipp_tag_t type, /* I - Type of attribute */
241 const char *name, /* I - Name of attribute */
242 const char *charset, /* I - Character set */
243 const char *value) /* I - Value */
244 {
245 ipp_attribute_t *attr; /* New attribute */
246
247
248 if (ipp == NULL || name == NULL)
249 return (NULL);
250
251 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
252 return (NULL);
253
254 attr->name = strdup(name);
255 attr->group_tag = group;
256 attr->value_tag = type;
257 attr->values[0].string.charset = charset ? strdup(charset) : NULL;
258 attr->values[0].string.text = strdup(value);
259
260 return (attr);
261 }
262
263
264 /*
265 * 'ippAddStrings()' - Add language-encoded strings to an IPP request.
266 */
267
268 ipp_attribute_t * /* O - New attribute */
269 ippAddStrings(ipp_t *ipp, /* I - IPP request */
270 ipp_tag_t group, /* I - IPP group */
271 ipp_tag_t type, /* I - Type of attribute */
272 const char *name, /* I - Name of attribute */
273 int num_values, /* I - Number of values */
274 const char *charset, /* I - Character set */
275 const char **values) /* I - Values */
276 {
277 int i; /* Looping var */
278 ipp_attribute_t *attr; /* New attribute */
279
280
281 if (ipp == NULL || name == NULL)
282 return (NULL);
283
284 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
285 return (NULL);
286
287 attr->name = strdup(name);
288 attr->group_tag = group;
289 attr->value_tag = type;
290
291 if (values != NULL)
292 for (i = 0; i < num_values; i ++)
293 {
294 if (i == 0)
295 attr->values[0].string.charset = charset ? strdup(charset) : NULL;
296 else
297 attr->values[i].string.charset = attr->values[0].string.charset;
298
299 attr->values[i].string.text = strdup(values[i]);
300 }
301
302 return (attr);
303 }
304
305
306 /*
307 * 'ippAddRange()' - Add a range of values to an IPP request.
308 */
309
310 ipp_attribute_t * /* O - New attribute */
311 ippAddRange(ipp_t *ipp, /* I - IPP request */
312 ipp_tag_t group, /* I - IPP group */
313 const char *name, /* I - Name of attribute */
314 int lower, /* I - Lower value */
315 int upper) /* I - Upper value */
316 {
317 ipp_attribute_t *attr; /* New attribute */
318
319
320 if (ipp == NULL || name == NULL)
321 return (NULL);
322
323 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
324 return (NULL);
325
326 attr->name = strdup(name);
327 attr->group_tag = group;
328 attr->value_tag = IPP_TAG_RANGE;
329 attr->values[0].range.lower = lower;
330 attr->values[0].range.upper = upper;
331
332 return (attr);
333 }
334
335
336 /*
337 * 'ippAddRanges()' - Add ranges of values to an IPP request.
338 */
339
340 ipp_attribute_t * /* O - New attribute */
341 ippAddRanges(ipp_t *ipp, /* I - IPP request */
342 ipp_tag_t group, /* I - IPP group */
343 const char *name, /* I - Name of attribute */
344 int num_values, /* I - Number of values */
345 const int *lower, /* I - Lower values */
346 const int *upper) /* I - Upper values */
347 {
348 int i; /* Looping var */
349 ipp_attribute_t *attr; /* New attribute */
350
351
352 if (ipp == NULL || name == NULL)
353 return (NULL);
354
355 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
356 return (NULL);
357
358 attr->name = strdup(name);
359 attr->group_tag = group;
360 attr->value_tag = IPP_TAG_RANGE;
361
362 if (lower != NULL && upper != NULL)
363 for (i = 0; i < num_values; i ++)
364 {
365 attr->values[i].range.lower = lower[i];
366 attr->values[i].range.upper = upper[i];
367 }
368
369 return (attr);
370 }
371
372
373 /*
374 * 'ippAddResolution()' - Add a resolution value to an IPP request.
375 */
376
377 ipp_attribute_t * /* O - New attribute */
378 ippAddResolution(ipp_t *ipp, /* I - IPP request */
379 ipp_tag_t group, /* I - IPP group */
380 const char *name, /* I - Name of attribute */
381 ipp_res_t units, /* I - Units for resolution */
382 int xres, /* I - X resolution */
383 int yres) /* I - Y resolution */
384 {
385 ipp_attribute_t *attr; /* New attribute */
386
387
388 if (ipp == NULL || name == NULL)
389 return (NULL);
390
391 if ((attr = _ipp_add_attr(ipp, 1)) == NULL)
392 return (NULL);
393
394 attr->name = strdup(name);
395 attr->group_tag = group;
396 attr->value_tag = IPP_TAG_RESOLUTION;
397 attr->values[0].resolution.xres = xres;
398 attr->values[0].resolution.yres = yres;
399 attr->values[0].resolution.units = units;
400
401 return (attr);
402 }
403
404
405 /*
406 * 'ippAddResolutions()' - Add resolution values to an IPP request.
407 */
408
409 ipp_attribute_t * /* O - New attribute */
410 ippAddResolutions(ipp_t *ipp, /* I - IPP request */
411 ipp_tag_t group, /* I - IPP group */
412 const char *name, /* I - Name of attribute */
413 int num_values,/* I - Number of values */
414 ipp_res_t units, /* I - Units for resolution */
415 const int *xres, /* I - X resolutions */
416 const int *yres) /* I - Y resolutions */
417 {
418 int i; /* Looping var */
419 ipp_attribute_t *attr; /* New attribute */
420
421
422 if (ipp == NULL || name == NULL)
423 return (NULL);
424
425 if ((attr = _ipp_add_attr(ipp, num_values)) == NULL)
426 return (NULL);
427
428 attr->name = strdup(name);
429 attr->group_tag = group;
430 attr->value_tag = IPP_TAG_RESOLUTION;
431
432 if (xres != NULL && yres != NULL)
433 for (i = 0; i < num_values; i ++)
434 {
435 attr->values[i].resolution.xres = xres[i];
436 attr->values[i].resolution.yres = yres[i];
437 attr->values[i].resolution.units = units;
438 }
439
440 return (attr);
441 }
442
443
444 /*
445 * 'ippAddSeparator()' - Add a group separator to an IPP request.
446 */
447
448 ipp_attribute_t * /* O - New attribute */
449 ippAddSeparator(ipp_t *ipp) /* I - IPP request */
450 {
451 ipp_attribute_t *attr; /* New attribute */
452
453
454 DEBUG_printf(("ippAddSeparator(%08x)\n", ipp));
455
456 if (ipp == NULL)
457 return (NULL);
458
459 if ((attr = _ipp_add_attr(ipp, 0)) == NULL)
460 return (NULL);
461
462 attr->group_tag = IPP_TAG_ZERO;
463 attr->value_tag = IPP_TAG_ZERO;
464
465 return (attr);
466 }
467
468
469 /*
470 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
471 * in seconds.
472 */
473
474 time_t /* O - UNIX time value */
475 ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */
476 {
477 struct tm unixdate; /* UNIX date/time info */
478 time_t t; /* Computed time */
479
480
481 memset(&unixdate, 0, sizeof(unixdate));
482
483 /*
484 * RFC-1903 date/time format is:
485 *
486 * Byte(s) Description
487 * ------- -----------
488 * 0-1 Year (0 to 65535)
489 * 2 Month (1 to 12)
490 * 3 Day (1 to 31)
491 * 4 Hours (0 to 23)
492 * 5 Minutes (0 to 59)
493 * 6 Seconds (0 to 60, 60 = "leap second")
494 * 7 Deciseconds (0 to 9)
495 * 8 +/- UTC
496 * 9 UTC hours (0 to 11)
497 * 10 UTC minutes (0 to 59)
498 */
499
500 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
501 unixdate.tm_mon = date[2] - 1;
502 unixdate.tm_mday = date[3];
503 unixdate.tm_hour = date[4];
504 unixdate.tm_min = date[5];
505 unixdate.tm_sec = date[6];
506
507 t = mktime(&unixdate);
508
509 if (date[8] == '-')
510 t += date[9] * 3600 + date[10] * 60;
511 else
512 t -= date[9] * 3600 + date[10] * 60;
513
514 return (t);
515 }
516
517
518 /*
519 * 'ippDelete()' - Delete an IPP request.
520 */
521
522 void
523 ippDelete(ipp_t *ipp) /* I - IPP request */
524 {
525 int i; /* Looping var */
526 ipp_attribute_t *attr, /* Current attribute */
527 *next; /* Next attribute */
528
529
530 if (ipp == NULL)
531 return;
532
533 for (attr = ipp->attrs; attr != NULL; attr = next)
534 {
535 switch (attr->value_tag)
536 {
537 case IPP_TAG_TEXT :
538 case IPP_TAG_NAME :
539 case IPP_TAG_KEYWORD :
540 case IPP_TAG_STRING :
541 case IPP_TAG_URI :
542 case IPP_TAG_URISCHEME :
543 case IPP_TAG_CHARSET :
544 case IPP_TAG_LANGUAGE :
545 case IPP_TAG_MIMETYPE :
546 for (i = 0; i < attr->num_values; i ++)
547 free(attr->values[i].string.text);
548 break;
549
550 case IPP_TAG_TEXTLANG :
551 case IPP_TAG_NAMELANG :
552 for (i = 0; i < attr->num_values; i ++)
553 {
554 if (attr->values[i].string.charset)
555 free(attr->values[i].string.charset);
556 free(attr->values[i].string.text);
557 }
558 break;
559 }
560
561 next = attr->next;
562
563 if (attr->name != NULL)
564 free(attr->name);
565
566 free(attr);
567 }
568
569 free(ipp);
570 }
571
572
573 /*
574 * 'ippFindAttribute()' - Find a named attribute in a request...
575 */
576
577 ipp_attribute_t * /* O - Matching attribute */
578 ippFindAttribute(ipp_t *ipp, /* I - IPP request */
579 const char *name, /* I - Name of attribute */
580 ipp_tag_t type) /* I - Type of attribute */
581 {
582 ipp_attribute_t *attr; /* Current atttribute */
583
584
585 DEBUG_printf(("ippFindAttribute(%08x, \'%s\')\n", ipp, name));
586
587 if (ipp == NULL || name == NULL)
588 return (NULL);
589
590 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
591 {
592 DEBUG_printf(("ippFindAttribute: attr = %08x, name = \'%s\'\n", attr,
593 attr->name));
594
595 if (attr->name != NULL && strcasecmp(attr->name, name) == 0 &&
596 (attr->value_tag == type ||
597 (attr->value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
598 (attr->value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
599 return (attr);
600 }
601
602 return (NULL);
603 }
604
605
606 /*
607 * 'ippLength()' - Compute the length of an IPP request.
608 */
609
610 size_t /* O - Size of IPP request */
611 ippLength(ipp_t *ipp) /* I - IPP request */
612 {
613 int i; /* Looping var */
614 int bytes; /* Number of bytes */
615 ipp_attribute_t *attr; /* Current attribute */
616 ipp_tag_t group; /* Current group */
617
618
619 if (ipp == NULL)
620 return (0);
621
622 /*
623 * Start with 8 bytes for the IPP request or status header...
624 */
625
626 bytes = 8;
627
628 /*
629 * Then add the lengths of each attribute...
630 */
631
632 group = IPP_TAG_ZERO;
633
634 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
635 {
636 if (attr->group_tag != group)
637 {
638 group = attr->group_tag;
639 if (group == IPP_TAG_ZERO)
640 continue;
641
642 bytes ++; /* Group tag */
643 }
644
645 DEBUG_printf(("attr->name = %s, attr->num_values = %d, bytes = %d\n",
646 attr->name, attr->num_values, bytes));
647
648 bytes += strlen(attr->name); /* Name */
649 bytes += attr->num_values; /* Value tag for each value */
650 bytes += 2 * attr->num_values; /* Name lengths */
651 bytes += 2 * attr->num_values; /* Value lengths */
652
653 switch (attr->value_tag)
654 {
655 case IPP_TAG_INTEGER :
656 case IPP_TAG_ENUM :
657 bytes += 4 * attr->num_values;
658 break;
659
660 case IPP_TAG_BOOLEAN :
661 bytes += attr->num_values;
662 break;
663
664 case IPP_TAG_TEXT :
665 case IPP_TAG_NAME :
666 case IPP_TAG_KEYWORD :
667 case IPP_TAG_STRING :
668 case IPP_TAG_URI :
669 case IPP_TAG_URISCHEME :
670 case IPP_TAG_CHARSET :
671 case IPP_TAG_LANGUAGE :
672 case IPP_TAG_MIMETYPE :
673 for (i = 0; i < attr->num_values; i ++)
674 bytes += strlen(attr->values[i].string.text);
675 break;
676
677 case IPP_TAG_DATE :
678 bytes += 11 * attr->num_values;
679 break;
680
681 case IPP_TAG_RESOLUTION :
682 bytes += 9 * attr->num_values;
683 break;
684
685 case IPP_TAG_RANGE :
686 bytes += 8 * attr->num_values;
687 break;
688
689 case IPP_TAG_TEXTLANG :
690 case IPP_TAG_NAMELANG :
691 bytes += 2 * attr->num_values;/* Charset length */
692 for (i = 0; i < attr->num_values; i ++)
693 bytes += strlen(attr->values[i].string.charset) +
694 strlen(attr->values[i].string.text);
695 break;
696 }
697 }
698
699 /*
700 * Finally, add 1 byte for the "end of attributes" tag and return...
701 */
702
703 DEBUG_printf(("bytes = %d\n", bytes + 1));
704
705 return (bytes + 1);
706 }
707
708
709 ipp_t * /* O - New IPP request */
710 ippNew(void)
711 {
712 return ((ipp_t *)calloc(sizeof(ipp_t), 1));
713 }
714
715
716 /*
717 * 'ippRead()' - Read data for an IPP request.
718 */
719
720 ipp_state_t /* O - Current state */
721 ippRead(http_t *http, /* I - HTTP data */
722 ipp_t *ipp) /* I - IPP data */
723 {
724 int n; /* Length of data */
725 unsigned char buffer[8192]; /* Data buffer */
726 ipp_attribute_t *attr; /* Current attribute */
727 ipp_tag_t tag; /* Current tag */
728
729
730 DEBUG_printf(("ippRead(%08x, %08x)\n", http, ipp));
731
732 if (http == NULL || ipp == NULL)
733 return (IPP_ERROR);
734
735 switch (ipp->state)
736 {
737 case IPP_IDLE :
738 ipp->state ++; /* Avoid common problem... */
739
740 case IPP_HEADER :
741 /*
742 * Get the request header...
743 */
744
745 if ((n = ipp_read(http, buffer, 8)) < 8)
746 {
747 DEBUG_printf(("ippRead: Unable to read header (%d bytes read)!\n", n));
748 return (n == 0 ? IPP_IDLE : IPP_ERROR);
749 }
750
751 /*
752 * Verify the major version number...
753 */
754
755 if (buffer[0] != 1)
756 {
757 DEBUG_printf(("ippRead: version number (%d.%d) is bad.\n", buffer[0],
758 buffer[1]));
759 return (IPP_ERROR);
760 }
761
762 /*
763 * Then copy the request header over...
764 */
765
766 ipp->request.any.version[0] = buffer[0];
767 ipp->request.any.version[1] = buffer[1];
768 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
769 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
770 buffer[6]) << 8) | buffer[7];
771
772 ipp->state = IPP_ATTRIBUTE;
773 ipp->current = NULL;
774 ipp->curtag = IPP_TAG_ZERO;
775
776 /*
777 * If blocking is disabled, stop here...
778 */
779
780 if (!http->blocking && http->used == 0)
781 break;
782
783 case IPP_ATTRIBUTE :
784 while (ipp_read(http, buffer, 1) > 0)
785 {
786 /*
787 * Read this attribute...
788 */
789
790 tag = (ipp_tag_t)buffer[0];
791
792 if (tag == IPP_TAG_END)
793 {
794 /*
795 * No more attributes left...
796 */
797
798 DEBUG_puts("ippRead: IPP_TAG_END!");
799
800 ipp->state = IPP_DATA;
801 break;
802 }
803 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
804 {
805 /*
806 * Group tag... Set the current group and continue...
807 */
808
809 if (ipp->curtag == tag)
810 ippAddSeparator(ipp);
811
812 ipp->curtag = tag;
813 ipp->current = NULL;
814 DEBUG_printf(("ippRead: group tag = %x\n", tag));
815 continue;
816 }
817
818 DEBUG_printf(("ippRead: value tag = %x\n", tag));
819
820 /*
821 * Get the name...
822 */
823
824 if (ipp_read(http, buffer, 2) < 2)
825 {
826 DEBUG_puts("ippRead: unable to read name length!");
827 return (IPP_ERROR);
828 }
829
830 n = (buffer[0] << 8) | buffer[1];
831
832 DEBUG_printf(("ippRead: name length = %d\n", n));
833
834 if (n == 0)
835 {
836 /*
837 * More values for current attribute...
838 */
839
840 if (ipp->current == NULL)
841 return (IPP_ERROR);
842
843 attr = ipp->current;
844
845 if (attr->num_values >= IPP_MAX_VALUES)
846 return (IPP_ERROR);
847 }
848 else
849 {
850 /*
851 * New attribute; read the name and add it...
852 */
853
854 if (ipp_read(http, buffer, n) < n)
855 {
856 DEBUG_puts("ippRead: unable to read name!");
857 return (IPP_ERROR);
858 }
859
860 buffer[n] = '\0';
861 DEBUG_printf(("ippRead: name = \'%s\'\n", buffer));
862
863 attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES);
864
865 attr->group_tag = ipp->curtag;
866 attr->value_tag = tag;
867 attr->name = strdup((char *)buffer);
868 attr->num_values = 0;
869 }
870
871 if (ipp_read(http, buffer, 2) < 2)
872 {
873 DEBUG_puts("ippRead: unable to read value length!");
874 return (IPP_ERROR);
875 }
876
877 n = (buffer[0] << 8) | buffer[1];
878 DEBUG_printf(("ippRead: value length = %d\n", n));
879
880 switch (tag)
881 {
882 case IPP_TAG_INTEGER :
883 case IPP_TAG_ENUM :
884 if (ipp_read(http, buffer, 4) < 4)
885 return (IPP_ERROR);
886
887 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
888 buffer[3];
889
890 attr->values[attr->num_values].integer = n;
891 break;
892 case IPP_TAG_BOOLEAN :
893 if (ipp_read(http, buffer, 1) < 1)
894 return (IPP_ERROR);
895
896 attr->values[attr->num_values].boolean = buffer[0];
897 break;
898 case IPP_TAG_TEXT :
899 case IPP_TAG_NAME :
900 case IPP_TAG_KEYWORD :
901 case IPP_TAG_STRING :
902 case IPP_TAG_URI :
903 case IPP_TAG_URISCHEME :
904 case IPP_TAG_CHARSET :
905 case IPP_TAG_LANGUAGE :
906 case IPP_TAG_MIMETYPE :
907 if (ipp_read(http, buffer, n) < n)
908 return (IPP_ERROR);
909
910 buffer[n] = '\0';
911 DEBUG_printf(("ippRead: value = \'%s\'\n", buffer));
912
913 attr->values[attr->num_values].string.text = strdup((char *)buffer);
914 break;
915 case IPP_TAG_DATE :
916 if (ipp_read(http, buffer, 11) < 11)
917 return (IPP_ERROR);
918
919 memcpy(attr->values[attr->num_values].date, buffer, 11);
920 break;
921 case IPP_TAG_RESOLUTION :
922 if (ipp_read(http, buffer, 9) < 9)
923 return (IPP_ERROR);
924
925 attr->values[attr->num_values].resolution.xres =
926 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
927 buffer[3];
928 attr->values[attr->num_values].resolution.yres =
929 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
930 buffer[7];
931 attr->values[attr->num_values].resolution.units =
932 (ipp_res_t)buffer[8];
933 break;
934 case IPP_TAG_RANGE :
935 if (ipp_read(http, buffer, 8) < 8)
936 return (IPP_ERROR);
937
938 attr->values[attr->num_values].range.lower =
939 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
940 buffer[3];
941 attr->values[attr->num_values].range.upper =
942 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
943 buffer[7];
944 break;
945 case IPP_TAG_TEXTLANG :
946 case IPP_TAG_NAMELANG :
947 if (ipp_read(http, buffer, n) < n)
948 return (IPP_ERROR);
949
950 buffer[n] = '\0';
951
952 attr->values[attr->num_values].string.charset = strdup((char *)buffer);
953
954 if (ipp_read(http, buffer, 2) < 2)
955 return (IPP_ERROR);
956
957 n = (buffer[0] << 8) | buffer[1];
958
959 if (ipp_read(http, buffer, n) < n)
960 return (IPP_ERROR);
961
962 buffer[n] = '\0';
963
964 attr->values[attr->num_values].string.text = strdup((char *)buffer);
965 break;
966 }
967
968 attr->num_values ++;
969
970 /*
971 * If blocking is disabled, stop here...
972 */
973
974 if (!http->blocking && http->used == 0)
975 break;
976 }
977 break;
978
979 case IPP_DATA :
980 break;
981 }
982
983 return (ipp->state);
984 }
985
986
987 /*
988 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
989 */
990
991 const ipp_uchar_t * /* O - RFC-1903 date/time data */
992 ippTimeToDate(time_t t) /* I - UNIX time value */
993 {
994 struct tm *unixdate; /* UNIX unixdate/time info */
995 static ipp_uchar_t date[11]; /* RFC-1903 date/time data */
996
997
998 /*
999 * RFC-1903 date/time format is:
1000 *
1001 * Byte(s) Description
1002 * ------- -----------
1003 * 0-1 Year (0 to 65535)
1004 * 2 Month (1 to 12)
1005 * 3 Day (1 to 31)
1006 * 4 Hours (0 to 23)
1007 * 5 Minutes (0 to 59)
1008 * 6 Seconds (0 to 60, 60 = "leap second")
1009 * 7 Deciseconds (0 to 9)
1010 * 8 +/- UTC
1011 * 9 UTC hours (0 to 11)
1012 * 10 UTC minutes (0 to 59)
1013 */
1014
1015 unixdate = gmtime(&t);
1016 unixdate->tm_year += 1900;
1017
1018 date[0] = unixdate->tm_year >> 8;
1019 date[1] = unixdate->tm_year;
1020 date[2] = unixdate->tm_mon + 1;
1021 date[3] = unixdate->tm_mday;
1022 date[4] = unixdate->tm_hour;
1023 date[5] = unixdate->tm_min;
1024 date[6] = unixdate->tm_sec;
1025 date[7] = 0;
1026 date[8] = '+';
1027 date[9] = 0;
1028 date[10] = 0;
1029
1030 return (date);
1031 }
1032
1033
1034 /*
1035 * 'ippWrite()' - Write data for an IPP request.
1036 */
1037
1038 ipp_state_t /* O - Current state */
1039 ippWrite(http_t *http, /* I - HTTP data */
1040 ipp_t *ipp) /* I - IPP data */
1041 {
1042 int i; /* Looping var */
1043 int n; /* Length of data */
1044 unsigned char buffer[8192], /* Data buffer */
1045 *bufptr; /* Pointer into buffer */
1046 ipp_attribute_t *attr; /* Current attribute */
1047
1048
1049 if (http == NULL || ipp == NULL)
1050 return (IPP_ERROR);
1051
1052 switch (ipp->state)
1053 {
1054 case IPP_IDLE :
1055 ipp->state ++; /* Avoid common problem... */
1056
1057 case IPP_HEADER :
1058 /*
1059 * Send the request header...
1060 */
1061
1062 bufptr = buffer;
1063
1064 *bufptr++ = 1;
1065 *bufptr++ = 0;
1066 *bufptr++ = ipp->request.any.op_status >> 8;
1067 *bufptr++ = ipp->request.any.op_status;
1068 *bufptr++ = ipp->request.any.request_id >> 24;
1069 *bufptr++ = ipp->request.any.request_id >> 16;
1070 *bufptr++ = ipp->request.any.request_id >> 8;
1071 *bufptr++ = ipp->request.any.request_id;
1072
1073 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1074 {
1075 DEBUG_puts("ippWrite: Could not write IPP header...");
1076 return (IPP_ERROR);
1077 }
1078
1079 ipp->state = IPP_ATTRIBUTE;
1080 ipp->current = ipp->attrs;
1081 ipp->curtag = IPP_TAG_ZERO;
1082
1083 /*
1084 * If blocking is disabled, stop here...
1085 */
1086
1087 if (!http->blocking)
1088 break;
1089
1090 case IPP_ATTRIBUTE :
1091 while (ipp->current != NULL)
1092 {
1093 /*
1094 * Write this attribute...
1095 */
1096
1097 bufptr = buffer;
1098 attr = ipp->current;
1099
1100 ipp->current = ipp->current->next;
1101
1102 if (ipp->curtag != attr->group_tag)
1103 {
1104 /*
1105 * Send a group operation tag...
1106 */
1107
1108 ipp->curtag = attr->group_tag;
1109
1110 if (attr->group_tag == IPP_TAG_ZERO)
1111 continue;
1112
1113 DEBUG_printf(("ippWrite: wrote group tag = %x\n", attr->group_tag));
1114 *bufptr++ = attr->group_tag;
1115 }
1116
1117 n = strlen(attr->name);
1118
1119 DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag));
1120 DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n, attr->name));
1121
1122 *bufptr++ = attr->value_tag;
1123 *bufptr++ = n >> 8;
1124 *bufptr++ = n;
1125 memcpy(bufptr, attr->name, n);
1126 bufptr += n;
1127
1128 switch (attr->value_tag)
1129 {
1130 case IPP_TAG_INTEGER :
1131 case IPP_TAG_ENUM :
1132 for (i = 0; i < attr->num_values; i ++)
1133 {
1134 if (i)
1135 {
1136 /*
1137 * Arrays and sets are done by sending additional
1138 * values with a zero-length name...
1139 */
1140
1141 *bufptr++ = attr->value_tag;
1142 *bufptr++ = 0;
1143 *bufptr++ = 0;
1144 }
1145
1146 *bufptr++ = 0;
1147 *bufptr++ = 4;
1148 *bufptr++ = attr->values[i].integer >> 24;
1149 *bufptr++ = attr->values[i].integer >> 16;
1150 *bufptr++ = attr->values[i].integer >> 8;
1151 *bufptr++ = attr->values[i].integer;
1152 }
1153 break;
1154
1155 case IPP_TAG_BOOLEAN :
1156 for (i = 0; i < attr->num_values; i ++)
1157 {
1158 if (i)
1159 {
1160 /*
1161 * Arrays and sets are done by sending additional
1162 * values with a zero-length name...
1163 */
1164
1165 *bufptr++ = attr->value_tag;
1166 *bufptr++ = 0;
1167 *bufptr++ = 0;
1168 }
1169
1170 *bufptr++ = 0;
1171 *bufptr++ = 1;
1172 *bufptr++ = attr->values[i].boolean;
1173 }
1174 break;
1175
1176 case IPP_TAG_TEXT :
1177 case IPP_TAG_NAME :
1178 case IPP_TAG_KEYWORD :
1179 case IPP_TAG_STRING :
1180 case IPP_TAG_URI :
1181 case IPP_TAG_URISCHEME :
1182 case IPP_TAG_CHARSET :
1183 case IPP_TAG_LANGUAGE :
1184 case IPP_TAG_MIMETYPE :
1185 for (i = 0; i < attr->num_values; i ++)
1186 {
1187 if (i)
1188 {
1189 /*
1190 * Arrays and sets are done by sending additional
1191 * values with a zero-length name...
1192 */
1193
1194 DEBUG_printf(("ippWrite: writing value tag = %x\n",
1195 attr->value_tag));
1196 DEBUG_printf(("ippWrite: writing name = 0, \'\'\n"));
1197
1198 *bufptr++ = attr->value_tag;
1199 *bufptr++ = 0;
1200 *bufptr++ = 0;
1201 }
1202
1203 n = strlen(attr->values[i].string.text);
1204
1205 DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n,
1206 attr->values[i].string.text));
1207
1208 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
1209 {
1210 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1211 {
1212 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1213 return (IPP_ERROR);
1214 }
1215
1216 bufptr = buffer;
1217 }
1218
1219 *bufptr++ = n >> 8;
1220 *bufptr++ = n;
1221 memcpy(bufptr, attr->values[i].string.text, n);
1222 bufptr += n;
1223 }
1224 break;
1225
1226 case IPP_TAG_DATE :
1227 for (i = 0; i < attr->num_values; i ++)
1228 {
1229 if (i)
1230 {
1231 /*
1232 * Arrays and sets are done by sending additional
1233 * values with a zero-length name...
1234 */
1235
1236 *bufptr++ = attr->value_tag;
1237 *bufptr++ = 0;
1238 *bufptr++ = 0;
1239 }
1240
1241 *bufptr++ = 0;
1242 *bufptr++ = 11;
1243 memcpy(bufptr, attr->values[i].date, 11);
1244 bufptr += 11;
1245 }
1246 break;
1247
1248 case IPP_TAG_RESOLUTION :
1249 for (i = 0; i < attr->num_values; i ++)
1250 {
1251 if (i)
1252 {
1253 /*
1254 * Arrays and sets are done by sending additional
1255 * values with a zero-length name...
1256 */
1257
1258 *bufptr++ = attr->value_tag;
1259 *bufptr++ = 0;
1260 *bufptr++ = 0;
1261 }
1262
1263 *bufptr++ = 0;
1264 *bufptr++ = 9;
1265 *bufptr++ = attr->values[i].resolution.xres >> 24;
1266 *bufptr++ = attr->values[i].resolution.xres >> 16;
1267 *bufptr++ = attr->values[i].resolution.xres >> 8;
1268 *bufptr++ = attr->values[i].resolution.xres;
1269 *bufptr++ = attr->values[i].resolution.yres >> 24;
1270 *bufptr++ = attr->values[i].resolution.yres >> 16;
1271 *bufptr++ = attr->values[i].resolution.yres >> 8;
1272 *bufptr++ = attr->values[i].resolution.yres;
1273 *bufptr++ = attr->values[i].resolution.units;
1274 }
1275 break;
1276
1277 case IPP_TAG_RANGE :
1278 for (i = 0; i < attr->num_values; i ++)
1279 {
1280 if (i)
1281 {
1282 /*
1283 * Arrays and sets are done by sending additional
1284 * values with a zero-length name...
1285 */
1286
1287 *bufptr++ = attr->value_tag;
1288 *bufptr++ = 0;
1289 *bufptr++ = 0;
1290 }
1291
1292 *bufptr++ = 0;
1293 *bufptr++ = 8;
1294 *bufptr++ = attr->values[i].range.lower >> 24;
1295 *bufptr++ = attr->values[i].range.lower >> 16;
1296 *bufptr++ = attr->values[i].range.lower >> 8;
1297 *bufptr++ = attr->values[i].range.lower;
1298 *bufptr++ = attr->values[i].range.upper >> 24;
1299 *bufptr++ = attr->values[i].range.upper >> 16;
1300 *bufptr++ = attr->values[i].range.upper >> 8;
1301 *bufptr++ = attr->values[i].range.upper;
1302 }
1303 break;
1304
1305 case IPP_TAG_TEXTLANG :
1306 case IPP_TAG_NAMELANG :
1307 for (i = 0; i < attr->num_values; i ++)
1308 {
1309 if (i)
1310 {
1311 /*
1312 * Arrays and sets are done by sending additional
1313 * values with a zero-length name...
1314 */
1315
1316 *bufptr++ = attr->value_tag;
1317 *bufptr++ = 0;
1318 *bufptr++ = 0;
1319 }
1320
1321 n = strlen(attr->values[i].string.charset);
1322
1323 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
1324 {
1325 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1326 {
1327 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1328 return (IPP_ERROR);
1329 }
1330
1331 bufptr = buffer;
1332 }
1333
1334 *bufptr++ = n >> 8;
1335 *bufptr++ = n;
1336 memcpy(bufptr, attr->values[i].string.charset, n);
1337 bufptr += n;
1338
1339 n = strlen(attr->values[i].string.text);
1340
1341 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
1342 {
1343 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1344 {
1345 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1346 return (IPP_ERROR);
1347 }
1348
1349 bufptr = buffer;
1350 }
1351
1352 *bufptr++ = n >> 8;
1353 *bufptr++ = n;
1354 memcpy(bufptr, attr->values[i].string.text, n);
1355 bufptr += n;
1356 }
1357 break;
1358 }
1359
1360 /*
1361 * Write the data out...
1362 */
1363
1364 if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0)
1365 {
1366 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1367 return (IPP_ERROR);
1368 }
1369
1370 DEBUG_printf(("ippWrite: wrote %d bytes\n", bufptr - buffer));
1371
1372 /*
1373 * If blocking is disabled, stop here...
1374 */
1375
1376 if (!http->blocking)
1377 break;
1378 }
1379
1380 if (ipp->current == NULL)
1381 {
1382 /*
1383 * Done with all of the attributes; add the end-of-attributes tag...
1384 */
1385
1386 buffer[0] = IPP_TAG_END;
1387 if (httpWrite(http, (char *)buffer, 1) < 0)
1388 {
1389 DEBUG_puts("ippWrite: Could not write IPP end-tag...");
1390 return (IPP_ERROR);
1391 }
1392
1393 ipp->state = IPP_DATA;
1394 }
1395 break;
1396
1397 case IPP_DATA :
1398 break;
1399 }
1400
1401 return (ipp->state);
1402 }
1403
1404
1405 /*
1406 * 'ippPort()' - Return the default IPP port number.
1407 */
1408
1409 int /* O - Port number */
1410 ippPort(void)
1411 {
1412 const char *server_port; /* SERVER_PORT environment variable */
1413 struct servent *port; /* Port number info */
1414
1415
1416 if ((server_port = getenv("IPP_PORT")) != NULL)
1417 return (atoi(server_port));
1418 else if ((port = getservbyname("ipp", NULL)) == NULL)
1419 return (IPP_PORT);
1420 else
1421 return (ntohs(port->s_port));
1422 }
1423
1424
1425 /*
1426 * '_ipp_add_attr()' - Add a new attribute to the request.
1427 */
1428
1429 ipp_attribute_t * /* O - New attribute */
1430 _ipp_add_attr(ipp_t *ipp, /* I - IPP request */
1431 int num_values) /* I - Number of values */
1432 {
1433 ipp_attribute_t *attr; /* New attribute */
1434
1435
1436 DEBUG_printf(("_ipp_add_attr(%08x, %d)\n", ipp, num_values));
1437
1438 if (ipp == NULL || num_values < 0)
1439 return (NULL);
1440
1441 attr = calloc(sizeof(ipp_attribute_t) +
1442 (num_values - 1) * sizeof(ipp_value_t), 1);
1443
1444 attr->num_values = num_values;
1445
1446 if (attr == NULL)
1447 return (NULL);
1448
1449 if (ipp->last == NULL)
1450 ipp->attrs = attr;
1451 else
1452 ipp->last->next = attr;
1453
1454 ipp->last = attr;
1455
1456 return (attr);
1457 }
1458
1459
1460 /*
1461 * 'ipp_read()' - Semi-blocking read on a HTTP connection...
1462 */
1463
1464 static int /* O - Number of bytes read */
1465 ipp_read(http_t *http, /* I - Client connection */
1466 unsigned char *buffer, /* O - Buffer for data */
1467 int length) /* I - Total length */
1468 {
1469 int tbytes, /* Total bytes read */
1470 bytes; /* Bytes read this pass */
1471
1472
1473 /*
1474 * Loop until all bytes are read...
1475 */
1476
1477 for (tbytes = 0; tbytes < length; tbytes += bytes, buffer += bytes)
1478 if ((bytes = httpRead(http, (char *)buffer, length - tbytes)) <= 0)
1479 break;
1480
1481 /*
1482 * Return the number of bytes read...
1483 */
1484
1485 return (tbytes);
1486 }
1487
1488
1489 /*
1490 * End of "$Id: ipp.c,v 1.30 2000/01/04 13:45:35 mike Exp $".
1491 */