193 lines
4.3 KiB
Go
193 lines
4.3 KiB
Go
|
package vnc
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
)
|
||
|
|
||
|
// A ServerMessage implements a message sent from the server to the client.
|
||
|
type ServerMessage interface {
|
||
|
// The type of the message that is sent down on the wire.
|
||
|
Type() uint8
|
||
|
|
||
|
// Read reads the contents of the message from the reader. At the point
|
||
|
// this is called, the message type has already been read from the reader.
|
||
|
// This should return a new ServerMessage that is the appropriate type.
|
||
|
Read(*ClientConn, io.Reader) (ServerMessage, error)
|
||
|
}
|
||
|
|
||
|
// FramebufferUpdateMessage consists of a sequence of rectangles of
|
||
|
// pixel data that the client should put into its framebuffer.
|
||
|
type FramebufferUpdateMessage struct {
|
||
|
Rectangles []Rectangle
|
||
|
}
|
||
|
|
||
|
// Rectangle represents a rectangle of pixel data.
|
||
|
type Rectangle struct {
|
||
|
X uint16
|
||
|
Y uint16
|
||
|
Width uint16
|
||
|
Height uint16
|
||
|
Enc Encoding
|
||
|
}
|
||
|
|
||
|
func (*FramebufferUpdateMessage) Type() uint8 {
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (*FramebufferUpdateMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) {
|
||
|
// Read off the padding
|
||
|
var padding [1]byte
|
||
|
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var numRects uint16
|
||
|
if err := binary.Read(r, binary.BigEndian, &numRects); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// Build the map of encodings supported
|
||
|
encMap := make(map[int32]Encoding)
|
||
|
for _, enc := range c.Encs {
|
||
|
encMap[enc.Type()] = enc
|
||
|
}
|
||
|
|
||
|
// We must always support the raw encoding
|
||
|
rawEnc := new(RawEncoding)
|
||
|
encMap[rawEnc.Type()] = rawEnc
|
||
|
|
||
|
rects := make([]Rectangle, numRects)
|
||
|
for i := uint16(0); i < numRects; i++ {
|
||
|
var encodingType int32
|
||
|
|
||
|
rect := &rects[i]
|
||
|
data := []interface{}{
|
||
|
&rect.X,
|
||
|
&rect.Y,
|
||
|
&rect.Width,
|
||
|
&rect.Height,
|
||
|
&encodingType,
|
||
|
}
|
||
|
|
||
|
for _, val := range data {
|
||
|
if err := binary.Read(r, binary.BigEndian, val); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
enc, ok := encMap[encodingType]
|
||
|
if !ok {
|
||
|
return nil, fmt.Errorf("unsupported encoding type: %d", encodingType)
|
||
|
}
|
||
|
|
||
|
var err error
|
||
|
rect.Enc, err = enc.Read(c, rect, r)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return &FramebufferUpdateMessage{rects}, nil
|
||
|
}
|
||
|
|
||
|
// SetColorMapEntriesMessage is sent by the server to set values into
|
||
|
// the color map. This message will automatically update the color map
|
||
|
// for the associated connection, but contains the color change data
|
||
|
// if the consumer wants to read it.
|
||
|
//
|
||
|
// See RFC 6143 Section 7.6.2
|
||
|
type SetColorMapEntriesMessage struct {
|
||
|
FirstColor uint16
|
||
|
Colors []Color
|
||
|
}
|
||
|
|
||
|
func (*SetColorMapEntriesMessage) Type() uint8 {
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
func (*SetColorMapEntriesMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) {
|
||
|
// Read off the padding
|
||
|
var padding [1]byte
|
||
|
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var result SetColorMapEntriesMessage
|
||
|
if err := binary.Read(r, binary.BigEndian, &result.FirstColor); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var numColors uint16
|
||
|
if err := binary.Read(r, binary.BigEndian, &numColors); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
result.Colors = make([]Color, numColors)
|
||
|
for i := uint16(0); i < numColors; i++ {
|
||
|
|
||
|
color := &result.Colors[i]
|
||
|
data := []interface{}{
|
||
|
&color.R,
|
||
|
&color.G,
|
||
|
&color.B,
|
||
|
}
|
||
|
|
||
|
for _, val := range data {
|
||
|
if err := binary.Read(r, binary.BigEndian, val); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update the connection's color map
|
||
|
c.ColorMap[result.FirstColor+i] = *color
|
||
|
}
|
||
|
|
||
|
return &result, nil
|
||
|
}
|
||
|
|
||
|
// Bell signals that an audible bell should be made on the client.
|
||
|
//
|
||
|
// See RFC 6143 Section 7.6.3
|
||
|
type BellMessage byte
|
||
|
|
||
|
func (*BellMessage) Type() uint8 {
|
||
|
return 2
|
||
|
}
|
||
|
|
||
|
func (*BellMessage) Read(*ClientConn, io.Reader) (ServerMessage, error) {
|
||
|
return new(BellMessage), nil
|
||
|
}
|
||
|
|
||
|
// ServerCutTextMessage indicates the server has new text in the cut buffer.
|
||
|
//
|
||
|
// See RFC 6143 Section 7.6.4
|
||
|
type ServerCutTextMessage struct {
|
||
|
Text string
|
||
|
}
|
||
|
|
||
|
func (*ServerCutTextMessage) Type() uint8 {
|
||
|
return 3
|
||
|
}
|
||
|
|
||
|
func (*ServerCutTextMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) {
|
||
|
// Read off the padding
|
||
|
var padding [1]byte
|
||
|
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var textLength uint32
|
||
|
if err := binary.Read(r, binary.BigEndian, &textLength); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
textBytes := make([]uint8, textLength)
|
||
|
if err := binary.Read(r, binary.BigEndian, &textBytes); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return &ServerCutTextMessage{string(textBytes)}, nil
|
||
|
}
|