Index: server/lib/gutenbach/ipp/attribute.py
===================================================================
--- server/lib/gutenbach/ipp/attribute.py	(revision f6c6897421d09df51b72b4539328adec41072c46)
+++ server/lib/gutenbach/ipp/attribute.py	(revision cad7502f2e3816fb8f3099cc05928f7fdc5e44f9)
@@ -93,12 +93,15 @@
                 name_length = 0
 
-            # get the value length and binary value
+            logger.debug("dumping name : %s" % self.name)
+            logger.debug("dumping name_length : %i" % name_length)
+            logger.debug("value tag : 0x%x" % v.tag)
+
+            # get the binary value
             value_bin = v.packed_value
+            # get the value length
             value_length = len(value_bin)
 
-            logger.debug("dumping name_length : %i" % name_length)
-            logger.debug("dumping name : %s" % self.name)
+            logger.debug("dumping value : %s" % v.value)
             logger.debug("dumping value_length : %i" % value_length)
-            logger.debug("dumping value (0x%x): %s" % (v.tag, v.value))
 
             # the value tag in binary
Index: server/lib/gutenbach/ipp/operations.py
===================================================================
--- server/lib/gutenbach/ipp/operations.py	(revision f6c6897421d09df51b72b4539328adec41072c46)
+++ server/lib/gutenbach/ipp/operations.py	(revision cad7502f2e3816fb8f3099cc05928f7fdc5e44f9)
@@ -5,4 +5,7 @@
 from .constants import AttributeTags, StatusCodes, operations_attribute_value_tags
 import exceptions as err
+import logging
+
+logger = logging.getLogger(__name__)
 
 def verify_operations(request):
@@ -14,4 +17,12 @@
     """
 
+    # XXX: check version
+    if False:
+        raise err.VersionNotSupported(str(request.version))
+
+    # check operation id
+    if False:
+        raise err.OperationNotSupported(str(request.operation_id))
+
     # check operation attributes tag
     op_attrs = request.attribute_groups[0]
@@ -20,12 +31,4 @@
             "Attribute group does not have OPERATION tag: 0x%x" % op_attrs.tag)
 
-    # XXX: check version
-    if False:
-        raise err.VersionNotSupported(str(request.version))
-
-    # check operation id
-    if False:
-        raise err.OperationNotSupported(str(request.operation_id))
-
     # # check compression
     # if False:
@@ -48,5 +51,4 @@
         raise err.BadRequest(
             "Too many values for attributes-charset: %d" % len(charset_attr.values))
-
     # check charset value
     charset_value = charset_attr.values[0]
@@ -65,5 +67,4 @@
         raise err.BadRequest(
             "Too many values for attributes-natural-language: %s" % len(natlang_attr.values))
-
     # check natural language value
     natlang_value = natlang_attr.values[0]
@@ -75,32 +76,27 @@
             "Invalid natural language value: %s" % natlang_value.value, [natlang_attr])
 
-def verify_printer_uri(uri_attr):
-    if uri_attr.name != 'printer-uri':
-        raise err.BadRequest(
-            "Unexpected name for attribute 'printer-uri': %s" % uri_attr.name)
-    if len(uri_attr.values) != 1:
-        raise err.BadRequest(
-            "Requesting printer uri attribute has too many values: %d" % len(uri_attr.values))
-    printer_name_value = uri_attr.values[0]
-    if printer_name_value.tag != operations_attribute_value_tags['printer-uri']:
-        raise err.BadRequest(
-            "Bad value tag (expected URI): 0x%x" % printer_name_value_tag)
+    return dict([(attr.name, attr.values) for attr in op_attrs.attributes])
+
+def verify_printer_uri(values):
+    if len(values) != 1:
+        raise err.BadRequest(
+            "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']:
+        raise err.BadRequest(
+            "Bad value tag (expected URI): 0x%x" % uri_value_tag)
     
     # actually get the printer name
-    printer_name_value = printer_name_attr.values[0].value
     # 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)
-    printer_name = printer_name_value.split("/")[-1]
-    return printer_name
-
-def verify_requesting_username(requser_attr):
-    if requser_attr.name != 'requesting-user-name':
-        raise err.BadRequest(
-            "Unexpected name for attribute 'requesting-user-name': %s" % requser_attr.name)
-    if len(requser_attr.values) != 1:
-        raise err.BadRequest(
-            "Requesting user name attribute has too many values: %d" % len(requser_attr.values))
-    requser_value = requser_attr.values[0]
+    uri = uri_value.value.split("/")[-1]
+    return uri
+
+def verify_requesting_username(values):
+    if len(values) != 1:
+        raise err.BadRequest(
+            "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']:
         raise err.BadRequest(
@@ -221,18 +217,19 @@
     """
 
+    out = {}
 
     # generic operations verification
-    verify_operations(request)
+    attrs = verify_operations(request)
+
     # requested printer uri
-    printeruri = verify_printer_uri(request.attribute_groups[0].attributes[2])
+    if 'printer-uri' not in attrs:
+        raise err.BadRequest("Missing 'printer-uri' attribute")
+    out['printer-uri'] = verify_printer_uri(attrs['printer-uri'])
+    
     # requesting username
-    requser = verify_requesting_username(request.attribute_groups[0].attributes[3])
-    # make the rest of the attributes into a dictionary
-    attrs = dict([(attr.name, attr.values) for attr in request.attributes[4:]])
-    
-    out = {
-        'printer-uri': printeruri,
-        'requesting-user-name': requser
-        }
+    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:
@@ -324,2 +321,177 @@
 
     pass
+
+## GET-PRINTER-ATTRIBUTES
+
+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(self, 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.
+
+    """
+    pass
Index: server/lib/gutenbach/server/printer.py
===================================================================
--- server/lib/gutenbach/server/printer.py	(revision 6effd500f1a343da7fc04b1dff40e47d90db5b3a)
+++ server/lib/gutenbach/server/printer.py	(revision cad7502f2e3816fb8f3099cc05928f7fdc5e44f9)
@@ -93,5 +93,5 @@
     @property
     def printer_state(self):
-        return self.state
+        return 3 # idle
 
     @property
@@ -106,5 +106,5 @@
     @property
     def operations_supported(self):
-        return "get-jobs"
+        return 0xa # get-jobs
 
     @property
Index: server/lib/gutenbach/server/requests.py
===================================================================
--- server/lib/gutenbach/server/requests.py	(revision 6effd500f1a343da7fc04b1dff40e47d90db5b3a)
+++ server/lib/gutenbach/server/requests.py	(revision cad7502f2e3816fb8f3099cc05928f7fdc5e44f9)
@@ -125,4 +125,46 @@
     @handler_for(const.Operations.GET_PRINTER_ATTRIBUTES)
     def get_printer_attributes(self, request, response):
+        """RFC 2911: 3.2.5 Get-Printer-Attributes Operation
+
+        This REQUIRED operation allows a client to request the values
+        of the attributes of a Printer object.
+        
+        In the request, the client supplies the set of Printer
+        attribute names and/or attribute group names in which the
+        requester is interested. In the response, the Printer object
+        returns a corresponding attribute set with the appropriate
+        attribute values filled in.
+
+        For Printer objects, the possible names of attribute groups are:
+        
+        - '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.
+
+        """
+
         # this is just like cups_get_default, except the printer name
         # is given
