./others/vnc.py

0.
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
import struct
from array import array
 
import PyD3DES
 
from AppKit import *
 
from twisted.internet.protocol import Protocol, ClientFactory
from twisted.internet import reactor
 
class NotEnoughDataException(Exception):
    pass
 
 
def tocard32(i):
    try:
        return struct.pack('!i', i)
    except struct.error, e:
        raise NotEnoughDataException(e)
 
def card32(i):
    if len(i) != 4:
        raise NotEnoughDataException(i)
    return array('i', i.tostring())[0]
 
def tocard16(i):
    try:
        return struct.pack('!h', i)
    except struct.error, e:
        raise NotEnoughDataException(e)
 
def card16(i):
    if len(i) != 2:
        raise NotEnoughDataException(i)
    return array('h', i.tostring())[0]
 
def tocard8(i):
    return chr(i)
 
def card8(i):
    return i
 
class PixelFormat(object):
    def __init__(self, **args):
        for k, v in args.items():
            setattr(self, k, v)
 
    def parse(klass, data):
        parts = list(data[:4])
        parts.append(card16(data[4:6]))
        parts.append(card16(data[6:8]))
        parts.append(card16(data[8:10]))
        parts += map(None, data[10:13])
        args = {}
        for attr, value in zip(('bpp', 'depth', 'bigendian', 'truecolor',
                                'red_max', 'green_max', 'blue_max',
                                'red_shift', 'green_shift',
                                'blue_shift'), parts):
            args[attr] = value
        args['size'] = args['bpp'] / 8
        return klass(**args)
    parse = classmethod(parse)
 
    def __str__(self):
        parts = [x for x in dir(self) if not x.startswith('_')]
        parts.sort()
        s = '\n'.join([('%12s: %s' % (x, getattr(self, x))) for x in parts])
        return s
 
    def pack(self):
        parts = [tocard8(self.bpp),
                 tocard8(self.depth),
                 tocard8(self.bigendian),
                 tocard8(self.truecolor),
                 tocard16(self.red_max),
                 tocard16(self.green_max),
                 tocard16(self.blue_max),
                 tocard8(self.red_shift),
                 tocard8(self.green_shift),
                 tocard8(self.blue_shift),
                 '\0' * 3]
        return ''.join(parts)
 
    def default(klass):
        return klass(bpp=32, depth=32, bigendian=0, truecolor=1, red_max=255, green_max=255, blue_max=255, red_shift=0, green_shift=8, blue_shift=16, size=4)
    default = classmethod(default)
 
 
