Index: server/lib/gutenbach/ipp/__init__.py
===================================================================
--- server/lib/gutenbach/ipp/__init__.py	(revision 793432f59cc3f6d9a34ba213d3911b9cb3b86b05)
+++ server/lib/gutenbach/ipp/__init__.py	(revision 103711508848c1db8aa0dfc6d977ac327ed6fb21)
@@ -3,5 +3,4 @@
 __all__ = ['core']
 __all__.extend(core.__all__)
-print __all__
 
 import attributes
@@ -9,8 +8,2 @@
 __all__.append('attributes')
 __all__.extend(attributes.__all__)
-
-# this import needs to come last
-import operations
-from operations import *
-__all__.append('operations')
-__all__.extend(operations.__all__)
Index: server/lib/gutenbach/ipp/core/__init__.py
===================================================================
--- server/lib/gutenbach/ipp/core/__init__.py	(revision 793432f59cc3f6d9a34ba213d3911b9cb3b86b05)
+++ server/lib/gutenbach/ipp/core/__init__.py	(revision 103711508848c1db8aa0dfc6d977ac327ed6fb21)
@@ -11,3 +11,5 @@
 
 import errors
+from errors import *
 __all__.append('errors')
+__all__.extend(errors.__all__)
Index: server/lib/gutenbach/ipp/core/errors.py
===================================================================
--- server/lib/gutenbach/ipp/core/errors.py	(revision 793432f59cc3f6d9a34ba213d3911b9cb3b86b05)
+++ server/lib/gutenbach/ipp/core/errors.py	(revision 103711508848c1db8aa0dfc6d977ac327ed6fb21)
@@ -1,2 +1,46 @@
+__all__ = [
+    'IPPException',
+    'IPPClientException',
+    'IPPServerException',
+
+    'ClientErrorBadRequest',
+    'ClientErrorForbidden',
+    'ClientErrorNotAuthenticated',
+    'ClientErrorNotAuthorized',
+    'ClientErrorNotPossible',
+    'ClientErrorTimeout',
+    'ClientErrorNotFound',
+    'ClientErrorGone',
+    'ClientErrorRequestEntity',
+    'ClientErrorRequestValue',
+    'ClientErrorDocumentFormatNotSupported',
+    'ClientErrorAttributes',
+    'ClientErrorUriSchemeNotSupported',
+    'ClientErrorCharsetNotSupported',
+    'ClientErrorConflict',
+    'ClientErrorCompressionNotSupported',
+    'ClientErrorCompressionError',
+    'ClientErrorDocumentFormatError',
+    'ClientErrorDocumentAccessError',
+    'ClientErrorAttributesNotSettable',
+    'ClientErrorIgnoredAllSubscriptions',
+    'ClientErrorTooManySubscriptions',
+    'ClientErrorIgnoredAllNotifications',
+    'ClientErrorPrintSupportFileNotFound',
+
+    'ServerErrorInternalError',
+    'ServerErrorOperationNotSupported',
+    'ServerErrorServiceUnavailable',
+    'ServerErrorVersionNotSupported',
+    'ServerErrorDeviceError',
+    'ServerErrorTemporaryError',
+    'ServerErrorNotAccepting',
+    'ServerErrorPrinterBusy',
+    'ServerErrorJobCancelled',
+    'ServerErrorMultipleJobsNotSupported',
+    'ServerErrorPrinterIsDeactivated',
+]
+    
+
 from .constants import ErrorCodes
 
@@ -129,5 +173,5 @@
     ipp_error_code = ErrorCodes.PRINTER_BUSY
 
-class ServerErrorErrorJobCancelled(IPPServerException):
+class ServerErrorJobCancelled(IPPServerException):
     ipp_error_code = ErrorCodes.ERROR_JOB_CANCELLED
 
