Index: server/lib/gutenbach/ipp/operations.py
===================================================================
--- server/lib/gutenbach/ipp/operations.py	(revision cad7502f2e3816fb8f3099cc05928f7fdc5e44f9)
+++ server/lib/gutenbach/ipp/operations.py	(revision ef8df33517ae78d621e3149fe0bdf958c1251aa3)
@@ -3,5 +3,5 @@
 from .attributegroup import AttributeGroup
 from .request import Request
-from .constants import AttributeTags, StatusCodes, operations_attribute_value_tags
+import constants as consts
 import exceptions as err
 import logging
@@ -27,5 +27,5 @@
     # check operation attributes tag
     op_attrs = request.attribute_groups[0]
-    if op_attrs.tag != AttributeTags.OPERATION:
+    if op_attrs.tag != consts.AttributeTags.OPERATION:
         raise err.BadRequest(
             "Attribute group does not have OPERATION tag: 0x%x" % op_attrs.tag)
@@ -53,5 +53,5 @@
     # check charset value
     charset_value = charset_attr.values[0]
-    if charset_value.tag != operations_attribute_value_tags['attributes-charset']:
+    if charset_value.tag != consts.operations_attribute_value_tags['attributes-charset']:
         raise err.BadRequest(
             "Wrong tag for charset value: 0x%x" % charset_value.tag)
@@ -69,5 +69,5 @@
     # check natural language value
     natlang_value = natlang_attr.values[0]
-    if natlang_value.tag != operations_attribute_value_tags['attributes-natural-language']:
+    if natlang_value.tag != consts.operations_attribute_value_tags['attributes-natural-language']:
         raise err.BadRequest(
             "Natural language value does not have NATURAL_LANGUAGE tag: 0x%x" % natlang_value.tag)
@@ -83,5 +83,5 @@
             "Requesting printer uri attribute has too many values: %d" % len(values))
     uri_value = values[0]
-    if uri_value.tag != operations_attribute_value_tags['printer-uri']:
+    if uri_value.tag != consts.operations_attribute_value_tags['printer-uri']:
         raise err.BadRequest(
             "Bad value tag (expected URI): 0x%x" % uri_value_tag)
@@ -99,5 +99,5 @@
             "Requesting user name attribute has too many values: %d" % len(values))
     requser_value = values[0]
-    if requser_value.tag != operations_attribute_value_tags['requesting-user-name']:
+    if requser_value.tag != consts.operations_attribute_value_tags['requesting-user-name']:
         raise err.BadRequest(
             "Bad value tag (expected NAME_WITHOUT_LANGUAGE): 0x%x" % requser_value.tag)
@@ -110,12 +110,13 @@
         Attribute(
             'attributes-charset',
-            [Value(operations_attribute_value_tags['attributes-charset'], 'utf-8')]),
+            [Value(consts.operations_attribute_value_tags['attributes-charset'], 'utf-8')]),
         Attribute(
             'attributes-natural-language',
-            [Value(operations_attribute_value_tags['attributes-natural-language'], 'en-us')])
+            [Value(consts.operations_attribute_value_tags['attributes-natural-language'],
+                   'en-us')])
         ]
     # Put the operation attributes in a group
     attribute_group = AttributeGroup(
-        AttributeTags.OPERATION,
+        consts.AttributeTags.OPERATION,
         attributes)
 
@@ -124,5 +125,5 @@
     response_kwargs = {}
     response_kwargs['version']          = request.version
-    response_kwargs['operation_id']     = StatusCodes.OK
+    response_kwargs['operation_id']     = consts.StatusCodes.OK
     response_kwargs['request_id']       = request.request_id
     response_kwargs['attribute_groups'] = [attribute_group]
@@ -130,4 +131,24 @@
 
     return response
