2 * "$Id: ipp-support.c 9371 2010-11-17 06:21:32Z mike $"
4 * Internet Printing Protocol support functions for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * _ippAttrString() - Convert the attribute's value to a string.
20 * ippErrorString() - Return a name for the given status code.
21 * ippErrorValue() - Return a status code for the given name.
22 * ippOpString() - Return a name for the given operation id.
23 * ippOpValue() - Return an operation id for the given name.
24 * ippPort() - Return the default IPP port number.
25 * ippSetPort() - Set the default port number.
26 * ippTagString() - Return the tag name corresponding to a tag value.
27 * ippTagValue() - Return the tag value corresponding to a tag name.
28 * ipp_col_string() - Convert a collection to a string.
32 * Include necessary headers...
35 #include "cups-private.h"
42 static const char * const ipp_status_oks
[] = /* "OK" status codes */
45 "successful-ok-ignored-or-substituted-attributes",
46 "successful-ok-conflicting-attributes",
47 "successful-ok-ignored-subscriptions",
48 "successful-ok-ignored-notifications",
49 "successful-ok-too-many-events",
50 "successful-ok-but-cancel-subscription",
51 "successful-ok-events-complete"
53 * const ipp_status_400s
[] = /* Client errors */
55 "client-error-bad-request",
56 "client-error-forbidden",
57 "client-error-not-authenticated",
58 "client-error-not-authorized",
59 "client-error-not-possible",
60 "client-error-timeout",
61 "client-error-not-found",
63 "client-error-request-entity-too-large",
64 "client-error-request-value-too-long",
65 "client-error-document-format-not-supported",
66 "client-error-attributes-or-values-not-supported",
67 "client-error-uri-scheme-not-supported",
68 "client-error-charset-not-supported",
69 "client-error-conflicting-attributes",
70 "client-error-compression-not-supported",
71 "client-error-compression-error",
72 "client-error-document-format-error",
73 "client-error-document-access-error",
74 "client-error-attributes-not-settable",
75 "client-error-ignored-all-subscriptions",
76 "client-error-too-many-subscriptions",
77 "client-error-ignored-all-notifications",
78 "client-error-print-support-file-not-found"
80 * const ipp_status_500s
[] = /* Server errors */
82 "server-error-internal-error",
83 "server-error-operation-not-supported",
84 "server-error-service-unavailable",
85 "server-error-version-not-supported",
86 "server-error-device-error",
87 "server-error-temporary-error",
88 "server-error-not-accepting-jobs",
90 "server-error-job-canceled",
91 "server-error-multiple-document-jobs-not-supported",
92 "server-error-printer-is-deactivated"
94 * const ipp_status_1000s
[] = /* CUPS internal */
96 "cups-authorization-canceled",
98 "cups-upgrade-required"
100 static char * const ipp_std_ops
[] =
102 /* 0x0000 - 0x000f */
112 "Get-Job-Attributes",
114 "Get-Printer-Attributes",
120 /* 0x0010 - 0x001f */
124 "Set-Printer-Attributes",
125 "Set-Job-Attributes",
126 "Get-Printer-Supported-Values",
127 "Create-Printer-Subscription",
128 "Create-Job-Subscription",
129 "Get-Subscription-Attributes",
131 "Renew-Subscription",
132 "Cancel-Subscription",
134 "Send-Notifications",
138 /* 0x0020 - 0x002f */
140 "Get-Printer-Support-Files",
143 "Pause-Printer-After-Current-Job",
145 "Release-Held-New-Jobs",
146 "Deactivate-Printer",
152 "Cancel-Current-Job",
153 "Suspend-Current-Job",
156 /* 0x0030 - 0x003b */
158 "Schedule-Job-After",
161 "Get-Document-Attributes",
164 "Set-Document-Attributes",
171 * const ipp_cups_ops
[] =
175 "CUPS-Add-Modify-Printer",
176 "CUPS-Delete-Printer",
178 "CUPS-Add-Modify-Class",
186 "CUPS-Authenticate-Job",
189 * const ipp_cups_ops2
[] =
193 * const ipp_tag_names
[] =
194 { /* Value/group tag names */
196 "operation-attributes-tag",
198 "job-attributes-tag", /* 0x02 */
199 "end-of-attributes-tag",
201 "printer-attributes-tag",
203 "unsupported-attributes-tag",
205 "subscription-attributes-tag",
207 "event-notification-attributes-tag",
209 "unknown-08", /* 0x08 */
210 "unknown-09", /* 0x09 */
211 "unknown-0a", /* 0x0a */
212 "unknown-0b", /* 0x0b */
213 "unknown-0c", /* 0x0c */
214 "unknown-0d", /* 0x0d */
215 "unknown-0e", /* 0x0e */
216 "unknown-0f", /* 0x0f */
217 "unsupported", /* 0x10 */
218 "default", /* 0x11 */
219 "unknown", /* 0x12 */
220 "no-value", /* 0x13 */
221 "unknown-14", /* 0x14 */
222 "not-settable", /* 0x15 */
223 "delete-attribute", /* 0x16 */
224 "admin-define", /* 0x17 */
225 "unknown-18", /* 0x18 */
226 "unknown-19", /* 0x19 */
227 "unknown-1a", /* 0x1a */
228 "unknown-1b", /* 0x1b */
229 "unknown-1c", /* 0x1c */
230 "unknown-1d", /* 0x1d */
231 "unknown-1e", /* 0x1e */
232 "unknown-1f", /* 0x1f */
233 "unknown-20", /* 0x20 */
234 "integer", /* 0x21 */
235 "boolean", /* 0x22 */
237 "unknown-24", /* 0x24 */
238 "unknown-25", /* 0x25 */
239 "unknown-26", /* 0x26 */
240 "unknown-27", /* 0x27 */
241 "unknown-28", /* 0x28 */
242 "unknown-29", /* 0x29 */
243 "unknown-2a", /* 0x2a */
244 "unknown-2b", /* 0x2b */
245 "unknown-2c", /* 0x2c */
246 "unknown-2d", /* 0x2d */
247 "unknown-2e", /* 0x2e */
248 "unknown-2f", /* 0x2f */
249 "octetString", /* 0x30 */
250 "dateTime", /* 0x31 */
251 "resolution", /* 0x32 */
252 "rangeOfInteger", /* 0x33 */
253 "collection", /* 0x34 */
254 "textWithLanguage", /* 0x35 */
255 "nameWithLanguage", /* 0x36 */
256 "endCollection", /* 0x37 */
257 "unknown-38", /* 0x38 */
258 "unknown-39", /* 0x39 */
259 "unknown-3a", /* 0x3a */
260 "unknown-3b", /* 0x3b */
261 "unknown-3c", /* 0x3c */
262 "unknown-3d", /* 0x3d */
263 "unknown-3e", /* 0x3e */
264 "unknown-3f", /* 0x3f */
265 "unknown-40", /* 0x40 */
266 "textWithoutLanguage",/* 0x41 */
267 "nameWithoutLanguage",/* 0x42 */
268 "unknown-43", /* 0x43 */
269 "keyword", /* 0x44 */
271 "uriScheme", /* 0x46 */
272 "charset", /* 0x47 */
273 "naturalLanguage", /* 0x48 */
274 "mimeMediaType", /* 0x49 */
275 "memberAttrName" /* 0x4a */
277 static const char * const job_states
[] =
278 { /* job-state enums */
282 "processing-stopped",
287 static const char * const printer_states
[] =
288 { /* printer-state enums */
299 static size_t ipp_col_string(ipp_t
*col
, char *buffer
, size_t bufsize
);
303 * '_ippAttrString()' - Convert the attribute's value to a string.
305 * Returns the number of bytes that would be written, not including the
306 * trailing nul. The buffer pointer can be NULL to get the required length,
307 * just like (v)snprintf.
310 size_t /* O - Number of bytes less nul */
311 _ippAttrString(ipp_attribute_t
*attr
, /* I - Attribute */
312 char *buffer
, /* I - String buffer or NULL */
313 size_t bufsize
) /* I - Size of string buffer */
315 int i
; /* Looping var */
316 char *bufptr
, /* Pointer into buffer */
317 *bufend
, /* End of buffer */
318 temp
[256]; /* Temporary string */
319 const char *ptr
; /* Pointer into string */
320 ipp_value_t
*val
; /* Current value */
323 if (!attr
|| !attr
->name
)
333 bufend
= buffer
+ bufsize
- 1;
337 for (i
= attr
->num_values
, val
= attr
->values
; i
> 0; i
--, val
++)
339 if (val
> attr
->values
)
341 if (buffer
&& bufptr
< bufend
)
347 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
350 if (!strcmp(attr
->name
, "printer-state") &&
351 val
->integer
>= IPP_PRINTER_IDLE
&&
352 val
->integer
<= IPP_PRINTER_STOPPED
)
354 ptr
= printer_states
[val
->integer
- IPP_PRINTER_IDLE
];
356 if (buffer
&& bufptr
< bufend
)
357 strlcpy(bufptr
, ptr
, bufend
- bufptr
+ 1);
359 bufptr
+= strlen(ptr
);
362 else if (!strcmp(attr
->name
, "job-state") &&
363 val
->integer
>= IPP_JOB_PENDING
&&
364 val
->integer
<= IPP_JOB_COMPLETED
)
366 ptr
= job_states
[val
->integer
- IPP_JOB_PENDING
];
368 if (buffer
&& bufptr
< bufend
)
369 strlcpy(bufptr
, ptr
, bufend
- bufptr
+ 1);
371 bufptr
+= strlen(ptr
);
374 else if (!strcmp(attr
->name
, "operations-supported"))
376 ptr
= ippOpString(val
->integer
);
378 if (buffer
&& bufptr
< bufend
)
379 strlcpy(bufptr
, ptr
, bufend
- bufptr
+ 1);
381 bufptr
+= strlen(ptr
);
385 case IPP_TAG_INTEGER
:
386 if (buffer
&& bufptr
< bufend
)
387 bufptr
+= snprintf(bufptr
, bufend
- bufptr
+ 1, "%d", val
->integer
);
389 bufptr
+= snprintf(temp
, sizeof(temp
), "%d", val
->integer
);
392 case IPP_TAG_BOOLEAN
:
393 if (buffer
&& bufptr
< bufend
)
394 strlcpy(bufptr
, val
->boolean
? "true" : "false",
395 bufend
- bufptr
+ 1);
397 bufptr
+= val
->boolean
? 4 : 5;
401 if (buffer
&& bufptr
< bufend
)
402 bufptr
+= snprintf(bufptr
, bufend
- bufptr
+ 1, "%d-%d",
403 val
->range
.lower
, val
->range
.upper
);
405 bufptr
+= snprintf(temp
, sizeof(temp
), "%d-%d", val
->range
.lower
,
409 case IPP_TAG_RESOLUTION
:
410 if (buffer
&& bufptr
< bufend
)
411 bufptr
+= snprintf(bufptr
, bufend
- bufptr
+ 1, "%dx%d%s",
412 val
->resolution
.xres
, val
->resolution
.yres
,
413 val
->resolution
.units
== IPP_RES_PER_INCH
?
416 bufptr
+= snprintf(temp
, sizeof(temp
), "%dx%d%s",
417 val
->resolution
.xres
, val
->resolution
.yres
,
418 val
->resolution
.units
== IPP_RES_PER_INCH
?
424 unsigned year
; /* Year */
426 year
= (val
->date
[0] << 8) + val
->date
[1];
428 if (val
->date
[9] == 0 && val
->date
[10] == 0)
429 snprintf(temp
, sizeof(temp
), "%04u-%02u-%02uT%02u:%02u:%02uZ",
430 year
, val
->date
[2], val
->date
[3], val
->date
[4],
431 val
->date
[5], val
->date
[6]);
433 snprintf(temp
, sizeof(temp
),
434 "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
435 year
, val
->date
[2], val
->date
[3], val
->date
[4],
436 val
->date
[5], val
->date
[6], val
->date
[8], val
->date
[9],
439 if (buffer
&& bufptr
< bufend
)
440 strlcpy(bufptr
, temp
, bufend
- bufptr
+ 1);
442 bufptr
+= strlen(temp
);
448 case IPP_TAG_KEYWORD
:
449 case IPP_TAG_CHARSET
:
451 case IPP_TAG_MIMETYPE
:
452 case IPP_TAG_LANGUAGE
:
453 case IPP_TAG_TEXTLANG
:
454 case IPP_TAG_NAMELANG
:
455 if (!val
->string
.text
)
458 for (ptr
= val
->string
.text
; *ptr
; ptr
++)
460 if (*ptr
== '\\' || *ptr
== '\"')
462 if (buffer
&& bufptr
< bufend
)
467 if (buffer
&& bufptr
< bufend
)
473 case IPP_TAG_BEGIN_COLLECTION
:
474 if (buffer
&& bufptr
< bufend
)
475 bufptr
+= ipp_col_string(val
->collection
, bufptr
,
476 bufend
- bufptr
+ 1);
478 bufptr
+= ipp_col_string(val
->collection
, NULL
, 0);
481 case IPP_TAG_STRING
:
482 for (ptr
= val
->string
.text
; *ptr
; ptr
++)
484 if (*ptr
== '\\' || _cups_isspace(*ptr
))
486 if (buffer
&& bufptr
< bufend
)
490 if (buffer
&& bufptr
< bufend
)
494 else if (!isprint(*ptr
& 255))
496 if (buffer
&& bufptr
< bufend
)
497 bufptr
+= snprintf(bufptr
, bufend
- bufptr
+ 1, "\\%03o",
500 bufptr
+= snprintf(temp
, sizeof(temp
), "\\%03o",
505 if (buffer
&& bufptr
< bufend
)
513 ptr
= ippTagString(attr
->value_tag
);
514 if (buffer
&& bufptr
< bufend
)
515 strlcpy(bufptr
, ptr
, bufend
- bufptr
+ 1);
516 bufptr
+= strlen(ptr
);
521 if (buffer
&& bufptr
< bufend
)
526 return (bufptr
- buffer
);
531 * 'ippErrorString()' - Return a name for the given status code.
534 const char * /* O - Text string */
535 ippErrorString(ipp_status_t error
) /* I - Error status */
537 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
541 * See if the error code is a known value...
544 if (error
>= IPP_OK
&& error
<= IPP_OK_EVENTS_COMPLETE
)
545 return (ipp_status_oks
[error
]);
546 else if (error
== IPP_REDIRECTION_OTHER_SITE
)
547 return ("redirection-other-site");
548 else if (error
== CUPS_SEE_OTHER
)
549 return ("cups-see-other");
550 else if (error
>= IPP_BAD_REQUEST
&& error
<= IPP_PRINT_SUPPORT_FILE_NOT_FOUND
)
551 return (ipp_status_400s
[error
- IPP_BAD_REQUEST
]);
552 else if (error
>= IPP_INTERNAL_ERROR
&& error
<= IPP_PRINTER_IS_DEACTIVATED
)
553 return (ipp_status_500s
[error
- IPP_INTERNAL_ERROR
]);
554 else if (error
>= IPP_AUTHENTICATION_CANCELED
&& error
<= IPP_UPGRADE_REQUIRED
)
555 return (ipp_status_1000s
[error
- IPP_AUTHENTICATION_CANCELED
]);
558 * No, build an "unknown-xxxx" error string...
561 sprintf(cg
->ipp_unknown
, "unknown-%04x", error
);
563 return (cg
->ipp_unknown
);
568 * 'ippErrorValue()' - Return a status code for the given name.
570 * @since CUPS 1.2/Mac OS X 10.5@
573 ipp_status_t
/* O - IPP status code */
574 ippErrorValue(const char *name
) /* I - Name */
579 for (i
= 0; i
< (sizeof(ipp_status_oks
) / sizeof(ipp_status_oks
[0])); i
++)
580 if (!_cups_strcasecmp(name
, ipp_status_oks
[i
]))
581 return ((ipp_status_t
)i
);
583 if (!_cups_strcasecmp(name
, "redirection-other-site"))
584 return (IPP_REDIRECTION_OTHER_SITE
);
586 if (!_cups_strcasecmp(name
, "cups-see-other"))
587 return (CUPS_SEE_OTHER
);
589 for (i
= 0; i
< (sizeof(ipp_status_400s
) / sizeof(ipp_status_400s
[0])); i
++)
590 if (!_cups_strcasecmp(name
, ipp_status_400s
[i
]))
591 return ((ipp_status_t
)(i
+ 0x400));
593 for (i
= 0; i
< (sizeof(ipp_status_500s
) / sizeof(ipp_status_500s
[0])); i
++)
594 if (!_cups_strcasecmp(name
, ipp_status_500s
[i
]))
595 return ((ipp_status_t
)(i
+ 0x500));
597 for (i
= 0; i
< (sizeof(ipp_status_1000s
) / sizeof(ipp_status_1000s
[0])); i
++)
598 if (!_cups_strcasecmp(name
, ipp_status_1000s
[i
]))
599 return ((ipp_status_t
)(i
+ 0x1000));
601 return ((ipp_status_t
)-1);
606 * 'ippOpString()' - Return a name for the given operation id.
608 * @since CUPS 1.2/Mac OS X 10.5@
611 const char * /* O - Name */
612 ippOpString(ipp_op_t op
) /* I - Operation ID */
614 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
618 * See if the operation ID is a known value...
621 if (op
>= IPP_PRINT_JOB
&& op
<= IPP_CLOSE_JOB
)
622 return (ipp_std_ops
[op
]);
623 else if (op
== IPP_PRIVATE
)
624 return ("windows-ext");
625 else if (op
>= CUPS_GET_DEFAULT
&& op
<= CUPS_GET_PPD
)
626 return (ipp_cups_ops
[op
- CUPS_GET_DEFAULT
]);
627 else if (op
== CUPS_GET_DOCUMENT
)
628 return (ipp_cups_ops2
[0]);
631 * No, build an "unknown-xxxx" operation string...
634 sprintf(cg
->ipp_unknown
, "0x%04x", op
);
636 return (cg
->ipp_unknown
);
641 * 'ippOpValue()' - Return an operation id for the given name.
643 * @since CUPS 1.2/Mac OS X 10.5@
646 ipp_op_t
/* O - Operation ID */
647 ippOpValue(const char *name
) /* I - Textual name */
652 if (!strncmp(name
, "0x", 2))
653 return ((ipp_op_t
)strtol(name
+ 2, NULL
, 16));
655 for (i
= 0; i
< (sizeof(ipp_std_ops
) / sizeof(ipp_std_ops
[0])); i
++)
656 if (!_cups_strcasecmp(name
, ipp_std_ops
[i
]))
657 return ((ipp_op_t
)i
);
659 if (!_cups_strcasecmp(name
, "windows-ext"))
660 return (IPP_PRIVATE
);
662 for (i
= 0; i
< (sizeof(ipp_cups_ops
) / sizeof(ipp_cups_ops
[0])); i
++)
663 if (!_cups_strcasecmp(name
, ipp_cups_ops
[i
]))
664 return ((ipp_op_t
)(i
+ 0x4001));
666 for (i
= 0; i
< (sizeof(ipp_cups_ops2
) / sizeof(ipp_cups_ops2
[0])); i
++)
667 if (!_cups_strcasecmp(name
, ipp_cups_ops2
[i
]))
668 return ((ipp_op_t
)(i
+ 0x4027));
670 if (!_cups_strcasecmp(name
, "CUPS-Add-Class"))
671 return (CUPS_ADD_MODIFY_CLASS
);
673 if (!_cups_strcasecmp(name
, "CUPS-Add-Printer"))
674 return (CUPS_ADD_MODIFY_PRINTER
);
676 return ((ipp_op_t
)-1);
681 * 'ippPort()' - Return the default IPP port number.
684 int /* O - Port number */
687 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
690 DEBUG_puts("ippPort()");
695 DEBUG_printf(("1ippPort: Returning %d...", cg
->ipp_port
));
697 return (cg
->ipp_port
);
702 * 'ippSetPort()' - Set the default port number.
706 ippSetPort(int p
) /* I - Port number to use */
708 DEBUG_printf(("ippSetPort(p=%d)", p
));
710 _cupsGlobals()->ipp_port
= p
;
715 * 'ippTagString()' - Return the tag name corresponding to a tag value.
717 * The returned names are defined in RFC 2911 and 3382.
719 * @since CUPS 1.4/Mac OS X 10.6@
722 const char * /* O - Tag name */
723 ippTagString(ipp_tag_t tag
) /* I - Tag value */
727 if (tag
< (ipp_tag_t
)(sizeof(ipp_tag_names
) / sizeof(ipp_tag_names
[0])))
728 return (ipp_tag_names
[tag
]);
735 * 'ippTagValue()' - Return the tag value corresponding to a tag name.
737 * The tag names are defined in RFC 2911 and 3382.
739 * @since CUPS 1.4/Mac OS X 10.6@
742 ipp_tag_t
/* O - Tag value */
743 ippTagValue(const char *name
) /* I - Tag name */
745 int i
; /* Looping var */
748 for (i
= 0; i
< (sizeof(ipp_tag_names
) / sizeof(ipp_tag_names
[0])); i
++)
749 if (!_cups_strcasecmp(name
, ipp_tag_names
[i
]))
750 return ((ipp_tag_t
)i
);
752 if (!_cups_strcasecmp(name
, "operation"))
753 return (IPP_TAG_OPERATION
);
754 else if (!_cups_strcasecmp(name
, "job"))
755 return (IPP_TAG_JOB
);
756 else if (!_cups_strcasecmp(name
, "printer"))
757 return (IPP_TAG_PRINTER
);
758 else if (!_cups_strcasecmp(name
, "unsupported"))
759 return (IPP_TAG_UNSUPPORTED_GROUP
);
760 else if (!_cups_strcasecmp(name
, "subscription"))
761 return (IPP_TAG_SUBSCRIPTION
);
762 else if (!_cups_strcasecmp(name
, "event"))
763 return (IPP_TAG_EVENT_NOTIFICATION
);
764 else if (!_cups_strcasecmp(name
, "language"))
765 return (IPP_TAG_LANGUAGE
);
766 else if (!_cups_strcasecmp(name
, "mimetype"))
767 return (IPP_TAG_MIMETYPE
);
768 else if (!_cups_strcasecmp(name
, "name"))
769 return (IPP_TAG_NAME
);
770 else if (!_cups_strcasecmp(name
, "text"))
771 return (IPP_TAG_TEXT
);
772 else if (!_cups_strcasecmp(name
, "begCollection"))
773 return (IPP_TAG_BEGIN_COLLECTION
);
775 return (IPP_TAG_ZERO
);
780 * 'ipp_col_string()' - Convert a collection to a string.
783 static size_t /* O - Number of bytes */
784 ipp_col_string(ipp_t
*col
, /* I - Collection attribute */
785 char *buffer
, /* I - Buffer or NULL */
786 size_t bufsize
) /* I - Size of buffer */
788 char *bufptr
, /* Position in buffer */
789 *bufend
, /* End of buffer */
790 temp
[256]; /* Temporary string */
791 ipp_attribute_t
*attr
; /* Current member attribute */
795 bufend
= buffer
+ bufsize
- 1;
797 if (buffer
&& bufptr
< bufend
)
801 for (attr
= col
->attrs
; attr
; attr
= attr
->next
)
806 if (buffer
&& bufptr
< bufend
)
807 bufptr
+= snprintf(bufptr
, bufend
- bufptr
+ 1, "%s=", attr
->name
);
809 bufptr
+= strlen(attr
->name
) + 1;
811 if (buffer
&& bufptr
< bufend
)
812 bufptr
+= _ippAttrString(attr
, bufptr
, bufend
- bufptr
+ 1);
814 bufptr
+= _ippAttrString(attr
, temp
, sizeof(temp
));
817 if (buffer
&& bufptr
< bufend
)
821 return (bufptr
- buffer
);
826 * End of "$Id: ipp-support.c 9371 2010-11-17 06:21:32Z mike $".