]>
Commit | Line | Data |
---|---|---|
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 | ||
76 | static int ipp_port = 0; | |
77 | ||
78 | ||
dec2f757 | 79 | /* |
3a193f5e | 80 | * Local functions... |
81 | */ | |
82 | ||
e09246c8 | 83 | static 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 | ||
90 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 91 | ippAddBoolean(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 | ||
120 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 121 | ippAddBooleans(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 | ||
159 | ipp_attribute_t * /* O - New attribute */ | |
3dab5e3b | 160 | ippAddDate(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 | ||
190 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 191 | ippAddInteger(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 | ||
222 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 223 | ippAddIntegers(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 | ||
259 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 260 | ippAddString(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 | ||
309 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 310 | ippAddStrings(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 | 356 | ipp_attribute_t * /* O - New attribute */ |
063e1ac7 | 357 | ippAddRange(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 | ||
386 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 387 | ippAddRanges(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 | ||
426 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 427 | ippAddResolution(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 | ||
458 | ipp_attribute_t * /* O - New attribute */ | |
063e1ac7 | 459 | ippAddResolutions(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 | ||
500 | ipp_attribute_t * /* O - New attribute */ | |
501 | ippAddSeparator(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 | 526 | time_t /* O - UNIX time value */ |
527 | ippDateToTime(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 | 574 | void |
50146867 | 575 | ippDelete(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 | ||
600 | const char * /* O - Text string */ | |
601 | ippErrorString(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 | 684 | ipp_attribute_t * /* O - Matching attribute */ |
063e1ac7 | 685 | ippFindAttribute(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 | ||
712 | ipp_attribute_t * /* O - Matching attribute */ | |
713 | ippFindNextAttribute(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 | 759 | size_t /* O - Size of IPP request */ |
760 | ippLength(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 | 874 | ipp_t * /* O - New IPP request */ |
875 | ippNew(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 | 900 | ipp_state_t /* O - Current state */ |
901 | ippRead(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 | 1254 | const ipp_uchar_t * /* O - RFC-1903 date/time data */ |
7551914d | 1255 | ippTimeToDate(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 | 1301 | ipp_state_t /* O - Current state */ |
1302 | ippWrite(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 | 1836 | int /* O - Port number */ |
4a73831b | 1837 | ippPort(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 | ||
1858 | void | |
1859 | ippSetPort(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 | 1869 | ipp_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 | ||
1906 | void | |
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 | 1959 | static int /* O - Number of bytes read */ |
1960 | ipp_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 | */ |