Index: server/lib/gutenbach/ipp/operations/__init__.py
===================================================================
--- server/lib/gutenbach/ipp/operations/__init__.py	(revision 793432f59cc3f6d9a34ba213d3911b9cb3b86b05)
+++ 	(revision )
@@ -1,157 +1,0 @@
-from .. import Attribute
-from .. import AttributeGroup
-from .. import Request
-from .. import Value
-from .. import errors
-from .. import constants
-from .. import attributes
-
-def verify_operations(request):
-    """Pretty much all requests have the first attribute group for
-    operation attributes, and these all have 'attributes-charset' and
-    'attributes-natural-language' as the first two attributes.  This
-    method just generically verifies that these attributes are there.
-
-    """
-
-    # XXX: check version
-    if False:
-        raise errors.ClientErrorVersionNotSupported(str(request.version))
-
-    # XXX: check operation id
-    if False:
-        raise errors.ClientErrorOperationNotSupported(str(request.operation_id))
-
-    # check operation attributes tag
-    op_attrs = request.attribute_groups[0]
-    if op_attrs.tag != constants.AttributeTags.OPERATION:
-        raise errors.ClientErrorBadRequest(
-            "Attribute group does not have OPERATION tag: 0x%x" % op_attrs.tag)
-
-    # XXX: if these aren't valid, then you HAVE to return something
-    # special.  See RFC 2911 3.1.6.1
-    # # check compression
-    # if False:
-    #     raise errors.ClientErrorCompressionNotSupported
-
-    # # check document format
-    # if False:
-    #     raise errors.ClientErrorDocumentFormatNotSupported
-
-    # # check document uri
-    # if False:
-    #     raise errors.ClientErrorUriSchemeNotSupported
-
-    # check charset
-    charset_attr = op_attrs.attributes[0]
-    expected = attributes.AttributesCharset('utf-8')
-    if charset_attr != expected:
-        raise errors.ClientErrorBadRequest("%s != %s" % (charset_attr, expected))
-
-    # check for attributes-natural-language
-    natlang_attr = op_attrs.attributes[1]
-    expected = attributes.AttributesNaturalLanguage('en-us')
-    if natlang_attr != expected:
-        raise errors.ClientErrorBadRequest("%s != %s" % (natlang_attr, expected))
-
-    return dict([(attr.name, attr) for attr in op_attrs.attributes])
-
-def verify_printer_uri(uri_attr):
-    expected = attributes.PrinterUri(uri_attr.values[0].value)
-    if uri_attr != expected:
-        raise errors.ClientErrorBadRequest("%s != %s" % (uri_attr, expected))
-    
-    # actually get the printer name
-    # XXX: hack -- CUPS will strip the port from the request, so
-    # we can't do an exact comparison (also the hostname might be
-    # different, depending on the CNAME or whether it's localhost)
-    uri = uri_attr.values[0].value.split("/")[-1]
-    return uri
-
-def verify_requesting_username(username_attr):
-    expected = attributes.RequestingUserName(username_attr.values[0].value)
-    if username_attr != expected:
-        raise errors.ClientErrorBadRequest("%s != %s" % (username_attr, expected))
-    return username_attr.values[0].value
-
-def make_empty_response(request):
-    # Operation attributes -- typically the same for any request
-    attribute_group = AttributeGroup(
-        constants.AttributeTags.OPERATION,
-        [attributes.AttributesCharset('utf-8'),
-         attributes.AttributesNaturalLanguage('en-us')])
-
-    # Set up the default response -- handlers will override these
-    # values if they need to
-    response_kwargs = {}
-    response_kwargs['version']          = request.version
-    response_kwargs['operation_id']     = constants.StatusCodes.OK
-    response_kwargs['request_id']       = request.request_id
-    response_kwargs['attribute_groups'] = [attribute_group]
-    response = Request(**response_kwargs)
-
-    return response
-
-def make_job_attributes(attrs, request, response):
-    response.attribute_groups.append(AttributeGroup(
-        constants.AttributeTags.JOB, attrs))
-
-def make_printer_attributes(attrs, request, response):
-    response.attribute_groups.append(AttributeGroup(
-        constants.AttributeTags.PRINTER, attrs))
-
-from cups_get_classes import verify_cups_get_classes_request, make_cups_get_classes_response
-from cups_get_default import verify_cups_get_default_request, make_cups_get_default_response
-from cups_get_document import verify_cups_get_document_request, make_cups_get_document_response
-from cups_get_printers import verify_cups_get_printers_request, make_cups_get_printers_response
-
-from cancel_job import verify_cancel_job_request, make_cancel_job_response
-from create_job import verify_create_job_request, make_create_job_response
-from get_jobs import verify_get_jobs_request, make_get_jobs_response
-from get_printer_attributes import make_get_printer_attributes_response
-from get_printer_attributes import verify_get_printer_attributes_request
-from pause_printer import verify_pause_printer_request, make_pause_printer_response
-from print_job import verify_print_job_request, make_print_job_response
-from print_uri import verify_print_uri_request, make_print_uri_response
-from promote_job import verify_promote_job_request, make_promote_job_response
-from restart_job import verify_restart_job_request, make_restart_job_response
-from resume_printer import verify_resume_printer_request, make_resume_printer_response
-from send_document import verify_send_document_request, make_send_document_response
-from send_uri import verify_send_uri_request, make_send_uri_response
-from set_job_attributes import make_set_job_attributes_response
-from set_job_attributes import verify_set_job_attributes_request
-from set_printer_attributes import make_set_printer_attributes_response
-from set_printer_attributes import verify_set_printer_attributes_request
-from validate_job import verify_validate_job_request, make_validate_job_response
-
-__all__ = ['verify_cups_get_classes_request', 'make_cups_get_classes_response',
-           'verify_cups_get_default_request', 'make_cups_get_default_response',
-           'verify_cups_get_document_request', 'make_cups_get_document_response',
-           'verify_cups_get_printers_request', 'make_cups_get_printers_response',
-
-           'verify_cancel_job_request', 'make_cancel_job_response',
-           'verify_create_job_request', 'make_create_job_response',
-           'verify_get_jobs_request', 'make_get_jobs_response',
-           'make_get_printer_attributes_response',
-           'verify_get_printer_attributes_request',
-           'verify_pause_printer_request', 'make_pause_printer_response',
-           'verify_print_job_request', 'make_print_job_response',
-           'verify_print_uri_request', 'make_print_uri_response',
-           'verify_promote_job_request', 'make_promote_job_response',
-           'verify_restart_job_request', 'make_restart_job_response',
-           'verify_resume_printer_request', 'make_resume_printer_response',
-           'verify_send_document_request', 'make_send_document_response',
-           'verify_send_uri_request', 'make_send_uri_response',
-           'make_set_job_attributes_response',
-           'verify_set_job_attributes_request',
-           'make_set_printer_attributes_response',
-           'verify_set_printer_attributes_request',
-           'verify_validate_job_request', 'make_validate_job_response',
-
-           'verify_operations',
-           'verify_printer_uri',
-           'verify_requesting_username',
-
-           'make_empty_response',
-           'make_job_attributes',
-           'make_printer_attributes']
Index: server/lib/gutenbach/ipp/operations/cancel_job.py
===================================================================
--- server/lib/gutenbach/ipp/operations/cancel_job.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_cancel_job_request(request):
-    pass
-
-def make_cancel_job_response(job, request):
-    pass
Index: server/lib/gutenbach/ipp/operations/create_job.py
===================================================================
--- server/lib/gutenbach/ipp/operations/create_job.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_create_job_request(request):
-    pass
-
-def make_create_job_response(job, request):
-    pass
Index: server/lib/gutenbach/ipp/operations/cups_get_classes.py
===================================================================
--- server/lib/gutenbach/ipp/operations/cups_get_classes.py	(revision 5e44432a90121b6549c44270dbae8ec7d3888f5b)
+++ 	(revision )
@@ -1,77 +1,0 @@
-from . import verify_operations
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_cups_get_classes_request(request):
-    """CUPS-Get-Classes Request
-
-    The following groups of attributes are supplied as part of the
-    CUPS-Get-Classes request:
-
-    Group 1: Operation Attributes
-        Natural Language and Character Set:
-            The 'attributes-charset' and
-            'attributes-natural-language' attributes as described
-            in section 3.1.4.1 of the IPP Model and Semantics
-            document.
-        'first-printer-name' (name(127)):CUPS 1.2/Mac OS X 10.5
-            The client OPTIONALLY supplies this attribute to
-            select the first printer that is returned.
-        'limit' (integer (1:MAX)):
-            The client OPTIONALLY supplies this attribute limiting
-            the number of printer classes that are returned.
-        'printer-location' (text(127)): CUPS 1.1.7
-            The client OPTIONALLY supplies this attribute to
-            select which printer classes are returned.
-        'printer-type' (type2 enum): CUPS 1.1.7
-            The client OPTIONALLY supplies a printer type
-            enumeration to select which printer classes are
-            returned.
-        'printer-type-mask' (type2 enum): CUPS 1.1.7
-            The client OPTIONALLY supplies a printer type mask
-            enumeration to select which bits are used in the
-            'printer-type' attribute.
-        'requested-attributes' (1setOf keyword) :
-            The client OPTIONALLY supplies a set of attribute
-            names and/or attribute group names in whose values the
-            requester is interested. If the client omits this
-            attribute, the server responds as if this attribute
-            had been supplied with a value of 'all'.
-        'requested-user-name' (name(127)) : CUPS 1.2/Mac OS X 10.5
-            The client OPTIONALLY supplies a user name that is
-            used to filter the returned printers.
-
-    (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_CLASSES )
-
-    """
-
-    # XXX: actually do something here
-    return {}
-
-def make_cups_get_classes_response(request):
-    """CUPS-Get-Classes Response
-
-    The following groups of attributes are send as part of the
-    CUPS-Get-Classes Response:
-
-    Group 1: Operation Attributes
-        Status Message:
-            The standard response status message.
-        Natural Language and Character Set:
-            The 'attributes-charset' and
-            'attributes-natural-language' attributes as described
-            in section 3.1.4.2 of the IPP Model and Semantics
-            document.
-
-    Group 2: Printer Class Object Attributes
-        The set of requested attributes and their current values
-        for each printer class.
-
-    (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_CLASSES )
-
-    """
-
-    response = make_empty_response(request)
-    return response
Index: server/lib/gutenbach/ipp/operations/cups_get_default.py
===================================================================
--- server/lib/gutenbach/ipp/operations/cups_get_default.py	(revision 5e44432a90121b6549c44270dbae8ec7d3888f5b)
+++ 	(revision )
@@ -1,57 +1,0 @@
-from . import verify_operations
-from . import make_empty_response
-from . import make_printer_attributes
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_cups_get_default_request(request):
-    """CUPS-Get-Default Request
-    
-    The following groups of attributes are supplied as part of the
-    CUPS-Get-Default request:
-
-    Group 1: Operation Attributes
-        Natural Language and Character Set:
-            The 'attributes-charset' and
-            'attributes-natural-language' attributes as described
-            in section 3.1.4.1 of the IPP Model and Semantics
-            document.
-        'requested-attributes' (1setOf keyword):
-            The client OPTIONALLY supplies a set of attribute
-            names and/or attribute group names in whose values the
-            requester is interested. If the client omits this
-            attribute, the server responds as if this attribute
-            had been supplied with a value of 'all'.
-
-    (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_DEFAULT )
-
-    """
-
-    return {}
-
-def make_cups_get_default_response(attrs, request):
-    """CUPS-Get-Default Response
-
-    The following groups of attributes are send as part of the
-    CUPS-Get-Default Response:
-
-    Group 1: Operation Attributes
-        Status Message:
-            The standard response status message.
-        Natural Language and Character Set:
-            The 'attributes-charset' and
-            'attributes-natural-language' attributes as described
-            in section 3.1.4.2 of the IPP Model and Semantics
-            document.
-
-    Group 2: Printer Object Attributes
-        The set of requested attributes and their current values.
-
-    (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_DEFAULT )
-
-    """
-
-    response = make_empty_response(request)
-    make_printer_attributes(attrs, request, response)
-    return response
Index: server/lib/gutenbach/ipp/operations/cups_get_document.py
===================================================================
--- server/lib/gutenbach/ipp/operations/cups_get_document.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,12 +1,0 @@
-from . import verify_operations
-from . import make_empty_response
-from . import make_printer_attributes
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_cups_get_document_request(request):
-    pass
-
-def make_cups_get_document_response(request):
-    pass
Index: server/lib/gutenbach/ipp/operations/cups_get_printers.py
===================================================================
--- server/lib/gutenbach/ipp/operations/cups_get_printers.py	(revision 5e44432a90121b6549c44270dbae8ec7d3888f5b)
+++ 	(revision )
@@ -1,79 +1,0 @@
-from . import verify_operations
-from . import make_empty_response
-from . import make_printer_attributes
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_cups_get_printers_request(request):
-    """CUPS-Get-Printers Request
-    
-    The following groups of attributes are supplied as part of the
-    CUPS-Get-Printers request:
-
-    Group 1: Operation Attributes
-        Natural Language and Character Set:
-            The 'attributes-charset' and
-            'attributes-natural-language' attributes as described
-            in section 3.1.4.1 of the IPP Model and Semantics
-            document.
-        'first-printer-name' (name(127)):CUPS 1.2/Mac OS X 10.5
-            The client OPTIONALLY supplies this attribute to
-            select the first printer that is returned.
-        'limit' (integer (1:MAX)):
-            The client OPTIONALLY supplies this attribute limiting
-            the number of printers that are returned.
-        'printer-location' (text(127)): CUPS 1.1.7
-            The client OPTIONALLY supplies this attribute to
-            select which printers are returned.
-        'printer-type' (type2 enum): CUPS 1.1.7
-            The client OPTIONALLY supplies a printer type
-            enumeration to select which printers are returned.
-        'printer-type-mask' (type2 enum): CUPS 1.1.7
-            The client OPTIONALLY supplies a printer type mask
-            enumeration to select which bits are used in the
-            'printer-type' attribute.
-        'requested-attributes' (1setOf keyword) :
-            The client OPTIONALLY supplies a set of attribute
-            names and/or attribute group names in whose values the
-            requester is interested. If the client omits this
-            attribute, the server responds as if this attribute
-            had been supplied with a value of 'all'.
-        'requested-user-name' (name(127)) : CUPS 1.2/Mac OS X 10.5
-            The client OPTIONALLY supplies a user name that is
-            used to filter the returned printers.
-
-    (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_PRINTERS )
-
-    """
-
-    # XXX: actually do something here
-    return {}
-
-def make_cups_get_printers_response(printers, request):
-    """CUPS-Get-Printers Response
-
-    The following groups of attributes are send as part of the
-    CUPS-Get-Printers Response:
-
-    Group 1: Operation Attributes
-        Status Message:
-            The standard response status message.
-        Natural Language and Character Set:
-            The 'attributes-charset' and
-            'attributes-natural-language' attributes as described
-            in section 3.1.4.2 of the IPP Model and Semantics
-            document.
-            
-    Group 2: Printer Object Attributes
-        The set of requested attributes and their current values
-        for each printer.
-
-    (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_PRINTERS )
-
-    """
-
-    response = make_empty_response(request)
-    for printer in printers:
-        make_printer_attributes(printer, request, response)
-    return response
Index: server/lib/gutenbach/ipp/operations/get_jobs.py
===================================================================
--- server/lib/gutenbach/ipp/operations/get_jobs.py	(revision aded2d1280aa9d2333d252f6f2557cfa3b1b1cd1)
+++ 	(revision )
@@ -1,201 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-from . import make_job_attributes
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_get_jobs_request(request):
-    """RFC 2911 3.2.6.1 Get-Jobs Request
-
-    The client submits the Get-Jobs request to a Printer object.
-    
-    The following groups of attributes are part of the Get-Jobs
-    Request:
-
-    Group 1: Operation Attributes
-        Natural Language and Character Set:
-            The 'attributes-charset' and
-            'attributes-natural-language' attributes as described
-            in section 3.1.4.1.
-        Target:
-            The 'printer-uri' (uri) operation attribute which is
-            the target for this operation as described in section
-            3.1.5.
-        Requesting User Name:
-            The 'requesting-user-name' (name(MAX)) attribute
-            SHOULD be supplied by the client as described in
-            section 8.3.
-        'limit' (integer(1:MAX)):
-            The client OPTIONALLY supplies this attribute. The
-            Printer object MUST support this attribute. It is an
-            integer value that determines the maximum number of
-            jobs that a client will receive from the Printer even
-            if 'which-jobs' or 'my-jobs' constrain which jobs are
-            returned. The limit is a 'stateless limit' in that if
-            the value supplied by the client is 'N', then only the
-            first 'N' jobs are returned in the Get-Jobs Response.
-            There is no mechanism to allow for the next 'M' jobs
-            after the first 'N' jobs. If the client does not
-            supply this attribute, the Printer object responds
-            with all applicable jobs.
-        'requested-attributes' (1setOf type2 keyword):
-            The client OPTIONALLY supplies this attribute. The
-            Printer object MUST support this attribute. It is a
-            set of Job attribute names and/or attribute groups
-            names in whose values the requester is
-            interested. This set of attributes is returned for
-            each Job object that is returned. The allowed
-            attribute group names are the same as those defined in
-            the Get-Job-Attributes operation in section 3.3.4. If
-            the client does not supply this attribute, the Printer
-            MUST respond as if the client had supplied this
-            attribute with two values: 'job-uri' and 'job-id'.
-        'which-jobs' (type2 keyword):
-            The client OPTIONALLY supplies this attribute. The
-            Printer object MUST support this attribute. It
-            indicates which Job objects MUST be returned by the
-            Printer object. The values for this attribute are:
-             - 'completed': This includes any Job object whose
-               state is 'completed', 'canceled', or 'aborted'.
-             - 'not-completed': This includes any Job object whose
-               state is 'pending', 'processing',
-               'processing-stopped', or 'pending-held'.
-            A Printer object MUST support both values. However, if
-            the implementation does not keep jobs in the
-            'completed', 'canceled', and 'aborted' states, then it
-            returns no jobs when the 'completed' value is
-            supplied.  If a client supplies some other value, the
-            Printer object MUST copy the attribute and the
-            unsupported value to the Unsupported Attributes
-            response group, reject the request, and return the
-            'client-error-attributes-or-values-not-supported'
-            status code.  If the client does not supply this
-            attribute, the Printer object MUST respond as if the
-            client had supplied the attribute with a value of
-            'not-completed'.
-        'my-jobs' (boolean):
-            The client OPTIONALLY supplies this attribute. The
-            Printer object MUST support this attribute. It
-            indicates whether jobs from all users or just the jobs
-            submitted by the requesting user of this request MUST
-            be considered as candidate jobs to be returned by the
-            Printer object. If the client does not supply this
-            attribute, the Printer object MUST respond as if the
-            client had supplied the attribute with a value of
-            'false', i.e., jobs from all users. The means for
-            authenticating the requesting user and matching the
-            jobs is described in section 8.
-
-    """
-
-    out = {}
-
-    # generic operations verification
-    attrs = verify_operations(request)
-
-    # requested printer uri
-    if 'printer-uri' not in attrs:
-        raise err.ClientErrorBadRequest("Missing 'printer-uri' attribute")
-    out['printer-uri'] = verify_printer_uri(attrs['printer-uri'])
-    
-    # requesting username
-    if 'requesting-user-name' not in attrs:
-        logger.warning("Missing 'requesting-user-name' attribute")
-    else:
-        out['requesting-user-name'] = verify_requesting_username(attrs['requesting-user-name'])
-
-    if 'limit' in attrs:
-        out['limit'] = None # XXX
-
-    if 'requested-attributes' in attrs:
-        out['requested-attributes'] = None # XXX
-
-    if 'which-jobs' in attrs:
-        out['which-jobs'] = None # XXX
-
-    if 'my-jobs' in attrs:
-        out['my-jobs'] = None # XXX
-
-    return out
-
-def make_get_jobs_response(jobs, request):
-    """RFC 2911: 3.2.6.2 Get-Jobs Response
-        
-    The Printer object returns all of the Job objects up to the number
-    specified by the 'limit' attribute that match the criteria as
-    defined by the attribute values supplied by the client in the
-    request. It is possible that no Job objects are returned since
-    there may literally be no Job objects at the Printer, or there may
-    be no Job objects that match the criteria supplied by the
-    client. If the client requests any Job attributes at all, there is
-    a set of Job Object Attributes returned for each Job object.
-
-    It is not an error for the Printer to return 0 jobs. If the
-    response returns 0 jobs because there are no jobs matching the
-    criteria, and the request would have returned 1 or more jobs
-    with a status code of 'successful-ok' if there had been jobs
-    matching the criteria, then the status code for 0 jobs MUST be
-    'successful-ok'.
-
-    Group 1: Operation Attributes
-        Status Message:
-            In addition to the REQUIRED status code returned in
-            every response, the response OPTIONALLY includes a
-            'status-message' (text(255)) and/or a
-            'detailed-status-message' (text(MAX)) operation
-            attribute as described in sections 13 and 3.1.6.
-        Natural Language and Character Set:
-            The 'attributes-charset' and
-            'attributes-natural-language' attributes as described
-            in section 3.1.4.2.
-
-    Group 2: Unsupported Attributes
-        See section 3.1.7 for details on returning Unsupported
-        Attributes.  The response NEED NOT contain the
-        'requested-attributes' operation attribute with any
-        supplied values (attribute keywords) that were requested
-        by the client but are not supported by the IPP object.  If
-        the Printer object does return unsupported attributes
-        referenced in the 'requested-attributes' operation
-        attribute and that attribute included group names, such as
-        'all', the unsupported attributes MUST NOT include
-        attributes described in the standard but not supported by
-        the implementation.
-
-    Groups 3 to N: Job Object Attributes
-        The Printer object responds with one set of Job Object
-        Attributes for each returned Job object. The Printer
-        object ignores (does not respond with) any requested
-        attribute or value which is not supported or which is
-        restricted by the security policy in force, including
-        whether the requesting user is the user that submitted the
-        job (job originating user) or not (see section
-        8). However, the Printer object MUST respond with the
-        'unknown' value for any supported attribute (including all
-        REQUIRED attributes) for which the Printer object does not
-        know the value, unless it would violate the security
-        policy. See the description of the 'out-of- band' values
-        in the beginning of Section 4.1.
-
-        Jobs are returned in the following order:
-        - If the client requests all 'completed' Jobs (Jobs in the
-          'completed', 'aborted', or 'canceled' states), then the
-          Jobs are returned newest to oldest (with respect to
-          actual completion time)
-        - If the client requests all 'not-completed' Jobs (Jobs in
-          the 'pending', 'processing', 'pending-held', and
-          'processing- stopped' states), then Jobs are returned in
-          relative chronological order of expected time to
-          complete (based on whatever scheduling algorithm is
-          configured for the Printer object).
-
-    """
-
-    response = make_empty_response(request)
-    # XXX: we need to honor the things that the request actually asks for
-    for job in jobs:
-        make_job_attributes(job, request, response)
-    return response
Index: server/lib/gutenbach/ipp/operations/get_printer_attributes.py
===================================================================
--- server/lib/gutenbach/ipp/operations/get_printer_attributes.py	(revision 5e44432a90121b6549c44270dbae8ec7d3888f5b)
+++ 	(revision )
@@ -1,183 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-from . import make_printer_attributes
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_get_printer_attributes_request(request):
-    """RFC 2911: 3.2.5.1 Get-Printer-Attributes Request
-
-    The following sets of attributes are part of the Get-Printer-
-    Attributes Request:
-
-    Group 1: Operation Attributes
-        Natural Language and Character Set:
-            The 'attributes-charset' and 'attributes-natural-language'
-            attributes as described in section 3.1.4.1.
-        Target:
-            The 'printer-uri' (uri) operation attribute which is the
-            target for this operation as described in section 3.1.5.
-        Requesting User Name:
-            The 'requesting-user-name' (name(MAX)) attribute SHOULD be
-            supplied by the client as described in section 8.3.
-        'requested-attributes' (1setOf keyword):
-            The client OPTIONALLY supplies a set of attribute names
-            and/or attribute group names in whose values the requester
-            is interested. The Printer object MUST support this
-            attribute.  If the client omits this attribute, the
-            Printer MUST respond as if this attribute had been
-            supplied with a value of 'all'.
-        'document-format' (mimeMediaType):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object MUST support this attribute. This attribute is
-            useful for a Printer object to determine the set of
-            supported attribute values that relate to the requested
-            document format.  The Printer object MUST return the
-            attributes and values that it uses to validate a job on a
-            create or Validate-Job operation in which this document
-            format is supplied. The Printer object SHOULD return only
-            (1) those attributes that are supported for the specified
-            format and (2) the attribute values that are supported for
-            the specified document format. By specifying the document
-            format, the client can get the Printer object to eliminate
-            the attributes and values that are not supported for a
-            specific document format. For example, a Printer object
-            might have multiple interpreters to support both
-            'application/postscript' (for PostScript) and 'text/plain'
-            (for text) documents. However, for only one of those
-            interpreters might the Printer object be able to support
-            'number-up' with values of '1', '2', and '4'. For the
-            other interpreter it might be able to only support
-            'number-up' with a value of '1'.  Thus a client can use
-            the Get-Printer-Attributes operation to obtain the
-            attributes and values that will be used to accept/reject a
-            create job operation.
-
-            If the Printer object does not distinguish between
-            different sets of supported values for each different
-            document format when validating jobs in the create and
-            Validate-Job operations, it MUST NOT distinguish between
-            different document formats in the Get-Printer-Attributes
-            operation. If the Printer object does distinguish between
-            different sets of supported values for each different
-            document format specified by the client, this
-            specialization applies only to the following Printer
-            object attributes:
-
-            - Printer attributes that are Job Template attributes
-              ('xxx- default' 'xxx-supported', and 'xxx-ready' in the
-              Table in Section 4.2),
-
-            - 'pdl-override-supported',
-            - 'compression-supported',
-            - 'job-k-octets-supported',
-            - 'job-impressions-supported',
-            - 'job-media-sheets-supported',
-            - 'printer-driver-installer',
-            - 'color-supported', and
-            - 'reference-uri-schemes-supported'
-
-            The values of all other Printer object attributes
-            (including 'document-format-supported') remain invariant
-            with respect to the client supplied document format
-            (except for new Printer description attribute as
-            registered according to section 6.2).
-
-            If the client omits this 'document-format' operation
-            attribute, the Printer object MUST respond as if the
-            attribute had been supplied with the value of the Printer
-            object's 'document-format- default' attribute. It is
-            RECOMMENDED that the client always supply a value for
-            'document-format', since the Printer object's
-            'document-format-default' may be
-            'application/octet-stream', in which case the returned
-            attributes and values are for the union of the document
-            formats that the Printer can automatically sense.  For
-            more details, see the description of the 'mimeMediaType'
-            attribute syntax in section 4.1.9.
-
-            If the client supplies a value for the 'document-format'
-            Operation attribute that is not supported by the Printer,
-            i.e., is not among the values of the Printer object's
-            'document-format-supported' attribute, the Printer object
-            MUST reject the operation and return the
-            'client-error-document-format-not-supported' status code.
-
-    """
-
-    out = {}
-
-    # generic operations verification
-    attrs = verify_operations(request)
-
-    # requested printer uri
-    if 'printer-uri' not in attrs:
-        raise err.BadRequest("Missing 'printer-uri' attribute")
-    out['printer-uri']  = verify_printer_uri(attrs['printer-uri'])
-
-    # requesting username
-    if 'requesting-user-name' not in attrs:
-        logger.warning("Missing 'requesting-user-name' attribute")
-    else:
-        out['requesting-user-name'] = verify_requesting_username(attrs['requesting-user-name'])
-
-    if 'requested-attributes' in attrs:
-        out['requested-attributes'] = None # XXX
-
-    if 'document-format' in attrs:
-        out['document-format'] = None # XXX
-
-    return out
-
-def make_get_printer_attributes_response(attrs, request):
-    """3.2.5.2 Get-Printer-Attributes Response
-
-    The Printer object returns the following sets of attributes as
-    part of the Get-Printer-Attributes Response:
-
-    Group 1: Operation Attributes
-        Status Message:
-            In addition to the REQUIRED status code returned in every
-            response, the response OPTIONALLY includes a
-            'status-message' (text(255)) and/or a
-            'detailed-status-message' (text(MAX)) operation attribute
-            as described in sections 13 and 3.1.6.
-        Natural Language and Character Set:
-            The 'attributes-charset' and 'attributes-natural-language'
-            attributes as described in section 3.1.4.2.
-
-    Group 2: Unsupported Attributes
-        See section 3.1.7 for details on returning Unsupported
-        Attributes.  The response NEED NOT contain the
-        'requested-attributes' operation attribute with any supplied
-        values (attribute keywords) that were requested by the client
-        but are not supported by the IPP object.  If the Printer
-        object does return unsupported attributes referenced in the
-        'requested-attributes' operation attribute and that attribute
-        included group names, such as 'all', the unsupported
-        attributes MUST NOT include attributes described in the
-        standard but not supported by the implementation.
-
-    Group 3: Printer Object Attributes
-        This is the set of requested attributes and their current
-        values.  The Printer object ignores (does not respond with)
-        any requested attribute which is not supported. The Printer
-        object MAY respond with a subset of the supported attributes
-        and values, depending on the security policy in
-        force. However, the Printer object MUST respond with the
-        'unknown' value for any supported attribute (including all
-        REQUIRED attributes) for which the Printer object does not
-        know the value. Also the Printer object MUST respond with the
-        'no-value' for any supported attribute (including all REQUIRED
-        attributes) for which the system administrator has not
-        configured a value. See the description of the 'out-of-band'
-        values in the beginning of Section 4.1.
-
-    """
-
-    response = make_empty_response(request)
-    make_printer_attributes(attrs, request, response)
-    return response
Index: server/lib/gutenbach/ipp/operations/pause_printer.py
===================================================================
--- server/lib/gutenbach/ipp/operations/pause_printer.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_pause_printer_request(request):
-    pass
-
-def make_pause_printer_response(request):
-    pass
Index: server/lib/gutenbach/ipp/operations/print_job.py
===================================================================
--- server/lib/gutenbach/ipp/operations/print_job.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,339 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_print_job_request(request):
-    """3.2.1.1 Print-Job Request
-
-    The following groups of attributes are supplied as part of the
-    Print-Job Request:
-
-    Group 1: Operation Attributes
-        Natural Language and Character Set:
-            The 'attributes-charset' and 'attributes-natural-language'
-            attributes as described in section 3.1.4.1. The Printer
-            object MUST copy these values to the corresponding Job
-            Description attributes described in sections 4.3.19 and
-            4.3.20.
-        Target:
-            The 'printer-uri' (uri) operation attribute which is the
-            target for this operation as described in section 3.1.5.
-        Requesting User Name:
-            The 'requesting-user-name' (name(MAX)) attribute SHOULD be
-            supplied by the client as described in section 8.3.
-        'job-name' (name(MAX)):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object MUST support this attribute. It contains the client
-            supplied Job name. If this attribute is supplied by the
-            client, its value is used for the 'job-name' attribute of
-            the newly created Job object. The client MAY automatically
-            include any information that will help the end-user
-            distinguish amongst his/her jobs, such as the name of the
-            application program along with information from the
-            document, such as the document name, document subject, or
-            source file name. If this attribute is not supplied by the
-            client, the Printer generates a name to use in the
-            'job-name' attribute of the newly created Job object (see
-            Section 4.3.5).
-        'ipp-attribute-fidelity' (boolean):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object MUST support this attribute. The value 'true'
-            indicates that total fidelity to client supplied Job
-            Template attributes and values is required, else the
-            Printer object MUST reject the Print-Job request. The
-            value 'false' indicates that a reasonable attempt to print
-            the Job object is acceptable and the Printer object MUST
-            accept the Print-Job request. If not supplied, the Printer
-            object assumes the value is 'false'. All Printer objects
-            MUST support both types of job processing. See section 15
-            for a full description of 'ipp-attribute-fidelity' and its
-            relationship to other attributes, especially the Printer
-            object's 'pdl-override-supported' attribute.
-        'document-name' (name(MAX)):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object MUST support this attribute.  It contains the
-            client supplied document name. The document name MAY be
-            different than the Job name. Typically, the client
-            software automatically supplies the document name on
-            behalf of the end user by using a file name or an
-            application generated name. If this attribute is supplied,
-            its value can be used in a manner defined by each
-            implementation. Examples include: printed along with the
-            Job (job start sheet, page adornments, etc.), used by
-            accounting or resource tracking management tools, or even
-            stored along with the document as a document level
-            attribute. IPP/1.1 does not support the concept of
-            document level attributes.
-        'compression' (type3 keyword):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object MUST support this attribute and the 'compression-
-            supported' attribute (see section 4.4.32). The client
-            supplied 'compression' operation attribute identifies the
-            compression algorithm used on the document data. The
-            following cases exist:
-            a) If the client omits this attribute, the Printer object
-               MUST assume that the data is not compressed (i.e. the
-               Printer follows the rules below as if the client
-               supplied the 'compression' attribute with a value of
-               'none').
-            b) If the client supplies this attribute, but the value is
-               not supported by the Printer object, i.e., the value is
-               not one of the values of the Printer object's
-               'compression- supported' attribute, the Printer object
-               MUST reject the request, and return the
-               'client-error-compression-not- supported' status
-               code. See section 3.1.7 for returning unsupported
-               attributes and values.
-            c) If the client supplies the attribute and the Printer
-               object supports the attribute value, the Printer object
-               uses the corresponding decompression algorithm on the
-               document data.
-            d) If the decompression algorithm fails before the Printer
-               returns an operation response, the Printer object MUST
-               reject the request and return the 'client-error-
-               compression-error' status code.
-            e) If the decompression algorithm fails after the Printer
-               returns an operation response, the Printer object MUST
-               abort the job and add the 'compression-error' value to
-               the job's 'job-state-reasons' attribute.
-            f) If the decompression algorithm succeeds, the document
-               data MUST then have the format specified by the job's
-               'document- format' attribute, if supplied (see
-               'document-format' operation attribute definition
-               below).
-        'document-format' (mimeMediaType):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object MUST support this attribute. The value of this
-            attribute identifies the format of the supplied document
-            data.  The following cases exist:
-            a) If the client does not supply this attribute, the
-               Printer object assumes that the document data is in the
-               format defined by the Printer object's
-               'document-format-default' attribute. (i.e. the Printer
-               follows the rules below as if the client supplied the
-               'document-format' attribute with a value equal to the
-               printer's default value).
-            b) If the client supplies this attribute, but the value is
-               not supported by the Printer object, i.e., the value is
-               not one of the values of the Printer object's
-               'document-format- supported' attribute, the Printer
-               object MUST reject the request and return the
-               'client-error-document-format-not- supported' status
-               code.
-            c) If the client supplies this attribute and its value is
-               'application/octet-stream' (i.e. to be auto-sensed, see
-               Section 4.1.9.1), and the format is not one of the
-               document-formats that the Printer can auto-sense, and
-               this check occurs before the Printer returns an
-               operation response, then the Printer MUST reject the
-               request and return the
-               'client-error-document-format-not-supported' status
-               code.
-            d) If the client supplies this attribute, and the value is
-               supported by the Printer object, the Printer is capable
-               of interpreting the document data.
-            e) If interpreting of the document data fails before the
-               Printer returns an operation response, the Printer
-               object MUST reject the request and return the
-               'client-error- document-format-error' status code.
-            f) If interpreting of the document data fails after the
-               Printer returns an operation response, the Printer
-               object MUST abort the job and add the
-               'document-format-error' value to the job's
-               'job-state-reasons' attribute.
-        'document-natural-language' (naturalLanguage):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object OPTIONALLY supports this attribute. This attribute
-            specifies the natural language of the document for those
-            document-formats that require a specification of the
-            natural language in order to image the document
-            unambiguously. There are no particular values required for
-            the Printer object to support.
-        'job-k-octets' (integer(0:MAX)):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object OPTIONALLY supports this attribute and the 'job-k-
-            octets-supported' attribute (see section 4.4.33). The
-            client supplied 'job-k-octets' operation attribute
-            identifies the total size of the document(s) in K octets
-            being submitted (see section 4.3.17.1 for the complete
-            semantics). If the client supplies the attribute and the
-            Printer object supports the attribute, the value of the
-            attribute is used to populate the Job object's
-            'job-k-octets' Job Description attribute.  For this
-            attribute and the following two attributes ('job-
-            impressions', and 'job-media-sheets'), if the client
-            supplies the attribute, but the Printer object does not
-            support the attribute, the Printer object ignores the
-            client-supplied value. If the client supplies the
-            attribute and the Printer supports the attribute, and the
-            value is within the range of the corresponding Printer
-            object's 'xxx-supported' attribute, the Printer object
-            MUST use the value to populate the Job object's 'xxx'
-            attribute. If the client supplies the attribute and the
-            Printer supports the attribute, but the value is outside
-            the range of the corresponding Printer object's 'xxx-
-            supported' attribute, the Printer object MUST copy the
-            attribute and its value to the Unsupported Attributes
-            response group, reject the request, and return the
-            'client-error- attributes-or-values-not-supported' status
-            code. If the client does not supply the attribute, the
-            Printer object MAY choose to populate the corresponding
-            Job object attribute depending on whether the Printer
-            object supports the attribute and is able to calculate or
-            discern the correct value.
-        'job-impressions' (integer(0:MAX)):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object OPTIONALLY supports this attribute and the 'job-
-            impressions-supported' attribute (see section 4.4.34). The
-            client supplied 'job-impressions' operation attribute
-            identifies the total size in number of impressions of the
-            document(s) being submitted (see section 4.3.17.2 for the
-            complete semantics).
-            See last paragraph under 'job-k-octets'.
-        'job-media-sheets' (integer(0:MAX)):
-            The client OPTIONALLY supplies this attribute. The Printer
-            object OPTIONALLY supports this attribute and the
-            'job-media- sheets-supported' attribute (see section
-            4.4.35). The client supplied 'job-media-sheets' operation
-            attribute identifies the total number of media sheets to
-            be produced for this job (see section 4.3.17.3 for the
-            complete semantics).
-            See last paragraph under 'job-k-octets'.
-
-    Group 2: Job Template Attributes
-        The client OPTIONALLY supplies a set of Job Template
-        attributes as defined in section 4.2. If the client is not
-        supplying any Job Template attributes in the request, the
-        client SHOULD omit Group 2 rather than sending an empty
-        group. However, a Printer object MUST be able to accept an
-        empty group.
-
-    Group 3: Document Content
-        The client MUST supply the document data to be processed.  In
-        addition to the MANDATORY parameters required for every
-        operation request, the simplest Print-Job Request consists of
-        just the 'attributes-charset' and
-        'attributes-natural-language' operation attributes; the
-        'printer-uri' target operation attribute; the Document Content
-        and nothing else. In this simple case, the Printer object:
-        - creates a new Job object (the Job object contains a single
-          document),
-        - stores a generated Job name in the 'job-name' attribute in
-          the natural language and charset requested (see Section
-          3.1.4.1) (if those are supported, otherwise using the
-          Printer object's default natural language and charset), and
-        - at job processing time, uses its corresponding default value
-          attributes for the supported Job Template attributes that
-          were not supplied by the client as IPP attribute or embedded
-          instructions in the document data.
-
-    """
-    
-    pass
-
-def make_print_job_response(job, request):
-    """3.2.1.2 Print-Job Response
-
-    The Printer object MUST return to the client the following sets of
-    attributes as part of the Print-Job Response:
-
-    Group 1: Operation Attributes
-        Status Message:
-            In addition to the REQUIRED status code returned in every
-            response, the response OPTIONALLY includes a
-            'status-message' (text(255)) and/or a
-            'detailed-status-message' (text(MAX)) operation attribute
-            as described in sections 13 and 3.1.6. If the client
-            supplies unsupported or conflicting Job Template
-            attributes or values, the Printer object MUST reject or
-            accept the Print-Job request depending on the whether the
-            client supplied a 'true' or 'false' value for the
-            'ipp-attribute- fidelity' operation attribute. See the
-            Implementer's Guide [IPP-IIG] for a complete description
-            of the suggested steps for processing a create request.
-        Natural Language and Character Set:
-            The 'attributes-charset' and 'attributes-natural-language'
-            attributes as described in section 3.1.4.2.
-
-    Group 2: Unsupported Attributes
-        See section 3.1.7 for details on returning Unsupported
-        Attributes.  The value of the 'ipp-attribute-fidelity'
-        supplied by the client does not affect what attributes the
-        Printer object returns in this group. The value of
-        'ipp-attribute-fidelity' only affects whether the Print-Job
-        operation is accepted or rejected. If the job is accepted, the
-        client may query the job using the Get-Job- Attributes
-        operation requesting the unsupported attributes that were
-        returned in the create response to see which attributes were
-        ignored (not stored on the Job object) and which attributes
-        were stored with other (substituted) values.
-
-    Group 3: Job Object Attributes
-        'job-uri' (uri):
-            The Printer object MUST return the Job object's URI by
-            returning the contents of the REQUIRED 'job-uri' Job
-            object attribute. The client uses the Job object's URI
-            when directing operations at the Job object. The Printer
-            object always uses its configured security policy when
-            creating the new URI.  However, if the Printer object
-            supports more than one URI, the Printer object also uses
-            information about which URI was used in the Print-Job
-            Request to generated the new URI so that the new URI
-            references the correct access channel. In other words, if
-            the Print-Job Request comes in over a secure channel, the
-            Printer object MUST generate a Job URI that uses the
-            secure channel as well.
-        'job-id' (integer(1:MAX)):
-            The Printer object MUST return the Job object's Job ID by
-            returning the REQUIRED 'job-id' Job object attribute. The
-            client uses this 'job-id' attribute in conjunction with
-            the 'printer-uri' attribute used in the Print-Job Request
-            when directing Job operations at the Printer object.
-        'job-state' (type1 enum):
-            The Printer object MUST return the Job object's REQUIRED
-            'job- state' attribute. The value of this attribute (along
-            with the value of the next attribute: 'job-state-reasons')
-            is taken from a 'snapshot' of the new Job object at some
-            meaningful point in time (implementation defined) between
-            when the Printer object receives the Print-Job Request and
-            when the Printer object returns the response.
-        'job-state-reasons' (1setOf type2 keyword):
-            The Printer object MUST return the Job object's REQUIRED
-            'job- state-reasons' attribute.
-        'job-state-message' (text(MAX)):
-            The Printer object OPTIONALLY returns the Job object's
-            OPTIONAL 'job-state-message' attribute. If the Printer
-            object supports this attribute then it MUST be returned in
-            the response. If this attribute is not returned in the
-            response, the client can assume that the
-            'job-state-message' attribute is not supported and will
-            not be returned in a subsequent Job object query.
-        'number-of-intervening-jobs' (integer(0:MAX)):
-            The Printer object OPTIONALLY returns the Job object's
-            OPTIONAL 'number-of-intervening-jobs' attribute. If the
-            Printer object supports this attribute then it MUST be
-            returned in the response. If this attribute is not
-            returned in the response, the client can assume that the
-            'number-of-intervening-jobs' attribute is not supported
-            and will not be returned in a subsequent Job object query.
-
-    Note: Since any printer state information which affects a job's
-    state is reflected in the 'job-state' and 'job-state-reasons'
-    attributes, it is sufficient to return only these attributes and
-    no specific printer status attributes.
-
-    Note: In addition to the MANDATORY parameters required for every
-    operation response, the simplest response consists of the just the
-    'attributes-charset' and 'attributes-natural-language' operation
-    attributes and the 'job-uri', 'job-id', and 'job-state' Job Object
-    Attributes. In this simplest case, the status code is 'successful-
-    ok' and there is no 'status-message' or 'detailed-status-message'
-    operation attribute.
-
-    """
-
-    pass
Index: server/lib/gutenbach/ipp/operations/print_uri.py
===================================================================
--- server/lib/gutenbach/ipp/operations/print_uri.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_print_uri_request(request):
-    pass
-
-def make_print_uri_response(uri, request):
-    pass
Index: server/lib/gutenbach/ipp/operations/promote_job.py
===================================================================
--- server/lib/gutenbach/ipp/operations/promote_job.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_promote_job_request(request):
-    pass
-
-def make_promote_job_response(request):
-    pass
Index: server/lib/gutenbach/ipp/operations/restart_job.py
===================================================================
--- server/lib/gutenbach/ipp/operations/restart_job.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_restart_job_request(request):
-    pass
-
-def make_restart_job_response(request):
-    pass
Index: server/lib/gutenbach/ipp/operations/resume_printer.py
===================================================================
--- server/lib/gutenbach/ipp/operations/resume_printer.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_resume_printer_request(request):
-    pass
-
-def make_resume_printer_response(request):
-    pass
Index: server/lib/gutenbach/ipp/operations/send_document.py
===================================================================
--- server/lib/gutenbach/ipp/operations/send_document.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_send_document_request(request):
-    pass
-
-def make_send_document_response(request):
-    pass
Index: server/lib/gutenbach/ipp/operations/send_uri.py
===================================================================
--- server/lib/gutenbach/ipp/operations/send_uri.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_send_uri_request(request):
-    pass
-
-def make_send_uri_response(request):
-    pass
Index: server/lib/gutenbach/ipp/operations/set_job_attributes.py
===================================================================
--- server/lib/gutenbach/ipp/operations/set_job_attributes.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_set_job_attributes_request(request):
-    pass
-
-def make_set_job_attributes_response(request):
-    pass
Index: server/lib/gutenbach/ipp/operations/set_printer_attributes.py
===================================================================
--- server/lib/gutenbach/ipp/operations/set_printer_attributes.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_set_printer_attributes_request(request):
-    pass
-
-def make_set_printer_attributes_response(attrs, request):
-    pass
Index: server/lib/gutenbach/ipp/operations/validate_job.py
===================================================================
--- server/lib/gutenbach/ipp/operations/validate_job.py	(revision e70c020a46e045a50a99e8f126ce7e154a298535)
+++ 	(revision )
@@ -1,13 +1,0 @@
-from . import verify_operations
-from . import verify_printer_uri
-from . import verify_requesting_username
-from . import make_empty_response
-
-import logging
-logger = logging.getLogger(__name__)
-
-def verify_validate_job_request(request):
-    pass
-
-def make_validate_job_response(job, request):
-    pass
Index: server/lib/gutenbach/server/requests.py
===================================================================
--- server/lib/gutenbach/server/requests.py	(revision 793432f59cc3f6d9a34ba213d3911b9cb3b86b05)
+++ server/lib/gutenbach/server/requests.py	(revision 103711508848c1db8aa0dfc6d977ac327ed6fb21)
@@ -20,4 +20,22 @@
     return f
 
