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

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

Move ipp error handling out of the server and into server/requests

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