source: server/lib/gutenbach/server/requests.py @ 4914b47

no-cups
Last change on this file since 4914b47 was 4914b47, checked in by Daniel Cooper <danny@…>, 12 years ago

added most of print_job

  • Property mode set to 100644
File size: 54.7 KB
Line 
1from . import InvalidJobException, InvalidPrinterStateException, InvalidJobStateException
2import gutenbach.ipp as ipp
3import logging
4import traceback
5import sys
6
7# initialize logger
8logger = logging.getLogger(__name__)
9
10def handler_for(operation):
11    """A decorator method to mark a function with the operation id
12    that it handles.  This value will be stored in
13    'func.ipp_operation'.
14
15    """
16   
17    def f(func):
18        func.ipp_operation = operation
19        return func
20    return f
21
22def make_empty_response(request):
23    # Operation attributes -- typically the same for any request
24    attribute_group = ipp.AttributeGroup(
25        ipp.AttributeTags.OPERATION,
26        [ipp.AttributesCharset('utf-8'),
27         ipp.AttributesNaturalLanguage('en-us')])
28   
29    # Set up the default response -- handlers will override these
30    # values if they need to
31    response_kwargs = {}
32    response_kwargs['version']          = request.version
33    response_kwargs['operation_id']     = ipp.StatusCodes.OK
34    response_kwargs['request_id']       = request.request_id
35    response_kwargs['attribute_groups'] = [attribute_group]
36    response = ipp.Request(**response_kwargs)
37   
38    return response
39
40def verify_attribute(attr, cls, length=1):
41    vals = [val.value for val in attr.values]
42    if attr != cls(*vals):
43        raise ipp.errors.ClientErrorBadRequest(str(attr))
44    if length is not None and len(vals) != length:
45        raise ipp.errors.ClientErrorBadRequest(str(attr))
46    return vals
47
48class GutenbachRequestHandler(object):
49
50    def __init__(self, gutenbach_printer):
51        self.printer = gutenbach_printer
52
53    def generic_handle(self, request):
54        # check the IPP version number
55        if request.version != (1, 1):
56            raise ipp.errors.ServerErrorVersionNotSupported(str(request.version))
57
58        # make sure the operation attribute group has the correct tag
59        operation = request.attribute_groups[0]
60        if operation.tag != ipp.AttributeTags.OPERATION:
61            raise ipp.errors.ClientErrorBadRequest(
62                "Attribute group does not have OPERATION tag: 0x%x" % operation.tag)
63
64        # check charset
65        charset_attr = operation.attributes[0]
66        charset = verify_attribute(charset_attr, ipp.AttributesCharset)[0]
67        if charset != 'utf-8':
68            raise ipp.errors.ClientErrorAttributes(str(charset_attr))
69
70        # check for attributes-natural-language
71        natlang_attr = operation.attributes[1]
72        natlang = verify_attribute(natlang_attr, ipp.AttributesNaturalLanguage)[0]
73        if natlang != 'en-us':
74            raise ipp.errors.ClientErrorAttributes(str(natlang_attr))
75   
76    def handle(self, request):
77        # look up the handler
78        handler = None
79        handler_name = None
80        for d in dir(self):
81            if getattr(getattr(self, d), "ipp_operation", None) == request.operation_id:
82                handler_name = d
83                break
84
85        # we couldn't find a handler, so default to unknown operation
86        if handler_name is None:
87            handler_name = "unknown_operation"
88
89        # actually get the handler
90        handler = getattr(self, handler_name)
91        logger.info("request is '%s'" % handler_name)
92
93        # try to handle the request
94        try:
95            self.generic_handle(request)
96            response = make_empty_response(request)
97            handler(request, response)
98
99        # Handle any errors that occur.  If an exception occurs that
100        # is an IPP error, then we can get the error code from the
101        # exception itself.
102        except ipp.errors.IPPException:
103            exctype, excval, exctb = sys.exc_info()
104            logger.error("%s: %s" % (exctype.__name__, excval.message))
105            response = make_empty_response(request)
106            excval.update_response(response)
107
108        # If it wasn't an IPP error, then it's our fault, so mark it
109        # as an internal server error
110        except Exception:
111            logger.error(traceback.format_exc())
112            response = make_empty_response(request)
113            response.operation_id = ipp.StatusCodes.INTERNAL_ERROR
114
115        return response
116
117    def unknown_operation(self, request, response):
118        logger.warning("unknown operation 0x%x" % request.operation_id)
119        response = make_empty_response(request)
120        response.operation_id = ipp.StatusCodes.OPERATION_NOT_SUPPORTED
121        return response
122       
123    ##### Printer Commands
124
125    @handler_for(ipp.OperationCodes.PRINT_JOB)
126    def print_job(self, request, response):
127        """RFC 2911: 3.2.1 Print-Job Operation
128
129        This REQUIRED operation allows a client to submit a print job
130        with only one document and supply the document data (rather
131        than just a reference to the data). See Section 15 for the
132        suggested steps for processing create operations and their
133        Operation and Job Template attributes.
134
135        Request
136        -------
137        Group 1: Operation Attributes
138            REQUIRED 'attributes-charset'
139            REQUIRED 'attributes-natural-language'
140            REQUIRED 'printer-uri' (uri)
141            OPTIONAL 'requesting-user-name' (name(MAX))
142            OPTIONAL 'job-name' (name(MAX))
143            OPTIONAL 'ipp-attribute-fidelity' (boolean)
144            OPTIONAL 'document-name' (name(MAX))
145            OPTIONAL 'compression' (type3 keyword)
146            OPTIONAL 'document-format' (mimeMediaType)
147            OPTIONAL 'document-natural-language' (naturalLanguage)
148            OPTIONAL 'job-k-octets' (integer(0:MAX))
149            OPTIONAL 'job-impressions' (integer(0:MAX))
150            OPTIONAL 'job-media-sheets' (integer(0:MAX))
151        Group 2: Job Template Attributes
152        Group 3: Document Content
153
154        Response
155        --------
156        Group 1: Operation Attributes
157            OPTIONAL 'status-message' (text(255))
158            OPTIONAL 'detailed-status-message' (text(MAX))
159            REQUIRED 'attributes-charset'
160            REQUIRED 'attributes-natural-language'
161        Group 2: Unsupported Attributes
162        Group 3: Job Object Attributes
163            REQUIRED 'job-uri' (uri)
164            REQUIRED 'job-id' (integer(1:MAX))
165            REQUIRED 'job-state' (type1 enum)
166            REQUIRED 'job-state-reasons' (1setOf type2 keyword)
167            OPTIONAL 'job-state-message' (text(MAX))
168            OPTIONAL 'number-of-intervening-jobs' (integer(0:MAX))
169
170        """
171        operation = request.attribute_groups[0]
172        # requested printer uri
173        if 'printer-uri' not in operation:
174            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
175        printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
176        if printer_uri not in self.printer.uris:
177            raise ipp.errors.ClientErrorAttributes(
178                str(operation['printer-uri']), operation['printer-uri'])
179
180        if 'requesting-user-name' in operation:
181            user_name = verify_attribute(
182                operation['requesting-user-name'], ipp.RequestingUserName)[0]
183
184        if 'job-name' in operation:
185            job_name = verify_attribute(
186                operation['job-name'], ipp.JobName)[0]
187
188        if 'job-k-octets' in operation:
189            job_k_octets = verify_attribute(
190                operation['job-k-octets'], ipp.JobKOctets)[0]
191
192        if 'ipp-attribute-fidelity' in operation:
193            pass # don't care
194        if 'job-impressions' in operation:
195            pass # don't care
196        if 'job-media-sheets' in operation:
197            pass # don't care
198
199        # get attributes from the printer and add to response
200        job_id = self.printer.create_job(
201            requesting_user_name=requesting_user_name,
202            job_name=job_name,
203            job_k_octets=job_k_octets)
204        attrs = self.printer.get_job_attributes(job_id)
205        response.attribute_groups.append(ipp.AttributeGroup(
206            ipp.AttributeTags.JOB, attrs))
207            #raise ipp.errors.ServerErrorOperationNotSupported
208        # Get nescessary information for calling send_document
209        # Any field being set to None here just means that we either aren't using or haven't implemented parsing it
210        document = request.attribute_groups[2]
211        #XXX
212        document_format = None
213        document_natural_language = None
214        compression = None
215        last_document = None
216
217
218       
219        # Actually put the document in the job
220        self.printer.send_document(job_id,document,
221                document_name = document_name,
222                document_format = document_format,
223                document_natural_language = document_natural_language,
224                requesting_user_name = requesting_user_name,
225                compression = compression,
226                last_document = last_document)
227        #fix this once jess pushes
228        self.print_job()
229    @handler_for(ipp.OperationCodes.VALIDATE_JOB)
230    def validate_job(self, request, response):
231
232        raise ipp.errors.ServerErrorOperationNotSupported
233
234    @handler_for(ipp.OperationCodes.GET_JOBS)
235    def get_jobs(self, request, response):
236        """3.2.6 Get-Jobs Operation
237       
238        This REQUIRED operation allows a client to retrieve the list
239        of Job objects belonging to the target Printer object. The
240        client may also supply a list of Job attribute names and/or
241        attribute group names. A group of Job object attributes will
242        be returned for each Job object that is returned.
243
244        This operation is similar to the Get-Job-Attributes operation,
245        except that this Get-Jobs operation returns attributes from
246        possibly more than one object.
247
248        Request
249        -------
250        Group 1: Operation Attributes
251            REQUIRED 'attributes-charset'
252            REQUIRED 'attributes-natural-language'
253            REQUIRED 'printer-uri' (uri)
254            OPTIONAL 'requesting-user-name' (name(MAX))
255            OPTIONAL 'limit' (integer(1:MAX))
256            OPTIONAL 'requested-attributes' (1setOf type2 keyword)
257            OPTIONAL 'which-jobs' (type2 keyword)
258            OPTIONAL 'my-jobs' (boolean)
259
260        Response
261        --------
262        Group 1: Operation Attributes
263            OPTIONAL 'status-message' (text(255))
264            OPTIONAL 'detailed-status-message' (text(MAX))
265            REQUIRED 'attributes-charset'
266            REQUIRED 'attributes-natural-language'
267        Group 2: Unsupported Attributes
268        Groups 3 to N: Job Object Attributes
269
270        """
271
272        operation = request.attribute_groups[0]
273
274        # initialize operation attribute variables
275        printer_name = None
276        user = None
277        limit = None
278        attributes = None
279        which_jobs = None
280        my_jobs = None
281
282        # requested printer uri
283        if 'printer-uri' not in operation:
284            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
285        printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
286        if printer_uri not in self.printer.uris and printer_uri != "ipp://localhost/":
287            raise ipp.errors.ClientErrorAttributes(
288                str(operation['printer-uri']), operation['printer-uri'])
289
290        # optional attributes
291        if 'limit' in operation:
292            limit = verify_attribute(
293                operation['limit'], ipp.Limit)[0]
294           
295        if 'requested-attributes' in operation:
296            attributes = verify_attribute(
297                operation['requested-attributes'], ipp.RequestedAttributes, length=None)
298           
299        if 'which-jobs' in operation:
300            which_jobs = verify_attribute(
301                operation['which-jobs'], ipp.WhichJobs)[0]
302           
303        if 'my-jobs' in operation:
304            my_jobs = verify_attribute(
305                operation['my-jobs'], ipp.MyJobs)[0]
306
307        if 'requesting-user-name' in operation:
308            user = verify_attribute(
309                operation['requesting-user-name'], ipp.RequestingUserName)[0]
310            # ignore if we're not filtering jobs by user
311            if not my_jobs:
312                user = None
313           
314        # get the job attributes and add them to the response
315        job_attrs = self.printer.get_jobs(
316            which_jobs=which_jobs,
317            requesting_user_name=user,
318            requested_attributes=attributes)
319        for attrs in job_attrs:
320            response.attribute_groups.append(ipp.AttributeGroup(
321                ipp.AttributeTags.JOB, attrs))
322
323    @handler_for(ipp.OperationCodes.PRINT_URI)
324    def print_uri(self, request, response):
325        """3.2.2 Print-URI Operation
326
327        This OPTIONAL operation is identical to the Print-Job operation
328        (section 3.2.1) except that a client supplies a URI reference to the
329        document data using the 'document-uri' (uri) operation attribute (in
330        Group 1) rather than including the document data itself.  Before
331        returning the response, the Printer MUST validate that the Printer
332        supports the retrieval method (e.g., http, ftp, etc.) implied by the
333        URI, and MUST check for valid URI syntax.  If the client-supplied URI
334        scheme is not supported, i.e. the value is not in the Printer
335        object's 'referenced-uri-scheme-supported' attribute, the Printer
336        object MUST reject the request and return the 'client-error-uri-
337        scheme-not-supported' status code.
338
339        The IPP Printer MAY validate the accessibility of the document as
340        part of the operation or subsequently.  If the Printer determines an
341        accessibility problem before returning an operation response, it
342        rejects the request and returns the 'client-error-document-access-
343        error' status code.  The Printer MAY also return a specific document
344        access error code using the 'document-access-error' operation
345        attribute (see section 3.1.6.4).
346
347        If the Printer determines this document accessibility problem after
348        accepting the request and returning an operation response with one
349        of the successful status codes, the Printer adds the
350        'document-access- error' value to the job's 'job-state-reasons'
351        attribute and MAY populate the job's 'job-document-access-errors'
352        Job Description attribute (see section 4.3.11).  See The
353        Implementer's Guide [IPP- IIG] for suggested additional checks.
354                                                                             
355        If the Printer object supports this operation, it MUST support the
356        'reference-uri-schemes-supported' Printer attribute (see section 4.4.27).
357
358        It is up to the IPP object to interpret the URI and subsequently
359        'pull' the document from the source referenced by the URI string."""
360        raise ipp.errors.ServerErrorOperationNotSupported
361
362    @handler_for(ipp.OperationCodes.CREATE_JOB)
363    def create_job(self, request, response):
364        """RFC 2911: 3.2.4 Create-Job Operation
365
366        This OPTIONAL operation is similar to the Print-Job operation
367        (section 3.2.1) except that in the Create-Job request, a
368        client does not supply document data or any reference to
369        document data. Also, the client does not supply any of the
370        'document-name', 'document- format', 'compression', or
371        'document-natural-language' operation attributes. This
372        operation is followed by one or more Send-Document or Send-URI
373        operations. In each of those operation requests, the client
374        OPTIONALLY supplies the 'document-name', 'document-format',
375        and 'document-natural-language' attributes for each document
376        in the multi-document Job object.
377
378        Request
379        -------
380        Group 1: Operation Attributes
381            REQUIRED 'attributes-charset'
382            REQUIRED 'attributes-natural-language'
383            REQUIRED 'printer-uri' (uri)
384            OPTIONAL 'requesting-user-name' (name(MAX))
385            OPTIONAL 'job-name' (name(MAX))
386            OPTIONAL 'ipp-attribute-fidelity' (boolean)
387            OPTIONAL 'job-k-octets' (integer(0:MAX))
388            OPTIONAL 'job-impressions' (integer(0:MAX))
389            OPTIONAL 'job-media-sheets' (integer(0:MAX))
390        Group 2: Job Template Attributes
391
392        Response
393        --------
394        Group 1: Operation Attributes
395            OPTIONAL 'status-message' (text(255))
396            OPTIONAL 'detailed-status-message' (text(MAX))
397            REQUIRED 'attributes-charset'
398            REQUIRED 'attributes-natural-language'
399        Group 2: Unsupported Attributes
400        Group 3: Job Object Attributes
401            REQUIRED 'job-uri' (uri)
402            REQUIRED 'job-id' (integer(1:MAX))
403            REQUIRED 'job-state' (type1 enum)
404            REQUIRED 'job-state-reasons' (1setOf type2 keyword)
405            OPTIONAL 'job-state-message' (text(MAX))
406            OPTIONAL 'number-of-intervening-jobs' (integer(0:MAX))
407       
408        """
409
410        operation = request.attribute_groups[0]
411
412        printer_uri = None
413        requesting_user_name = None
414        job_name = None
415        ipp_attribute_fidelity=None
416        job_k_octets = None
417
418        # requested printer uri
419        if 'printer-uri' not in operation:
420            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
421        printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
422        if printer_uri not in self.printer.uris:
423            raise ipp.errors.ClientErrorAttributes(
424                str(operation['printer-uri']), operation['printer-uri'])
425
426        if 'requesting-user-name' in operation:
427            user_name = verify_attribute(
428                operation['requesting-user-name'], ipp.RequestingUserName)[0]
429
430        if 'job-name' in operation:
431            job_name = verify_attribute(
432                operation['job-name'], ipp.JobName)[0]
433
434        if 'job-k-octets' in operation:
435            job_k_octets = verify_attribute(
436                operation['job-k-octets'], ipp.JobKOctets)[0]
437
438        if 'ipp-attribute-fidelity' in operation:
439            pass # don't care
440        if 'job-impressions' in operation:
441            pass # don't care
442        if 'job-media-sheets' in operation:
443            pass # don't care
444
445        # get attributes from the printer and add to response
446        job_id = self.printer.create_job(
447            requesting_user_name=requesting_user_name,
448            job_name=job_name,
449            job_k_octets=job_k_octets)
450        attrs = self.printer.get_job_attributes(job_id)
451        response.attribute_groups.append(ipp.AttributeGroup(
452            ipp.AttributeTags.JOB, attrs))
453   
454    @handler_for(ipp.OperationCodes.PAUSE_PRINTER)
455    def pause_printer(self, request, response):
456        """
457            3.2.7 Pause-Printer Operation
458
459            This OPTIONAL operation allows a client to stop the Printer object
460            from scheduling jobs on all its devices.  Depending on
461            implementation, the Pause-Printer operation MAY also stop the Printer
462            from processing the current job or jobs.  Any job that is currently
463            being printed is either stopped as soon as the implementation permits
464            or is completed, depending on implementation.  The Printer object
465            MUST still accept create operations to create new jobs, but MUST
466            prevent any jobs from entering the 'processing' state.
467
468            If the Pause-Printer operation is supported, then the Resume-Printer
469            operation MUST be supported, and vice-versa.
470
471            The IPP Printer stops the current job(s) on its device(s) that were
472            in the 'processing' or 'processing-stopped' states as soon as the
473            implementation permits.  If the implementation will take appreciable
474            time to stop, the IPP Printer adds the 'moving-to-paused' value to
475            the Printer object's 'printer-state-reasons' attribute (see section
476            4.4.12).  When the device(s) have all stopped, the IPP Printer
477            transitions the Printer object to the 'stopped' state, removes the
478            'moving-to-paused' value, if present, and adds the 'paused' value to
479            the Printer object's 'printer-state-reasons' attribute.
480
481            When the current job(s) complete that were in the 'processing' state,
482            the IPP Printer transitions them to the 'completed' state.  When the
483            current job(s) stop in mid processing that were in the 'processing'
484            state, the IPP Printer transitions them to the 'processing-stopped'
485            state and adds the 'printer-stopped' value to the job's 'job-state-
486            reasons' attribute.
487
488            For any jobs that are 'pending' or 'pending-held', the 'printer-
489            stopped' value of the jobs' 'job-state-reasons' attribute also
490            applies.  However, the IPP Printer NEED NOT update those jobs' 'job-
491            state-reasons' attributes and only need return the 'printer-stopped'
492            value when those jobs are queried (so-called 'lazy evaluation').
493
494            Whether the Pause-Printer operation affects jobs that were submitted
495            to the device from other sources than the IPP Printer object in the
496            same way that the Pause-Printer operation affects jobs that were
497            submitted to the IPP Printer object using IPP, depends on
498            implementation, i.e., on whether the IPP protocol is being used as a
499            universal management protocol or just to manage IPP jobs,
500            respectively.
501
502            The IPP Printer MUST accept the request in any state and transition
503            the Printer to the indicated new 'printer-state' before returning as
504            follows:
505
506            Current        New      'printer   IPP Printer's response status
507            'printer-    'printer-   -state-          code and action:
508            state'       state'    reasons'
509
510            'idle'       'stopped'    'paused'  'successful-ok'
511            'processing' 'processing' 'moving-  OPTION 1: 'successful-ok';
512                                                      to-       Later, when all output has
513                                                      paused'   stopped, the 'printer-state'
514                                                                            becomes 'stopped', and the
515                                                                            'paused' value replaces the
516                                                                            'moving-to-paused' value in the
517                                                                            'printer-state-reasons'
518                                                                            attribute
519            'processing' 'stopped'    'paused'  OPTION 2: 'successful-ok';
520                                                                            all device output stopped
521                                                                            immediately
522            'stopped'    'stopped'    'paused'  'successful-ok'
523
524            Access Rights: The authenticated user (see section 8.3) performing
525            this operation must be an operator or administrator of the Printer
526            object (see Sections 1 and 8.5).   Otherwise, the IPP Printer MUST
527            reject the operation and return:  'client-error-forbidden', 'client-
528            error-not-authenticated', or 'client-error-not-authorized' as
529            appropriate.
530
531            3.2.7.1 Pause-Printer Request
532
533            The following groups of attributes are part of the Pause-Printer
534            Request:
535
536            Group 1: Operation Attributes
537
538            Natural Language and Character Set:
539            The 'attributes-charset' and 'attributes-natural-language'
540            attributes as described in section 3.1.4.1.
541
542            Target:
543            The 'printer-uri' (uri) operation attribute which is the target
544            for this operation as described in section 3.1.5.
545
546            Requesting User Name:
547            The 'requesting-user-name' (name(MAX)) attribute SHOULD be
548            supplied by the client as described in section 8.3.
549
550            3.2.7.2 Pause-Printer Response
551
552            The following groups of attributes are part of the Pause-Printer
553            Response:
554
555            Group 1: Operation Attributes
556
557            Status Message:
558            In addition to the REQUIRED status code returned in every
559            response, the response OPTIONALLY includes a 'status-message'
560            (text(255)) and/or a 'detailed-status-message' (text(MAX))
561            operation attribute as described in sections 13 and  3.1.6.
562
563            Natural Language and Character Set:
564            The 'attributes-charset' and 'attributes-natural-language'
565            attributes as described in section 3.1.4.2.
566
567            Group 2: Unsupported Attributes
568
569            See section 3.1.7 for details on returning Unsupported Attributes.
570
571   
572    """
573        raise ipp.errors.ServerErrorOperationNotSupported
574
575    @handler_for(ipp.OperationCodes.RESUME_PRINTER)
576    def resume_printer(self, request, response):
577        """
578        3.2.8 Resume-Printer Operation
579
580        This operation allows a client to resume the Printer object
581        scheduling jobs on all its devices.  The Printer object MUST remove
582        the 'paused' and 'moving-to-paused' values from the Printer object's
583        'printer-state-reasons' attribute, if present.  If there are no other
584        reasons to keep a device paused (such as media-jam), the IPP Printer
585        is free to transition itself to the 'processing' or 'idle' states,
586        depending on whether there are jobs to be processed or not,
587        respectively, and the device(s) resume processing jobs.
588
589        If the Pause-Printer operation is supported, then the Resume-Printer
590        operation MUST be supported, and vice-versa.
591
592        The IPP Printer removes the 'printer-stopped' value from any job's
593        'job-state-reasons' attributes contained in that Printer.
594
595        The IPP Printer MUST accept the request in any state, transition the
596        Printer object to the indicated new state as follows:
597
598
599        Current    New 'printer-  IPP Printer's response status code and
600        'printer-      state'                     action:
601        state'
602
603        'idle'       'idle'         'successful-ok'
604        'processing' 'processing'   'successful-ok'
605
606        'stopped'    'processing'   'successful-ok';
607                                                   when there are jobs to be processed
608        'stopped'    'idle'         'successful-ok';
609                                                   when there are no jobs to be processed.
610
611        Access Rights: The authenticated user (see section 8.3) performing
612        this operation must be an operator or administrator of the Printer
613        object (see Sections 1 and 8.5).  Otherwise, the IPP Printer MUST
614        reject the operation and return:  'client-error-forbidden', 'client-
615        error-not-authenticated', or 'client-error-not-authorized' as
616        appropriate.
617
618        The Resume-Printer Request and Resume-Printer Response have the same
619        attribute groups and attributes as the Pause-Printer operation (see
620        sections 3.2.7.1 and 3.2.7.2).                 
621        """
622        raise ipp.errors.ServerErrorOperationNotSupported
623
624    @handler_for(ipp.OperationCodes.GET_PRINTER_ATTRIBUTES)
625    def get_printer_attributes(self, request, response):
626        """RFC 2911: 3.2.5 Get-Printer-Attributes Operation
627
628        This REQUIRED operation allows a client to request the values
629        of the attributes of a Printer object.
630       
631        In the request, the client supplies the set of Printer
632        attribute names and/or attribute group names in which the
633        requester is interested. In the response, the Printer object
634        returns a corresponding attribute set with the appropriate
635        attribute values filled in.
636
637        Request
638        -------
639
640        Group 1: Operation Attributes
641            REQUIRED 'attributes-charset'
642            REQUIRED 'attributes-natural-language'
643            REQUIRED 'printer-uri' (uri)
644            OPTIONAL 'requesting-user-name' (name(MAX))
645            OPTIONAL 'requested-attributes' (1setOf type2 keyword)
646            OPTIONAL 'document-format' (mimeMediaType)
647           
648        Response
649        --------
650
651        Group 1: Operation Attributes
652            OPTIONAL 'status-message' (text(255))
653            OPTIONAL 'detailed-status-message' (text(MAX))
654            REQUIRED 'attributes-charset'
655            REQUIRED 'attributes-natural-language'
656        Group 2: Unsupported Attributes
657        Group 3: Printer Object Attributes
658
659        """
660
661        operation = request.attribute_groups[0]
662
663        printer_uri = None
664        requesting_user_name = None
665        requested_attributes = None
666        document_format = None
667
668        # requested printer uri
669        if 'printer-uri' not in operation:
670            raise ipp.errors.ClientErrorBadRequest("Missing 'printer-uri' attribute")
671        printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
672        if printer_uri not in self.printer.uris:
673            raise ipp.errors.ClientErrorAttributes(
674                str(operation['printer-uri']), operation['printer-uri'])
675
676        # optional attributes
677        if 'requesting-user-name' in operation:
678            user_name = verify_attribute(
679                operation['requesting-user-name'], ipp.RequestingUserName)[0]
680           
681        if 'requested-attributes' in operation:
682            requested_attributes = verify_attribute(
683                operation['requested-attributes'], ipp.RequestedAttributes, length=None)
684
685        if 'document-format' in operation:
686            pass # XXX: todo
687
688        # get attributes from the printer and add to response
689        response.attribute_groups.append(ipp.AttributeGroup(
690            ipp.AttributeTags.PRINTER,
691            self.printer.get_printer_attributes(
692                requested_attributes=requested_attributes)))
693
694    @handler_for(ipp.OperationCodes.SET_PRINTER_ATTRIBUTES)
695    def set_printer_attributes(self, request, response):
696
697        raise ipp.errors.ServerErrorOperationNotSupported
698
699    ##### Job Commands
700
701    @handler_for(ipp.OperationCodes.CANCEL_JOB)
702    def cancel_job(self, request, response):
703        """3.3.3 Cancel-Job Operation
704
705        This REQUIRED operation allows a client to cancel a Print Job from
706        the time the job is created up to the time it is completed, canceled,
707        or aborted. Since a Job might already be printing by the time a
708        Cancel-Job is received, some media sheet pages might be printed
709        before the job is actually terminated.
710
711        The IPP object MUST accept or reject the request based on the job's
712        current state and transition the job to the indicated new state as
713        follows:
714
715        Current State       New State           Response
716        -----------------------------------------------------------------
717        pending             canceled            successful-ok
718        pending-held        canceled            successful-ok
719        processing          canceled            successful-ok
720        processing          processing          successful-ok               See Rule 1
721        processing          processing          client-error-not-possible   See Rule 2
722        processing-stopped  canceled            successful-ok
723        processing-stopped  processing-stopped  successful-ok               See Rule 1
724        processing-stopped  processing-stopped  client-error-not-possible   See Rule 2
725        completed           completed           client-error-not-possible
726        canceled            canceled            client-error-not-possible
727        aborted             aborted             client-error-not-possible
728
729        Rule 1: If the implementation requires some measurable time to
730        cancel the job in the 'processing' or 'processing-stopped' job
731        states, the IPP object MUST add the 'processing-to-stop-point'
732        value to the job's 'job-state-reasons' attribute and then
733        transition the job to the 'canceled' state when the processing
734        ceases (see section 4.3.8).
735
736        Rule 2: If the Job object already has the
737        'processing-to-stop-point' value in its 'job-state-reasons'
738        attribute, then the Printer object MUST reject a Cancel-Job
739        operation.
740
741        Access Rights: The authenticated user (see section 8.3)
742        performing this operation must either be the job owner or an
743        operator or administrator of the Printer object (see Sections
744        1 and 8.5).  Otherwise, the IPP object MUST reject the
745        operation and return: 'client-error-forbidden',
746        'client-error-not-authenticated', or
747        'client-error-not-authorized' as appropriate.
748
749        Request
750        -------
751
752        Group 1: Operation Attributes
753            REQUIRED 'attributes-charset'
754            REQUIRED 'attributes-natural-language'
755            REQUIRED 'job-id' (integer(1:MAX)) and 'printer-uri' (uri)
756              -or-   'job-uri' (uri)
757            OPTIONAL 'requesting-user-name' (name(MAX))
758            OPTIONAL 'message' (text(127))
759           
760        Response
761        --------
762
763        Group 1: Operation Attributes
764            OPTIONAL 'status-message' (text(255))
765            OPTIONAL 'detailed-status-message' (text(MAX))
766            REQUIRED 'attributes-charset'
767            REQUIRED 'attributes-natural-language'
768        Group 2: Unsupported Attributes
769
770        """
771
772        operation = request.attribute_groups[0]
773
774        job_id = None
775        printer_uri = None
776        requesting_user_name = None
777        message = None
778
779        # required attributes
780        if 'job-id' in operation and 'printer-uri' in operation:
781            job_id = verify_attribute(operation['job-id'], ipp.JobId)[0]
782            printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
783            if printer_uri not in self.printer.uris:
784                raise ipp.errors.ClientErrorAttributes(
785                    str(operation['printer-uri']), operation['printer-uri'])
786
787        elif 'job-uri' in operation:
788            job_uri = verify_attribute(operation['job-uri'], ipp.JobUri)[0]
789            job_id = int(job_uri.split("/")[-1])
790
791        if 'requesting-user-name' in operation:
792            requesting_user_name = verify_attribute(
793                operation['requesting-user-name'], ipp.RequestingUserName)[0]
794
795        try:
796            self.printer.cancel_job(job_id, requesting_user_name=requesting_user_name)
797        except InvalidJobException:
798            raise ipp.errors.ClientErrorNotFound("bad job: %d" % job_id)
799
800    @handler_for(ipp.OperationCodes.SEND_DOCUMENT)
801    def send_document(self, request, response):
802        """3.3.1 Send-Document Operation
803       
804        This OPTIONAL operation allows a client to create a
805        multi-document Job object that is initially 'empty' (contains
806        no documents). In the Create-Job response, the Printer object
807        returns the Job object's URI (the 'job-uri' attribute) and the
808        Job object's 32-bit identifier (the 'job-id' attribute). For
809        each new document that the client desires to add, the client
810        uses a Send-Document operation. Each Send- Document Request
811        contains the entire stream of document data for one document.
812
813        If the Printer supports this operation but does not support
814        multiple documents per job, the Printer MUST reject subsequent
815        Send-Document operations supplied with data and return the
816        'server-error-multiple- document-jobs-not-supported'. However,
817        the Printer MUST accept the first document with a 'true' or
818        'false' value for the 'last-document' operation attribute (see
819        below), so that clients MAY always submit one document jobs
820        with a 'false' value for 'last-document' in the first
821        Send-Document and a 'true' for 'last-document' in the second
822        Send-Document (with no data).
823       
824        Since the Create-Job and the send operations (Send-Document or
825        Send- URI operations) that follow could occur over an
826        arbitrarily long period of time for a particular job, a client
827        MUST send another send operation within an IPP Printer defined
828        minimum time interval after the receipt of the previous
829        request for the job. If a Printer object supports the
830        Create-Job and Send-Document operations, the Printer object
831        MUST support the 'multiple-operation-time-out' attribute (see
832        section 4.4.31). This attribute indicates the minimum number
833        of seconds the Printer object will wait for the next send
834        operation before taking some recovery action.
835
836        An IPP object MUST recover from an errant client that does not
837        supply a send operation, sometime after the minimum time
838        interval specified by the Printer object's
839        'multiple-operation-time-out' attribute.
840
841        Access Rights: The authenticated user (see section 8.3)
842        performing this operation must either be the job owner (as
843        determined in the Create-Job operation) or an operator or
844        administrator of the Printer object (see Sections 1 and
845        8.5). Otherwise, the IPP object MUST reject the operation and
846        return: 'client-error-forbidden', 'client-
847        error-not-authenticated', or 'client-error-not-authorized' as
848        appropriate.
849
850        Request
851        -------
852
853        Group 1: Operation Attributes
854            REQUIRED 'attributes-charset'
855            REQUIRED 'attributes-natural-language'
856            REQUIRED 'job-id' (integer(1:MAX)) and 'printer-uri' (uri)
857              -or-   'job-uri' (uri)
858            OPTIONAL 'requesting-user-name' (name(MAX))
859            OPTIONAL 'document-name' (name(MAX))
860            OPTIONAL 'compression' (type3 keyword)
861            OPTIONAL 'document-format' (mimeMediaType)
862            OPTIONAL 'document-natural-language' (naturalLanguage)
863            OPTIONAL 'last-document' (boolean)
864        Group 2: Document Content
865           
866        Response
867        --------
868
869        Group 1: Operation Attributes
870            OPTIONAL 'status-message' (text(255))
871            OPTIONAL 'detailed-status-message' (text(MAX))
872            REQUIRED 'attributes-charset'
873            REQUIRED 'attributes-natural-language'
874        Group 2: Unsupported Attributes
875        Group 3: Job Object Attributes
876            REQUIRED 'job-uri' (uri)
877            REQUIRED 'job-id' (integer(1:MAX))
878            REQUIRED 'job-state' (type1 enum)
879            REQUIRED 'job-state-reasons' (1setOf type2 keyword)
880            OPTIONAL 'job-state-message' (text(MAX))
881            OPTIONAL 'number-of-intervening-jobs' (integer(0:MAX))
882
883        """
884       
885        operation = request.attribute_groups[0]
886
887        job_id = None
888        printer_uri = None
889        requesting_user_name = None
890        document_name = None
891        compression = None
892        document_format = None
893        document_natural_language = None
894        last_document = None
895
896        # required attributes
897        if 'job-id' not in operation:
898            raise ipp.errors.ClientErrorBadRequest("Missing 'job-id' attribute")
899        job_id = verify_attribute(operation['job-id'], ipp.JobId)[0]
900
901        if 'last-document' not in operation:
902            raise ipp.errors.ClientErrorBadRequest("Missing 'last-document' attribute")
903        last_document = verify_attribute(operation['last-document'], ipp.LastDocument)[0]
904        if not last_document:
905            raise ipp.errors.ServerErrorMultipleJobsNotSupported
906
907        # optional attributes
908        if 'printer-uri' in operation:
909            printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
910            if printer_uri not in self.printer.uris:
911                raise ipp.errors.ClientErrorAttributes(
912                    str(operation['printer-uri']), operation['printer-uri'])
913
914        if 'requesting-user-name' in operation:
915            user_name = verify_attribute(
916                operation['requesting-user-name'], ipp.RequestingUserName)[0]
917
918        if 'document-name' in operation:
919            document_name = verify_attribute(
920                operation['document-name'], ipp.DocumentName)[0]
921
922        if 'compression' in operation:
923            compression = verify_attribute(
924                operation['compression'], ipp.Compression)[0]
925
926        if 'document-format' in operation:
927            document_format = verify_attribute(
928                operation['document-format'], ipp.DocumentFormat)[0]
929
930        if 'document-natural-language' in operation:
931            document_natural_language = verify_attribute(
932                operation['document_natural_language'],
933                ipp.DocumentNaturalLanguage)[0]
934
935        try:
936            self.printer.send_document(
937                job_id,
938                request.data,
939                document_name=document_name,
940                document_format=document_format,
941                document_natural_language=document_natural_language,
942                requesting_user_name=user_name,
943                compression=compression,
944                last_document=last_document)
945            attrs = self.printer.get_job_attributes(job_id)
946        except InvalidJobException:
947            raise ipp.errors.ClientErrorNotFound("bad job: %d" % job_id)
948
949        response.attribute_groups.append(ipp.AttributeGroup(
950            ipp.AttributeTags.JOB, attrs))
951
952    @handler_for(ipp.OperationCodes.SEND_URI)
953    def send_uri(self, request, response):
954
955        """3.2.2 Send URI
956
957        This OPTIONAL operation is identical to the Send-Document
958        operation (see section 3.3.1) except that a client MUST supply
959        a URI reference ('document-uri' operation attribute) rather
960        than the document data itself.  If a Printer object supports
961        this operation, clients can use both Send-URI or Send-Document
962        operations to add new documents to an existing multi-document
963        Job object.  However, if a client needs to indicate that the
964        previous Send-URI or Send-Document was the last document, the
965        client MUST use the Send-Document operation with no document
966        data and the 'last-document' flag set to 'true' (rather than
967        using a Send-URI operation with no 'document-uri' operation
968        attribute).
969
970        If a Printer object supports this operation, it MUST also
971        support the Print-URI operation (see section 3.2.2).
972
973        The Printer object MUST validate the syntax and URI scheme of
974        the supplied URI before returning a response, just as in the
975        Print-URI operation.  The IPP Printer MAY validate the
976        accessibility of the document as part of the operation or
977        subsequently (see section 3.2.2).
978
979        Request
980        -------
981
982        Group 1: Operation Attributes
983            REQUIRED 'attributes-charset'
984            REQUIRED 'attributes-natural-language'
985            REQUIRED 'job-id' (integer(1:MAX)) and 'printer-uri' (uri)
986            REQUIRED 'document-uri' (uri)
987              -or-   'job-uri' (uri)
988            OPTIONAL 'requesting-user-name' (name(MAX))
989            OPTIONAL 'document-name' (name(MAX))
990            OPTIONAL 'compression' (type3 keyword)
991            OPTIONAL 'document-format' (mimeMediaType)
992            OPTIONAL 'document-natural-language' (naturalLanguage)
993        Group 2: Document Content
994           
995        Response
996        --------
997
998        Group 1: Operation Attributes
999            OPTIONAL 'status-message' (text(255))
1000            OPTIONAL 'detailed-status-message' (text(MAX))
1001            REQUIRED 'attributes-charset'
1002            REQUIRED 'attributes-natural-language'
1003        Group 2: Unsupported Attributes
1004        Group 3: Job Object Attributes
1005            REQUIRED 'job-uri' (uri)
1006            REQUIRED 'job-id' (integer(1:MAX))
1007            REQUIRED 'job-state' (type1 enum)
1008            REQUIRED 'job-state-reasons' (1setOf type2 keyword)
1009            OPTIONAL 'job-state-message' (text(MAX))
1010            OPTIONAL 'number-of-intervening-jobs' (integer(0:MAX))
1011
1012        """
1013       
1014        operation = request.attribute_groups[0]
1015
1016        job_id = None
1017        printer_uri = None
1018        requesting_user_name = None
1019        document_name = None
1020        compression = None
1021        document_format = None
1022        document_natural_language = None
1023        last_document = None
1024
1025        # required attributes
1026        if 'job-id' not in operation:
1027            raise ipp.errors.ClientErrorBadRequest("Missing 'job-id' attribute")
1028        job_id = verify_attribute(operation['job-id'], ipp.JobId)[0]
1029
1030        if 'last-document' not in operation:
1031            raise ipp.errors.ClientErrorBadRequest("Missing 'last-document' attribute")
1032        last_document = verify_attribute(operation['last-document'], ipp.LastDocument)[0]
1033
1034        if 'document-uri' not in operation:
1035            raise ipp.errors.ClientErrorBadRequest("Missing 'document-uri' attribute")
1036        document_uri = verify_attribute(operation['document-uri'], ipp.DocumentUri)[0]
1037        if not last_document:
1038            raise ipp.errors.ServerErrorMultipleJobsNotSupported
1039
1040        # optional attributes
1041        if 'printer-uri' in operation:
1042            printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
1043            if printer_uri not in self.printer.uris:
1044                raise ipp.errors.ClientErrorAttributes(
1045                    str(operation['printer-uri']), operation['printer-uri'])
1046
1047        if 'requesting-user-name' in operation:
1048            user_name = verify_attribute(
1049                operation['requesting-user-name'], ipp.RequestingUserName)[0]
1050
1051        if 'document-name' in operation:
1052            document_name = verify_attribute(
1053                operation['document-name'], ipp.DocumentName)[0]
1054
1055        if 'compression' in operation:
1056            compression = verify_attribute(
1057                operation['compression'], ipp.Compression)[0]
1058
1059        if 'document-format' in operation:
1060            document_format = verify_attribute(
1061                operation['document-format'], ipp.DocumentFormat)[0]
1062
1063        if 'document-natural-language' in operation:
1064            document_natural_language = verify_attribute(
1065                operation['document_natural_language'],
1066                ipp.DocumentNaturalLanguage)[0]
1067
1068        try:
1069            self.printer.send_uri(
1070                job_id,
1071                document_uri=document_uri,
1072                document_name=document_name,
1073                document_format=document_format,
1074                document_natural_language=document_natural_language,
1075                requesting_user_name=user_name,
1076                compression=compression,
1077                last_document=last_document)
1078            attrs = self.printer.get_job_attributes(job_id)
1079        except InvalidJobException:
1080            raise ipp.errors.ClientErrorNotFound("bad job: %d" % job_id)
1081
1082        response.attribute_groups.append(ipp.AttributeGroup(
1083            ipp.AttributeTags.JOB, attrs))
1084
1085    @handler_for(ipp.OperationCodes.GET_JOB_ATTRIBUTES)
1086    def get_job_attributes(self, request, response):
1087        """3.3.4 Get-Job-Attributes Operation
1088
1089        This REQUIRED operation allows a client to request the values
1090        of attributes of a Job object and it is almost identical to
1091        the Get- Printer-Attributes operation (see section 3.2.5). The
1092        only differences are that the operation is directed at a Job
1093        object rather than a Printer object, there is no
1094        'document-format' operation attribute used when querying a Job
1095        object, and the returned attribute group is a set of Job
1096        object attributes rather than a set of Printer object
1097        attributes.
1098
1099        For Jobs, the possible names of attribute groups are:
1100          - 'job-template': the subset of the Job Template attributes
1101            that apply to a Job object (the first column of the table
1102            in Section 4.2) that the implementation supports for Job
1103            objects.
1104          - 'job-description': the subset of the Job Description
1105            attributes specified in Section 4.3 that the
1106            implementation supports for Job objects.
1107          - 'all': the special group 'all' that includes all
1108            attributes that the implementation supports for Job
1109            objects.
1110
1111        Since a client MAY request specific attributes or named
1112        groups, there is a potential that there is some overlap. For
1113        example, if a client requests, 'job-name' and
1114        'job-description', the client is actually requesting the
1115        'job-name' attribute once by naming it explicitly, and once by
1116        inclusion in the 'job-description' group. In such cases, the
1117        Printer object NEED NOT return the attribute only once in the
1118        response even if it is requested multiple times. The client
1119        SHOULD NOT request the same attribute in multiple ways.
1120
1121        It is NOT REQUIRED that a Job object support all attributes
1122        belonging to a group (since some attributes are
1123        OPTIONAL). However it is REQUIRED that each Job object support
1124        all these group names.
1125
1126        Request
1127        -------
1128
1129        Group 1: Operation Attributes
1130            REQUIRED 'attributes-charset'
1131            REQUIRED 'attributes-natural-language'
1132            REQUIRED 'job-id' (integer(1:MAX)) and 'printer-uri' (uri)
1133              -or-   'job-uri' (uri)
1134            OPTIONAL 'requesting-user-name' (name(MAX))
1135            OPTIONAL 'requested-attributes' (1setOf keyword)
1136           
1137        Response
1138        --------
1139
1140        Group 1: Operation Attributes
1141            OPTIONAL 'status-message' (text(255))
1142            OPTIONAL 'detailed-status-message' (text(MAX))
1143            REQUIRED 'attributes-charset'
1144            REQUIRED 'attributes-natural-language'
1145        Group 2: Unsupported Attributes
1146        Group 3: Job Object Attributes
1147
1148        """
1149       
1150        operation = request.attribute_groups[0]
1151
1152        job_id = None
1153        printer_uri = None
1154        requesting_user_name = None
1155        requested_attributes = None
1156
1157        # required attributes
1158        if 'job-id' not in operation:
1159            raise ipp.errors.ClientErrorBadRequest("Missing 'job-id' attribute")
1160        job_id = verify_attribute(operation['job-id'], ipp.JobId)[0]
1161
1162        # optional attributes
1163        if 'printer-uri' in operation:
1164            printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
1165            if printer_uri not in self.printer.uris:
1166                raise ipp.errors.ClientErrorAttributes(
1167                    str(operation['printer-uri']), operation['printer-uri'])
1168
1169        # optional attributes
1170        if 'requesting-user-name' in operation:
1171            user_name = verify_attribute(
1172                operation['requesting-user-name'], ipp.RequestingUserName)[0]
1173           
1174        if 'requested-attributes' in operation:
1175            requested_attributes = verify_attribute(
1176                operation['requested-attributes'], ipp.RequestedAttributes, length=None)
1177
1178        # get the job attributes and add them to the response
1179        try:
1180            attrs = self.printer.get_job_attributes(
1181                job_id,
1182                requested_attributes=requested_attributes)
1183        except InvalidJobException:
1184            raise ipp.errors.ClientErrorNotFound("bad job: %d" % job_id)
1185
1186        response.attribute_groups.append(ipp.AttributeGroup(
1187            ipp.AttributeTags.JOB, attrs))
1188
1189    @handler_for(ipp.OperationCodes.SET_JOB_ATTRIBUTES)
1190    def set_job_attributes(self, request, response):
1191       
1192        raise ipp.errors.ServerErrorOperationNotSupported
1193
1194    @handler_for(ipp.OperationCodes.RESTART_JOB)
1195    def restart_job(self, request, response):
1196        raise ipp.errors.ServerErrorOperationNotSupported
1197
1198    @handler_for(ipp.OperationCodes.PROMOTE_JOB)
1199    def promote_job(self, request, response):
1200        raise ipp.errors.ServerErrorOperationNotSupported
1201
1202    ##### CUPS Specific Commands
1203
1204    @handler_for(ipp.OperationCodes.CUPS_GET_DOCUMENT)
1205    def cups_get_document(self, request, response):
1206        raise ipp.errors.ServerErrorOperationNotSupported
1207
1208    @handler_for(ipp.OperationCodes.CUPS_GET_DEFAULT)
1209    def cups_get_default(self, request, response):
1210        """The CUPS-Get-Default operation (0x4001) returns the default
1211        printer URI and attributes.
1212
1213        Request
1214        -------
1215
1216        Group 1: Operation Attributes
1217            REQUIRED 'attributes-charset'
1218            REQUIRED 'attributes-natural-language'
1219            OPTIONAL 'requested-attributes' (1setOf type2 keyword)
1220
1221        Response
1222        --------
1223
1224        Group 1: Operation Attributes
1225            OPTIONAL 'status-message' (text(255))
1226            REQUIRED 'attributes-charset'
1227            REQUIRED 'attributes-natural-language'
1228        Group 2: Printer Object Attributes
1229
1230        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_DEFAULT )
1231
1232        """
1233
1234        operation = request.attribute_groups[0]
1235        requested_attributes = None
1236       
1237        if 'requested-attributes' in operation:
1238            requested_attributes = verify_attribute(
1239                operation['requested-attributes'], ipp.RequestedAttributes, length=None)
1240
1241        # get attributes from the printer and add to response
1242        attrs = self.printer.get_printer_attributes(
1243            requested_attributes=requested_attributes)
1244        response.attribute_groups.append(ipp.AttributeGroup(
1245            ipp.AttributeTags.PRINTER, attrs))
1246
1247    @handler_for(ipp.OperationCodes.CUPS_GET_PRINTERS)
1248    def cups_get_printers(self, request, response):
1249        """The CUPS-Get-Printers operation (0x4002) returns the
1250        printer attributes for every printer known to the system. This
1251        may include printers that are not served directly by the
1252        server.
1253
1254        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_PRINTERS )
1255           
1256        """
1257
1258        # get attributes from the printer and add to response
1259        response.attribute_groups.append(ipp.AttributeGroup(
1260            ipp.AttributeTags.PRINTER, self.printer.get_printer_attributes()))
1261
1262    @handler_for(ipp.OperationCodes.CUPS_GET_CLASSES)
1263    def cups_get_classes(self, request, response):
1264        """The CUPS-Get-Classes operation (0x4005) returns the printer
1265        attributes for every printer class known to the system. This
1266        may include printer classes that are not served directly by
1267        the server.
1268
1269        Request
1270        -------
1271
1272        Group 1: Operation Attributes
1273            REQUIRED 'attributes-charset'
1274            REQUIRED 'attributes-natural-language'
1275            OPTIONAL 'first-printer-name' (name(127)) CUPS 1.2/Mac OS X 10.5
1276            OPTIONAL 'limit' (integer (1:MAX))
1277            OPTIONAL 'printer-location' (text(127)) CUPS 1.1.7
1278            OPTIONAL 'printer-type' (type2 enum) CUPS 1.1.7
1279            OPTIONAL 'printer-type-mask' (type2 enum) CUPS 1.1.7
1280            OPTIONAL 'requested-attributes' (1setOf keyword)
1281            OPTOINAL 'requested-user-name' (name(127)) CUPS 1.2/Mac OS X 10.5
1282            OPTIONAL 'requested-attributes' (1setOf type2 keyword)
1283
1284        Response
1285        --------
1286
1287        Group 1: Operation Attributes
1288            OPTIONAL 'status-message' (text(255))
1289            REQUIRED 'attributes-charset'
1290            REQUIRED 'attributes-natural-language'
1291        Group 2: Printer Class Object Attributes
1292
1293        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_CLASSES )
1294
1295        """
1296
1297        raise ipp.errors.ServerErrorOperationNotSupported
1298
Note: See TracBrowser for help on using the repository browser.