+def make_empty_response(request):
+    # Operation attributes -- typically the same for any request
+    attribute_group = ipp.AttributeGroup(
+        ipp.AttributeTags.OPERATION,
+        [ipp.AttributesCharset('utf-8'),
+         ipp.AttributesNaturalLanguage('en-us')])
+    
+    # Set up the default response -- handlers will override these
+    # values if they need to
+    response_kwargs = {}
+    response_kwargs['version']          = request.version
+    response_kwargs['operation_id']     = ipp.StatusCodes.OK
+    response_kwargs['request_id']       = request.request_id
+    response_kwargs['attribute_groups'] = [attribute_group]
+    response = ipp.Request(**response_kwargs)
+    
+    return response
+
 class GutenbachRequestHandler(object):
 
@@ -27,4 +45,31 @@
             }
         self.default = "test"
+
+    def generic_handle(self, request):
+        # check the IPP version number
+        if request.version != (1, 1):
+            raise ipp.errors.ServerErrorVersionNotSupported(str(request.version))
+
+        # make sure the operation attribute group has the correct tag
+        operation = request.attribute_groups[0]
+        if operation.tag != ipp.AttributeTags.OPERATION:
+            raise ipp.errors.ClientErrorBadRequest(
+                "Attribute group does not have OPERATION tag: 0x%x" % operation.tag)
+
+        # check charset
+        charset_attr = operation.attributes[0]
+        expected = ipp.AttributesCharset(charset_attr.values[0].value)
+        if charset_attr != expected:
+            raise ipp.errors.ClientErrorBadRequest(str(charset_attr))
+        if charset_attr.values[0].value != 'utf-8':
+            raise ipp.errors.ClientErrorAttributes(str(charset_attr))
+
+        # check for attributes-natural-language
+        natlang_attr = operation.attributes[1]
+        expected = ipp.AttributesNaturalLanguage(natlang_attr.values[0].value)
+        if natlang_attr != expected:
+            raise ipp.errors.ClientErrorBadRequest(str(natlang_attr))
+        if natlang_attr.values[0].value != 'en-us':
+            raise ipp.errors.ClientErrorAttributes(str(natlang_attr))
     
     def handle(self, request):