class VNCClient(Protocol):
    RAW_ENCODING, COPYRECT_ENCODING, RRE_ENCODING, CORRE_ENCODING, HEXTILE_ENCODING = 0, 1, 2, 4, 5
 
    def __init__(self, passwd=''):
        self.read_buffer = array('B')
 
        self.state = 'ProtocolVersion'
        self.states = { 'ProtocolVersion': self.do_ProtocolVersion,
                        'Authentication': self.do_Auth,
                        'Initialization': self.do_Init,
                        'Connected': self.do_ConnectedHandler
                        }
        self.auth_types = [self.do_ConnectionFailed,
                            self.do_NoAuth,
                            self.do_VNCAuth,
                            ]
        self.vnc_auth_state = 0
        self.vnc_auth_states = [self.do_VNCAuth1,
                                self.do_VNCAuth2,
                                ]
        self.connected_msgs = {0: self.do_FramebufferUpdate,
                               2: self.do_Bell,
                               3: self.do_ServerCutText,
                               }
 
    def dataReceived(self, data):
        self.read_buffer.extend(array('B', data))
        self.states[self.state]()
 
 
    def setFrameBufferRect(self, x, y, w, h, data):
        destRect = ((x, y), (w, h))
        srcRect = ((0, 0), (w, h))
 
        self.frameBuffer.lockFocus()
        data.drawInRect_fromRect_operation_fraction_(destRect, srcRect, NSCompositeCopy, 1.0)
        self.frameBuffer.unlockFocus()
 
    def setFrameBufferRectToRawData(self, x, y, w, h, rawData):
        imgRep = NSBitmapImageRep.alloc().initWithBitmapDataPlanes_pixelsWide_pixelsHigh_bitsPerSample_samplesPerPixel_hasAlpha_isPlanar_colorSpaceName_bytesPerRow_bitsPerPixel_((rawData, None, None, None, None), w, h, 8, 4, True, False, NSCalibratedRGBColorSpace, 0, 4 * 8)
        imgRep.setAlpha_(False)
        img = NSImage.alloc().initWithSize_((w, h))
        img.setFlipped_(True)
        img.lockFocus()
        imgRep.drawInRect_(((0, 0), (w, h)))
        img.unlockFocus()
        self.setFrameBufferRect(x, y, w, h, img)
 
    def dumpFramebufferToFile(self):
        self.frameBuffer.TIFFRepresentationUsingCompression_factor_(NSTIFFCompressionLZW, 1.0).writeToFile_atomically_('VNC - %s.tiff' % (self.name, ), False)
 
 
    def do_ProtocolVersion(self):
        # Remove the servers version and return our own
        print('Protocol version recieved "%s"' % (''.join(self.read_buffer[:11].tostring()), ))
        self.read_buffer = self.read_buffer[12:]
        self.transport.write('RFB 003.003\n')
        self.state = 'Authentication'
 
    def do_ConnectionFailed(self):
        try:
            reason_length = card32(self.read_buffer[4:8])
            reason = self.read_buffer[8:8 + reason_length]
            self.read_buffer = self.read_buffer[8 + reason_length:]
            self.transport.loseConnection()
            print('Connection failed: %s' % (reason,))
            return 1
        except Exception, e:
            print repr(e)
 
    def do_Auth(self):
        t = self.read_buffer[:4]
        t = card32(t)
        print('Authentication type is %d (%r)' % (t, self.auth_types[t]))
        if self.auth_types[t]():
            pass
 
 
    def do_NoAuth(self):
        pass
 
    def do_VNCAuth(self):
        self.vnc_auth_states[self.vnc_auth_state]()
 
    def do_VNCAuth1(self):
        try:
            if len(self.read_buffer) < 20:
                raise IndexError
            challenge = self.read_buffer[4:20]
            self.read_buffer = self.read_buffer[20:]
            self.read_buffer.extend(array('B', '\x00\x00\x00\x02'))
            PyD3DES.setkey(self.factory.password)
            self.transport.write(PyD3DES.encrypt(challenge[:8]) + PyD3DES.encrypt(challenge[8:]))
            self.vnc_auth_state += 1
        except Exception, e:
            print repr(e), e
            return
 
    def do_VNCAuth2(self):
        try:
            if len(self.read_buffer) < 8:
                raise IndexError
            response = card32(self.read_buffer[4:8])
            if response == 0:
                print('Authentication succeeded')
                self.state = 'Initialization'
                self.read_buffer = self.read_buffer[8:]
                # Send the ClientInit message that consists
                # of a card32 that is 1 if the session is shared
                try:
                    self.transport.write(chr(self.shared))
                except:
                    self.transport.write(chr(0))
            elif response == 1:
                print('Invalid password')
                self.transport.loseConnection()
            elif response == 2:
                print('Too many connections!')
                self.transport.loseConnection()
        except Exception, e:
            print(e)
 
 
    def do_Init(self):
        """
        Handle a ServerInitialisation message.
        """
        if len(self.read_buffer) >= 24:
            print('ServerInitialisation buffer length: %d' % (len(self.read_buffer), ))
            self.fbsize = (card16(self.read_buffer[:2]), card16(self.read_buffer[2:4]))
            self.pixel_format = PixelFormat.parse(self.read_buffer[4:20])
            name_length = card32(self.read_buffer[20:24])
        else:
            return
 
        if len(self.read_buffer) < 24 + name_length:
            return
        self.name = ''.join(self.read_buffer[24:24 + name_length].tostring())
        print('Connected to %s' % (self.name, ))
        print('Servers pixel format: \n%s' % (self.pixel_format, ))
 
        self.frameBuffer = NSImage.alloc().initWithSize_(self.fbsize)
        self.frameBuffer.setFlipped_(True)
 
        self.alreadyProcessedRectangles = (0, 4)
 
 
        self.read_buffer = self.read_buffer[24 + name_length:]
        self.state = 'Connected'
        self.send_SetPixelFormat(PixelFormat.default())
        self.send_SetEncoding((self.CORRE_ENCODING, ))
        self.send_FramebufferUpdateRequest((0, 0, self.fbsize[0], self.fbsize[1]), 0)
 
 
    def do_ConnectedHandler(self):
        """ """
        p = NSAutoreleasePool.alloc().init()
        self.connected_msgs[self.read_buffer[0]]()
        del p
 
    def do_FramebufferUpdate(self):
        buf = self.read_buffer
 
        try:
            messageType = buf[0]
            numberOfRectangles = card16(buf[2:4])
 
            firstRectangle, currentRectangleStart = self.alreadyProcessedRectangles
 
            for currentRectangle in range(firstRectangle, numberOfRectangles):
                currentRectangleLength = 0
                x, y, width, height = card16(buf[currentRectangleStart    :currentRectangleStart + 2]), \
                                      card16(buf[currentRectangleStart + 2:currentRectangleStart + 4]), \
                                      card16(buf[currentRectangleStart + 4:currentRectangleStart + 6]), \
                                      card16(buf[currentRectangleStart + 6:currentRectangleStart + 8])
                encodingType = card32(buf[currentRectangleStart + 8:currentRectangleStart + 12])
                currentRectangleLength += 12
 
                currentEncodingStart = currentRectangleStart + 12
                currentEncodingLength = 0
                if encodingType == self.RAW_ENCODING:
                    currentEncodingLength = VNCClient._Raw(self, currentEncodingStart, x, y, width, height, NotEnoughDataException)
                elif encodingType == self.CORRE_ENCODING:
                    currentEncodingLength = VNCClient._CoRRE(self, currentEncodingStart, x, y, width, height, NotEnoughDataException)
 
                else:
                    print '\t\tUnknown encoding!', encodingType
 
                currentRectangleLength += currentEncodingLength
                currentRectangleStart += currentRectangleLength
 
                self.alreadyProcessedRectangles = (currentRectangle + 1, currentRectangleStart)
 
            self.read_buffer = self.read_buffer[currentRectangleStart:]
            self.alreadyProcessedRectangles = (0, 4)
