2 * "$Id: ipp-support.c 10108 2011-11-04 22:22:22Z 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",
93 "server-error-too-many-jobs",
94 "server-error-too-many-documents"
96 * const ipp_status_1000s[] = /* CUPS internal */
98 "cups-authorization-canceled",
100 "cups-upgrade-required"
102 static char * const ipp_std_ops[] =
104 /* 0x0000 - 0x000f */
114 "Get-Job-Attributes",
116 "Get-Printer-Attributes",
122 /* 0x0010 - 0x001f */
126 "Set-Printer-Attributes",
127 "Set-Job-Attributes",
128 "Get-Printer-Supported-Values",
129 "Create-Printer-Subscription",
130 "Create-Job-Subscription",
131 "Get-Subscription-Attributes",
133 "Renew-Subscription",
134 "Cancel-Subscription",
136 "Send-Notifications",
140 /* 0x0020 - 0x002f */
142 "Get-Printer-Support-Files",
145 "Pause-Printer-After-Current-Job",
147 "Release-Held-New-Jobs",
148 "Deactivate-Printer",
154 "Cancel-Current-Job",
155 "Suspend-Current-Job",
158 /* 0x0030 - 0x003b */
160 "Schedule-Job-After",
163 "Get-Document-Attributes",
166 "Set-Document-Attributes",
173 * const ipp_cups_ops[] =
177 "CUPS-Add-Modify-Printer",
178 "CUPS-Delete-Printer",
180 "CUPS-Add-Modify-Class",
188 "CUPS-Authenticate-Job",
191 * const ipp_cups_ops2[] =
195 * const ipp_tag_names[] =
196 { /* Value/group tag names */
198 "operation-attributes-tag",
200 "job-attributes-tag", /* 0x02 */
201 "end-of-attributes-tag",
203 "printer-attributes-tag",
205 "unsupported-attributes-tag",
207 "subscription-attributes-tag",
209 "event-notification-attributes-tag",
212 "document-attributes-tag",
220 "unsupported", /* 0x10 */
221 "default", /* 0x11 */
222 "unknown", /* 0x12 */
223 "no-value", /* 0x13 */
225 "not-settable", /* 0x15 */
226 "delete-attribute", /* 0x16 */
227 "admin-define", /* 0x17 */
237 "integer", /* 0x21 */
238 "boolean", /* 0x22 */
252 "octetString", /* 0x30 */
253 "dateTime", /* 0x31 */
254 "resolution", /* 0x32 */
255 "rangeOfInteger", /* 0x33 */
256 "collection", /* 0x34 */
257 "textWithLanguage", /* 0x35 */
258 "nameWithLanguage", /* 0x36 */
259 "endCollection", /* 0x37 */
269 "textWithoutLanguage",/* 0x41 */
270 "nameWithoutLanguage",/* 0x42 */
272 "keyword", /* 0x44 */
274 "uriScheme", /* 0x46 */
275 "charset", /* 0x47 */
276 "naturalLanguage", /* 0x48 */
277 "mimeMediaType", /* 0x49 */
278 "memberAttrName" /* 0x4a */
280 static const char * const job_states[] =
281 { /* job-state enums */
285 "processing-stopped",
290 static const char * const printer_states[] =
291 { /* printer-state enums */
302 static size_t ipp_col_string(ipp_t *col, char *buffer, size_t bufsize);
306 * '_ippAttrString()' - Convert the attribute's value to a string.
308 * Returns the number of bytes that would be written, not including the
309 * trailing nul. The buffer pointer can be NULL to get the required length,
310 * just like (v)snprintf.
313 size_t /* O - Number of bytes less nul */
314 _ippAttrString(ipp_attribute_t *attr, /* I - Attribute */
315 char *buffer, /* I - String buffer or NULL */
316 size_t bufsize) /* I - Size of string buffer */
318 int i; /* Looping var */
319 char *bufptr, /* Pointer into buffer */
320 *bufend, /* End of buffer */
321 temp[256]; /* Temporary string */
322 const char *ptr; /* Pointer into string */
323 ipp_value_t *val; /* Current value */
326 if (!attr || !attr->name)
336 bufend = buffer + bufsize - 1;
340 for (i = attr->num_values, val = attr->values; i > 0; i --, val ++)
342 if (val > attr->values)
344 if (buffer && bufptr < bufend)
350 switch (attr->value_tag & ~IPP_TAG_COPY)
353 if (!strcmp(attr->name, "printer-state") &&
354 val->integer >= IPP_PRINTER_IDLE &&
355 val->integer <= IPP_PRINTER_STOPPED)
357 ptr = printer_states[val->integer - IPP_PRINTER_IDLE];
359 if (buffer && bufptr < bufend)
360 strlcpy(bufptr, ptr, bufend - bufptr + 1);
362 bufptr += strlen(ptr);
365 else if (!strcmp(attr->name, "job-state") &&
366 val->integer >= IPP_JOB_PENDING &&
367 val->integer <= IPP_JOB_COMPLETED)
369 ptr = job_states[val->integer - IPP_JOB_PENDING];
371 if (buffer && bufptr < bufend)
372 strlcpy(bufptr, ptr, bufend - bufptr + 1);
374 bufptr += strlen(ptr);
377 else if (!strcmp(attr->name, "operations-supported"))
379 ptr = ippOpString(val->integer);
381 if (buffer && bufptr < bufend)
382 strlcpy(bufptr, ptr, bufend - bufptr + 1);
384 bufptr += strlen(ptr);
388 case IPP_TAG_INTEGER :
389 if (buffer && bufptr < bufend)
390 bufptr += snprintf(bufptr, bufend - bufptr + 1, "%d", val->integer);
392 bufptr += snprintf(temp, sizeof(temp), "%d", val->integer);
395 case IPP_TAG_BOOLEAN :
396 if (buffer && bufptr < bufend)
397 strlcpy(bufptr, val->boolean ? "true" : "false",
398 bufend - bufptr + 1);
400 bufptr += val->boolean ? 4 : 5;
404 if (buffer && bufptr < bufend)
405 bufptr += snprintf(bufptr, bufend - bufptr + 1, "%d-%d",
406 val->range.lower, val->range.upper);
408 bufptr += snprintf(temp, sizeof(temp), "%d-%d", val->range.lower,
412 case IPP_TAG_RESOLUTION :
413 if (buffer && bufptr < bufend)
414 bufptr += snprintf(bufptr, bufend - bufptr + 1, "%dx%d%s",
415 val->resolution.xres, val->resolution.yres,
416 val->resolution.units == IPP_RES_PER_INCH ?
419 bufptr += snprintf(temp, sizeof(temp), "%dx%d%s",
420 val->resolution.xres, val->resolution.yres,
421 val->resolution.units == IPP_RES_PER_INCH ?
427 unsigned year; /* Year */
429 year = (val->date[0] << 8) + val->date[1];
431 if (val->date[9] == 0 && val->date[10] == 0)
432 snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ",
433 year, val->date[2], val->date[3], val->date[4],
434 val->date[5], val->date[6]);
436 snprintf(temp, sizeof(temp),
437 "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
438 year, val->date[2], val->date[3], val->date[4],
439 val->date[5], val->date[6], val->date[8], val->date[9],
442 if (buffer && bufptr < bufend)
443 strlcpy(bufptr, temp, bufend - bufptr + 1);
445 bufptr += strlen(temp);
451 case IPP_TAG_KEYWORD :
452 case IPP_TAG_CHARSET :
454 case IPP_TAG_URISCHEME :
455 case IPP_TAG_MIMETYPE :
456 case IPP_TAG_LANGUAGE :
457 case IPP_TAG_TEXTLANG :
458 case IPP_TAG_NAMELANG :
459 if (!val->string.text)
462 for (ptr = val->string.text; *ptr; ptr ++)
464 if (*ptr == '\\' || *ptr == '\"')
466 if (buffer && bufptr < bufend)
471 if (buffer && bufptr < bufend)
477 case IPP_TAG_BEGIN_COLLECTION :
478 if (buffer && bufptr < bufend)
479 bufptr += ipp_col_string(val->collection, bufptr,
480 bufend - bufptr + 1);
482 bufptr += ipp_col_string(val->collection, NULL, 0);
485 case IPP_TAG_STRING :
486 for (ptr = val->string.text; *ptr; ptr ++)
488 if (*ptr == '\\' || _cups_isspace(*ptr))
490 if (buffer && bufptr < bufend)
494 if (buffer && bufptr < bufend)
498 else if (!isprint(*ptr & 255))
500 if (buffer && bufptr < bufend)
501 bufptr += snprintf(bufptr, bufend - bufptr + 1, "\\%03o",
504 bufptr += snprintf(temp, sizeof(temp), "\\%03o",
509 if (buffer && bufptr < bufend)
517 ptr = ippTagString(attr->value_tag);
518 if (buffer && bufptr < bufend)
519 strlcpy(bufptr, ptr, bufend - bufptr + 1);
520 bufptr += strlen(ptr);
525 if (buffer && bufptr < bufend)
530 return (bufptr - buffer);
535 * 'ippErrorString()' - Return a name for the given status code.
538 const char * /* O - Text string */
539 ippErrorString(ipp_status_t error) /* I - Error status */
541 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
545 * See if the error code is a known value...
548 if (error >= IPP_OK && error <= IPP_OK_EVENTS_COMPLETE)
549 return (ipp_status_oks[error]);
550 else if (error == IPP_REDIRECTION_OTHER_SITE)
551 return ("redirection-other-site");
552 else if (error == CUPS_SEE_OTHER)
553 return ("cups-see-other");
554 else if (error >= IPP_BAD_REQUEST && error <= IPP_PRINT_SUPPORT_FILE_NOT_FOUND)
555 return (ipp_status_400s[error - IPP_BAD_REQUEST]);
556 else if (error >= IPP_INTERNAL_ERROR && error <= IPP_PRINTER_IS_DEACTIVATED)
557 return (ipp_status_500s[error - IPP_INTERNAL_ERROR]);
558 else if (error >= IPP_AUTHENTICATION_CANCELED && error <= IPP_UPGRADE_REQUIRED)
559 return (ipp_status_1000s[error - IPP_AUTHENTICATION_CANCELED]);
562 * No, build an "0xxxxx" error string...
565 sprintf(cg->ipp_unknown, "0x%04x", error);
567 return (cg->ipp_unknown);
572 * 'ippErrorValue()' - Return a status code for the given name.
574 * @since CUPS 1.2/Mac OS X 10.5@
577 ipp_status_t /* O - IPP status code */
578 ippErrorValue(const char *name) /* I - Name */
583 for (i = 0; i < (sizeof(ipp_status_oks) / sizeof(ipp_status_oks[0])); i ++)
584 if (!_cups_strcasecmp(name, ipp_status_oks[i]))
585 return ((ipp_status_t)i);
587 if (!_cups_strcasecmp(name, "redirection-other-site"))
588 return (IPP_REDIRECTION_OTHER_SITE);
590 if (!_cups_strcasecmp(name, "cups-see-other"))
591 return (CUPS_SEE_OTHER);
593 for (i = 0; i < (sizeof(ipp_status_400s) / sizeof(ipp_status_400s[0])); i ++)
594 if (!_cups_strcasecmp(name, ipp_status_400s[i]))
595 return ((ipp_status_t)(i + 0x400));
597 for (i = 0; i < (sizeof(ipp_status_500s) / sizeof(ipp_status_500s[0])); i ++)
598 if (!_cups_strcasecmp(name, ipp_status_500s[i]))
599 return ((ipp_status_t)(i + 0x500));
601 for (i = 0; i < (sizeof(ipp_status_1000s) / sizeof(ipp_status_1000s[0])); i ++)
602 if (!_cups_strcasecmp(name, ipp_status_1000s[i]))
603 return ((ipp_status_t)(i + 0x1000));
605 return ((ipp_status_t)-1);
610 * 'ippOpString()' - Return a name for the given operation id.
612 * @since CUPS 1.2/Mac OS X 10.5@
615 const char * /* O - Name */
616 ippOpString(ipp_op_t op) /* I - Operation ID */
618 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
622 * See if the operation ID is a known value...
625 if (op >= IPP_PRINT_JOB && op <= IPP_CLOSE_JOB)
626 return (ipp_std_ops[op]);
627 else if (op == IPP_PRIVATE)
628 return ("windows-ext");
629 else if (op >= CUPS_GET_DEFAULT && op <= CUPS_GET_PPD)
630 return (ipp_cups_ops[op - CUPS_GET_DEFAULT]);
631 else if (op == CUPS_GET_DOCUMENT)
632 return (ipp_cups_ops2[0]);
635 * No, build an "0xxxxx" operation string...
638 sprintf(cg->ipp_unknown, "0x%04x", op);
640 return (cg->ipp_unknown);
645 * 'ippOpValue()' - Return an operation id for the given name.
647 * @since CUPS 1.2/Mac OS X 10.5@
650 ipp_op_t /* O - Operation ID */
651 ippOpValue(const char *name) /* I - Textual name */
656 if (!strncmp(name, "0x", 2))
657 return ((ipp_op_t)strtol(name + 2, NULL, 16));
659 for (i = 0; i < (sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])); i ++)
660 if (!_cups_strcasecmp(name, ipp_std_ops[i]))
661 return ((ipp_op_t)i);
663 if (!_cups_strcasecmp(name, "windows-ext"))
664 return (IPP_PRIVATE);
666 for (i = 0; i < (sizeof(ipp_cups_ops) / sizeof(ipp_cups_ops[0])); i ++)
667 if (!_cups_strcasecmp(name, ipp_cups_ops[i]))
668 return ((ipp_op_t)(i + 0x4001));
670 for (i = 0; i < (sizeof(ipp_cups_ops2) / sizeof(ipp_cups_ops2[0])); i ++)
671 if (!_cups_strcasecmp(name, ipp_cups_ops2[i]))
672 return ((ipp_op_t)(i + 0x4027));
674 if (!_cups_strcasecmp(name, "CUPS-Add-Class"))
675 return (CUPS_ADD_MODIFY_CLASS);
677 if (!_cups_strcasecmp(name, "CUPS-Add-Printer"))
678 return (CUPS_ADD_MODIFY_PRINTER);
680 return ((ipp_op_t)-1);
685 * 'ippPort()' - Return the default IPP port number.
688 int /* O - Port number */
691 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
694 DEBUG_puts("ippPort()");
699 DEBUG_printf(("1ippPort: Returning %d...", cg->ipp_port));
701 return (cg->ipp_port);
706 * 'ippSetPort()' - Set the default port number.
710 ippSetPort(int p) /* I - Port number to use */
712 DEBUG_printf(("ippSetPort(p=%d)", p));
714 _cupsGlobals()->ipp_port = p;
719 * 'ippTagString()' - Return the tag name corresponding to a tag value.
721 * The returned names are defined in RFC 2911 and 3382.
723 * @since CUPS 1.4/Mac OS X 10.6@
726 const char * /* O - Tag name */
727 ippTagString(ipp_tag_t tag) /* I - Tag value */
731 if (tag < (ipp_tag_t)(sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])))
732 return (ipp_tag_names[tag]);
739 * 'ippTagValue()' - Return the tag value corresponding to a tag name.
741 * The tag names are defined in RFC 2911 and 3382.
743 * @since CUPS 1.4/Mac OS X 10.6@
746 ipp_tag_t /* O - Tag value */
747 ippTagValue(const char *name) /* I - Tag name */
749 int i; /* Looping var */
752 for (i = 0; i < (sizeof(ipp_tag_names) / sizeof(ipp_tag_names[0])); i ++)
753 if (!_cups_strcasecmp(name, ipp_tag_names[i]))
754 return ((ipp_tag_t)i);
756 if (!_cups_strcasecmp(name, "operation"))
757 return (IPP_TAG_OPERATION);
758 else if (!_cups_strcasecmp(name, "job"))
759 return (IPP_TAG_JOB);
760 else if (!_cups_strcasecmp(name, "printer"))
761 return (IPP_TAG_PRINTER);
762 else if (!_cups_strcasecmp(name, "unsupported"))
763 return (IPP_TAG_UNSUPPORTED_GROUP);
764 else if (!_cups_strcasecmp(name, "subscription"))
765 return (IPP_TAG_SUBSCRIPTION);
766 else if (!_cups_strcasecmp(name, "event"))
767 return (IPP_TAG_EVENT_NOTIFICATION);
768 else if (!_cups_strcasecmp(name, "language"))
769 return (IPP_TAG_LANGUAGE);
770 else if (!_cups_strcasecmp(name, "mimetype"))
771 return (IPP_TAG_MIMETYPE);
772 else if (!_cups_strcasecmp(name, "name"))
773 return (IPP_TAG_NAME);
774 else if (!_cups_strcasecmp(name, "text"))
775 return (IPP_TAG_TEXT);
776 else if (!_cups_strcasecmp(name, "begCollection"))
777 return (IPP_TAG_BEGIN_COLLECTION);
779 return (IPP_TAG_ZERO);
784 * 'ipp_col_string()' - Convert a collection to a string.
787 static size_t /* O - Number of bytes */
788 ipp_col_string(ipp_t *col, /* I - Collection attribute */
789 char *buffer, /* I - Buffer or NULL */
790 size_t bufsize) /* I - Size of buffer */
792 char *bufptr, /* Position in buffer */
793 *bufend, /* End of buffer */
794 temp[256]; /* Temporary string */
795 ipp_attribute_t *attr; /* Current member attribute */
799 bufend = buffer + bufsize - 1;
801 if (buffer && bufptr < bufend)
805 for (attr = col->attrs; attr; attr = attr->next)
810 if (buffer && bufptr < bufend)
811 bufptr += snprintf(bufptr, bufend - bufptr + 1, "%s=", attr->name);
813 bufptr += strlen(attr->name) + 1;
815 if (buffer && bufptr < bufend)
816 bufptr += _ippAttrString(attr, bufptr, bufend - bufptr + 1);
818 bufptr += _ippAttrString(attr, temp, sizeof(temp));
821 if (buffer && bufptr < bufend)
825 return (bufptr - buffer);
830 * End of "$Id: ipp-support.c 10108 2011-11-04 22:22:22Z mike $".