@@ -36,14 +81,18 @@
                 handler_name = d
                 break
+
         # we couldn't find a handler, so default to unknown operation
         if handler_name is None:
             handler_name = "unknown_operation"
-        # call the handler
+
+        # actually get the handler
         handler = getattr(self, handler_name)
         logger.info("Handling request of type '%s'" % handler_name)
 
-        # Try to handle the request
+        # try to handle the request
         try:
-            response = handler(request)
+            self.generic_handle(request)
+            response = make_empty_response(request)
+            handler(request, response)
 
         # Handle any errors that occur.  If an exception occurs that
@@ -53,5 +102,5 @@
             exctype, excval, exctb = sys.exc_info()
             logger.error("%s: %s" % (exctype.__name__, excval.message))
-            response = ipp.operations.make_empty_response(request)
+            response = make_empty_response(request)
             excval.update_response(response)
 
@@ -60,12 +109,12 @@
         except Exception:
             logger.error(traceback.format_exc())
-            response = ipp.operations.make_empty_response(request)
+            response = make_empty_response(request)
             response.operation_id = ipp.StatusCodes.INTERNAL_ERROR
 
         return response
 
-    def unknown_operation(self, request):
+    def unknown_operation(self, request, response):
         logger.warning("Received unknown operation 0x%x" % request.operation_id)
