#
# Usage:
#
-# ./ipptool -f filename -t printer-uri ipp-1.1.test
+# ./ipptool -f filename [-d document-uri=SOMEURI] -t printer-uri ipp-1.1.test
#
-# Regular expression for IPP URI schemes
-# Matches strings beginning with ipp:// or ipps://
+# Regular expressions for URI schemes:
+#
+# HTTP_URI_SCHEME - Matches strings beginning with http:// or https://
+# IPP_URI_SCHEME - Matches strings beginning with ipp:// or ipps://
+
+DEFINE HTTP_URI_SCHEME "/^https?://.+$$/"
DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
# Test that a request-id value of 0 is not accepted.
#
# Required by: RFC 2911 section 3.1.1
{
- NAME "3.1.1: Bad request-id value 0"
+ NAME "RFC 2911 section 3.1.1: Bad request-id value 0"
REQUEST-ID 0
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
#
# Required by: RFC 2911 section 3.1.4
{
- NAME "3.1.4: No Operation Attributes"
+ NAME "RFC 2911 section 3.1.4: No Operation Attributes"
REQUEST-ID random
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
EXPECT !printer-uri-supported
}
{
- NAME "3.1.4: attributes-charset"
+ NAME "RFC 2911 section 3.1.4: attributes-charset"
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
EXPECT !printer-uri-supported
}
{
- NAME "3.1.4: attributes-natural-language"
+ NAME "RFC 2911 section 3.1.4: attributes-natural-language"
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
ATTR naturalLanguage attributes-natural-language en
EXPECT !printer-uri-supported
}
{
- NAME "3.1.4: attributes-natural-language + attributes-charset"
+ NAME "RFC 2911 section 3.1.4: attributes-natural-language + attributes-charset"
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
ATTR naturalLanguage attributes-natural-language en
EXPECT !printer-uri-supported
}
{
- NAME "3.1.4: attributes-charset + attributes-natural-language"
+ NAME "RFC 2911 section 3.1.4: attributes-charset + attributes-natural-language"
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
# Required by: RFC 2911 section 3.1.8
{
# The name of the test...
- NAME "3.1.8: Unsupported IPP version 0.0"
+ NAME "RFC 2911 section 3.1.8: Unsupported IPP version 0.0"
VERSION 0.0
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
#
# Required by: RFC 2911 section 3.2
{
- NAME "3.2: No printer-uri operation attribute"
+ NAME "RFC 2911 section 3.2: No printer-uri operation attribute"
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
#
# Required by: RFC 2911 section 3.2.1
{
- NAME "3.2.1: Print-Job Operation"
+ NAME "RFC 2911 section 3.2.1: Print-Job Operation"
OPERATION Print-Job
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
ATTR boolean ipp-attribute-fidelity false
ATTR name document-name $filename
ATTR keyword compression none
- ATTR mimeMediaType document-format application/octet-stream
+ ATTR mimeMediaType document-format $filetype
FILE $filename
STATUS successful-ok
STATUS client-error-document-format-not-supported
+ STATUS server-error-job-canceled
+
EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
WITH-VALUE >0
IN-GROUP job-attributes-tag WITH-VALUE >-1
}
+# Test Validate-Job operation
+#
+# Required by: RFC 2911 section 3.2.3
+{
+ NAME "RFC 2911 section 3.2.3: Validate-Job Operation"
+ OPERATION Validate-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format $filetype
+
+ STATUS successful-ok
+}
+
+
# Test Get-Printer-Attributes operation
#
# Required by: RFC 2911 section 3.2.5
{
- NAME "3.2.5: Get-Printer-Attributes Operation (default)"
+ NAME "RFC 2911 section 3.2.5: Get-Printer-Attributes Operation (default)"
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
ATTR naturalLanguage attributes-natural-language en
ATTR uri printer-uri $uri
ATTR name requesting-user-name $user
- ATTR mimeMediaType document-format application/octet-stream
+ ATTR mimeMediaType document-format $filetype
STATUS successful-ok
EXPECT ?printer-location OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
EXPECT ?printer-make-and-model OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
EXPECT ?printer-message-from-operator OF-TYPE text IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{0,127}$$/"
- EXPECT ?printer-more-info OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
- EXPECT ?printer-more-info-manufacturer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1
+ EXPECT ?printer-more-info OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "$HTTP_URI_SCHEME"
+ EXPECT ?printer-more-info-manufacturer OF-TYPE uri IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "$HTTP_URI_SCHEME"
EXPECT ?printer-state-message OF-TYPE text IN-GROUP printer-attributes-tag
EXPECT ?reference-uri-schemes-supported OF-TYPE uriScheme IN-GROUP printer-attributes-tag
EXPECT charset-configured OF-TYPE charset IN-GROUP printer-attributes-tag COUNT 1
EXPECT ipp-versions-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE 1.1
EXPECT natural-language-configured OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag COUNT 1
EXPECT operations-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 0x0002 # Print-Job
+ EXPECT operations-supported WITH-VALUE 0x0003 DEFINE-MATCH HAVE_PRINT_URI # Print-URI
EXPECT operations-supported WITH-VALUE 0x0004 # Validate-Job
+ EXPECT operations-supported WITH-VALUE 0x0005 DEFINE-MATCH HAVE_CREATE_JOB # Create-Job
+ EXPECT operations-supported WITH-VALUE 0x0006 DEFINE-MATCH HAVE_SEND_DOCUMENT # Send-Document
+ EXPECT operations-supported WITH-VALUE 0x0007 DEFINE-MATCH HAVE_SEND_URI # Send-URI
EXPECT operations-supported WITH-VALUE 0x0008 # Cancel-Job
EXPECT operations-supported WITH-VALUE 0x0009 # Get-Job-Attributes
EXPECT operations-supported WITH-VALUE 0x000a # Get-Jobs
EXPECT operations-supported WITH-VALUE 0x000b # Get-Printer-Attributes
+ EXPECT operations-supported WITH-VALUE 0x000c DEFINE-MATCH HAVE_HOLD_JOB # Hold-Job
+ EXPECT operations-supported WITH-VALUE 0x000d DEFINE-MATCH HAVE_RELEASE_JOB # Release-Job
+ EXPECT operations-supported WITH-VALUE 0x000e DEFINE-MATCH HAVE_RESTART_JOB # Restart-Job
+ EXPECT operations-supported WITH-VALUE 0x0010 DEFINE-MATCH HAVE_PAUSE_PRINTER # Pause-Printer
+ EXPECT operations-supported WITH-VALUE 0x0011 DEFINE-MATCH HAVE_RESUME_PRINTER # Resume-Printer
+ EXPECT operations-supported WITH-VALUE 0x0012 DEFINE-MATCH HAVE_PURGE_JOBS # Purge-Jobs
EXPECT pdl-override-supported OF-TYPE keyword IN-GROUP printer-attributes-tag COUNT 1
EXPECT printer-is-accepting-jobs OF-TYPE boolean IN-GROUP printer-attributes-tag COUNT 1
EXPECT printer-name OF-TYPE name IN-GROUP printer-attributes-tag COUNT 1 WITH-VALUE "/^.{1,127}$$/"
#
# Required by: RFC 2911 section 3.2.5
{
- NAME "3.2.5: Get-Printer-Attributes Operation (requested-attributes)"
+ NAME "RFC 2911 section 3.2.5: Get-Printer-Attributes Operation (requested-attributes)"
OPERATION Get-Printer-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
ATTR naturalLanguage attributes-natural-language en
ATTR uri printer-uri $uri
ATTR name requesting-user-name $user
- ATTR mimeMediaType document-format application/octet-stream
+ ATTR mimeMediaType document-format $filetype
ATTR keyword requested-attributes printer-uri-supported
STATUS successful-ok
#
# Required by: RFC 2911 section 3.2.6
{
- NAME "3.2.6: Get-Jobs Operation (default)"
+ NAME "RFC 2911 section 3.2.6: Get-Jobs Operation (default)"
OPERATION Get-Jobs
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
#
# Required by: RFC 2911 section 3.2.6
{
- NAME "3.2.6: Get-Jobs Operation (requested-attributes)"
+ NAME "RFC 2911 section 3.2.6: Get-Jobs Operation (requested-attributes)"
OPERATION Get-Jobs
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
STATUS successful-ok
EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "$IPP_URI_SCHEME"
- EXPECT job-printer-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
- EXPECT ?job-more-info OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-printer-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "$IPP_URI_SCHEME"
+ EXPECT ?job-more-info OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "$HTTP_URI_SCHEME"
EXPECT job-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
EXPECT job-originating-user-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
EXPECT job-state OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >2,<10
#
# Required by: RFC 2911 section 3.2.6
{
- NAME "3.2.6: Get-Jobs Operation (my-jobs)"
+ NAME "RFC 2911 section 3.2.6: Get-Jobs Operation (my-jobs)"
OPERATION Get-Jobs
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
# use the authenticated username over the requesting-user-name value.
SKIP-IF-DEFINED uriuser
- NAME "3.2.6: Get-Jobs Operation (my-jobs different user)"
+ NAME "RFC 2911 section 3.2.6: Get-Jobs Operation (my-jobs different user)"
OPERATION Get-Jobs
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
#
# Required by: RFC 2911 section 3.2.6
{
- NAME "3.2.6: Get-Jobs Operation (which-jobs=not-completed)"
+ NAME "RFC 2911 section 3.2.6: Get-Jobs Operation (which-jobs=not-completed)"
OPERATION Get-Jobs
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
#
# Required by: RFC 2911 section 3.2.6
{
- NAME "3.2.6: Get-Jobs Operation (which-jobs=completed)"
+ NAME "RFC 2911 section 3.2.6: Get-Jobs Operation (which-jobs=completed)"
OPERATION Get-Jobs
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
#
# Required by: RFC 2911 section 3.3.3
{
- NAME "3.3.3: Cancel-Job Operation (completed job)"
+ NAME "RFC 2911 section 3.3.3: Cancel-Job Operation (completed job)"
OPERATION Cancel-Job
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
#
# Required by: RFC 2911 section 3.2.1
{
- NAME "3.2.1: Print-Job Operation"
+ NAME "RFC 2911 section 3.2.1: Print-Job Operation"
OPERATION Print-Job
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
ATTR boolean ipp-attribute-fidelity false
ATTR name document-name $filename
ATTR keyword compression none
- ATTR mimeMediaType document-format application/octet-stream
+ ATTR mimeMediaType document-format $filetype
FILE $filename
STATUS successful-ok
STATUS client-error-document-format-not-supported
+ STATUS server-error-job-canceled
+
EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
WITH-VALUE >0
#
# Required by: RFC 2911 section 3.3.3
{
- NAME "3.3.3: Cancel-Job Operation (pending/processing job)"
+ NAME "RFC 2911 section 3.3.3: Cancel-Job Operation (pending/processing job)"
OPERATION Cancel-Job
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
#
# Required by: RFC 2911 section 3.3.4
{
- NAME "3.3.4: Get-Job-Attributes Operation"
+ NAME "RFC 2911 section 3.3.4: Get-Job-Attributes Operation"
OPERATION Get-Job-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
STATUS successful-ok
EXPECT job-id OF-TYPE integer IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >0
EXPECT job-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "$IPP_URI_SCHEME"
- EXPECT job-printer-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
- EXPECT ?job-more-info OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1
+ EXPECT job-printer-uri OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "$IPP_URI_SCHEME"
+ EXPECT ?job-more-info OF-TYPE uri IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE "$HTTP_URI_SCHEME"
EXPECT job-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
EXPECT job-originating-user-name OF-TYPE name IN-GROUP job-attributes-tag COUNT 1
EXPECT job-state OF-TYPE enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >2,<10
}
+# Test Print-URI operation
+#
+# Defined by: RFC 2911 section 3.2.2
+{
+ SKIP-IF-NOT-DEFINED HAVE_PRINT_URI
+ SKIP-IF-NOT-DEFINED document-uri
+
+ NAME "RFC 2911 section 3.2.2: Print-URI Operation"
+ OPERATION Print-URI
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format $filetype
+ ATTR uri document-uri $document-uri
+
+ STATUS successful-ok
+ STATUS client-error-document-access-error
+ STATUS client-error-document-format-not-supported
+ STATUS client-error-uri-scheme-not-supported
+ STATUS server-error-job-canceled
+
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+
+# Test Print-URI operation with bad document-uri
+#
+# Defined by: RFC 2911 section 3.2.2
+{
+ SKIP-IF-NOT-DEFINED HAVE_PRINT_URI
+
+ NAME "Print-URI with bad URI: Print-URI Operation"
+ OPERATION Print-URI
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format $filetype
+ ATTR uri document-uri "bogus://bogus"
+
+ STATUS client-error-uri-scheme-not-supported
+
+ EXPECT !job-uri
+ EXPECT !job-id
+ EXPECT !job-state
+ EXPECT !job-state-reasons
+ EXPECT !job-state-message
+}
+
+
+# Test Create-Job and Send-Document operations
+#
+# Defined by: RFC 2911 section 3.2.4 and 3.3.1
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_DOCUMENT
+
+ NAME "RFC 2911 section 3.2.4: Create-Job Operation"
+ OPERATION Create-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+
+ STATUS successful-ok
+
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_DOCUMENT
+
+ NAME "RFC 2911 section 3.3.1: Send-Document Operation"
+ OPERATION Send-Document
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR boolean last-document true
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format $filetype
+ FILE $filename
+
+ STATUS successful-ok
+ STATUS client-error-document-format-not-supported
+ STATUS server-error-job-canceled
+}
+
+# Test Create-Job and Send-Document operations (no last-document)
+#
+# Defined by: RFC 2911 section 3.2.4 and 3.3.1
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_DOCUMENT
+
+ NAME "Send-Document missing last-document: Create-Job Operation"
+ OPERATION Create-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+
+ STATUS successful-ok
+
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_DOCUMENT
+
+ NAME "Send-Document missing last-document: Send-Document Operation"
+ OPERATION Send-Document
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format $filetype
+ FILE $filename
+
+ STATUS client-error-bad-request
+}
+
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_DOCUMENT
+
+ NAME "RFC 2911 section 3.3.3: Cancel-Job Operation"
+ OPERATION Cancel-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+ STATUS server-error-job-canceled
+}
+
+# Test Create-Job and Send-URI operations
+#
+# Defined by: RFC 2911 section 3.2.4 and 3.3.2
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_URI
+ SKIP-IF-NOT-DEFINED document-uri
+
+ NAME "RFC 2911 section 3.2.4: Create-Job Operation"
+ OPERATION Create-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+
+ STATUS successful-ok
+
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_DOCUMENT
+ SKIP-IF-NOT-DEFINED document-uri
+
+ NAME "RFC 2911 section 3.3.2: Send-URI Operation"
+ OPERATION Send-URI
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR boolean last-document true
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format $filetype
+ ATTR uri document-uri $document-uri
+
+ STATUS successful-ok
+ STATUS client-error-document-access-error
+ STATUS client-error-document-format-not-supported
+ STATUS client-error-uri-scheme-not-supported
+ STATUS server-error-job-canceled
+}
+
+
+# Test Create-Job and Send-URI operations (bad URI)
+#
+# Defined by: RFC 2911 section 3.2.4 and 3.3.2
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_URI
+
+ NAME "Send-URI with bad URI: Create-Job Operation"
+ OPERATION Create-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR name requesting-user-name $user
+ ATTR name job-name $filename
+ ATTR boolean ipp-attribute-fidelity false
+
+ STATUS successful-ok
+
+ EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
+ EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE >0
+ EXPECT job-state OF-TYPE enum COUNT 1 IN-GROUP job-attributes-tag
+ WITH-VALUE 3,4,5,6,7,8,9
+ EXPECT job-state-reasons OF-TYPE keyword IN-GROUP job-attributes-tag
+ EXPECT ?job-state-message OF-TYPE text IN-GROUP job-attributes-tag
+ EXPECT ?number-of-intervening-jobs OF-TYPE integer
+ IN-GROUP job-attributes-tag WITH-VALUE >-1
+}
+
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_DOCUMENT
+
+ NAME "Send-URI with bad URI: Send-URI Operation (bad URI)"
+ OPERATION Send-URI
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+ ATTR boolean last-document true
+ ATTR name document-name $filename
+ ATTR keyword compression none
+ ATTR mimeMediaType document-format $filetype
+ ATTR uri document-uri "bogus://bogus"
+
+ STATUS client-error-uri-scheme-not-supported
+}
+
+{
+ SKIP-IF-NOT-DEFINED HAVE_CREATE_JOB
+ SKIP-IF-NOT-DEFINED HAVE_SEND_DOCUMENT
+
+ NAME "Send-URI with bad URI: Cancel-Job Operation"
+ OPERATION Cancel-Job
+ GROUP operation-attributes-tag
+ ATTR charset attributes-charset utf-8
+ ATTR naturalLanguage attributes-natural-language en
+ ATTR uri printer-uri $uri
+ ATTR integer job-id $job-id
+ ATTR name requesting-user-name $user
+
+ STATUS successful-ok
+ STATUS server-error-job-canceled
+}
+
+
#
# End of "$Id$".
#
*
* Contents:
*
- * main() - Main entry to the sample server.
- * clean_jobs() - Clean out old (completed) jobs.
- * compare_jobs() - Compare two jobs.
- * copy_attribute() - Copy a single attribute.
- * copy_attributes() - Copy attributes from one request to another.
- * copy_job_attrs() - Copy job attributes to the response.
- * create_client() - Accept a new network connection and create a
- * client object.
- * create_job() - Create a new job object from a Print-Job or
- * Create-Job request.
- * create_listener() - Create a listener socket.
- * create_media_col() - Create a media-col value.
- * create_printer() - Create, register, and listen for connections
- * to a printer object.
- * create_requested_array() - Create an array for requested-attributes.
- * debug_attributes() - Print attributes in a request or response.
- * delete_client() - Close the socket and free all memory used by
- * a client object.
- * delete_job() - Remove from the printer and free all memory
- * used by a job object.
- * delete_printer() - Unregister, close listen sockets, and free
- * all memory used by a printer object.
- * dnssd_callback() - Handle Bonjour registration events.
- * find_job() - Find a job specified in a request.
- * html_escape() - Write a HTML-safe string.
- * html_printf() - Send formatted text to the client, quoting
- * as needed.
- * ipp_cancel_job() - Cancel a job.
- * ipp_create_job() - Create a job object.
- * ipp_get_job_attributes() - Get the attributes for a job object.
- * ipp_get_jobs() - Get a list of job objects.
- * ipp_get_printer_attributes() - Get the attributes for a printer object.
- * ipp_print_job() - Create a job object with an attached
- * document.
- * ipp_send_document() - Add an attached document to a job object
- * created with Create-Job.
- * ipp_validate_job() - Validate job creation attributes.
- * process_client() - Process client requests on a thread.
- * process_http() - Process a HTTP request.
- * process_ipp() - Process an IPP request.
- * process_job() - Process a print job.
- * register_printer() - Register a printer object via Bonjour.
- * respond_http() - Send a HTTP response.
- * respond_ipp() - Send an IPP response.
- * run_printer() - Run the printer service.
- * usage() - Show program usage.
- * valid_job_attributes() - Determine whether the job attributes are
- * valid.
*/
/*
"na_index-3x5_3x5in", /* 3x5 */
"oe_photo-l_3.5x5in", /* L */
"na_index-4x6_4x6in", /* 4x6 */
- "na_5x7_5x7in" /* 5x7 */
+ "na_5x7_5x7in" /* 5x7 aka 2L */
};
static const int media_col_sizes[][3] =
{ /* media-col-database sizes */
{ 7630, 12700, _IPP_PHOTO_ONLY }, /* 3x5 */
{ 8890, 12700, _IPP_PHOTO_ONLY }, /* L */
{ 10160, 15240, _IPP_PHOTO_ONLY }, /* 4x6 */
- { 12700, 17780, _IPP_PHOTO_ONLY } /* 5x7 */
+ { 12700, 17780, _IPP_PHOTO_ONLY } /* 5x7 aka 2L */
};
static const char * const media_type_supported[] =
/* media-type-supported values */
...) __attribute__((__format__(__printf__,
2, 3)));
static void ipp_cancel_job(_ipp_client_t *client);
-#if 0
static void ipp_create_job(_ipp_client_t *client);
-#endif /* 0 */
static void ipp_get_job_attributes(_ipp_client_t *client);
static void ipp_get_jobs(_ipp_client_t *client);
static void ipp_get_printer_attributes(_ipp_client_t *client);
static void ipp_print_job(_ipp_client_t *client);
-#if 0
+static void ipp_print_uri(_ipp_client_t *client);
static void ipp_send_document(_ipp_client_t *client);
-#endif /* 0 */
+static void ipp_send_uri(_ipp_client_t *client);
static void ipp_validate_job(_ipp_client_t *client);
static void *process_client(_ipp_client_t *client);
static int process_http(_ipp_client_t *client);
__attribute__ ((__format__ (__printf__, 3, 4)));
static void run_printer(_ipp_printer_t *printer);
static void usage(int status) __attribute__((noreturn));
+static int valid_doc_attributes(_ipp_client_t *client);
static int valid_job_attributes(_ipp_client_t *client);
return (NULL);
}
- client->printer = printer;
- client->http.activity = time(NULL);
- client->http.hostaddr = &(client->addr);
- client->http.blocking = 1;
+ client->printer = printer;
+ client->http.activity = time(NULL);
+ client->http.hostaddr = &(client->addr);
+ client->http.blocking = 1;
+ client->http.wait_value = 60000;
/*
* Accept the client and get the remote address...
static const int ops[] = /* operations-supported values */
{
IPP_PRINT_JOB,
+ IPP_PRINT_URI,
IPP_VALIDATE_JOB,
IPP_CREATE_JOB,
IPP_SEND_DOCUMENT,
+ IPP_SEND_URI,
IPP_CANCEL_JOB,
IPP_GET_JOB_ATTRIBUTES,
IPP_GET_JOBS,
IPP_QUALITY_NORMAL,
IPP_QUALITY_HIGH
};
+ static const char * const referenced_uri_scheme_supported[] =
+ { /* referenced-uri-scheme-supported */
+ "file",
+ "http"
+#ifdef HAVE_SSL
+ , "https"
+#endif /* HAVE_SSL */
+ };
static const char * const sides_supported[] =
{ /* sides-supported values */
"one-sided",
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
"printer-uri-supported", NULL, uri);
+ /* referenced-uri-scheme-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_TAG_URISCHEME | IPP_TAG_COPY,
+ "referenced-uri-scheme-supported",
+ (int)(sizeof(referenced_uri_scheme_supported) /
+ sizeof(referenced_uri_scheme_supported[0])),
+ NULL, referenced_uri_scheme_supported);
+
/* sides-default */
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"sides-default", NULL, "one-sided");
*/
if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_NOT_FOUND, "Job does not exist.");
return;
+ }
/*
* See if the job is already completed, canceled, or aborted; if so,
}
-#if 0
/*
* 'ipp_create_job()' - Create a job object.
*/
static void
ipp_create_job(_ipp_client_t *client) /* I - Client */
{
+ _ipp_job_t *job; /* New job */
+ cups_array_t *ra; /* Attributes to send in response */
+
+
+ /*
+ * Validate print job attributes...
+ */
+
+ if (!valid_job_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (client->http.state == HTTP_POST_RECV)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Unexpected document data following request.");
+ return;
+ }
+
+ /*
+ * Create the job...
+ */
+
+ if ((job = create_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_PRINTER_BUSY, "Currently printing another job.");
+ return;
+ }
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
}
-#endif /* 0 */
/*
}
-#if 0
-/*
- * 'ipp_send_document()' - Add an attached document to a job object created with
- * Create-Job.
- */
-
-static void
-ipp_send_document(_ipp_client_t *client)/* I - Client */
-{
-}
-#endif /* 0 */
-
-
/*
- * 'ipp_validate_job()' - Validate job creation attributes.
+ * 'ipp_print_uri()' - Create a job object with a referenced document.
*/
static void
-ipp_validate_job(_ipp_client_t *client) /* I - Client */
+ipp_print_uri(_ipp_client_t *client) /* I - Client */
{
-}
-
+ _ipp_job_t *job; /* New job */
+ ipp_attribute_t *uri; /* document-uri */
+ char scheme[256], /* URI scheme */
+ userpass[256], /* Username and password info */
+ hostname[256], /* Hostname */
+ resource[1024]; /* Resource path */
+ int port; /* Port number */
+ http_uri_status_t uri_status; /* URI decode status */
+ http_encryption_t encryption; /* Encryption to use, if any */
+ http_t *http; /* Connection for http/https URIs */
+ http_status_t status; /* Access status for http/https URIs */
+ int infile; /* Input file for local file URIs */
+ char filename[1024], /* Filename buffer */
+ buffer[4096]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read */
+ cups_array_t *ra; /* Attributes to send in response */
+ static const char * const uri_status_strings[] =
+ { /* URI decode errors */
+ "URI too large.",
+ "Bad arguments to function.",
+ "Bad resource in URI.",
+ "Bad port number in URI.",
+ "Bad hostname in URI.",
+ "Bad username in URI.",
+ "Bad scheme in URI.",
+ "Bad/empty URI."
+ };
-/*
- * 'process_client()' - Process client requests on a thread.
- */
-static void * /* O - Exit status */
-process_client(_ipp_client_t *client) /* I - Client */
-{
/*
- * Loop until we are out of requests or timeout (30 seconds)...
+ * Validate print job attributes...
*/
- while (httpWait(&(client->http), 30000))
- if (!process_http(client))
- break;
+ if (!valid_job_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
/*
- * Close the conection to the client and return...
+ * Do we have a file to print?
*/
- delete_client(client);
-
- return (NULL);
-}
-
-
-/*
- * 'process_http()' - Process a HTTP request.
- */
-
-int /* O - 1 on success, 0 on failure */
-process_http(_ipp_client_t *client) /* I - Client connection */
-{
- char line[4096], /* Line from client... */
- operation[64], /* Operation code from socket */
- uri[1024], /* URI */
- version[64], /* HTTP version number string */
- *ptr; /* Pointer into strings */
- int major, minor; /* HTTP version numbers */
- http_status_t status; /* Transfer status */
- ipp_state_t state; /* State of IPP transfer */
-
+ if (client->http.state == HTTP_POST_RECV)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Unexpected document data following request.");
+ return;
+ }
/*
- * Abort if we have an error on the connection...
+ * Do we have a document URI?
*/
- if (client->http.error)
- return (0);
+ if ((uri = ippFindAttribute(client->request, "document-uri",
+ IPP_TAG_URI)) == NULL)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Missing document-uri.");
+ return;
+ }
- /*
- * Clear state variables...
- */
+ if (uri->num_values != 1)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Too many document-uri values.");
+ return;
+ }
- httpClearFields(&(client->http));
- ippDelete(client->request);
- ippDelete(client->response);
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text,
+ scheme, sizeof(scheme), userpass,
+ sizeof(userpass), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+ if (uri_status < HTTP_URI_OK)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Bad document-uri: %s",
+ uri_status_strings[uri_status - HTTP_URI_OVERFLOW]);
+ return;
+ }
- client->http.activity = time(NULL);
- client->http.version = HTTP_1_1;
- client->http.keep_alive = HTTP_KEEPALIVE_OFF;
- client->http.data_encoding = HTTP_ENCODE_LENGTH;
- client->http.data_remaining = 0;
- client->request = NULL;
- client->response = NULL;
- client->operation = HTTP_WAITING;
+ if (strcmp(scheme, "file") &&
+#ifdef HAVE_SSL
+ strcmp(scheme, "https") &&
+#endif /* HAVE_SSL */
+ strcmp(scheme, "http"))
+ {
+ respond_ipp(client, IPP_URI_SCHEME, "URI scheme \"%s\" not supported.",
+ scheme);
+ return;
+ }
+
+ if (!strcmp(scheme, "file") && access(resource, R_OK))
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ strerror(errno));
+ return;
+ }
/*
- * Read a request from the connection...
+ * Print the job...
*/
- while ((ptr = httpGets(line, sizeof(line) - 1, &(client->http))) != NULL)
- if (*ptr)
- break;
-
- if (!ptr)
- return (0);
+ if ((job = create_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_PRINTER_BUSY, "Currently printing another job.");
+ return;
+ }
/*
- * Parse the request line...
+ * Create a file for the request data...
*/
- fprintf(stderr, "%s %s\n", client->http.hostname, line);
+ if (!_cups_strcasecmp(job->format, "image/jpeg"))
+ snprintf(filename, sizeof(filename), "%s/%d.jpg",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "image/png"))
+ snprintf(filename, sizeof(filename), "%s/%d.png",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/pdf"))
+ snprintf(filename, sizeof(filename), "%s/%d.pdf",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/postscript"))
+ snprintf(filename, sizeof(filename), "%s/%d.ps",
+ client->printer->directory, job->id);
+ else
+ snprintf(filename, sizeof(filename), "%s/%d.prn",
+ client->printer->directory, job->id);
- switch (sscanf(line, "%63s%1023s%63s", operation, uri, version))
+ if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
{
- case 1 :
- fprintf(stderr, "%s Bad request line.\n", client->http.hostname);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
- return (0);
+ job->state = IPP_JOB_ABORTED;
- case 2 :
- client->http.version = HTTP_0_9;
- break;
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
- case 3 :
- if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
- {
- fprintf(stderr, "%s Bad HTTP version.\n", client->http.hostname);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
- return (0);
- }
+ if (!strcmp(scheme, "file"))
+ {
+ if ((infile = open(resource, O_RDONLY)) < 0)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ strerror(errno));
+ return;
+ }
- if (major < 2)
- {
- client->http.version = (http_version_t)(major * 100 + minor);
- if (client->http.version == HTTP_1_1)
- client->http.keep_alive = HTTP_KEEPALIVE_ON;
- else
- client->http.keep_alive = HTTP_KEEPALIVE_OFF;
- }
- else
- {
- respond_http(client, HTTP_NOT_SUPPORTED, NULL, 0);
- return (0);
- }
- break;
- }
+ do
+ {
+ if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 &&
+ (errno == EAGAIN || errno == EINTR))
+ bytes = 1;
+ else if (bytes > 0 && write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
- /*
- * Handle full URLs in the request line...
- */
+ job->state = IPP_JOB_ABORTED;
- if (!strncmp(client->uri, "http:", 5) || !strncmp(client->uri, "ipp:", 4))
- {
- char scheme[32], /* Method/scheme */
- userpass[128], /* Username:password */
- hostname[HTTP_MAX_HOST];/* Hostname */
- int port; /* Port number */
+ close(job->fd);
+ job->fd = -1;
- /*
- * Separate the URI into its components...
- */
+ unlink(filename);
+ close(infile);
- if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme),
- userpass, sizeof(userpass),
- hostname, sizeof(hostname), &port,
- client->uri, sizeof(client->uri)) < HTTP_URI_OK)
- {
- fprintf(stderr, "%s Bad URI \"%s\".\n", client->http.hostname, uri);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
- return (0);
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
}
+ while (bytes > 0);
+
+ close(infile);
}
else
{
- /*
- * Decode URI
- */
+#ifdef HAVE_SSL
+ if (port == 443 || !strcmp(scheme, "https"))
+ encryption = HTTP_ENCRYPT_ALWAYS;
+ else
+#endif /* HAVE_SSL */
+ encryption = HTTP_ENCRYPT_IF_REQUESTED;
- if (!_httpDecodeURI(client->uri, uri, sizeof(client->uri)))
+ if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL)
{
- fprintf(stderr, "%s Bad URI \"%s\".\n", client->http.hostname, uri);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
- return (0);
- }
- }
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ cupsLastErrorString());
+ job->state = IPP_JOB_ABORTED;
- /*
- * Process the request...
- */
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ return;
+ }
+
+ if (!httpGet(http, resource))
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ cupsLastErrorString());
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (status != HTTP_OK)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ httpStatus(status));
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
+ {
+ if (write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ httpClose(http);
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to write print file: %s",
+ strerror(error));
+ return;
+ }
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JOB_PENDING;
+
+ /*
+ * Process the job...
+ */
+
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JOB_ABORTED;
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to process job.");
+ return;
+ }
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
+}
+
+
+/*
+ * 'ipp_send_document()' - Add an attached document to a job object created with
+ * Create-Job.
+ */
+
+static void
+ipp_send_document(_ipp_client_t *client)/* I - Client */
+{
+ _ipp_job_t *job; /* Job information */
+ char filename[1024], /* Filename buffer */
+ buffer[4096]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_array_t *ra; /* Attributes to send in response */
+
+
+ /*
+ * Get the job...
+ */
+
+ if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_NOT_FOUND, "Job does not exist.");
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * See if we already have a document for this job or the job has already
+ * in a non-pending state...
+ */
+
+ if (job->state > IPP_JOB_HELD)
+ {
+ respond_ipp(client, IPP_NOT_POSSIBLE, "Job is not in a pending state.");
+ httpFlush(&(client->http));
+ return;
+ }
+ else if (job->filename || job->fd >= 0)
+ {
+ respond_ipp(client, IPP_MULTIPLE_JOBS_NOT_SUPPORTED,
+ "Multiple document jobs are not supported.");
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Validate document attributes...
+ */
+
+ if (!valid_doc_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Get the document format for the job...
+ */
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ if ((attr = ippFindAttribute(job->attrs, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ job->format = attr->values[0].string.text;
+ else
+ job->format = "application/octet-stream";
+
+ /*
+ * Create a file for the request data...
+ */
+
+ if (!_cups_strcasecmp(job->format, "image/jpeg"))
+ snprintf(filename, sizeof(filename), "%s/%d.jpg",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "image/png"))
+ snprintf(filename, sizeof(filename), "%s/%d.png",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/pdf"))
+ snprintf(filename, sizeof(filename), "%s/%d.pdf",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/postscript"))
+ snprintf(filename, sizeof(filename), "%s/%d.ps",
+ client->printer->directory, job->id);
+ else
+ snprintf(filename, sizeof(filename), "%s/%d.prn",
+ client->printer->directory, job->id);
+
+ job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ if (job->fd < 0)
+ {
+ job->state = IPP_JOB_ABORTED;
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ while ((bytes = httpRead2(&(client->http), buffer, sizeof(buffer))) > 0)
+ {
+ if (write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ if (bytes < 0)
+ {
+ /*
+ * Got an error while reading the print data, so abort this job.
+ */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to read print file.");
+ return;
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to write print file: %s",
+ strerror(error));
+ return;
+ }
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JOB_PENDING;
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ /*
+ * Process the job...
+ */
+
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JOB_ABORTED;
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to process job.");
+ return;
+ }
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
+}
+
+
+/*
+ * 'ipp_send_uri()' - Add a referenced document to a job object created with
+ * Create-Job.
+ */
+
+static void
+ipp_send_uri(_ipp_client_t *client) /* I - Client */
+{
+ _ipp_job_t *job; /* Job information */
+ ipp_attribute_t *uri; /* document-uri */
+ char scheme[256], /* URI scheme */
+ userpass[256], /* Username and password info */
+ hostname[256], /* Hostname */
+ resource[1024]; /* Resource path */
+ int port; /* Port number */
+ http_uri_status_t uri_status; /* URI decode status */
+ http_encryption_t encryption; /* Encryption to use, if any */
+ http_t *http; /* Connection for http/https URIs */
+ http_status_t status; /* Access status for http/https URIs */
+ int infile; /* Input file for local file URIs */
+ char filename[1024], /* Filename buffer */
+ buffer[4096]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_array_t *ra; /* Attributes to send in response */
+ static const char * const uri_status_strings[] =
+ { /* URI decode errors */
+ "URI too large.",
+ "Bad arguments to function.",
+ "Bad resource in URI.",
+ "Bad port number in URI.",
+ "Bad hostname in URI.",
+ "Bad username in URI.",
+ "Bad scheme in URI.",
+ "Bad/empty URI."
+ };
+
+
+ /*
+ * Get the job...
+ */
+
+ if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_NOT_FOUND, "Job does not exist.");
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * See if we already have a document for this job or the job has already
+ * in a non-pending state...
+ */
+
+ if (job->state > IPP_JOB_HELD)
+ {
+ respond_ipp(client, IPP_NOT_POSSIBLE, "Job is not in a pending state.");
+ httpFlush(&(client->http));
+ return;
+ }
+ else if (job->filename || job->fd >= 0)
+ {
+ respond_ipp(client, IPP_MULTIPLE_JOBS_NOT_SUPPORTED,
+ "Multiple document jobs are not supported.");
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Validate document attributes...
+ */
+
+ if (!valid_doc_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (client->http.state == HTTP_POST_RECV)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Unexpected document data following request.");
+ return;
+ }
+
+ /*
+ * Do we have a document URI?
+ */
+
+ if ((uri = ippFindAttribute(client->request, "document-uri",
+ IPP_TAG_URI)) == NULL)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Missing document-uri.");
+ return;
+ }
+
+ if (uri->num_values != 1)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Too many document-uri values.");
+ return;
+ }
+
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text,
+ scheme, sizeof(scheme), userpass,
+ sizeof(userpass), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+ if (uri_status < HTTP_URI_OK)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Bad document-uri: %s",
+ uri_status_strings[uri_status - HTTP_URI_OVERFLOW]);
+ return;
+ }
+
+ if (strcmp(scheme, "file") &&
+#ifdef HAVE_SSL
+ strcmp(scheme, "https") &&
+#endif /* HAVE_SSL */
+ strcmp(scheme, "http"))
+ {
+ respond_ipp(client, IPP_URI_SCHEME, "URI scheme \"%s\" not supported.",
+ scheme);
+ return;
+ }
+
+ if (!strcmp(scheme, "file") && access(resource, R_OK))
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ strerror(errno));
+ return;
+ }
+
+ /*
+ * Get the document format for the job...
+ */
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ if ((attr = ippFindAttribute(job->attrs, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ job->format = attr->values[0].string.text;
+ else
+ job->format = "application/octet-stream";
+
+ /*
+ * Create a file for the request data...
+ */
+
+ if (!_cups_strcasecmp(job->format, "image/jpeg"))
+ snprintf(filename, sizeof(filename), "%s/%d.jpg",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "image/png"))
+ snprintf(filename, sizeof(filename), "%s/%d.png",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/pdf"))
+ snprintf(filename, sizeof(filename), "%s/%d.pdf",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/postscript"))
+ snprintf(filename, sizeof(filename), "%s/%d.ps",
+ client->printer->directory, job->id);
+ else
+ snprintf(filename, sizeof(filename), "%s/%d.prn",
+ client->printer->directory, job->id);
+
+ job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ if (job->fd < 0)
+ {
+ job->state = IPP_JOB_ABORTED;
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ if (!strcmp(scheme, "file"))
+ {
+ if ((infile = open(resource, O_RDONLY)) < 0)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ strerror(errno));
+ return;
+ }
+
+ do
+ {
+ if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 &&
+ (errno == EAGAIN || errno == EINTR))
+ bytes = 1;
+ else if (bytes > 0 && write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ close(infile);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+ while (bytes > 0);
+
+ close(infile);
+ }
+ else
+ {
+#ifdef HAVE_SSL
+ if (port == 443 || !strcmp(scheme, "https"))
+ encryption = HTTP_ENCRYPT_ALWAYS;
+ else
+#endif /* HAVE_SSL */
+ encryption = HTTP_ENCRYPT_IF_REQUESTED;
+
+ if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ cupsLastErrorString());
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ return;
+ }
+
+ if (!httpGet(http, resource))
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ cupsLastErrorString());
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (status != HTTP_OK)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ httpStatus(status));
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
+ {
+ if (write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ httpClose(http);
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to write print file: %s",
+ strerror(error));
+ return;
+ }
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JOB_PENDING;
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ /*
+ * Process the job...
+ */
+
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JOB_ABORTED;
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to process job.");
+ return;
+ }
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
+}
+
+
+/*
+ * 'ipp_validate_job()' - Validate job creation attributes.
+ */
+
+static void
+ipp_validate_job(_ipp_client_t *client) /* I - Client */
+{
+ if (valid_job_attributes(client))
+ respond_ipp(client, IPP_OK, NULL);
+}
+
+
+/*
+ * 'process_client()' - Process client requests on a thread.
+ */
+
+static void * /* O - Exit status */
+process_client(_ipp_client_t *client) /* I - Client */
+{
+ /*
+ * Loop until we are out of requests or timeout (30 seconds)...
+ */
+
+ while (httpWait(&(client->http), 30000))
+ if (!process_http(client))
+ break;
+
+ /*
+ * Close the conection to the client and return...
+ */
+
+ delete_client(client);
+
+ return (NULL);
+}
+
+
+/*
+ * 'process_http()' - Process a HTTP request.
+ */
+
+int /* O - 1 on success, 0 on failure */
+process_http(_ipp_client_t *client) /* I - Client connection */
+{
+ char line[4096], /* Line from client... */
+ operation[64], /* Operation code from socket */
+ uri[1024], /* URI */
+ version[64], /* HTTP version number string */
+ *ptr; /* Pointer into strings */
+ int major, minor; /* HTTP version numbers */
+ http_status_t status; /* Transfer status */
+ ipp_state_t state; /* State of IPP transfer */
+
+
+ /*
+ * Abort if we have an error on the connection...
+ */
+
+ if (client->http.error)
+ return (0);
+
+ /*
+ * Clear state variables...
+ */
+
+ httpClearFields(&(client->http));
+ ippDelete(client->request);
+ ippDelete(client->response);
+
+ client->http.activity = time(NULL);
+ client->http.version = HTTP_1_1;
+ client->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ client->http.data_encoding = HTTP_ENCODE_LENGTH;
+ client->http.data_remaining = 0;
+ client->request = NULL;
+ client->response = NULL;
+ client->operation = HTTP_WAITING;
+
+ /*
+ * Read a request from the connection...
+ */
+
+ while ((ptr = httpGets(line, sizeof(line) - 1, &(client->http))) != NULL)
+ if (*ptr)
+ break;
+
+ if (!ptr)
+ return (0);
+
+ /*
+ * Parse the request line...
+ */
+
+ fprintf(stderr, "%s %s\n", client->http.hostname, line);
+
+ switch (sscanf(line, "%63s%1023s%63s", operation, uri, version))
+ {
+ case 1 :
+ fprintf(stderr, "%s Bad request line.\n", client->http.hostname);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+
+ case 2 :
+ client->http.version = HTTP_0_9;
+ break;
+
+ case 3 :
+ if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
+ {
+ fprintf(stderr, "%s Bad HTTP version.\n", client->http.hostname);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+
+ if (major < 2)
+ {
+ client->http.version = (http_version_t)(major * 100 + minor);
+ if (client->http.version == HTTP_1_1)
+ client->http.keep_alive = HTTP_KEEPALIVE_ON;
+ else
+ client->http.keep_alive = HTTP_KEEPALIVE_OFF;
+ }
+ else
+ {
+ respond_http(client, HTTP_NOT_SUPPORTED, NULL, 0);
+ return (0);
+ }
+ break;
+ }
+
+ /*
+ * Handle full URLs in the request line...
+ */
+
+ if (!strncmp(client->uri, "http:", 5) || !strncmp(client->uri, "ipp:", 4))
+ {
+ char scheme[32], /* Method/scheme */
+ userpass[128], /* Username:password */
+ hostname[HTTP_MAX_HOST];/* Hostname */
+ int port; /* Port number */
+
+ /*
+ * Separate the URI into its components...
+ */
+
+ if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port,
+ client->uri, sizeof(client->uri)) < HTTP_URI_OK)
+ {
+ fprintf(stderr, "%s Bad URI \"%s\".\n", client->http.hostname, uri);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+ }
+ else
+ {
+ /*
+ * Decode URI
+ */
+
+ if (!_httpDecodeURI(client->uri, uri, sizeof(client->uri)))
+ {
+ fprintf(stderr, "%s Bad URI \"%s\".\n", client->http.hostname, uri);
+ respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ return (0);
+ }
+ }
+
+ /*
+ * Process the request...
+ */
if (!strcmp(operation, "GET"))
client->http.state = HTTP_GET;
if (state == IPP_ERROR)
{
fprintf(stderr, "%s IPP read error (%s).\n", client->http.hostname,
- ippOpString(client->request->request.op.operation_id));
+ cupsLastErrorString());
respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
return (0);
}
ipp_print_job(client);
break;
+ case IPP_PRINT_URI :
+ ipp_print_uri(client);
+ break;
+
case IPP_VALIDATE_JOB :
ipp_validate_job(client);
break;
+ case IPP_CREATE_JOB :
+ ipp_create_job(client);
+ break;
+
+ case IPP_SEND_DOCUMENT :
+ ipp_send_document(client);
+ break;
+
+ case IPP_SEND_URI :
+ ipp_send_uri(client);
+ break;
+
case IPP_CANCEL_JOB :
ipp_cancel_job(client);
break;
}
+/*
+ * 'respond_unsupported()' - Respond with an unsupported attribute.
+ */
+
+static void
+respond_unsupported(
+ _ipp_client_t *client, /* I - Client */
+ ipp_attribute_t *attr) /* I - Atribute */
+{
+ if (!client->response->attrs)
+ respond_ipp(client, IPP_ATTRIBUTES, "Unsupported %s %s%s value.",
+ attr->name, attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag));
+
+ copy_attribute(client->response, attr, IPP_TAG_UNSUPPORTED_GROUP, 0);
+}
+
+
/*
* 'run_printer()' - Run the printer service.
*/
/*
- * 'valid_job_attributes()' - Determine whether the job attributes are valid.
+ * 'valid_doc_attributes()' - Determine whether the document attributes are
+ * valid.
*
- * When one or more job attributes are invalid, this function adds a suitable
- * response and attributes to the unsupported group.
+ * When one or more document attributes are invalid, this function adds a
+ * suitable response and attributes to the unsupported group.
*/
static int /* O - 1 if valid, 0 if not */
-valid_job_attributes(
+valid_doc_attributes(
_ipp_client_t *client) /* I - Client */
{
int i; /* Looping var */
ipp_attribute_t *attr, /* Current attribute */
*supported; /* document-format-supported */
const char *format = NULL; /* document-format value */
- int valid = 1; /* Valid attributes? */
/*
* Check operation attributes...
*/
-#define respond_unsupported(client, attr) \
- if (valid) \
- { \
- respond_ipp(client, IPP_ATTRIBUTES, "Unsupported %s %s%s value.", \
- attr->name, attr->num_values > 1 ? "1setOf " : "", \
- ippTagString(attr->value_tag)); \
- valid = 0; \
- } \
- copy_attribute(client->response, attr, IPP_TAG_UNSUPPORTED_GROUP, 0)
-
if ((attr = ippFindAttribute(client->request, "compression",
IPP_TAG_ZERO)) != NULL)
{
respond_unsupported(client, attr);
}
else
- fprintf(stderr, "%s Print-Job compression=\"%s\"\n",
- client->http.hostname, attr->values[0].string.text);
+ fprintf(stderr, "%s %s compression=\"%s\"\n",
+ client->http.hostname,
+ ippOpString(client->request->request.op.operation_id),
+ attr->values[0].string.text);
}
/*
format = "application/octet-stream";
if (!strcmp(format, "application/octet-stream") &&
- client->request->request.op.operation_id != IPP_VALIDATE_JOB)
+ (client->request->request.op.operation_id == IPP_PRINT_JOB ||
+ client->request->request.op.operation_id != IPP_SEND_DOCUMENT))
{
/*
* Auto-type the file using the first 4 bytes of the file...
}
}
+ return (!client->response->attrs ||
+ !client->response->attrs->next ||
+ !client->response->attrs->next->next);
+}
+
+
+/*
+ * 'valid_job_attributes()' - Determine whether the job attributes are valid.
+ *
+ * When one or more job attributes are invalid, this function adds a suitable
+ * response and attributes to the unsupported group.
+ */
+
+static int /* O - 1 if valid, 0 if not */
+valid_job_attributes(
+ _ipp_client_t *client) /* I - Client */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr, /* Current attribute */
+ *supported; /* xxx-supported attribute */
+
+
+ /*
+ * Check operation attributes...
+ */
+
+ valid_doc_attributes(client);
+
/*
* Check the various job template attributes...
*/
}
}
- return (valid);
+ return (!client->response->attrs ||
+ !client->response->attrs->next ||
+ !client->response->attrs->next->next);
}