#            self.dumpFramebufferToFile()
            self.send_FramebufferUpdateRequest((0, 0, self.fbsize[0], self.fbsize[1]), 0)
#            self.transport.loseConnection()
        except NotEnoughDataException, e:
            pass
 
    def _Raw(self, currentEncodingStart, x, y, width, height, NotEnoughDataException):
        rawDataLength = width * height * self.pixel_format.size
        rawData = self.read_buffer[currentEncodingStart:currentEncodingStart + rawDataLength]
        if len(rawData) < rawDataLength:
            raise NotEnoughDataException
 
        self.setFrameBufferRectToRawData(x, y, width, height, rawData)
        return rawDataLength
 
 
    def _CoRRE(self, currentEncodingStart, x, y, width, height, NotEnoughDataException):
        buf = self.read_buffer
        if len(buf) < currentEncodingStart + 8:
            raise NotEnoughDataException
 
        numberOfSubRectangles = card32(buf[currentEncodingStart:currentEncodingStart + 4])
        r, g, b, a = buf[currentEncodingStart + 4:currentEncodingStart + 8]
 
        self.frameBuffer.lockFocus()
        NSColor.colorWithCalibratedRed_green_blue_alpha_(r / 255.0, g / 255.0, b / 255.0, 1.0).set()
        NSRectFill(((x, y), (width, height)))
 
        currentSubRectangleStart = currentEncodingStart + 8
 
        if len(buf) < currentSubRectangleStart + (8 * numberOfSubRectangles):
            raise NotEnoughDataException
 
        subRectangleRects = []
        subRectangleColors = []
        if numberOfSubRectangles:
            for currentSubRectangle in range(numberOfSubRectangles):
                r, g, b, a, srX, srY, srWidth, srHeight = buf[currentSubRectangleStart:currentSubRectangleStart + 8]
 
                subRectangleRects.append(((x + srX, y + srY), (srWidth, srHeight)))
                subRectangleColors.append((r / 255.0, g / 255.0, b / 255.0, 1.0))
                currentSubRectangleStart += 8
 
            subRectangleColors = map(NSColor.colorWithCalibratedRed_green_blue_alpha_, *zip(*subRectangleColors))        
            NSRectFillListWithColors(subRectangleRects, subRectangleColors)
 
        self.frameBuffer.unlockFocus()
 
        currentEncodingLength = 8 * (numberOfSubRectangles + 1)
        return currentEncodingLength
 
    try:
        from _CoRRE import _CoRRE
    except ImportError:
        pass
 
    def do_Bell(self):
        self.read_buffer = self.read_buffer[1:]
 
    def do_ServerCutText(self):
        length = card32(self.read_buffer[4:8])
        text = self.read_buffer[8:8 + length]
        print text
        self.read_buffer = self.read_buffer[8 + length:]
 
 
 
    def send_SetPixelFormat(self, pixelFormat):
        self.pixel_format = pixelFormat
        msg = tocard8(0)
        msg += '\0' * 3
        msg += pixelFormat.pack()
        self.transport.write(msg)
 
    def send_SetEncoding(self, encodings):
        msg = tocard8(2)
        msg = msg + '\0'
        msg = msg + tocard16(len(encodings))
 
        encs = map(tocard32, encodings)
        msg = msg + ''.join(encs)
        self.transport.write(msg)
 
    def send_FramebufferUpdateRequest(self, pos, incremental):
        msg = tocard8(3)
        msg = msg + tocard8(incremental)
        msg = msg + ''.join(map(tocard16, pos))
        self.transport.write(msg)
 
    def send_KeyEvent(self, down, key):
        msg = tocard8(4)
        msg = msg + tocard8(down) + '\0'
        msg = msg + tocard32(key)
        self.transport.write(msg)
 
    def send_PointerEvent(self, pos, buttons):
        msg = tocard8(5)
        msg = msg + tocard8(buttons)
        msg = msg + ''.join(map(tocard16, pos))
        self.transport.write(msg)
 
    def send_ClientCutText(self, text):
        msg = tocard8(6)
        msg = msg + ' ' + card32(len(text))
        msg = msg + text
        self.transport.write(msg)
 
class VNCClientFactory(ClientFactory):
    protocol = VNCClient
    def __init__(self, password):
        self.password = password
 
    def startedConnecting(self, connector):
        print 'startedConnecting'
 
    def clientConnectionFailed(self, connector, reason):
        print 'Connection failed. Reason:', reason
 
    def clientConnectionLost(self, connector, reason):
        print 'Connection lost. Reason:', reason
        if reactor.running:
            reactor.stop()
 
import hotshot, hotshot.stats
def main():
    import sys
    if len(sys.argv) < 4:
        print 'Usage: %s hostname port password' % (sys.argv[0], )
        return
 
    NSApplicationLoad()
    reactor.connectTCP(sys.argv[1], int(sys.argv[2]), VNCClientFactory(sys.argv[3]))
    reactor.run()
 
import profile, pstats
if __name__ == '__main__':
    main()
 

Back