-        response = ipp.operations.make_empty_response(request)
+        response = make_empty_response(request)
         response.operation_id = ipp.StatusCodes.OPERATION_NOT_SUPPORTED
         return response
@@ -74,5 +123,5 @@
 
     @handler_for(ipp.OperationCodes.PRINT_JOB)
-    def print_job(self, request):
+    def print_job(self, request, response):
         """RFC 2911: 3.2.1 Print-Job Operation
 
@@ -83,4 +132,39 @@
         Operation and Job Template attributes.
 
+        Request
+        -------
+        Group 1: Operation Attributes
+            REQUIRED 'attributes-charset' 
+            REQUIRED 'attributes-natural-language' 
+            REQUIRED 'printer-uri' (uri) 
+            OPTIONAL 'requesting-user-name' (name(MAX))
+            OPTIONAL 'job-name' (name(MAX))
+            OPTIONAL 'ipp-attribute-fidelity' (boolean)
+            OPTIONAL 'document-name' (name(MAX))
+            OPTIONAL 'compression' (type3 keyword)
+            OPTIONAL 'document-format' (mimeMediaType)
+            OPTIONAL 'document-natural-language' (naturalLanguage)
+            OPTIONAL 'job-k-octets' (integer(0:MAX))
+            OPTIONAL 'job-impressions' (integer(0:MAX))
+            OPTIONAL 'job-media-sheets' (integer(0:MAX))
+        Group 2: Job Template Attributes
+        Group 3: Document Content
+
+        Response
+        --------
+        Group 1: Operation Attributes
+            OPTIONAL 'status-message' (text(255))
+            OPTIONAL 'detailed-status-message' (text(MAX))
+            REQUIRED 'attributes-charset'
+            REQUIRED 'attributes-natural-language'
+        Group 2: Unsupported Attributes
+        Group 3: Job Object Attributes
+            REQUIRED 'job-uri' (uri)
+            REQUIRED 'job-id' (integer(1:MAX))
+            REQUIRED 'job-state' (type1 enum)
+            REQUIRED 'job-state-reasons' (1setOf type2 keyword)
+            OPTIONAL 'job-state-message' (text(MAX))
+            OPTIONAL 'number-of-intervening-jobs' (integer(0:MAX))
+
         """
         
