source: server/lib/gutenbach/server/requests.py @ 5e44432

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

Move operations into separate files since the functions are so bulky

  • 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
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        pass
77
78    def validate_job(self, request):
79        pass
80
81    @handler_for(consts.Operations.GET_JOBS)
82    def get_jobs(self, request):
83        """RFC 2911: 3.2.6 Get-Jobs Operation
84       
85        This REQUIRED operation allows a client to retrieve the list
86        of Job objects belonging to the target Printer object. The
87        client may also supply a list of Job attribute names and/or
88        attribute group names. A group of Job object attributes will
89        be returned for each Job object that is returned.
90
91        This operation is similar to the Get-Job-Attributes operation,
92        except that this Get-Jobs operation returns attributes from
93        possibly more than one object.
94
95        """
96
97        # verify the request and get an attribute dictionary
98        req_dict = ipp.ops.verify_get_jobs_request(request)
99
100        # lookup printer name
101        printer_name = req_dict['printer-uri']
102        if printer_name not in self.printers:
103            raise ipp.errors.Attributes(
104                "Invalid printer uri: %s" % printer_name,
105                [request.attribute_groups[0].attributes[2]])
106
107        # get the job attributes
108        jobs = [job.get_job_attributes(request) for job in \
109                self.printers[printer_name].get_jobs()]
110
111        # build the response
112        response = ipp.ops.make_get_jobs_response(jobs, request)
113        return response
114
115    def print_uri(self, request):
116        pass
117
118    def create_job(self, request):
119        pass
120
121    def pause_printer(self, request):
122        pass
123
124    def resume_printer(self, request):
125        pass
126
127    @handler_for(consts.Operations.GET_PRINTER_ATTRIBUTES)
128    def get_printer_attributes(self, request):
129        """RFC 2911: 3.2.5 Get-Printer-Attributes Operation
130
131        This REQUIRED operation allows a client to request the values
132        of the attributes of a Printer object.
133       
134        In the request, the client supplies the set of Printer
135        attribute names and/or attribute group names in which the
136        requester is interested. In the response, the Printer object
137        returns a corresponding attribute set with the appropriate
138        attribute values filled in.
139
140        For Printer objects, the possible names of attribute groups are:
141       
142        - 'job-template': the subset of the Job Template attributes
143          that apply to a Printer object (the last two columns of the
144          table in Section 4.2) that the implementation supports for
145          Printer objects.
146
147        - 'printer-description': the subset of the attributes
148          specified in Section 4.4 that the implementation supports
149          for Printer objects.
150
151        - 'all': the special group 'all' that includes all attributes
152          that the implementation supports for Printer objects.
153       
154        Since a client MAY request specific attributes or named
155        groups, there is a potential that there is some overlap. For
156        example, if a client requests, 'printer-name' and 'all', the
157        client is actually requesting the 'printer-name' attribute
158        twice: once by naming it explicitly, and once by inclusion in
159        the 'all' group. In such cases, the Printer object NEED NOT
160        return each attribute only once in the response even if it is
161        requested multiple times. The client SHOULD NOT request the
162        same attribute in multiple ways.
163
164        It is NOT REQUIRED that a Printer object support all
165        attributes belonging to a group (since some attributes are
166        OPTIONAL). However, it is REQUIRED that each Printer object
167        support all group names.
168
169        """
170
171        # verify the request and get the attributes dictionary
172        req_dict = ipp.ops.verify_get_printer_attributes_request(request)
173
174        # lookup the printer name
175        printer_name = req_dict['printer-uri']
176        if printer_name not in self.printers:
177            raise ipp.errors.Attributes(
178                "Invalid printer uri: %s" % printer_name,
179                [request.attribute_groups[0].attributes[2]])
180
181        # bulid response
182        response = ipp.ops.make_get_printer_attributes_response(
183            self.printers[printer_name].get_printer_attributes(request), request)
184        return response
185
186    def set_printer_attributes(self, request):
187        pass
188
189    ##### Job Commands
190
191    def cancel_job(self, request):
192        pass
193
194    def send_document(self, request):
195        pass
196
197    def send_uri(self, request):
198        pass
199
200    def get_job_attributes(self, request):
201       
202        # verify the request and get the attributes dictionary
203        req_dict = ipp.ops.verify_get_jobs_request(request)
204       
205        # lookup the printer name
206        printer_name = req_dict['printer-uri']
207        if printer_name not in self.printers:
208            raise ipp.errors.Attributes(
209                "Invalid printer uri: %s" % printer_name,
210                [request.attribute_groups[0].attributes[2]])
211
212        # lookup the job id
213        job_id = req_dict['job-id']
214        try: job = self.printers[printer_name].get_job(job_id)
215        except InvalidJobException:
216            raise ipp.errors.Attributes(
217                "Invalid job id: %d" % job_id,
218                [request.attribute_groups[0].attributes[2]]) # XXX: this is wrong
219
220        # XXX: we need to honor the things that the request actually asks for
221        # build the response
222        response = ipp.ops.make_get_job_attributes_response(
223            job.get_job_attributes(request), request)
224        return response
225
226    def set_job_attributes(self, request):
227        pass
228
229    def cups_get_document(self, request):
230        pass
231
232    def restart_job(self, request):
233        pass
234
235    def promote_job(self, request):
236        pass
237
238    ##### CUPS Specific Commands
239
240    @handler_for(consts.Operations.CUPS_GET_DEFAULT)
241    def cups_get_default(self, request):
242        """The CUPS-Get-Default operation (0x4001) returns the default
243        printer URI and attributes.
244
245        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_DEFAULT )
246
247        """
248
249        # verify the request and get the attributes dictionary
250        req_dict = ipp.ops.verify_cups_get_default_request(request)
251        # build the response
252        response = ipp.ops.make_get_printer_attributes_response(
253            self.printers[self.default].get_printer_attributes(request), request)
254        return response
255
256    @handler_for(consts.Operations.CUPS_GET_PRINTERS)
257    def cups_get_printers(self, request):
258        """The CUPS-Get-Printers operation (0x4002) returns the
259        printer attributes for every printer known to the system. This
260        may include printers that are not served directly by the
261        server.
262
263        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_PRINTERS )
264           
265        """
266
267        # verify the request and get the attributes dictionary
268        req_dict = ipp.ops.verify_cups_get_printers_request(request)
269        # get the printer attributes
270        attrs = [self.printers[printer].get_printer_attributes(request) \
271                 for printer in self.printers]
272        # build the response
273        response = ipp.ops.make_cups_get_printers_response(attrs, request)
274        return response
275
276    @handler_for(consts.Operations.CUPS_GET_CLASSES)
277    def cups_get_classes(self, request):
278        """The CUPS-Get-Classes operation (0x4005) returns the printer
279        attributes for every printer class known to the system. This
280        may include printer classes that are not served directly by
281        the server.
282       
283        (Source: http://www.cups.org/documentation.php/spec-ipp.html#CUPS_GET_CLASSES )
284
285        """
286
287        # verify the request and get the attributes dictionaryu
288        req_dict = ipp.ops.verify_cups_get_classes_request(request)
289        # build the response
290        response = ipp.ops.make_cups_get_classes_response(request)
291        return response
Note: See TracBrowser for help on using the repository browser.