source: server/lib/gutenbach/server/requests.py @ e70c020

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

Add skeleton files for the other operations that need to be implemented

  • Property mode set to 100644
File size: 10.5 KB
Line 
1from gutenbach.server.printer import GutenbachPrinter
2import gutenbach.ipp as ipp
3import gutenbach.ipp.constants as consts
4import logging
5import traceback
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
22class GutenbachRequestHandler(object):
23
24    def __init__(self):
25        self.printers = {
26            "test": GutenbachPrinter(name="test")
27            }
28        self.default = "test"
29   
30    def handle(self, request):
31        # look up the handler
32        handler = None
33        handler_name = None
34        for d in dir(self):
35            if getattr(getattr(self, d), "ipp_operation", None) == request.operation_id:
36                handler_name = d
37                break
38        # we couldn't find a handler, so default to unknown operation
39        if handler_name is None:
40            handler_name = "unknown_operation"
41        # call the handler
42        handler = getattr(self, handler_name)
43        logger.info("Handling request of type '%s'" % handler_name)
44
45        # Try to handle the request
46        try:
47            response = handler(request)
48
49        # Handle any errors that occur.  If an exception occurs that
50        # is an IPP error, then we can get the error code from the
51        # exception itself.
52        except ipp.errors.IPPException:
53            exctype, excval, exctb = sys.exc_info()
54            logger.error(traceback.format_exc())
55            response = ipp.ops.make_empty_response(request)
56            excval.update_response(response)
57
58        # If it wasn't an IPP error, then it's our fault, so mark it
59        # as an internal server error
60        except Exception:
61            logger.error(traceback.format_exc())
62            response = ipp.ops.make_empty_response(request)
63            response.operation_id = ipp.StatusCodes.INTERNAL_ERROR
64
65        return response
66
67    def unknown_operation(self, request):
68        logger.warning("Received unknown operation 0x%x" % request.operation_id)
69        response = ipp.ops.make_empty_response(request)
70        response.operation_id = consts.StatusCodes.OPERATION_NOT_SUPPORTED
71        return response
72       
73    ##### Printer Commands
74
75    def print_job(self, request):
76        """RFC 2911: 3.2.1 Print-Job Operation
77
78        This REQUIRED operation allows a client to submit a print job
79        with only one document and supply the document data (rather
80        than just a reference to the data). See Section 15 for the
81        suggested steps for processing create operations and their
82        Operation and Job Template attributes.
83
84        """
85       
86        pass
87
88    def validate_job(self, request):
89        pass
90
91    @handler_for(consts.Operations.GET_JOBS)
92    def get_jobs(self, request):
93        """RFC 2911: 3.2.6 Get-Jobs Operation
94       
95        This REQUIRED operation allows a client to retrieve the list
96        of Job objects belonging to the target Printer object. The
97        client may also supply a list of Job attribute names and/or
98        attribute group names. A group of Job object attributes will
99        be returned for each Job object that is returned.
100
101        This operation is similar to the Get-Job-Attributes operation,
102        except that this Get-Jobs operation returns attributes from
103        possibly more than one object.
104
105        """
106
107        # verify the request and get an attribute dictionary
108        req_dict = ipp.ops.verify_get_jobs_request(request)
109
110        # lookup printer name
111        printer_name = req_dict['printer-uri']
112        if printer_name not in self.printers:
113            raise ipp.errors.Attributes(
114                "Invalid printer uri: %s" % printer_name,
115                [request.attribute_groups[0].attributes[2]])
116
117        # get the job attributes
118        jobs = [job.get_job_attributes(request) for job in \
119                self.printers[printer_name].get_jobs()]
120
121        # build the response
122        response = ipp.ops.make_get_jobs_response(jobs, request)
123        return response
124
125    def print_uri(self, request):
126        pass
127
128    def create_job(self, request):
129        pass
130
131    def pause_printer(self, request):
132        pass
133
134    def resume_printer(self, request):
135        pass
136
137    @handler_for(consts.Operations.GET_PRINTER_ATTRIBUTES)
138    def get_printer_attributes(self, request):
139        """RFC 2911: 3.2.5 Get-Printer-Attributes Operation
140
141        This REQUIRED operation allows a client to request the values
142        of the attributes of a Printer object.
143       
144        In the request, the client supplies the set of Printer
145        attribute names and/or attribute group names in which the
146        requester is interested. In the response, the Printer object
147        returns a corresponding attribute set with the appropriate
148        attribute values filled in.
149
150        For Printer objects, the possible names of attribute groups are:
151       
152        - 'job-template': the subset of the Job Template attributes
153          that apply to a Printer object (the last two columns of the
154          table in Section 4.2) that the implementation supports for
155          Printer objects.
156
157        - 'printer-description': the subset of the attributes
158          specified in Section 4.4 that the implementation supports
159          for Printer objects.
160
161        - 'all': the special group 'all' that includes all attributes
162          that the implementation supports for Printer objects.
163       
164        Since a client MAY request specific attributes or named
165        groups, there is a potential that there is some overlap. For
166        example, if a client requests, 'printer-name' and 'all', the
167        client is actually requesting the 'printer-name' attribute
168        twice: once by naming it explicitly, and once by inclusion in
169        the 'all' group. In such cases, the Printer object NEED NOT
170        return each attribute only once in the response even if it is
171        requested multiple times. The client SHOULD NOT request the
172        same attribute in multiple ways.
173
174        It is NOT REQUIRED that a Printer object support all
175        attributes belonging to a group (since some attributes are
176        OPTIONAL). However, it is REQUIRED that each Printer object
177        support all group names.
178
179        """
180
181        # verify the request and get the attributes dictionary
182        req_dict = ipp.ops.verify_get_printer_attributes_request(request)
183
184        # lookup the printer name
185        printer_name = req_dict['printer-uri']
186        if printer_name not in self.printers:
187            raise ipp.errors.Attributes(
188                "Invalid printer uri: %s" % printer_name,
189                [request.attribute_groups[0].attributes[2]])
190
191        # bulid response
192        response = ipp.ops.make_get_printer_attributes_response(
193            self.printers[printer_name].get_printer_attributes(request), request)
194        return response
195
196    def set_printer_attributes(self, request):
197        pass
198
199    ##### Job Commands
200
201    def cancel_job(self, request):
202        pass
203
204    def send_document(self, request):
205        pass
206
207    def send_uri(self, request):
208        pass
209
210    def get_job_attributes(self, request):
211       
212        # verify the request and get the attributes dictionary
213        req_dict = ipp.ops.verify_get_jobs_request(request)
214       
215        # lookup the printer name
216        printer_name = req_dict['printer-uri']
217        if printer_name not in self.printers:
218            raise ipp.errors.Attributes(
219                "Invalid printer uri: %s" % printer_name,
220                [request.attribute_groups[0].attributes[2]])
221
222        # lookup the job id
223        job_id = req_dict['job-id']
224        try: job = self.printers[printer_name].get_job(job_id)
225        except InvalidJobException:
226            raise ipp.errors.Attributes(
227                "Invalid job id: %d" % job_id,
228                [request.attribute_groups[0].attributes[2]]) # XXX: this is wrong
229
230        # XXX: we need to honor the things that the request actually asks for
231        # build the response
232        response = ipp.ops.make_get_job_attributes_response(
233            job.get_job_attributes(request), request)
234        return response
235
236    def set_job_attributes(self, request):
237        pass
238
239    def restart_job(self, request):
240        pass
241
242    def promote_job(self, request):
243        pass
244
245    ##### CUPS Specific Commands
246
247    def cups_get_document(self, request):
248        pass
249
250    @handler_for(consts.Operations.CUPS_GET_DEFAULT)
251    def cups_get_default(self, request):
252        """The CUPS-Get-Default operation (0x4001) returns the default
253        printer URI and attributes.
254
255        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_DEFAULT )
256
257        """
258
259        # verify the request and get the attributes dictionary
260        req_dict = ipp.ops.verify_cups_get_default_request(request)
261        # build the response
262        response = ipp.ops.make_get_printer_attributes_response(
263            self.printers[self.default].get_printer_attributes(request), request)
264        return response
265
266    @handler_for(consts.Operations.CUPS_GET_PRINTERS)
267    def cups_get_printers(self, request):
268        """The CUPS-Get-Printers operation (0x4002) returns the
269        printer attributes for every printer known to the system. This
270        may include printers that are not served directly by the
271        server.
272
273        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_PRINTERS )
274           
275        """
276
277        # verify the request and get the attributes dictionary
278        req_dict = ipp.ops.verify_cups_get_printers_request(request)
279        # get the printer attributes
280        attrs = [self.printers[printer].get_printer_attributes(request) \
281                 for printer in self.printers]
282        # build the response
283        response = ipp.ops.make_cups_get_printers_response(attrs, request)
284        return response
285
286    @handler_for(consts.Operations.CUPS_GET_CLASSES)
287    def cups_get_classes(self, request):
288        """The CUPS-Get-Classes operation (0x4005) returns the printer
289        attributes for every printer class known to the system. This
290        may include printer classes that are not served directly by
291        the server.
292       
293        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_CLASSES )
294
295        """
296
297        # verify the request and get the attributes dictionaryu
298        req_dict = ipp.ops.verify_cups_get_classes_request(request)
299        # build the response
300        response = ipp.ops.make_cups_get_classes_response(request)
301        return response
Note: See TracBrowser for help on using the repository browser.