package client import ( "encoding/binary" "encoding/json" "fmt" "io" "strings" "github.com/amitbet/vncproxy/common" "github.com/amitbet/vncproxy/encodings" "github.com/amitbet/vncproxy/logger" ) // MsgFramebufferUpdate consists of a sequence of rectangles of // pixel data that the client should put into its framebuffer. type MsgFramebufferUpdate struct { Rectangles []common.Rectangle } func (m *MsgFramebufferUpdate) String() string { str := fmt.Sprintf("MsgFramebufferUpdate (type=%d) Rects: ", m.Type()) for _, rect := range m.Rectangles { str += rect.String() + "\n" //if this is the last rect, break the loop if rect.Enc.Type() == int32(common.EncLastRectPseudo) { break } } return str } func (*MsgFramebufferUpdate) Type() uint8 { return 0 } func (fbm *MsgFramebufferUpdate) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error { reader := common.NewRfbReadHelper(r) writeTo := &WriteTo{w, "MsgFramebufferUpdate.CopyTo"} reader.Listeners.AddListener(writeTo) _, err := fbm.Read(c, reader) return err } func (fbm *MsgFramebufferUpdate) Read(c common.IClientConn, r *common.RfbReadHelper) (common.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]common.IEncoding) for _, enc := range c.Encodings() { encMap[enc.Type()] = enc } // We must always support the raw encoding rawEnc := new(encodings.RawEncoding) encMap[rawEnc.Type()] = rawEnc logger.Debugf("MsgFramebufferUpdate.Read: numrects= %d", numRects) rects := make([]common.Rectangle, numRects) for i := uint16(0); i < numRects; i++ { logger.Debugf("MsgFramebufferUpdate.Read: ###############rect################: %d", i) var encodingTypeInt int32 r.SendRectSeparator(-1) rect := &rects[i] data := []interface{}{ &rect.X, &rect.Y, &rect.Width, &rect.Height, &encodingTypeInt, } for _, val := range data { if err := binary.Read(r, binary.BigEndian, val); err != nil { logger.Errorf("err: %v", err) return nil, err } } jBytes, _ := json.Marshal(data) encType := common.EncodingType(encodingTypeInt) logger.Debugf("MsgFramebufferUpdate.Read: rect# %d, rect hdr data: enctype=%s, data: %s", i, encType, string(jBytes)) enc, supported := encMap[encodingTypeInt] if supported { var err error rect.Enc, err = enc.Read(c.CurrentPixelFormat(), rect, r) if err != nil { return nil, err } } else { if strings.Contains(encType.String(), "Pseudo") { rect.Enc = &encodings.PseudoEncoding{encodingTypeInt} //if this is the last rect, break the for loop if rect.Enc.Type() == int32(common.EncLastRectPseudo) { break } } else { logger.Errorf("MsgFramebufferUpdate.Read: unsupported encoding type: %d, %s", encodingTypeInt, encType) return nil, fmt.Errorf("MsgFramebufferUpdate.Read: unsupported encoding type: %d, %s", encodingTypeInt, encType) } } } r.SendMessageEnd(common.ServerMessageType(fbm.Type())) return &MsgFramebufferUpdate{rects}, nil } // MsgSetColorMapEntries 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 MsgSetColorMapEntries struct { FirstColor uint16 Colors []common.Color } func (fbm *MsgSetColorMapEntries) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error { reader := common.NewRfbReadHelper(r) writeTo := &WriteTo{w, "MsgSetColorMapEntries.CopyTo"} reader.Listeners.AddListener(writeTo) _, err := fbm.Read(c, reader) return err } func (m *MsgSetColorMapEntries) String() string { return fmt.Sprintf("MsgSetColorMapEntries (type=%d) first:%d colors: %v: ", m.Type(), m.FirstColor, m.Colors) } func (*MsgSetColorMapEntries) Type() uint8 { return 1 } func (m *MsgSetColorMapEntries) Read(c common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) { // Read off the padding var padding [1]byte if _, err := io.ReadFull(r, padding[:]); err != nil { return nil, err } var result MsgSetColorMapEntries 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([]common.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 } } // cmap := c.CurrentColorMap() // // Update the connection's color map // cmap[result.FirstColor+i] = *color } r.SendMessageEnd(common.ServerMessageType(m.Type())) return &result, nil } // Bell signals that an audible bell should be made on the client. // // See RFC 6143 Section 7.6.3 type MsgBell byte func (fbm *MsgBell) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error { return nil } func (m *MsgBell) String() string { return fmt.Sprintf("MsgBell (type=%d)", m.Type()) } func (*MsgBell) Type() uint8 { return 2 } func (m *MsgBell) Read(c common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) { r.SendMessageEnd(common.ServerMessageType(m.Type())) return new(MsgBell), nil } type MsgServerFence byte func (fbm *MsgServerFence) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error { return nil } func (m *MsgServerFence) String() string { return fmt.Sprintf("MsgServerFence (type=%d)", m.Type()) } func (*MsgServerFence) Type() uint8 { return uint8(common.ServerFence) } func (sf *MsgServerFence) Read(info common.IClientConn, c *common.RfbReadHelper) (common.ServerMessage, error) { bytes := make([]byte, 3) c.Read(bytes) if _, err := c.Read(bytes); err != nil { return nil, err } var flags uint32 if err := binary.Read(c, binary.BigEndian, &flags); err != nil { return nil, err } var length uint8 if err := binary.Read(c, binary.BigEndian, &length); err != nil { return nil, err } bytes = make([]byte, length) if _, err := c.Read(bytes); err != nil { return nil, err } c.SendMessageEnd(common.ServerMessageType(sf.Type())) return sf, nil } // MsgServerCutText indicates the server has new text in the cut buffer. // // See RFC 6143 Section 7.6.4 type MsgServerCutText struct { Text string } func (fbm *MsgServerCutText) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error { reader := &common.RfbReadHelper{Reader: r} writeTo := &WriteTo{w, "MsgServerCutText.CopyTo"} reader.Listeners.AddListener(writeTo) _, err := fbm.Read(c, reader) return err } func (m *MsgServerCutText) String() string { return fmt.Sprintf("MsgServerCutText (type=%d)", m.Type()) } func (*MsgServerCutText) Type() uint8 { return 3 } func (m *MsgServerCutText) Read(conn common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) { //reader := common.RfbReadHelper{Reader: r} // Read off the padding var padding [3]byte if _, err := io.ReadFull(r, padding[:]); err != nil { return nil, err } textLength, err := r.ReadUint32() if err != nil { return nil, err } textBytes, err := r.ReadBytes(int(textLength)) if err != nil { return nil, err } r.SendMessageEnd(common.ServerMessageType(m.Type())) return &MsgServerCutText{string(textBytes)}, nil }