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

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

Refactor code to handle the operations a little bit more logically

  • Property mode set to 100644
File size: 7.6 KB
Line 
1import BaseHTTPServer
2import gutenbach.ipp as ipp
3import gutenbach.ipp.constants as const
4from gutenbach.server.printer import GutenbachPrinter
5from gutenbach.server.exceptions import MalformedIPPRequestException
6import logging
7
8# initialize logger
9logger = logging.getLogger(__name__)
10
11def handler_for(operation):
12    """A decorator method to mark a function with the operation id
13    that it handles.  This value will be stored in
14    'func.ipp_operation'.
15
16    """
17   
18    def f(func):
19        func.ipp_operation = operation
20        return func
21    return f
22
23class GutenbachRequestHandler(object):
24
25    def __init__(self):
26        self.printers = {
27            "test": GutenbachPrinter(name="test")
28            }
29        self.default = "test"
30   
31    def handle(self, request, response):
32        # look up the handler
33        handler = None
34        for d in dir(self):
35            if getattr(getattr(self, d), "ipp_operation", None) == request.operation_id:
36                handler = getattr(self, d)
37                break
38        # we couldn't find a handler, so default to unknown operation
39        if handler is None:
40            handler = self.unknown_operation
41        # call the handler
42        handler(request, response)
43
44    def unknown_operation(self, request, response):
45        print "Received unknown operation %x" % request.operation_id
46        response.operation_id = const.StatusCodes.OPERATION_NOT_SUPPORTED
47
48    def _get_printer_attributes(self, printer, request, response):
49        response.attribute_groups.append(ipp.AttributeGroup(
50            const.AttributeTags.PRINTER,
51            printer.get_printer_attributes(request)))
52
53    def _get_job_attributes(self, job_id, printer, request, response):
54        response.attribute_groups.append(ipp.AttributeGroup(
55            const.AttributeTags.JOB,
56            job.get_job_attributes(request)))
57
58    def _get_printer_name(self, request):
59        # make sure the first group is an OPERATION group
60        group_tag = request.attribute_groups[0].tag
61        if group_tag != const.AttributeTags.OPERATION:
62            raise MalformedIPPRequestException, \
63                  "Expected OPERATION group tag, got %d\n", group_tag
64
65        # make sure the printer-uri value is appropriate
66        printername_attr = request.attribute_groups[0]['printer-uri']
67        printername_value_tag = printername_attr.values[0].value_tag
68        if printername_value_tag != const.CharacterStringTags.URI:
69            raise MalformedIPPRequestException, \
70                  "Expected URI value tag, got %s" % printername_value_tag
71
72        # actually get the printer name
73        printername_value = printername_attr.values[0].value
74        # XXX: hack -- CUPS will strip the port from the request, so
75        # we can't do an exact comparison (also the hostname might be
76        # different, depending on the CNAME or whether it's localhost)
77        printername = printername_value.split("/")[-1]
78
79        # make sure the printername is valid
80        if printername not in self.printers:
81            raise ValueError, "Invalid printer uri: %s" % printername_value
82
83        return printername
84
85    @handler_for(const.Operations.CUPS_GET_DEFAULT)
86    def cups_get_default(self, request, response):
87        print "get_default called"
88        self._get_printer_attributes(self.printers[self.default], request, response)
89        response.operation_id = const.StatusCodes.OK
90
91    @handler_for(const.Operations.GET_PRINTER_ATTRIBUTES)
92    def get_printer_attributes(self, request, response):
93        print "get_printer_attributes called"
94
95        # this is just like cups_get_default, except the printer name
96        # is given
97        printername = self._get_printer_name(request)
98        self._get_printer_attributes(self.printers[printername], request, response)
99        response.operation_id = const.StatusCodes.OK
100
101    @handler_for(const.Operations.CUPS_GET_PRINTERS)
102    def cups_get_printers(self, request, response):
103        print "get_printers called"
104       
105        # Each printer will append a new printer attribute group.
106        for printer in self.printers:
107            self._get_printer_attributes(self.printers[printer], request, response)
108        response.operation_id = const.StatusCodes.OK
109
110    @handler_for(const.Operations.CUPS_GET_CLASSES)
111    def cups_get_classes(self, request, response):
112        print "get_classes called"
113        response.operation_id = const.StatusCodes.OK
114        # We have no printer classes, so nothing to return.
115
116    @handler_for(const.Operations.GET_JOBS)
117    def get_jobs(self, request, response):
118        print "get_jobs called"
119
120        printername = self._get_printer_name(request)
121        # Each job will append a new job attribute group.
122        for job in self.printers[printername].get_jobs():
123            self._get_job_attributes(job, request, response)
124        response.operation_id = const.StatusCodes.OK
125
126class GutenbachIPPServer(BaseHTTPServer.BaseHTTPRequestHandler):
127    def setup(self):
128        self.root = GutenbachRequestHandler()
129        BaseHTTPServer.BaseHTTPRequestHandler.setup(self)
130
131    def handle_one_request(self):
132        self.raw_requestline = self.rfile.readline()
133        if not self.raw_requestline:
134            self.close_connection = 1
135            return
136        if not self.parse_request(): # An error code has been sent, just exit
137            return
138        self.handle_ipp()
139
140    def handle_ipp(self):
141        # Receive a request
142        length = int(self.headers.getheader('content-length', 0))
143        request = ipp.Request(request=self.rfile, length=length)
144        print "Received request:", repr(request)
145
146        # Attributes
147        attributes = [
148            ipp.Attribute(
149                'attributes-charset',
150                [ipp.Value(ipp.Tags.CHARSET, 'utf-8')]),
151            ipp.Attribute(
152                'attributes-natural-language',
153                [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, 'en-us')])
154            ]
155        # Attribute group
156        attribute_group = ipp.AttributeGroup(
157            const.AttributeTags.OPERATION,
158            attributes)
159
160        # Set up the response
161        response_kwargs = {}
162        response_kwargs['version']          = request.version
163        response_kwargs['operation_id']     = const.StatusCodes.INTERNAL_ERROR
164        response_kwargs['request_id']       = request.request_id
165        response_kwargs['attribute_groups'] = [attribute_group]
166        response = ipp.Request(**response_kwargs)
167
168        # Get the handler and pass it the request and response objects
169        self.root.handle(request, response)
170        print "Sending response:", repr(response)
171
172        # Send the response across HTTP
173        self.send_response(200, "o hai")
174        self.send_header("Content-Type", "application/ipp")
175        self.send_header("Connection", "close")
176        self.end_headers()
177        self.wfile.write(response.packed_value)
178
179    ##### Printer Commands
180
181    def print_job(self, request):
182        pass
183
184    def validate_job(self, request):
185        pass
186
187    #def get_jobs(self, request):
188    #    pass
189
190    def print_uri(self, request):
191        pass
192
193    def create_job(self, request):
194        pass
195
196    def pause_printer(self, request):
197        pass
198
199    def resume_printer(self, request):
200        pass
201
202    def set_printer_attributes(self, request):
203        pass
204
205    ##### Job Commands
206
207    def cancel_job(self, request):
208        pass
209
210    def get_job_attributes(self, request):
211        pass
212
213    def send_document(self, request):
214        pass
215
216    def send_uri(self, request):
217        pass
218
219    def set_job_attributes(self, request):
220        pass
221
222    def cups_get_document(self, request):
223        pass
224
225    def restart_job(self, request):
226        pass
227
228    def promote_job(self, request):
229        pass
Note: See TracBrowser for help on using the repository browser.