+
+def make_job_attributes(attrs, request, response):
+    ipp_attrs = []
+    for attr, vals in attrs:
+        ipp_vals = [Value(
+            tag=consts.job_attribute_value_tags[attr],
+            value=val) for val in vals]
+        ipp_attrs.append(Attribute(name=attr, values=ipp_vals))
+    response.attribute_groups.append(AttributeGroup(
+        consts.AttributeTags.JOB, ipp_attrs))
+
+def make_printer_attributes(attrs, request, response):
+    ipp_attrs = []
+    for attr, vals in attrs:
+        ipp_vals = [Value(
+            tag=consts.printer_attribute_value_tags[attr],
+            value=val) for val in vals]
+        ipp_attrs.append(Attribute(name=attr, values=ipp_vals))
+    response.attribute_groups.append(AttributeGroup(
+        consts.AttributeTags.PRINTER, ipp_attrs))
 
 #### GET-JOBS
@@ -247,5 +268,5 @@
     return out
 
-def make_get_jobs_response(self, request):
+def make_get_jobs_response(jobs, request):
     """RFC 2911: 3.2.6.2 Get-Jobs Response
         
@@ -320,5 +341,9 @@
     """
 
-    pass
+    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
 
 ## GET-PRINTER-ATTRIBUTES
@@ -450,5 +475,5 @@
 
 
-def make_get_printer_attributes_response(self, request):
+def make_get_printer_attributes_response(attrs, request):
     """3.2.5.2 Get-Printer-Attributes Response
 
@@ -495,3 +520,201 @@
 
     """
-    pass
+
+    response = make_empty_response(request)
+    make_printer_attributes(attrs, request, response)
+    return response
+
+
+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
+
+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 )
+
+    """
+
+    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
+
+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 )
+
+    """
+
+    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/server/requests.py
===================================================================
--- server/lib/gutenbach/server/requests.py	(revision cad7502f2e3816fb8f3099cc05928f7fdc5e44f9)
+++ server/lib/gutenbach/server/requests.py	(revision ef8df33517ae78d621e3149fe0bdf958c1251aa3)
@@ -2,5 +2,4 @@
 import gutenbach.ipp as ipp
 import gutenbach.ipp.constants as const
-from gutenbach.ipp.constants import job_attribute_value_tags, printer_attribute_value_tags
 import logging
 
@@ -28,5 +27,5 @@
         self.default = "test"
     
-    def handle(self, request, response):
+    def handle(self, request):
         # look up the handler
         handler = None
@@ -42,47 +41,23 @@
         handler = getattr(self, handler_name)
         logger.info("Handling request of type '%s'" % handler_name)
-        handler(request, response)
-
-    def unknown_operation(self, request, response):
+        response = handler(request)
+        return response
+
+    def unknown_operation(self, request):
         logger.warning("Received unknown operation 0x%x" % request.operation_id)
+        response = ipp.ops.make_empty_response(request)
         response.operation_id = const.StatusCodes.OPERATION_NOT_SUPPORTED
-
-    ##### Helper functions
-
-    def _get_printer_attributes(self, printer, request, response):
-        attrs = printer.get_printer_attributes(request)
-        ipp_attrs = []
-        for attr, vals in attrs:
-            ipp_vals = [ipp.Value(
-                tag=printer_attribute_value_tags[attr],
-                value=val) for val in vals]
-            ipp_attrs.append(ipp.Attribute(name=attr, values=ipp_vals))
-        response.attribute_groups.append(ipp.AttributeGroup(
-            const.AttributeTags.PRINTER, ipp_attrs))
-
-    def _get_job_attributes(self, job, request, response):
-        attrs = job.get_job_attributes(request)
-        ipp_attrs = []
-        for attr, vals in attrs:
-            ipp_vals = [ipp.Value(
-                tag=job_attribute_value_tags[attr],
-                value=val) for val in vals]
-            ipp_attrs.append(ipp.Attribute(name=attr, values=ipp_vals))
-        response.attribute_groups.append(ipp.AttributeGroup(
-            const.AttributeTags.JOB, ipp_attrs))
-
-    def _get_job_id(self, request):
-        pass
+        return response
         
     ##### Printer Commands
 
