source: server/lib/gutenbach/server/requests.py @ 287d6ec

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

Move request-related code into new requests.py; increase readability; some documentation

  • Property mode set to 100644
File size: 10.0 KB
Line 
1import gutenbach.ipp
2import gutenbach.ipp.constants as const
3import logging
4import time
5
6logging.basicConfig(level=logging.DEBUG)
7
8def handler_for(operation):
9    """A decorator method to mark a function with the operation id
10    that it handles.  This value will be stored in
11    'func.ipp_operation'.
12
13    """
14   
15    def f(func):
16        func.ipp_operation = operation
17        return func
18    return f
19
20class IPPRequestHandler(object):
21    """A generic base class for IPP requests.  Provides a dispatch
22    function to conver request operation ids to handler functions.
23
24    """
25   
26    def _ipp_dispatch(self, request):
27        for d in dir(self):
28            if getattr(getattr(self, d), "ipp_operation", None) == request.operation_id:
29                return getattr(self, d)
30        return self.unknown_operation
31
32    def unknown_operation(self, request, response):
33        print "Received UNKNOWN OPERATION %x" % request.operation_id
34        response.operation_id = const.StatusCodes.OPERATION_NOT_SUPPORTED
35
36class PrinterRequestHandler(IPPRequestHandler):
37    """This handles requests that are printer-specific: for example,
38    the printer's name or state.
39
40    """
41   
42    def __init__(self, name):
43        self.name = name
44
45    @handler_for(const.Operations.GET_PRINTER_ATTRIBUTES)
46    def get_printer_attributes(self, request, response):
47        printer_attributes = ipp.AttributeGroup(const.AttributeTags.PRINTER)
48        printer_attributes.append(ipp.Attribute(
49            "printer-uri-supported",
50            [ipp.Value(ipp.Tags.URI, "ipp://localhost:8000/printers/" + self.name)]))
51
52        printer_attributes.append(ipp.Attribute(
53            "uri-authentication-supported",
54            [ipp.Value(ipp.Tags.KEYWORD, "none")]))
55
56        printer_attributes.append(ipp.Attribute(
57            "uri-security-supported",
58            [ipp.Value(ipp.Tags.KEYWORD, "none")]))
59
60        printer_attributes.append(ipp.Attribute(
61            "printer-name",
62            [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, self.name)]))
63
64        printer_attributes.append(ipp.Attribute(
65            "printer-state",
66            [ipp.Value(ipp.Tags.ENUM, const.PrinterStates.IDLE)]))
67
68        printer_attributes.append(ipp.Attribute(
69            "printer-state-reasons",
70            [ipp.Value(ipp.Tags.KEYWORD, "none")]))
71
72        printer_attributes.append(ipp.Attribute(
73            "ipp-versions-supported",
74            [ipp.Value(ipp.Tags.KEYWORD, "1.0"),
75             ipp.Value(ipp.Tags.KEYWORD, "1.1")]))
76
77        # XXX: We should query ourself for the supported operations
78        printer_attributes.append(ipp.Attribute(
79            "operations-supported",
80            [ipp.Value(ipp.Tags.ENUM, const.Operations.GET_JOBS)]))
81
82        printer_attributes.append(ipp.Attribute(
83            "charset-configured",
84            [ipp.Value(ipp.Tags.CHARSET, "utf-8")]))
85
86        printer_attributes.append(ipp.Attribute(
87            "charset-supported",
88            [ipp.Value(ipp.Tags.CHARSET, "utf-8")]))
89
90        printer_attributes.append(ipp.Attribute(
91            "natural-language-configured",
92            [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, "en-us")]))
93
94        printer_attributes.append(ipp.Attribute(
95            "generated-natural-language-supported",
96            [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, "en-us")]))
97
98        printer_attributes.append(ipp.Attribute(
99            "document-format-default",
100            [ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "application/octet-stream")]))
101
102        printer_attributes.append(ipp.Attribute(
103            "document-format-supported",
104            [ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "application/octet-stream"),
105             ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "audio/mp3")]))
106
107        printer_attributes.append(ipp.Attribute(
108            "printer-is-accepting-jobs",
109            [ipp.Value(ipp.Tags.BOOLEAN, True)]))
110
111        printer_attributes.append(ipp.Attribute(
112            "queued-job-count",
113            [ipp.Value(ipp.Tags.INTEGER, 1)]))
114
115        printer_attributes.append(ipp.Attribute(
116            "pdl-override-supported",
117            [ipp.Value(ipp.Tags.KEYWORD, "not-attempted")]))
118
119        printer_attributes.append(ipp.Attribute(
120            "printer-up-time",
121            [ipp.Value(ipp.Tags.INTEGER, int(time.time()))]))
122
123        printer_attributes.append(ipp.Attribute(
124            "compression-supported",
125            [ipp.Value(ipp.Tags.KEYWORD, "none")]))
126
127        response.attribute_groups.append(printer_attributes)
128        response.operation_id = const.StatusCodes.OK
129        print "get_printer_attributes called"
130
131class RootRequestHandler(IPPRequestHandler):
132    printers = [PrinterRequestHandler(name="sipbmp3")]
133
134    @handler_for(const.Operations.CUPS_GET_DEFAULT)
135    def cups_get_default(self, request, response):
136        print "get_default called"
137        return self.printers[0].get_printer_attributes(request, response)
138
139    @handler_for(const.Operations.CUPS_GET_PRINTERS)
140    def cups_get_printers(self, request, response):
141        print "get_printers called"
142        response.operation_id = const.StatusCodes.OK
143        # Each printer will append a new printer attribute group.
144        for p in self.printers:
145            p.get_printer_attributes(request, response)
146
147    @handler_for(const.Operations.CUPS_GET_CLASSES)
148    def cups_get_classes(self, request, response):
149        print "get_classes called"
150        response.operation_id = const.StatusCodes.OK
151        # We have no printer classes, so nothing to return.
152
153class GutenbachIPPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
154    def setup(self):
155        self.root = RootRequestHandler()
156        BaseHTTPServer.BaseHTTPRequestHandler.setup(self)
157
158    def handle_one_request(self):
159        self.raw_requestline = self.rfile.readline()
160        if not self.raw_requestline:
161            self.close_connection = 1
162            return
163        if not self.parse_request(): # An error code has been sent, just exit
164            return
165        self.handle_ipp()
166
167    def handle_ipp(self):
168        # Receive a request
169        length = int(self.headers.getheader('content-length', 0))
170        request = ipp.Request(request=self.rfile, length=length)
171        print "Received request:", repr(request)
172
173        # Attributes
174        attributes = [
175            ipp.Attribute(
176                'attributes-charset',
177                [ipp.Value(ipp.Tags.CHARSET, 'utf-8')]),
178            ipp.Attribute(
179                'attributes-natural-language',
180                [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, 'en-us')])
181            ]
182        # Attribute group
183        attribute_group = ipp.AttributeGroup(
184            const.AttributeTags.OPERATION,
185            attributes)
186
187        # Set up the response
188        response_kwargs = {}
189        response_kwargs['version']          = request.version
190        response_kwargs['operation_id']     = const.StatusCodes.INTERNAL_ERROR
191        response_kwargs['request_id']       = request.request_id
192        response_kwargs['attribute_groups'] = [attribute_group]
193        response = ipp.Request(**response_kwargs)
194
195        # Get the handler and pass it the request and response objects
196        handler = self.root._ipp_dispatch(request)
197        handler(request, response)
198        print "Sending response:", repr(response)
199
200        # Send the response across HTTP
201        self.send_response(200, "o hai")
202        self.send_header("Content-Type", "application/ipp")
203        self.send_header("Connection", "close")
204        self.end_headers()
205        self.wfile.write(response.packed_value)
206
207    def get_jobs(self, request, response_kwargs):
208        """get-jobs response"""
209
210        # Job attributes
211        job_attributes = [
212            ipp.Attribute(
213                'job-id',
214                [ipp.Value(ipp.Tags.INTEGER, 12345)]),
215            ipp.Attribute(
216                'job-name',
217                [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, 'foo')]),
218            ipp.Attribute(
219                'job-originating-user-name',
220                [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, 'jhamrick')]),
221            ipp.Attribute(
222                'job-k-octets',
223                [ipp.Value(ipp.Tags.INTEGER, 1)]),
224            ipp.Attribute(
225                'job-state',
226                [ipp.Value(ipp.Tags.ENUM, const.JobStates.HELD)]),
227            ipp.Attribute(
228                'job-printer-uri',
229                [ipp.Value(ipp.Tags.URI, 'ipp://localhost:8000/printers/foo')])
230            ]
231        # Job attribute group
232        job_attribute_group = ipp.AttributeGroup(
233            const.AttributeTags.JOB,
234            job_attributes)
235
236        # Operation attributions
237        op_attributes = [
238            ipp.Attribute(
239                'attributes-charset',
240                [ipp.Value(ipp.Tags.CHARSET, 'utf-8')]),
241            ipp.Attribute(
242                'attributes-natural-language',
243                [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, 'en-us')])
244            ]
245        # Operation attribution group
246        op_attributes_group = ipp.AttributeGroup(
247            const.AttributeTags.OPERATION,
248            op_attributes)
249
250        # Setup the actual response dictionary
251        response_kwargs['attribute_groups'] = [op_attributes_group,job_attribute_group]
252        response_kwargs['operation_id'] = const.StatusCodes.OK
253
254        return response_kwargs
255
256    ##### Printer Commands
257
258    def print_job(self, request):
259        pass
260
261    def validate_job(self, request):
262        pass
263
264    #def get_jobs(self, request):
265    #    pass
266
267    def print_uri(self, request):
268        pass
269
270    def create_job(self, request):
271        pass
272
273    def pause_printer(self, request):
274        pass
275
276    def resume_printer(self, request):
277        pass
278
279    def set_printer_attributes(self, request):
280        pass
281
282    ##### Job Commands
283
284    def cancel_job(self, request):
285        pass
286
287    def get_job_attributes(self, request):
288        pass
289
290    def send_document(self, request):
291        pass
292
293    def send_uri(self, request):
294        pass
295
296    def set_job_attributes(self, request):
297        pass
298
299    def cups_get_document(self, request):
300        pass
301
302    def restart_job(self, request):
303        pass
304
305    def promote_job(self, request):
306        pass
Note: See TracBrowser for help on using the repository browser.