2 * "$Id: ipp.c,v 1.30 2000/01/04 13:45:35 mike Exp $"
4 * Internet Printing Protocol support functions for the Common UNIX
5 * Printing System (CUPS).
7 * Copyright 1997-2000 by Easy Software Products, all rights reserved.
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
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636-3111 USA
21 * Voice: (301) 373-9603
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
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...
52 * Include necessary headers...
67 static int ipp_read(http_t
*http
, unsigned char *buffer
, int length
);
71 * 'ippAddBoolean()' - Add a boolean attribute to an IPP request.
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 */
80 ipp_attribute_t
*attr
; /* New attribute */
83 DEBUG_printf(("ippAddBoolean(%08x, %02x, \'%s\', %d)\n", ipp
, group
, name
, value
));
85 if (ipp
== NULL
|| name
== NULL
)
88 if ((attr
= _ipp_add_attr(ipp
, 1)) == NULL
)
91 attr
->name
= strdup(name
);
92 attr
->group_tag
= group
;
93 attr
->value_tag
= IPP_TAG_BOOLEAN
;
94 attr
->values
[0].boolean
= value
;
101 * 'ippAddBooleans()' - Add an array of boolean values.
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 */
111 int i
; /* Looping var */
112 ipp_attribute_t
*attr
; /* New attribute */
115 DEBUG_printf(("ippAddBooleans(%08x, %02x, \'%s\', %d, %08x)\n", ipp
,
116 group
, name
, num_values
, values
));
118 if (ipp
== NULL
|| name
== NULL
)
121 if ((attr
= _ipp_add_attr(ipp
, num_values
)) == NULL
)
124 attr
->name
= strdup(name
);
125 attr
->group_tag
= group
;
126 attr
->value_tag
= IPP_TAG_BOOLEAN
;
129 for (i
= 0; i
< num_values
; i
++)
130 attr
->values
[i
].boolean
= values
[i
];
137 * 'ippAddDate()' - Add a date attribute to an IPP request.
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 */
146 ipp_attribute_t
*attr
; /* New attribute */
149 DEBUG_printf(("ippAddDate(%08x, %02x, \'%s\', %08x)\n", ipp
, group
, name
,
152 if (ipp
== NULL
|| name
== NULL
|| value
== NULL
)
155 if ((attr
= _ipp_add_attr(ipp
, 1)) == NULL
)
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);
168 * 'ippAddInteger()' - Add a integer attribute to an IPP request.
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 */
178 ipp_attribute_t
*attr
; /* New attribute */
181 DEBUG_printf(("ippAddInteger(%08x, %d, \'%s\', %d)\n", ipp
, group
, name
,
184 if (ipp
== NULL
|| name
== NULL
)
187 if ((attr
= _ipp_add_attr(ipp
, 1)) == NULL
)
190 attr
->name
= strdup(name
);
191 attr
->group_tag
= group
;
192 attr
->value_tag
= type
;
193 attr
->values
[0].integer
= value
;
200 * 'ippAddIntegers()' - Add an array of integer values.
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 */
211 int i
; /* Looping var */
212 ipp_attribute_t
*attr
; /* New attribute */
215 if (ipp
== NULL
|| name
== NULL
)
218 if ((attr
= _ipp_add_attr(ipp
, num_values
)) == NULL
)
221 attr
->name
= strdup(name
);
222 attr
->group_tag
= group
;
223 attr
->value_tag
= type
;
226 for (i
= 0; i
< num_values
; i
++)
227 attr
->values
[i
].integer
= values
[i
];
234 * 'ippAddString()' - Add a language-encoded string to an IPP request.
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 */
245 ipp_attribute_t
*attr
; /* New attribute */
248 if (ipp
== NULL
|| name
== NULL
)
251 if ((attr
= _ipp_add_attr(ipp
, 1)) == NULL
)
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
);
265 * 'ippAddStrings()' - Add language-encoded strings to an IPP request.
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 */
277 int i
; /* Looping var */
278 ipp_attribute_t
*attr
; /* New attribute */
281 if (ipp
== NULL
|| name
== NULL
)
284 if ((attr
= _ipp_add_attr(ipp
, num_values
)) == NULL
)
287 attr
->name
= strdup(name
);
288 attr
->group_tag
= group
;
289 attr
->value_tag
= type
;
292 for (i
= 0; i
< num_values
; i
++)
295 attr
->values
[0].string
.charset
= charset
? strdup(charset
) : NULL
;
297 attr
->values
[i
].string
.charset
= attr
->values
[0].string
.charset
;
299 attr
->values
[i
].string
.text
= strdup(values
[i
]);
307 * 'ippAddRange()' - Add a range of values to an IPP request.
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 */
317 ipp_attribute_t
*attr
; /* New attribute */
320 if (ipp
== NULL
|| name
== NULL
)
323 if ((attr
= _ipp_add_attr(ipp
, 1)) == NULL
)
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
;
337 * 'ippAddRanges()' - Add ranges of values to an IPP request.
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 */
348 int i
; /* Looping var */
349 ipp_attribute_t
*attr
; /* New attribute */
352 if (ipp
== NULL
|| name
== NULL
)
355 if ((attr
= _ipp_add_attr(ipp
, num_values
)) == NULL
)
358 attr
->name
= strdup(name
);
359 attr
->group_tag
= group
;
360 attr
->value_tag
= IPP_TAG_RANGE
;
362 if (lower
!= NULL
&& upper
!= NULL
)
363 for (i
= 0; i
< num_values
; i
++)
365 attr
->values
[i
].range
.lower
= lower
[i
];
366 attr
->values
[i
].range
.upper
= upper
[i
];
374 * 'ippAddResolution()' - Add a resolution value to an IPP request.
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 */
385 ipp_attribute_t
*attr
; /* New attribute */
388 if (ipp
== NULL
|| name
== NULL
)
391 if ((attr
= _ipp_add_attr(ipp
, 1)) == NULL
)
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
;
406 * 'ippAddResolutions()' - Add resolution values to an IPP request.
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 */
418 int i
; /* Looping var */
419 ipp_attribute_t
*attr
; /* New attribute */
422 if (ipp
== NULL
|| name
== NULL
)
425 if ((attr
= _ipp_add_attr(ipp
, num_values
)) == NULL
)
428 attr
->name
= strdup(name
);
429 attr
->group_tag
= group
;
430 attr
->value_tag
= IPP_TAG_RESOLUTION
;
432 if (xres
!= NULL
&& yres
!= NULL
)
433 for (i
= 0; i
< num_values
; i
++)
435 attr
->values
[i
].resolution
.xres
= xres
[i
];
436 attr
->values
[i
].resolution
.yres
= yres
[i
];
437 attr
->values
[i
].resolution
.units
= units
;
445 * 'ippAddSeparator()' - Add a group separator to an IPP request.
448 ipp_attribute_t
* /* O - New attribute */
449 ippAddSeparator(ipp_t
*ipp
) /* I - IPP request */
451 ipp_attribute_t
*attr
; /* New attribute */
454 DEBUG_printf(("ippAddSeparator(%08x)\n", ipp
));
459 if ((attr
= _ipp_add_attr(ipp
, 0)) == NULL
)
462 attr
->group_tag
= IPP_TAG_ZERO
;
463 attr
->value_tag
= IPP_TAG_ZERO
;
470 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
474 time_t /* O - UNIX time value */
475 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
477 struct tm unixdate
; /* UNIX date/time info */
478 time_t t
; /* Computed time */
481 memset(&unixdate
, 0, sizeof(unixdate
));
484 * RFC-1903 date/time format is:
486 * Byte(s) Description
487 * ------- -----------
488 * 0-1 Year (0 to 65535)
492 * 5 Minutes (0 to 59)
493 * 6 Seconds (0 to 60, 60 = "leap second")
494 * 7 Deciseconds (0 to 9)
496 * 9 UTC hours (0 to 11)
497 * 10 UTC minutes (0 to 59)
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];
507 t
= mktime(&unixdate
);
510 t
+= date
[9] * 3600 + date
[10] * 60;
512 t
-= date
[9] * 3600 + date
[10] * 60;
519 * 'ippDelete()' - Delete an IPP request.
523 ippDelete(ipp_t
*ipp
) /* I - IPP request */
525 int i
; /* Looping var */
526 ipp_attribute_t
*attr
, /* Current attribute */
527 *next
; /* Next attribute */
533 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
535 switch (attr
->value_tag
)
539 case IPP_TAG_KEYWORD
:
540 case IPP_TAG_STRING
:
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
);
550 case IPP_TAG_TEXTLANG
:
551 case IPP_TAG_NAMELANG
:
552 for (i
= 0; i
< attr
->num_values
; i
++)
554 if (attr
->values
[i
].string
.charset
)
555 free(attr
->values
[i
].string
.charset
);
556 free(attr
->values
[i
].string
.text
);
563 if (attr
->name
!= NULL
)
574 * 'ippFindAttribute()' - Find a named attribute in a request...
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 */
582 ipp_attribute_t
*attr
; /* Current atttribute */
585 DEBUG_printf(("ippFindAttribute(%08x, \'%s\')\n", ipp
, name
));
587 if (ipp
== NULL
|| name
== NULL
)
590 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
592 DEBUG_printf(("ippFindAttribute: attr = %08x, name = \'%s\'\n", attr
,
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
)))
607 * 'ippLength()' - Compute the length of an IPP request.
610 size_t /* O - Size of IPP request */
611 ippLength(ipp_t
*ipp
) /* I - IPP request */
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 */
623 * Start with 8 bytes for the IPP request or status header...
629 * Then add the lengths of each attribute...
632 group
= IPP_TAG_ZERO
;
634 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
636 if (attr
->group_tag
!= group
)
638 group
= attr
->group_tag
;
639 if (group
== IPP_TAG_ZERO
)
642 bytes
++; /* Group tag */
645 DEBUG_printf(("attr->name = %s, attr->num_values = %d, bytes = %d\n",
646 attr
->name
, attr
->num_values
, bytes
));
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 */
653 switch (attr
->value_tag
)
655 case IPP_TAG_INTEGER
:
657 bytes
+= 4 * attr
->num_values
;
660 case IPP_TAG_BOOLEAN
:
661 bytes
+= attr
->num_values
;
666 case IPP_TAG_KEYWORD
:
667 case IPP_TAG_STRING
:
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
);
678 bytes
+= 11 * attr
->num_values
;
681 case IPP_TAG_RESOLUTION
:
682 bytes
+= 9 * attr
->num_values
;
686 bytes
+= 8 * attr
->num_values
;
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
);
700 * Finally, add 1 byte for the "end of attributes" tag and return...
703 DEBUG_printf(("bytes = %d\n", bytes
+ 1));
709 ipp_t
* /* O - New IPP request */
712 return ((ipp_t
*)calloc(sizeof(ipp_t
), 1));
717 * 'ippRead()' - Read data for an IPP request.
720 ipp_state_t
/* O - Current state */
721 ippRead(http_t
*http
, /* I - HTTP data */
722 ipp_t
*ipp
) /* I - IPP data */
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 */
730 DEBUG_printf(("ippRead(%08x, %08x)\n", http
, ipp
));
732 if (http
== NULL
|| ipp
== NULL
)
738 ipp
->state
++; /* Avoid common problem... */
742 * Get the request header...
745 if ((n
= ipp_read(http
, buffer
, 8)) < 8)
747 DEBUG_printf(("ippRead: Unable to read header (%d bytes read)!\n", n
));
748 return (n
== 0 ? IPP_IDLE
: IPP_ERROR
);
752 * Verify the major version number...
757 DEBUG_printf(("ippRead: version number (%d.%d) is bad.\n", buffer
[0],
763 * Then copy the request header over...
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];
772 ipp
->state
= IPP_ATTRIBUTE
;
774 ipp
->curtag
= IPP_TAG_ZERO
;
777 * If blocking is disabled, stop here...
780 if (!http
->blocking
&& http
->used
== 0)
784 while (ipp_read(http
, buffer
, 1) > 0)
787 * Read this attribute...
790 tag
= (ipp_tag_t
)buffer
[0];
792 if (tag
== IPP_TAG_END
)
795 * No more attributes left...
798 DEBUG_puts("ippRead: IPP_TAG_END!");
800 ipp
->state
= IPP_DATA
;
803 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
806 * Group tag... Set the current group and continue...
809 if (ipp
->curtag
== tag
)
810 ippAddSeparator(ipp
);
814 DEBUG_printf(("ippRead: group tag = %x\n", tag
));
818 DEBUG_printf(("ippRead: value tag = %x\n", tag
));
824 if (ipp_read(http
, buffer
, 2) < 2)
826 DEBUG_puts("ippRead: unable to read name length!");
830 n
= (buffer
[0] << 8) | buffer
[1];
832 DEBUG_printf(("ippRead: name length = %d\n", n
));
837 * More values for current attribute...
840 if (ipp
->current
== NULL
)
845 if (attr
->num_values
>= IPP_MAX_VALUES
)
851 * New attribute; read the name and add it...
854 if (ipp_read(http
, buffer
, n
) < n
)
856 DEBUG_puts("ippRead: unable to read name!");
861 DEBUG_printf(("ippRead: name = \'%s\'\n", buffer
));
863 attr
= ipp
->current
= _ipp_add_attr(ipp
, IPP_MAX_VALUES
);
865 attr
->group_tag
= ipp
->curtag
;
866 attr
->value_tag
= tag
;
867 attr
->name
= strdup((char *)buffer
);
868 attr
->num_values
= 0;
871 if (ipp_read(http
, buffer
, 2) < 2)
873 DEBUG_puts("ippRead: unable to read value length!");
877 n
= (buffer
[0] << 8) | buffer
[1];
878 DEBUG_printf(("ippRead: value length = %d\n", n
));
882 case IPP_TAG_INTEGER
:
884 if (ipp_read(http
, buffer
, 4) < 4)
887 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
890 attr
->values
[attr
->num_values
].integer
= n
;
892 case IPP_TAG_BOOLEAN
:
893 if (ipp_read(http
, buffer
, 1) < 1)
896 attr
->values
[attr
->num_values
].boolean
= buffer
[0];
900 case IPP_TAG_KEYWORD
:
901 case IPP_TAG_STRING
:
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
)
911 DEBUG_printf(("ippRead: value = \'%s\'\n", buffer
));
913 attr
->values
[attr
->num_values
].string
.text
= strdup((char *)buffer
);
916 if (ipp_read(http
, buffer
, 11) < 11)
919 memcpy(attr
->values
[attr
->num_values
].date
, buffer
, 11);
921 case IPP_TAG_RESOLUTION
:
922 if (ipp_read(http
, buffer
, 9) < 9)
925 attr
->values
[attr
->num_values
].resolution
.xres
=
926 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
928 attr
->values
[attr
->num_values
].resolution
.yres
=
929 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
931 attr
->values
[attr
->num_values
].resolution
.units
=
932 (ipp_res_t
)buffer
[8];
935 if (ipp_read(http
, buffer
, 8) < 8)
938 attr
->values
[attr
->num_values
].range
.lower
=
939 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
941 attr
->values
[attr
->num_values
].range
.upper
=
942 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
945 case IPP_TAG_TEXTLANG
:
946 case IPP_TAG_NAMELANG
:
947 if (ipp_read(http
, buffer
, n
) < n
)
952 attr
->values
[attr
->num_values
].string
.charset
= strdup((char *)buffer
);
954 if (ipp_read(http
, buffer
, 2) < 2)
957 n
= (buffer
[0] << 8) | buffer
[1];
959 if (ipp_read(http
, buffer
, n
) < n
)
964 attr
->values
[attr
->num_values
].string
.text
= strdup((char *)buffer
);
971 * If blocking is disabled, stop here...
974 if (!http
->blocking
&& http
->used
== 0)
988 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
991 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
992 ippTimeToDate(time_t t
) /* I - UNIX time value */
994 struct tm
*unixdate
; /* UNIX unixdate/time info */
995 static ipp_uchar_t date
[11]; /* RFC-1903 date/time data */
999 * RFC-1903 date/time format is:
1001 * Byte(s) Description
1002 * ------- -----------
1003 * 0-1 Year (0 to 65535)
1007 * 5 Minutes (0 to 59)
1008 * 6 Seconds (0 to 60, 60 = "leap second")
1009 * 7 Deciseconds (0 to 9)
1011 * 9 UTC hours (0 to 11)
1012 * 10 UTC minutes (0 to 59)
1015 unixdate
= gmtime(&t
);
1016 unixdate
->tm_year
+= 1900;
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
;
1035 * 'ippWrite()' - Write data for an IPP request.
1038 ipp_state_t
/* O - Current state */
1039 ippWrite(http_t
*http
, /* I - HTTP data */
1040 ipp_t
*ipp
) /* I - IPP data */
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 */
1049 if (http
== NULL
|| ipp
== NULL
)
1055 ipp
->state
++; /* Avoid common problem... */
1059 * Send the request header...
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
;
1073 if (httpWrite(http
, (char *)buffer
, bufptr
- buffer
) < 0)
1075 DEBUG_puts("ippWrite: Could not write IPP header...");
1079 ipp
->state
= IPP_ATTRIBUTE
;
1080 ipp
->current
= ipp
->attrs
;
1081 ipp
->curtag
= IPP_TAG_ZERO
;
1084 * If blocking is disabled, stop here...
1087 if (!http
->blocking
)
1090 case IPP_ATTRIBUTE
:
1091 while (ipp
->current
!= NULL
)
1094 * Write this attribute...
1098 attr
= ipp
->current
;
1100 ipp
->current
= ipp
->current
->next
;
1102 if (ipp
->curtag
!= attr
->group_tag
)
1105 * Send a group operation tag...
1108 ipp
->curtag
= attr
->group_tag
;
1110 if (attr
->group_tag
== IPP_TAG_ZERO
)
1113 DEBUG_printf(("ippWrite: wrote group tag = %x\n", attr
->group_tag
));
1114 *bufptr
++ = attr
->group_tag
;
1117 n
= strlen(attr
->name
);
1119 DEBUG_printf(("ippWrite: writing value tag = %x\n", attr
->value_tag
));
1120 DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n
, attr
->name
));
1122 *bufptr
++ = attr
->value_tag
;
1125 memcpy(bufptr
, attr
->name
, n
);
1128 switch (attr
->value_tag
)
1130 case IPP_TAG_INTEGER
:
1132 for (i
= 0; i
< attr
->num_values
; i
++)
1137 * Arrays and sets are done by sending additional
1138 * values with a zero-length name...
1141 *bufptr
++ = attr
->value_tag
;
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
;
1155 case IPP_TAG_BOOLEAN
:
1156 for (i
= 0; i
< attr
->num_values
; i
++)
1161 * Arrays and sets are done by sending additional
1162 * values with a zero-length name...
1165 *bufptr
++ = attr
->value_tag
;
1172 *bufptr
++ = attr
->values
[i
].boolean
;
1178 case IPP_TAG_KEYWORD
:
1179 case IPP_TAG_STRING
:
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
++)
1190 * Arrays and sets are done by sending additional
1191 * values with a zero-length name...
1194 DEBUG_printf(("ippWrite: writing value tag = %x\n",
1196 DEBUG_printf(("ippWrite: writing name = 0, \'\'\n"));
1198 *bufptr
++ = attr
->value_tag
;
1203 n
= strlen(attr
->values
[i
].string
.text
);
1205 DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n
,
1206 attr
->values
[i
].string
.text
));
1208 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
1210 if (httpWrite(http
, (char *)buffer
, bufptr
- buffer
) < 0)
1212 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1221 memcpy(bufptr
, attr
->values
[i
].string
.text
, n
);
1227 for (i
= 0; i
< attr
->num_values
; i
++)
1232 * Arrays and sets are done by sending additional
1233 * values with a zero-length name...
1236 *bufptr
++ = attr
->value_tag
;
1243 memcpy(bufptr
, attr
->values
[i
].date
, 11);
1248 case IPP_TAG_RESOLUTION
:
1249 for (i
= 0; i
< attr
->num_values
; i
++)
1254 * Arrays and sets are done by sending additional
1255 * values with a zero-length name...
1258 *bufptr
++ = attr
->value_tag
;
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
;
1277 case IPP_TAG_RANGE
:
1278 for (i
= 0; i
< attr
->num_values
; i
++)
1283 * Arrays and sets are done by sending additional
1284 * values with a zero-length name...
1287 *bufptr
++ = attr
->value_tag
;
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
;
1305 case IPP_TAG_TEXTLANG
:
1306 case IPP_TAG_NAMELANG
:
1307 for (i
= 0; i
< attr
->num_values
; i
++)
1312 * Arrays and sets are done by sending additional
1313 * values with a zero-length name...
1316 *bufptr
++ = attr
->value_tag
;
1321 n
= strlen(attr
->values
[i
].string
.charset
);
1323 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
1325 if (httpWrite(http
, (char *)buffer
, bufptr
- buffer
) < 0)
1327 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1336 memcpy(bufptr
, attr
->values
[i
].string
.charset
, n
);
1339 n
= strlen(attr
->values
[i
].string
.text
);
1341 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
1343 if (httpWrite(http
, (char *)buffer
, bufptr
- buffer
) < 0)
1345 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1354 memcpy(bufptr
, attr
->values
[i
].string
.text
, n
);
1361 * Write the data out...
1364 if (httpWrite(http
, (char *)buffer
, bufptr
- buffer
) < 0)
1366 DEBUG_puts("ippWrite: Could not write IPP attribute...");
1370 DEBUG_printf(("ippWrite: wrote %d bytes\n", bufptr
- buffer
));
1373 * If blocking is disabled, stop here...
1376 if (!http
->blocking
)
1380 if (ipp
->current
== NULL
)
1383 * Done with all of the attributes; add the end-of-attributes tag...
1386 buffer
[0] = IPP_TAG_END
;
1387 if (httpWrite(http
, (char *)buffer
, 1) < 0)
1389 DEBUG_puts("ippWrite: Could not write IPP end-tag...");
1393 ipp
->state
= IPP_DATA
;
1401 return (ipp
->state
);
1406 * 'ippPort()' - Return the default IPP port number.
1409 int /* O - Port number */
1412 const char *server_port
; /* SERVER_PORT environment variable */
1413 struct servent
*port
; /* Port number info */
1416 if ((server_port
= getenv("IPP_PORT")) != NULL
)
1417 return (atoi(server_port
));
1418 else if ((port
= getservbyname("ipp", NULL
)) == NULL
)
1421 return (ntohs(port
->s_port
));
1426 * '_ipp_add_attr()' - Add a new attribute to the request.
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 */
1433 ipp_attribute_t
*attr
; /* New attribute */
1436 DEBUG_printf(("_ipp_add_attr(%08x, %d)\n", ipp
, num_values
));
1438 if (ipp
== NULL
|| num_values
< 0)
1441 attr
= calloc(sizeof(ipp_attribute_t
) +
1442 (num_values
- 1) * sizeof(ipp_value_t
), 1);
1444 attr
->num_values
= num_values
;
1449 if (ipp
->last
== NULL
)
1452 ipp
->last
->next
= attr
;
1461 * 'ipp_read()' - Semi-blocking read on a HTTP connection...
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 */
1469 int tbytes
, /* Total bytes read */
1470 bytes
; /* Bytes read this pass */
1474 * Loop until all bytes are read...
1477 for (tbytes
= 0; tbytes
< length
; tbytes
+= bytes
, buffer
+= bytes
)
1478 if ((bytes
= httpRead(http
, (char *)buffer
, length
- tbytes
)) <= 0)
1482 * Return the number of bytes read...
1490 * End of "$Id: ipp.c,v 1.30 2000/01/04 13:45:35 mike Exp $".