-    def print_job(self, request, response):
-        pass
-
-    def validate_job(self, request, response):
+    def print_job(self, request):
+        pass
+
+    def validate_job(self, request):
         pass
 
     @handler_for(const.Operations.GET_JOBS)
-    def get_jobs(self, request, response):
+    def get_jobs(self, request):
         """RFC 2911: 3.2.6 Get-Jobs Operation
         
@@ -99,6 +74,6 @@
         """
         
-        reqdict = ipp.ops.verify_get_jobs_request(request)
-        printer_name = reqdict['printer-uri']
+        req_dict = ipp.ops.verify_get_jobs_request(request)
+        printer_name = req_dict['printer-uri']
         if printer_name not in self.printers:
             raise ipp.errors.Attributes(
@@ -107,22 +82,23 @@
 
         # Each job will append a new job attribute group.
-        # XXX: we need to honor the things that the request actually asks for
-        for job in self.printers[printer_name].get_jobs():
-            self._get_job_attributes(job, request, response)
-
-    def print_uri(self, request, response):
-        pass
-
-    def create_job(self, request, response):
-        pass
-
-    def pause_printer(self, request, response):
-        pass
-
-    def resume_printer(self, request, response):
+        jobs = [job.get_job_attributes(request) for job in \
+                self.printers[printer_name].get_jobs()]
+        response = ipp.ops.make_get_jobs_response(jobs, request)
+        return response
+
+    def print_uri(self, request):
+        pass
+
+    def create_job(self, request):
+        pass
+
+    def pause_printer(self, request):
+        pass
+
+    def resume_printer(self, request):
         pass
 
     @handler_for(const.Operations.GET_PRINTER_ATTRIBUTES)
-    def get_printer_attributes(self, request, response):
+    def get_printer_attributes(self, request):
         """RFC 2911: 3.2.5 Get-Printer-Attributes Operation
 
@@ -169,6 +145,6 @@
         # this is just like cups_get_default, except the printer name
         # is given
-        reqdict = ipp.ops.verify_get_printer_attributes_request(request)
-        printer_name = reqdict['printer-uri']
+        req_dict = ipp.ops.verify_get_printer_attributes_request(request)
+        printer_name = req_dict['printer-uri']
         if printer_name not in self.printers:
             raise ipp.errors.Attributes(
@@ -176,24 +152,26 @@
                 [request.attribute_groups[0].attributes[2]])
         
-        self._get_printer_attributes(self.printers[printer_name], request, response)
-
-    def set_printer_attributes(self, request, response):
+        response = ipp.ops.make_get_printer_attributes_response(
+            self.printers[printer_name].get_printer_attributes(request), request)
+        return response
+
+    def set_printer_attributes(self, request):
         pass
 
     ##### Job Commands
 
-    def cancel_job(self, request, response):
-        pass
-
-    def send_document(self, request, response):
-        pass
-
-    def send_uri(self, request, response):
-        pass
-
-    def get_job_attributes(self, request, response):
-        reqdict = ipp.ops.verify_get_jobs_request(request)
-        printer_name = reqdict['printer-uri']
-        job_id = reqdict['job-id']
+    def cancel_job(self, request):
+        pass
+
+    def send_document(self, request):
+        pass
+
+    def send_uri(self, request):
+        pass
+
+    def get_job_attributes(self, request):
+        req_dict = ipp.ops.verify_get_jobs_request(request)
+        printer_name = req_dict['printer-uri']
+        job_id = req_dict['job-id']
         
         if printer_name not in self.printers:
@@ -210,16 +188,18 @@
         # Each job will append a new job attribute group.
         # XXX: we need to honor the things that the request actually asks for
-        self._get_job_attributes(job, request, response)
-
-    def set_job_attributes(self, request, response):
-        pass
-
-    def cups_get_document(self, request, response):
-        pass
-
-    def restart_job(self, request, response):
-        pass
-
-    def promote_job(self, request, response):
+        response = ipp.ops.make_get_job_attributes_response(
+            job.get_job_attributes(request), request)
+        return response
+
+    def set_job_attributes(self, request):
+        pass
+
+    def cups_get_document(self, request):
+        pass
+
+    def restart_job(self, request):
+        pass
+
+    def promote_job(self, request):
         pass
 
@@ -227,114 +207,23 @@
 
     @handler_for(const.Operations.CUPS_GET_DEFAULT)
-    def cups_get_default(self, request, response):
+    def cups_get_default(self, request):
         """The CUPS-Get-Default operation (0x4001) returns the default
         printer URI and attributes.
 
-        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'.
-        
-        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 )
 
         """
-            
-        self._get_printer_attributes(self.printers[self.default], request, response)
+
+        req_dict = ipp.ops.verify_cups_get_default_request(request)
+        response = ipp.ops.make_get_printer_attributes_response(
+            self.printers[self.default].get_printer_attributes(request), request)
+        return response
 
     @handler_for(const.Operations.CUPS_GET_PRINTERS)
-    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 may
-        include printers that are not served directly by the server.
-
-        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.
-
-        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.
+    def cups_get_printers(self, request):
+        """The CUPS-Get-Printers operation (0x4002) returns the
+        printer attributes for every printer known to the system. This
+        may include printers that are not served directly by the
+        server.
 
         (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_PRINTERS )
