From 38bb90b6b5aa3d875fb9e101ab21ee7645ee918e Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Mon, 12 Oct 2015 16:03:48 -0700 Subject: [PATCH] Adding capability to OpenChannel and SendMessage --- chat/chat.go | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ ricochet.go | 59 ++++++++++++++++++++++++++-- 2 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 chat/chat.go diff --git a/chat/chat.go b/chat/chat.go new file mode 100644 index 0000000..6cedf6a --- /dev/null +++ b/chat/chat.go @@ -0,0 +1,107 @@ +// Code generated by protoc-gen-go. +// source: ChatChannel.proto +// DO NOT EDIT! + +/* +Package Protocol_Data_Chat is a generated protocol buffer package. + +It is generated from these files: + ChatChannel.proto + +It has these top-level messages: + Packet + ChatMessage + ChatAcknowledge +*/ +package Protocol_Data_Chat + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +type Packet struct { + ChatMessage *ChatMessage `protobuf:"bytes,1,opt,name=chat_message" json:"chat_message,omitempty"` + ChatAcknowledge *ChatAcknowledge `protobuf:"bytes,2,opt,name=chat_acknowledge" json:"chat_acknowledge,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Packet) Reset() { *m = Packet{} } +func (m *Packet) String() string { return proto.CompactTextString(m) } +func (*Packet) ProtoMessage() {} + +func (m *Packet) GetChatMessage() *ChatMessage { + if m != nil { + return m.ChatMessage + } + return nil +} + +func (m *Packet) GetChatAcknowledge() *ChatAcknowledge { + if m != nil { + return m.ChatAcknowledge + } + return nil +} + +type ChatMessage struct { + MessageText *string `protobuf:"bytes,1,req,name=message_text" json:"message_text,omitempty"` + MessageId *uint32 `protobuf:"varint,2,opt,name=message_id" json:"message_id,omitempty"` + TimeDelta *int64 `protobuf:"varint,3,opt,name=time_delta" json:"time_delta,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ChatMessage) Reset() { *m = ChatMessage{} } +func (m *ChatMessage) String() string { return proto.CompactTextString(m) } +func (*ChatMessage) ProtoMessage() {} + +func (m *ChatMessage) GetMessageText() string { + if m != nil && m.MessageText != nil { + return *m.MessageText + } + return "" +} + +func (m *ChatMessage) GetMessageId() uint32 { + if m != nil && m.MessageId != nil { + return *m.MessageId + } + return 0 +} + +func (m *ChatMessage) GetTimeDelta() int64 { + if m != nil && m.TimeDelta != nil { + return *m.TimeDelta + } + return 0 +} + +type ChatAcknowledge struct { + MessageId *uint32 `protobuf:"varint,1,opt,name=message_id" json:"message_id,omitempty"` + Accepted *bool `protobuf:"varint,2,opt,name=accepted,def=1" json:"accepted,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *ChatAcknowledge) Reset() { *m = ChatAcknowledge{} } +func (m *ChatAcknowledge) String() string { return proto.CompactTextString(m) } +func (*ChatAcknowledge) ProtoMessage() {} + +const Default_ChatAcknowledge_Accepted bool = true + +func (m *ChatAcknowledge) GetMessageId() uint32 { + if m != nil && m.MessageId != nil { + return *m.MessageId + } + return 0 +} + +func (m *ChatAcknowledge) GetAccepted() bool { + if m != nil && m.Accepted != nil { + return *m.Accepted + } + return Default_ChatAcknowledge_Accepted +} diff --git a/ricochet.go b/ricochet.go index 3037803..bbb9148 100644 --- a/ricochet.go +++ b/ricochet.go @@ -8,9 +8,11 @@ import ( "crypto/x509" "encoding/asn1" "encoding/pem" + "errors" "fmt" "github.com/golang/protobuf/proto" "github.com/s-rah/go-ricochet/auth" + "github.com/s-rah/go-ricochet/chat" "github.com/s-rah/go-ricochet/contact" "github.com/s-rah/go-ricochet/control" "io/ioutil" @@ -98,13 +100,13 @@ func (r *Ricochet) decodeResult(response []byte) *Protocol_Data_AuthHiddenServic return res } -func (r *Ricochet) constructProtocol(data []byte, channel byte) []byte { +func (r *Ricochet) constructProtocol(data []byte, channel int) []byte { header := make([]byte, 4+len(data)) r.logger.Print("Wrting Packet of Size: ", len(header)) header[0] = byte(len(header) >> 8) header[1] = byte(len(header) & 0x00FF) header[2] = 0x00 - header[3] = channel + header[3] = byte(channel) copy(header[4:], data[:]) return header } @@ -123,7 +125,7 @@ func (r *Ricochet) Connect(from string, to string) error { // TODO: For now hardcoding port numbers, these change // on startup so need to be reset every time. - tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:49952") + tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:43978") if err != nil { r.logger.Fatal("Cannot Resolve TCP Address ", err) return err @@ -222,6 +224,38 @@ func (r *Ricochet) Connect(from string, to string) error { return nil } +// OpenChannel opens a new channel with the given type and id +// Prerequisites: +// * Must have Previously issued a successful Connect() +// * If acting as the client, id must be odd (currently this is the +// only supported option. +func (r *Ricochet) OpenChannel(channelType string, id int) error { + oc := &Protocol_Data_Control.OpenChannel{ + ChannelIdentifier: proto.Int32(int32(id)), + ChannelType: proto.String(channelType), + } + + pc := &Protocol_Data_Control.Packet{ + OpenChannel: oc, + } + + data, _ := proto.Marshal(pc) + openChannel := r.constructProtocol(data, 0) + r.logger.Print("Opening Channel: ", pc) + r.send(openChannel) + response, _ := r.recv() + openChannelResponse := r.decodePacket(response) + r.logger.Print("Received Response: ", openChannelResponse) + + channelResult := openChannelResponse.GetChannelResult() + + if channelResult.GetOpened() == true { + r.logger.Print("Channel Opened Successfully: ", channelResult.GetChannelIdentifier()) + return nil + } + return errors.New("failed to open channel") +} + // SendContactRequest initiates a contact request to the server. // Prerequisites: // * Must have Previously issued a successful Connect() @@ -256,6 +290,25 @@ func (r *Ricochet) SendContactRequest(nick string, message string) { r.logger.Print("Received Response: ", openChannelResponse) } +// SendMessage sends a Chat Message (message) to a give Channel (channel). +// Prerequisites: +// * Must have previously issued a successful Connect() +// * Must have previously opened channel with OpenChanel +func (r *Ricochet) SendMessage(message string, channel int) { + // Construct a Contact Request Channel + cm := &Protocol_Data_Chat.ChatMessage{ + MessageText: proto.String(message), + } + chatPacket := &Protocol_Data_Chat.Packet{ + ChatMessage: cm, + } + + data, _ := proto.Marshal(chatPacket) + chatMessageBytes := r.constructProtocol(data, channel) + r.logger.Print("Sending Message: ", chatPacket) + r.send(chatMessageBytes) +} + // negotiateVersion Perform version negotiation with the connected host. func (r *Ricochet) negotiateVersion() { version := make([]byte, 4)