@@ -88,11 +172,11 @@
 
     @handler_for(ipp.OperationCodes.VALIDATE_JOB)
-    def validate_job(self, request):
+    def validate_job(self, request, response):
 
         raise ipp.errors.ServerErrorOperationNotSupported
 
     @handler_for(ipp.OperationCodes.GET_JOBS)
-    def get_jobs(self, request):
-        """RFC 2911: 3.2.6 Get-Jobs Operation
+    def get_jobs(self, request, response):
+        """3.2.6 Get-Jobs Operation
         
         This REQUIRED operation allows a client to retrieve the list
@@ -106,30 +190,60 @@
         possibly more than one object.
 
-        """
-
-        # verify the request and get an attribute dictionary
-        req_dict = ipp.operations.verify_get_jobs_request(request)
-
-        # lookup printer name
-        printer_name = req_dict['printer-uri']
+        Request
+        -------
+        Group 1: Operation Attributes
+            REQUIRED 'attributes-charset' 
+            REQUIRED 'attributes-natural-language' 
+            REQUIRED 'printer-uri' (uri) 
+            OPTIONAL 'requesting-user-name' (name(MAX))
+            OPTIONAL 'limit' (integer(1:MAX)) 
+            OPTIONAL 'requested-attributes' (1setOf type2 keyword) 
+            OPTIONAL 'which-jobs' (type2 keyword) 
+            OPTIONAL 'my-jobs' (boolean) 
+
+        Response
+        --------
+        Group 1: Operation Attributes
+            OPTIONAL 'status-message' (text(255))
+            OPTIONAL 'detailed-status-message' (text(MAX))
+            REQUIRED 'attributes-charset'
+            REQUIRED 'attributes-natural-language'
+        Group 2: Unsupported Attributes
+        Groups 3 to N: Job Object Attributes
+
+        """
+
+        operation = request.attribute_groups[0]
+
+        # requested printer uri
+        if 'printer-uri' not in operation:
+            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
+        uri_attr = operation['printer-uri']
+        printer_name = uri_attr.values[0].value.split("/")[-1]
+        if uri_attr != ipp.PrinterUri(uri_attr.values[0].value):
+            raise ipp.errors.ClientErrorBadRequest(str(uri_attr))
         if printer_name not in self.printers:
-            raise ipp.errors.ClientErrorAttributes(
-                "Invalid printer uri: %s" % printer_name,
-                [request.attribute_groups[0].attributes[2]])
-
-        # get the job attributes
-        jobs = [job.get_job_attributes(request) for job in \
-                self.printers[printer_name].get_jobs()]
-
-        # build the response
-        response = ipp.operations.make_get_jobs_response(jobs, request)
-        return response
+            raise ipp.errors.ClientErrorAttributes(str(uri_attr), uri_attr)
+        jobs = self.printers[printer_name].get_jobs()
+
+        # requesting username
+        if 'requesting-user-name' in operation:
+            username_attr = operation['requesting-user-name']
+            username = username_attr.values[0].value
+            if username_attr != ipp.RequestingUserName(username):
+                raise ipp.errors.ClientErrorBadRequest(str(username_attr))
+
+        # get the job attributes and add them to the response
+        for job in self.printers[printer_name].get_jobs():
+            attrs = job.get_job_attributes(request)
+            response.attribute_groups.append(ipp.AttributeGroup(
+                ipp.AttributeTags.JOB, attrs))
 
     @handler_for(ipp.OperationCodes.PRINT_URI)
-    def print_uri(self, request):
+    def print_uri(self, request, response):
         raise ipp.errors.ServerErrorOperationNotSupported
 
     @handler_for(ipp.OperationCodes.CREATE_JOB)
-    def create_job(self, request):
+    def create_job(self, request, response):
         """RFC 2911: 3.2.4 Create-Job Operation
 
@@ -146,35 +260,5 @@
         in the multi-document Job object.
 
-        If a Printer object supports the Create-Job operation, it MUST
-        also support the Send-Document operation and also MAY support
-        the Send-URI operation.
-        
-        If the Printer object supports this operation, it MUST support
-        the 'multiple-operation-time-out' Printer attribute (see
-        section 4.4.31).  If the Printer object supports this
-        operation, then it MUST support the
-        'multiple-document-jobs-supported' Printer Description
-        attribute (see section 4.4.16) and indicate whether or not it
-        supports multiple-document jobs.
-        
-        If the Printer object supports this operation and supports
-        multiple documents in a job, then it MUST support the
-        'multiple-document- handling' Job Template job attribute with
-        at least one value (see section 4.2.4) and the associated
-        'multiple-document-handling- default' and
-        'multiple-document-handling-supported' Job Template Printer
-        attributes (see section 4.2).
-        
-        After the Create-Job operation has completed, the value of the
-        'job- state' attribute is similar to the 'job-state' after a
-        Print-Job, even though no document-data has arrived. A Printer
-        MAY set the 'job-data-insufficient' value of the job's
-        'job-state-reason' attribute to indicate that processing
-        cannot begin until sufficient data has arrived and set the
-        'job-state' to either 'pending' or 'pending-held'. A
-        non-spooling printer that doesn't implement the 'pending' job
-        state may even set the 'job-state' to 'processing', even
-        though there is not yet any data to process. See sections
-        4.3.7 and 4.3.8.
+        Group 1: Operation Attributes
         
         """
@@ -183,13 +267,13 @@
     
     @handler_for(ipp.OperationCodes.PAUSE_PRINTER)
-    def pause_printer(self, request):
+    def pause_printer(self, request, response):
         raise ipp.errors.ServerErrorOperationNotSupported
 
     @handler_for(ipp.OperationCodes.RESUME_PRINTER)
-    def resume_printer(self, request):
+    def resume_printer(self, request, response):
         raise ipp.errors.ServerErrorOperationNotSupported
 
     @handler_for(ipp.OperationCodes.GET_PRINTER_ATTRIBUTES)
-    def get_printer_attributes(self, request):
+    def get_printer_attributes(self, request, response):
         """RFC 2911: 3.2.5 Get-Printer-Attributes Operation
 
@@ -203,105 +287,118 @@
         attribute values filled in.
 
-        For Printer objects, the possible names of attribute groups are:
+        Request
+        -------
+
+        Group 1: Operation Attributes
+            REQUIRED 'attributes-charset' 
+            REQUIRED 'attributes-natural-language' 
+            REQUIRED 'printer-uri' (uri)
+            OPTIONAL 'requesting-user-name' (name(MAX))
+            OPTIONAL 'requested-attributes' (1setOf type2 keyword) 
+            OPTIONAL 'document-format' (mimeMediaType):
+
+        Response
+        --------
+
+        Group 1: Operation Attributes
+            OPTIONAL 'status-message' (text(255))
+            OPTIONAL 'detailed-status-message' (text(MAX))
+            REQUIRED 'attributes-charset'
+            REQUIRED 'attributes-natural-language'
+        Group 2: Unsupported Attributes
+        Group 3: Printer Object Attributes
+
+        """
+
+        operation = request.attribute_groups[0]
+
+        # requested printer uri
+        if 'printer-uri' not in operation:
+            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
+        uri_attr = operation['printer-uri']
+        printer_name = uri_attr.values[0].value.split("/")[-1]
+        if uri_attr != ipp.PrinterUri(uri_attr.values[0].value):
+            raise ipp.errors.ClientErrorBadRequest(str(uri_attr))
+        if printer_name not in self.printers:
+            raise ipp.errors.ClientErrorAttributes(str(uri_attr), uri_attr)
+        printer = self.printers[printer_name]
+
+        # requesting username
+        if 'requesting-user-name' in operation:
+            username_attr = operation['requesting-user-name']
+            username = username_attr.values[0].value
+            if username_attr != ipp.RequestingUserName(username):
+                raise ipp.errors.ClientErrorBadRequest(str(username_attr))
+
+        # get attributes from the printer and add to response
+        response.attribute_groups.append(ipp.AttributeGroup(
+            ipp.AttributeTags.PRINTER, printer.get_printer_attributes(request)))
+
+    @handler_for(ipp.OperationCodes.SET_PRINTER_ATTRIBUTES)
+    def set_printer_attributes(self, request, response):
+        raise ipp.errors.ServerErrorOperationNotSupported
+
+    ##### Job Commands
+
+    @handler_for(ipp.OperationCodes.CANCEL_JOB)
+    def cancel_job(self, request, response):
+        raise ipp.errors.ServerErrorOperationNotSupported
+
+    @handler_for(ipp.OperationCodes.SEND_DOCUMENT)
+    def send_document(self, request, response):
+        raise ipp.errors.ServerErrorOperationNotSupported
+
+    @handler_for(ipp.OperationCodes.SEND_URI)
+    def send_uri(self, request, response):
+        raise ipp.errors.ServerErrorOperationNotSupported
+
+    @handler_for(ipp.OperationCodes.GET_JOB_ATTRIBUTES)
+    def get_job_attributes(self, request, response):
         