@@ -342,77 +231,22 @@
         """
 
-        # Each printer will append a new printer attribute group.
-        for printer in self.printers:
-            self._get_printer_attributes(self.printers[printer], request, response)
+        req_dict = ipp.ops.verify_cups_get_printers_request(request)
+        attrs = [self.printers[printer].get_printer_attributes(request) \
+                 for printer in self.printers]
+        response = ipp.ops.make_cups_get_printers_response(attrs, request)
+        return response
 
     @handler_for(const.Operations.CUPS_GET_CLASSES)
-    def cups_get_classes(self, request, response):
+    def cups_get_classes(self, request):
         """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.
-
-        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.
-                
-        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 )
 
         """
-        
-        # We have no printer classes, so we don't need to do anything
-        pass
+
+        req_dict = ipp.ops.verify_cups_get_classes_request(request)
+        response = ipp.ops.make_cups_get_classes_response(request)
+        return response
Index: server/lib/gutenbach/server/server.py
===================================================================
--- server/lib/gutenbach/server/server.py	(revision 6effd500f1a343da7fc04b1dff40e47d90db5b3a)
+++ server/lib/gutenbach/server/server.py	(revision ef8df33517ae78d621e3149fe0bdf958c1251aa3)
@@ -29,12 +29,9 @@
         logger.debug("Received request: %s" % repr(request))
 
-        # Create an empty response object
-        response = ipp.ops.make_empty_response(request)
-
         # Get the handler and pass it the request and response
         # objects.  It will fill in values for the response object or
         # thrown an error.
         try:
-            self.root.handle(request, response)
+            response = self.root.handle(request)
             
         # Handle any errors that occur.  If an exception occurs that
@@ -43,12 +40,14 @@
         except ipp.errors.IPPException:
             exctype, excval, exctb = sys.exc_info()
+            logger.error(traceback.format_exc())
+            response = ipp.ops.make_empty_response(request)
             excval.update_response(response)
-            logger.error(traceback.format_exc())
 
         # If it wasn't an IPP error, then it's our fault, so mark it
         # as an internal server error
         except Exception:
+            logger.error(traceback.format_exc())
+            response = ipp.ops.make_empty_response(request)
             response.operation_id = ipp.StatusCodes.INTERNAL_ERROR
-            logger.error(traceback.format_exc())
 
         # Send the response across HTTP
