diff --git a/client.go b/client.go index 89da710..de78d15 100644 --- a/client.go +++ b/client.go @@ -285,20 +285,29 @@ func (client *Client) receiver() { } } -// Send the channel list to a client. func (client *Client) sendChannelList() { - server := client.server - root := server.root + client.sendChannelTree(client.server.root) +} +func (client *Client) sendChannelTree(channel *Channel) { // Start at the root channel. - err := client.sendProtoMessage(MessageChannelState, &mumbleproto.ChannelState{ - ChannelId: proto.Uint32(uint32(root.Id)), - Name: proto.String(root.Name), - Description: proto.String(root.Description), - }) + log.Printf("sending channel ID=%i, NAME=%s", channel.Id, channel.Name) + chanstate := &mumbleproto.ChannelState{ + ChannelId: proto.Uint32(uint32(channel.Id)), + Name: proto.String(channel.Name), + Description: proto.String(channel.Description), + } + if channel.parent != nil { + chanstate.Parent = proto.Uint32(uint32(channel.parent.Id)) + } + + err := client.sendProtoMessage(MessageChannelState, chanstate) if err != nil { - // panic! - log.Printf("poanic!") + client.Panic(err.String()) + } + + for _, subchannel := range channel.children { + client.sendChannelTree(subchannel) } } diff --git a/message.go b/message.go index 8729542..19f1b07 100644 --- a/message.go +++ b/message.go @@ -137,6 +137,98 @@ func (server *Server) handleUserRemoveMessage(client *Client, msg *Message) { } func (server *Server) handleUserStateMessage(client *Client, msg *Message) { + log.Printf("UserState!") + userstate := &mumbleproto.UserState{} + err := proto.Unmarshal(msg.buf, userstate) + if err != nil { + client.Panic(err.String()) + } + + if userstate.Session == nil { + log.Printf("UserState without session.") + return + } + + actor := server.clients[client.Session] + user := server.clients[*userstate.Session] + + log.Printf("actor = %v", actor) + log.Printf("user = %v", user) + + userstate.Session = proto.Uint32(user.Session) + userstate.Actor = proto.Uint32(actor.Session) + + // Has a channel ID + if userstate.ChannelId != nil { + // Destination channel + dstChan := server.channels[int(*userstate.ChannelId)] + log.Printf("dstChan = %v", dstChan) + + // If the user and the actor aren't the same, check whether the actor has the 'move' permission + // on the user's channel to move. + + // Check whether the actor has 'move' permissions on dstChan. Check whether user has 'enter' + // permissions on dstChan. + + // Check whether the channel is full. + } + + if userstate.Mute != nil || userstate.Deaf != nil || userstate.Suppress != nil || userstate.PrioritySpeaker != nil { + // Disallow for SuperUser + + // Check whether the actor has 'mutedeafen' permission on user's channel. + + // Check if this was a suppress operation. Only the server can suppress users. + } + + // Comment set/clear + if userstate.Comment != nil { + comment := *userstate.Comment + log.Printf("comment = %v", comment) + + // Clearing another user's comment. + if user != actor { + // Check if actor has 'move' permissions on the root channel. It is needed + // to clear another user's comment. + + // Only allow empty text. + } + + // Check if the text is allowed. + + // Only set the comment if it is different from the current + // user comment. + } + + // Texture change + if userstate.Texture != nil { + // Check the length of the texture + } + + // Registration + if userstate.UserId != nil { + // If user == actor, check for 'selfregister' permission on root channel. + // If user != actor, check for 'register' permission on root channel. + + // Check if the UserId in the message is >= 0. A registration attempt + // must use a negative UserId. + } + + // Prevent self-targetting state changes to be applied to other users + // That is, if actor != user, then: + // Discard message if it has any of the following things set: + // - SelfDeaf + // - SelfMute + // - Texture + // - PluginContext + // - PluginIdentity + // - Recording + if actor != user && (userstate.SelfDeaf != nil || userstate.SelfMute != nil || + userstate.Texture != nil || userstate.PluginContext != nil || userstate.PluginIdentity != nil || + userstate.Recording != nil) { + return + } + } func (server *Server) handleBanListMessage(client *Client, msg *Message) { diff --git a/pkg/mumbleproto/Mumble.pb.go b/pkg/mumbleproto/Mumble.pb.go index 2a783ea..bd53db1 100644 --- a/pkg/mumbleproto/Mumble.pb.go +++ b/pkg/mumbleproto/Mumble.pb.go @@ -245,6 +245,8 @@ type UserState struct { Hash *string "PB(bytes,15,opt,name=hash)" CommentHash []byte "PB(bytes,16,opt,name=comment_hash)" TextureHash []byte "PB(bytes,17,opt,name=texture_hash)" + PrioritySpeaker *bool "PB(varint,18,opt,name=priority_speaker)" + Recording *bool "PB(varint,19,opt,name=recording)" XXX_unrecognized []byte } func (this *UserState) Reset() { diff --git a/pkg/mumbleproto/Mumble.proto b/pkg/mumbleproto/Mumble.proto index fdfd3a8..6042464 100644 --- a/pkg/mumbleproto/Mumble.proto +++ b/pkg/mumbleproto/Mumble.proto @@ -106,6 +106,8 @@ message UserState { optional string hash = 15; optional bytes comment_hash = 16; optional bytes texture_hash = 17; + optional bool priority_speaker = 18; + optional bool recording = 19; } message BanList { diff --git a/server.go b/server.go index 2bf8ea7..069aa9e 100644 --- a/server.go +++ b/server.go @@ -41,7 +41,6 @@ type Server struct { udpconn *net.UDPConn incoming chan *Message - outgoing chan *Message udpsend chan *Message voicebroadcast chan *VoiceBroadcast @@ -63,7 +62,10 @@ type Server struct { BetaCodec int32 PreferAlphaCodec bool + // Channels + chanid int root *Channel + channels map[int]*Channel } // Allocate a new Murmur instance @@ -78,7 +80,6 @@ func NewServer(addr string, port int) (s *Server, err os.Error) { s.hclients = make(map[string][]*Client) s.hpclients = make(map[string]*Client) - s.outgoing = make(chan *Message) s.incoming = make(chan *Message) s.udpsend = make(chan *Message) s.voicebroadcast = make(chan *VoiceBroadcast) @@ -86,10 +87,13 @@ func NewServer(addr string, port int) (s *Server, err os.Error) { s.MaxBandwidth = 300000 s.MaxUsers = 10 - s.root = NewChannel(0, "Root") + s.channels = make(map[int]*Channel) + + s.root = s.NewChannel("Root") + subChan := s.NewChannel("SubChannel") + s.root.AddChild(subChan) go s.handler() - go s.multiplexer() return } @@ -152,6 +156,23 @@ func (server *Server) RemoveClient(client *Client) { } } +// Add a new channel to the server. +func (server *Server) NewChannel(name string) (channel *Channel) { + channel = NewChannel(server.chanid, name) + server.channels[channel.Id] = channel + server.chanid += 1 + return +} + +// Remove a channel from the server. +func (server *Server) RemoveChanel(channel *Channel) { + if (channel.Id == 0) { + log.Printf("Attempted to remove root channel.") + return + } + server.channels[channel.Id] = nil, false +} + // This is the synchronous handler goroutine. // Important control channel messages are routed through this Goroutine // to keep server state synchronized. @@ -263,7 +284,6 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) { // Broadcast the the user entered a channel server.root.AddClient(client) - log.Printf("server.root = %p", server.root) err = server.broadcastProtoMessage(MessageUserState, &mumbleproto.UserState{ Session: proto.Uint32(client.Session), Name: proto.String(client.Username), @@ -364,10 +384,8 @@ func (server *Server) sendUserList(client *Client) { ChannelId: proto.Uint32(0), }) - log.Printf("Sent one user") - if err != nil { - log.Printf("unable to send!") + // Server panic? continue } } @@ -432,13 +450,6 @@ func (server *Server) handleIncomingMessage(client *Client, msg *Message) { } } -func (server *Server) multiplexer() { - for { - _ = <-server.outgoing - log.Printf("recvd message to multiplex") - } -} - func (s *Server) SetupUDP() (err os.Error) { addr := &net.UDPAddr{ Port: s.port,