-        - 'job-template': the subset of the Job Template attributes
-          that apply to a Printer object (the last two columns of the
-          table in Section 4.2) that the implementation supports for
-          Printer objects.
-
-        - 'printer-description': the subset of the attributes
-          specified in Section 4.4 that the implementation supports
-          for Printer objects.
-
-        - 'all': the special group 'all' that includes all attributes
-          that the implementation supports for Printer objects.
-        
-        Since a client MAY request specific attributes or named
-        groups, there is a potential that there is some overlap. For
-        example, if a client requests, 'printer-name' and 'all', the
-        client is actually requesting the 'printer-name' attribute
-        twice: once by naming it explicitly, and once by inclusion in
-        the 'all' group. In such cases, the Printer object NEED NOT
-        return each attribute only once in the response even if it is
-        requested multiple times. The client SHOULD NOT request the
-        same attribute in multiple ways.
-
-        It is NOT REQUIRED that a Printer object support all
-        attributes belonging to a group (since some attributes are
-        OPTIONAL). However, it is REQUIRED that each Printer object
-        support all group names.
-
-        """
-
-        # verify the request and get the attributes dictionary
-        req_dict = ipp.operations.verify_get_printer_attributes_request(request)
-
-        # lookup the printer name
-        printer_name = req_dict['printer-uri']
+        operation = request.attribute_groups[0]
+
+        # requested printer uri
+        if 'printer-uri' not in operation:
+            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
+        uri_attr = operation['printer-uri']
+        printer_name = uri_attr.values[0].value.split("/")[-1]
+        if uri_attr != ipp.PrinterUri(uri_attr.values[0].value):
+            raise ipp.errors.ClientErrorBadRequest(str(uri_attr))
         if printer_name not in self.printers:
-            raise ipp.errors.ClientErrorAttributes(
-                "Invalid printer uri: %s" % printer_name,
-                [request.attribute_groups[0].attributes[2]])
-
-        # bulid response
-        response = ipp.operations.make_get_printer_attributes_response(
-            self.printers[printer_name].get_printer_attributes(request), request)
-        return response
-
-    @handler_for(ipp.OperationCodes.SET_PRINTER_ATTRIBUTES)
-    def set_printer_attributes(self, request):
-        raise ipp.errors.ServerErrorOperationNotSupported
-
-    ##### Job Commands
-
-    @handler_for(ipp.OperationCodes.CANCEL_JOB)
-    def cancel_job(self, request):
-        raise ipp.errors.ServerErrorOperationNotSupported
-
-    @handler_for(ipp.OperationCodes.SEND_DOCUMENT)
-    def send_document(self, request):
-        raise ipp.errors.ServerErrorOperationNotSupported
-
-    @handler_for(ipp.OperationCodes.SEND_URI)
-    def send_uri(self, request):
-        raise ipp.errors.ServerErrorOperationNotSupported
-
-    @handler_for(ipp.OperationCodes.GET_JOB_ATTRIBUTES)
-    def get_job_attributes(self, request):
-        
-        # verify the request and get the attributes dictionary
-        req_dict = ipp.operations.verify_get_jobs_request(request)
-        
-        # lookup the printer name
-        printer_name = req_dict['printer-uri']
-        if printer_name not in self.printers:
-            raise ipp.errors.ClientErrorAttributes(
-                "Invalid printer uri: %s" % printer_name,
-                [request.attribute_groups[0].attributes[2]])
-
-        # lookup the job id
-        job_id = req_dict['job-id']
-        try: job = self.printers[printer_name].get_job(job_id)
-        except InvalidJobException:
-            raise ipp.errors.ClientErrorAttributes(
-                "Invalid job id: %d" % job_id,
-                [request.attribute_groups[0].attributes[2]]) # XXX: this is wrong
-
-        # XXX: we need to honor the things that the request actually asks for
-        # build the response
-        response = ipp.operations.make_get_job_attributes_response(
-            job.get_job_attributes(request), request)
-        return response
+            raise ipp.errors.ClientErrorAttributes(str(uri_attr), uri_attr)
+        printer = self.printers[printer_name]
+
+        if 'job-id' not in operation:
+            raise ipp.errors.ClientErrorBadRequest("Missing 'job-id' attribute")
+        job_id_attr = operation['job-id']
+        job_id = job_id_attr.values[0].value
+        if job_id_attr != ipp.JobId(job_id_attr.values[0].value):
+            raise ipp.errors.ClientErrorBadRequest(str(job_id_attr))
+        if job_id not in printer.jobs:
+            raise ipp.errors.ClientErrorAttributes(str(job_id_attr))
+        job = printer.get_job(job_id)
+
+        # requesting username
+        if 'requesting-user-name' in operation:
+            username_attr = operation['requesting-user-name']
+            username = username_attr.values[0].value
+            if username_attr != ipp.RequestingUserName(username):
+                raise ipp.errors.ClientErrorBadRequest(str(username_attr))
+
+        # get the job attributes and add them to the response
+        attrs = job.get_job_attributes(request)
+        response.attribute_groups.append(ipp.AttributeGroup(
+            ipp.AttributeTags.JOB, attrs))
 
     @handler_for(ipp.OperationCodes.SET_JOB_ATTRIBUTES)
-    def set_job_attributes(self, request):
+    def set_job_attributes(self, request, response):
         raise ipp.errors.ServerErrorOperationNotSupported
 
     @handler_for(ipp.OperationCodes.RESTART_JOB)
-    def restart_job(self, request):
+    def restart_job(self, request, response):
         raise ipp.errors.ServerErrorOperationNotSupported
 
     @handler_for(ipp.OperationCodes.PROMOTE_JOB)
-    def promote_job(self, request):
+    def promote_job(self, request, response):
         raise ipp.errors.ServerErrorOperationNotSupported
 
@@ -309,25 +406,49 @@
 
     @handler_for(ipp.OperationCodes.CUPS_GET_DOCUMENT)
-    def cups_get_document(self, request):
+    def cups_get_document(self, request, response):
         raise ipp.errors.ServerErrorOperationNotSupported
 
     @handler_for(ipp.OperationCodes.CUPS_GET_DEFAULT)
-    def cups_get_default(self, request):
+    def cups_get_default(self, request, response):
         """The CUPS-Get-Default operation (0x4001) returns the default
         printer URI and attributes.
 
+        Request
+        -------
+
+        Group 1: Operation Attributes
+            REQUIRED 'attributes-charset' 
+            REQUIRED 'attributes-natural-language' 
+            OPTIONAL 'requested-attributes' (1setOf type2 keyword)
+
+        Response
+        --------
+
+        Group 1: Operation Attributes
+            OPTIONAL 'status-message' (text(255))
+            REQUIRED 'attributes-charset'
+            REQUIRED 'attributes-natural-language'
+        Group 2: Printer Object Attributes
+
         (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_DEFAULT )
 
         """
 
-        # verify the request and get the attributes dictionary
-        req_dict = ipp.operations.verify_cups_get_default_request(request)
-        # build the response
-        response = ipp.operations.make_get_printer_attributes_response(
-            self.printers[self.default].get_printer_attributes(request), request)
-        return response
+        operation = request.attribute_groups[0]
+        printer = self.printers[self.default]
+
+        # requesting username
+        if 'requesting-user-name' in operation:
+            username_attr = operation['requesting-user-name']
+            username = username_attr.values[0].value
+            if username_attr != ipp.RequestingUserName(username):
+                raise ipp.errors.ClientErrorBadRequest(str(username_attr))
+
+        # get attributes from the printer and add to response
+        response.attribute_groups.append(ipp.AttributeGroup(
+            ipp.AttributeTags.PRINTER, printer.get_printer_attributes(request)))
 
     @handler_for(ipp.OperationCodes.CUPS_GET_PRINTERS)
-    def cups_get_printers(self, request):
+    def cups_get_printers(self, request, response):
         """The CUPS-Get-Printers operation (0x4002) returns the
         printer attributes for every printer known to the system. This
@@ -339,27 +460,53 @@
         """
 
-        # verify the request and get the attributes dictionary
-        req_dict = ipp.operations.verify_cups_get_printers_request(request)
-        # get the printer attributes
-        attrs = [self.printers[printer].get_printer_attributes(request) \
-                 for printer in self.printers]
-        # build the response
-        response = ipp.operations.make_cups_get_printers_response(attrs, request)
-        return response
+        operation = request.attribute_groups[0]
+
+        # requesting username
+        if 'requesting-user-name' in operation:
+            username_attr = operation['requesting-user-name']
+            username = username_attr.values[0].value
+            if username_attr != ipp.RequestingUserName(username):
+                raise ipp.errors.ClientErrorBadRequest(str(username_attr))
+
+        # get attributes from the printer and add to response
+        for printer in self.printers.values():
+            response.attribute_groups.append(ipp.AttributeGroup(
+                ipp.AttributeTags.PRINTER, printer.get_printer_attributes(request)))
 
     @handler_for(ipp.OperationCodes.CUPS_GET_CLASSES)
-    def cups_get_classes(self, request):
+    def cups_get_classes(self, request, response):
         """The CUPS-Get-Classes operation (0x4005) returns the printer
         attributes for every printer class known to the system. This
         may include printer classes that are not served directly by
         the server.
-        
+
+        Request
+        -------
+
+        Group 1: Operation Attributes
+            REQUIRED 'attributes-charset' 
+            REQUIRED 'attributes-natural-language'
+            OPTIONAL 'first-printer-name' (name(127)) CUPS 1.2/Mac OS X 10.5
+            OPTIONAL 'limit' (integer (1:MAX))
+            OPTIONAL 'printer-location' (text(127)) CUPS 1.1.7
+            OPTIONAL 'printer-type' (type2 enum) CUPS 1.1.7
+            OPTIONAL 'printer-type-mask' (type2 enum) CUPS 1.1.7
+            OPTIONAL 'requested-attributes' (1setOf keyword)
+            OPTOINAL 'requested-user-name' (name(127)) CUPS 1.2/Mac OS X 10.5
+            OPTIONAL 'requested-attributes' (1setOf type2 keyword)
+
+        Response
+        --------
+
+        Group 1: Operation Attributes
+            OPTIONAL 'status-message' (text(255))
+            REQUIRED 'attributes-charset'
+            REQUIRED 'attributes-natural-language'
+        Group 2: Printer Class Object Attributes
+
         (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_CLASSES )
 
         """
 
-        # verify the request and get the attributes dictionaryu
-        req_dict = ipp.operations.verify_cups_get_classes_request(request)
-        # build the response
-        response = ipp.operations.make_cups_get_classes_response(request)
-        return response
+        raise ipp.errors.ServerErrorOperationNotSupported
+
