source: server/lib/gutenbach/ipp/operations.py @ 71bfce0

no-cups
Last change on this file since 71bfce0 was 71bfce0, checked in by Jessica B. Hamrick <jhamrick@…>, 12 years ago

Add dictionaries to ipp/constants to map attribute names to value tags

  • Property mode set to 100644
File size: 14.3 KB
Line 
1from .value import Value
2from .attribute import Attribute
3from .attributegroup import AttributeGroup
4from .request import Request
5from .constants import AttributeTags, operations_attribute_value_tags
6import exceptions as err
7
8from collections import OrderedDictionary as odict
9
10def verify_operations(request):
11    """Pretty much all requests have the first attribute group for
12    operation attributes, and these all have 'attributes-charset' and
13    'attributes-natural-language' as the first two attributes.  This
14    method just generically verifies that these attributes are there.
15
16    """
17
18    # check operation attributes tag
19    op_attrs = request.attribute_groups[0]
20    if op_attrs.tag != AttributeTags.OPERATION:
21        raise err.BadRequest(
22            "Attribute group does not have OPERATION tag: 0x%x" % op_attrs.tag)
23
24    # XXX: check version
25    if False:
26        raise err.VersionNotSupported(str(request.version))
27
28    # check operation id
29    if False:
30        raise err.OperationNotSupported(str(request.operation_id))
31
32    # # check compression
33    # if False:
34    #     raise err.CompressionNotSupported
35
36    # # check document format
37    # if False:
38    #     raise err.DocumentFormatNotSupported
39
40    # # check document uri
41    # if False:
42    #     raise err.UriSchemeNotSupported
43
44    # check charset
45    charset attribute
46    charset_attr = op_attrs.attributes[0]
47    if charset_attr.name != 'attributes-charset':
48        raise err.BadRequest(
49            "Attribute is not attributes-charset: %s" % charset_attr.name)
50    if len(charset_attr.values) != 1:
51        raise err.BadRequest(
52            "Too many values for attributes-charset: %d" % len(charset_attr.values))
53
54    # check charset value
55    charset_value = charset_attr.values[0]
56    if charset_value.tag != operations_attribute_value_tags['attributes-charset']:
57        raise err.BadRequest(
58            "Wrong tag for charset value: 0x%x" % charset_value.tag)
59    if charset_value.value != 'utf-8':
60        raise err.CharsetNotSupported(str(charset_value.value))
61
62    # check for attributes-natural-language
63    natlang_attr = op_attrs.attributes[1]
64    if natlang_attr.name != 'attributes-natural-language':
65        raise err.BadRequest(
66            "Attribute is not attributes-natural-language: %s" % natlang_attr.name)
67    if len(charset_attr.values) != 1:
68        raise err.BadRequest(
69            "Too many values for attributes-natural-language: %s" % len(natlang_attr.values))
70
71    # check natural language value
72    natlang_value = natlang_attr.values[0]
73    if natlang_value.tag != operations_attribute_value_tags['attributes-natural-language']:
74        raise err.BadRequest(
75            "Natural language value does not have NATURAL_LANGUAGE tag: 0x%x" natlang_value.tag)
76    if natlang_value.value != 'en-us':
77        raise err.Attributes(
78            "Invalid natural language value: %s" % natlang_value.value, [natlang_attr])
79
80def verify_printer_uri(uri_attr):
81    if uri_attr.name != 'printer-uri':
82        raise err.BadRequest(
83            "Unexpected name for attribute 'printer-uri': %s" % uri_attr.name)
84    if len(uri_attr.values) != 1:
85        raise err.BadRequest(
86            "Requesting printer uri attribute has too many values: %d" % len(uri_attr.values))
87    printer_name_value = uri_attr.values[0]
88    if printer_name_value.tag != operations_attribute_value_tags['printer-uri']:
89        raise err.BadRequest(
90            "Bad value tag (expected URI): 0x%x" % printer_name_value_tag)
91   
92    # actually get the printer name
93    printer_name_value = printer_name_attr.values[0].value
94    # XXX: hack -- CUPS will strip the port from the request, so
95    # we can't do an exact comparison (also the hostname might be
96    # different, depending on the CNAME or whether it's localhost)
97    printer_name = printer_name_value.split("/")[-1]
98    return printer_name
99
100def verify_requesting_username(requser_attr):
101    if requser_attr.name != 'requesting-user-name':
102        raise err.BadRequest(
103            "Unexpected name for attribute 'requesting-user-name': %s" % requser_attr.name)
104    if len(requser_attr.values) != 1:
105        raise err.BadRequest(
106            "Requesting user name attribute has too many values: %d" % len(requser_attr.values))
107    requser_value = requser_attr.values[0]
108    if requser_value.tag != operations_attribute_value_tags['requesting-user-name']:
109        raise err.BadRequest(
110            "Bad value tag (expected NAME_WITHOUT_LANGUAGE): 0x%x" % requser_value.tag)
111   
112    return requser_value.value
113
114def make_empty_response(request):
115    # Operation attributes -- typically the same for any request
116    attributes = [
117        ipp.Attribute(
118            'attributes-charset',
119            [(operations_attribute_value_tags['attributes-charset'], 'utf-8')]),
120        ipp.Attribute(
121            'attributes-natural-language',
122            [(operations_attribute_value_tags['attributes-natural-language'], 'en-us')])
123        ]
124    # Put the operation attributes in a group
125    attribute_group = ipp.AttributeGroup(
126        const.AttributeTags.OPERATION,
127        attributes)
128
129    # Set up the default response -- handlers will override these
130    # values if they need to
131    response_kwargs = {}
132    response_kwargs['version']          = request.version
133    response_kwargs['operation_id']     = const.StatusCodes.OK
134    response_kwargs['request_id']       = request.request_id
135    response_kwargs['attribute_groups'] = [attribute_group]
136    response = ipp.Request(**response_kwargs)
137
138    return response
139
140#### GET-JOBS
141
142def verify_get_jobs_request(request):
143    """RFC 2911 3.2.6.1 Get-Jobs Request
144
145    The client submits the Get-Jobs request to a Printer object.
146   
147    The following groups of attributes are part of the Get-Jobs
148    Request:
149
150    Group 1: Operation Attributes
151        Natural Language and Character Set:
152            The 'attributes-charset' and
153            'attributes-natural-language' attributes as described
154            in section 3.1.4.1.
155        Target:
156            The 'printer-uri' (uri) operation attribute which is
157            the target for this operation as described in section
158            3.1.5.
159        Requesting User Name:
160            The 'requesting-user-name' (name(MAX)) attribute
161            SHOULD be supplied by the client as described in
162            section 8.3.
163        'limit' (integer(1:MAX)):
164            The client OPTIONALLY supplies this attribute. The
165            Printer object MUST support this attribute. It is an
166            integer value that determines the maximum number of
167            jobs that a client will receive from the Printer even
168            if 'which-jobs' or 'my-jobs' constrain which jobs are
169            returned. The limit is a 'stateless limit' in that if
170            the value supplied by the client is ’N’, then only the
171            first ’N’ jobs are returned in the Get-Jobs Response.
172            There is no mechanism to allow for the next ’M’ jobs
173            after the first ’N’ jobs. If the client does not
174            supply this attribute, the Printer object responds
175            with all applicable jobs.
176        'requested-attributes' (1setOf type2 keyword):
177            The client OPTIONALLY supplies this attribute. The
178            Printer object MUST support this attribute. It is a
179            set of Job attribute names and/or attribute groups
180            names in whose values the requester is
181            interested. This set of attributes is returned for
182            each Job object that is returned. The allowed
183            attribute group names are the same as those defined in
184            the Get-Job-Attributes operation in section 3.3.4. If
185            the client does not supply this attribute, the Printer
186            MUST respond as if the client had supplied this
187            attribute with two values: ’job-uri’ and ’job-id’.
188        'which-jobs' (type2 keyword):
189            The client OPTIONALLY supplies this attribute. The
190            Printer object MUST support this attribute. It
191            indicates which Job objects MUST be returned by the
192            Printer object. The values for this attribute are:
193             - ’completed’: This includes any Job object whose
194               state is ’completed’, ’canceled’, or ’aborted’.
195             - ’not-completed’: This includes any Job object whose
196               state is ’pending’, ’processing’,
197               ’processing-stopped’, or ’pending-held’.
198            A Printer object MUST support both values. However, if
199            the implementation does not keep jobs in the
200            ’completed’, ’canceled’, and ’aborted’ states, then it
201            returns no jobs when the ’completed’ value is
202            supplied.  If a client supplies some other value, the
203            Printer object MUST copy the attribute and the
204            unsupported value to the Unsupported Attributes
205            response group, reject the request, and return the
206            ’client-error-attributes-or-values-not-supported’
207            status code.  If the client does not supply this
208            attribute, the Printer object MUST respond as if the
209            client had supplied the attribute with a value of
210            ’not-completed’.
211        'my-jobs' (boolean):
212            The client OPTIONALLY supplies this attribute. The
213            Printer object MUST support this attribute. It
214            indicates whether jobs from all users or just the jobs
215            submitted by the requesting user of this request MUST
216            be considered as candidate jobs to be returned by the
217            Printer object. If the client does not supply this
218            attribute, the Printer object MUST respond as if the
219            client had supplied the attribute with a value of
220            ’false’, i.e., jobs from all users. The means for
221            authenticating the requesting user and matching the
222            jobs is described in section 8.
223
224    """
225
226
227    # generic operations verification
228    verify_operations(request)
229    # requested printer uri
230    printeruri = verify_printer_uri(request.attribute_groups[0].attributes[2])
231    # requesting username
232    requser = verify_requesting_username(request.attribute_groups[0].attributes[3])
233    # make the rest of the attributes into a dictionary
234    attrs = dict([(attr.name, attr.values) for attr in request.attributes[4:]])
235   
236    out = {
237        'printer-uri': printeruri,
238        'requesting-user-name': requser
239        }
240
241    if 'limit' in attrs:
242        out['limit'] = None # XXX
243
244    if 'requested-attributes' in attrs:
245        out['requested-attributes'] = None # XXX
246
247    if 'which-jobs' in attrs:
248        out['which-jobs'] = None # XXX
249
250    if 'my-jobs' in attrs:
251        out['my-jobs'] = None # XXX
252
253    return out
254
255def make_get_jobs_response(self, request):
256    """RFC 2911: 3.2.6.2 Get-Jobs Response
257       
258    The Printer object returns all of the Job objects up to the number
259    specified by the 'limit' attribute that match the criteria as
260    defined by the attribute values supplied by the client in the
261    request. It is possible that no Job objects are returned since
262    there may literally be no Job objects at the Printer, or there may
263    be no Job objects that match the criteria supplied by the
264    client. If the client requests any Job attributes at all, there is
265    a set of Job Object Attributes returned for each Job object.
266
267    It is not an error for the Printer to return 0 jobs. If the
268    response returns 0 jobs because there are no jobs matching the
269    criteria, and the request would have returned 1 or more jobs
270    with a status code of ’successful-ok’ if there had been jobs
271    matching the criteria, then the status code for 0 jobs MUST be
272    ’successful-ok’.
273
274    Group 1: Operation Attributes
275        Status Message:
276            In addition to the REQUIRED status code returned in
277            every response, the response OPTIONALLY includes a
278            'status-message' (text(255)) and/or a
279            'detailed-status-message' (text(MAX)) operation
280            attribute as described in sections 13 and 3.1.6.
281        Natural Language and Character Set:
282            The 'attributes-charset' and
283            'attributes-natural-language' attributes as described
284            in section 3.1.4.2.
285
286    Group 2: Unsupported Attributes
287        See section 3.1.7 for details on returning Unsupported
288        Attributes.  The response NEED NOT contain the
289        'requested-attributes' operation attribute with any
290        supplied values (attribute keywords) that were requested
291        by the client but are not supported by the IPP object.  If
292        the Printer object does return unsupported attributes
293        referenced in the 'requested-attributes' operation
294        attribute and that attribute included group names, such as
295        ’all’, the unsupported attributes MUST NOT include
296        attributes described in the standard but not supported by
297        the implementation.
298
299    Groups 3 to N: Job Object Attributes
300        The Printer object responds with one set of Job Object
301        Attributes for each returned Job object. The Printer
302        object ignores (does not respond with) any requested
303        attribute or value which is not supported or which is
304        restricted by the security policy in force, including
305        whether the requesting user is the user that submitted the
306        job (job originating user) or not (see section
307        8). However, the Printer object MUST respond with the
308        ’unknown’ value for any supported attribute (including all
309        REQUIRED attributes) for which the Printer object does not
310        know the value, unless it would violate the security
311        policy. See the description of the 'out-of- band' values
312        in the beginning of Section 4.1.
313
314        Jobs are returned in the following order:
315        - If the client requests all ’completed’ Jobs (Jobs in the
316          ’completed’, ’aborted’, or ’canceled’ states), then the
317          Jobs are returned newest to oldest (with respect to
318          actual completion time)
319        - If the client requests all ’not-completed’ Jobs (Jobs in
320          the ’pending’, ’processing’, ’pending-held’, and
321          ’processing- stopped’ states), then Jobs are returned in
322          relative chronological order of expected time to
323          complete (based on whatever scheduling algorithm is
324          configured for the Printer object).
325
326    """
327
328    pass
Note: See TracBrowser for help on using the repository browser.