func (r *Room) HandleMsg(m message.Message) {
	var fromID string
	if fromMsg, ok := m.(message.MessageFrom); ok {
		fromID = fromMsg.From().ID()
	}
	if fromID != "" {
		if item, err := r.Members.Get(fromID); err != nil {
			logger.Printf("Room received unexpected message from a non-member: %v", m)
			return
		} else if member, ok := item.Value().(*Member); ok && member.IsMuted() {
			if _, ok = m.(*message.CommandMsg); !ok {
				member.User.Send(m)
			}
			return
		}
	}
	switch m := m.(type) {
	case *message.CommandMsg:
		cmd := *m
		err := r.commands.Run(r, cmd)
		if err != nil {
			m := message.NewSystemMsg(fmt.Sprintf("Err: %s", err), cmd.From())
			go r.HandleMsg(m)
		}
	case message.MessageTo:
		user := m.To()
		if user.Ignored.In(fromID) {
			return  
		}
		user.Send(m)
	default:
		r.history.Add(m)
		r.Members.Each(func(_ string, item set.Item) (err error) {
			user := item.Value().(*Member).User
			if user.Ignored.In(fromID) {
				return  
			}
			if _, ok := m.(*message.AnnounceMsg); ok {
				if user.Config().Quiet {
					return  
				}
			}
			user.Send(m)
			return
		})
	}
}
HandleMsg reacts to a message, will block until done.
package chat
import (
	"errors"
	"fmt"
	"io"
	"sort"
	"sync"
	"github.com/shazow/ssh-chat/chat/message"
	"github.com/shazow/ssh-chat/internal/humantime"
	"github.com/shazow/ssh-chat/set"
)
const historyLen = 20
const roomBuffer = 10
var ErrRoomClosed = errors.New("room closed")
var ErrInvalidName = errors.New("invalid name")
type Member struct {
	*message.User
	IsOp bool
	mu      sync.Mutex
	isMuted bool  
}
func (m *Member) IsMuted() bool {
	m.mu.Lock()
	defer m.mu.Unlock()
	return m.isMuted
}
func (m *Member) SetMute(muted bool) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.isMuted = muted
}
type Room struct {
	topic     string
	history   *message.History
	broadcast chan message.Message
	commands  Commands
	closed    bool
	closeOnce sync.Once
	Members *set.Set
}
func NewRoom() *Room {
	broadcast := make(chan message.Message, roomBuffer)
	return &Room{
		broadcast: broadcast,
		history:   message.NewHistory(historyLen),
		commands:  *defaultCommands,
		Members: set.New(),
	}
}
func (r *Room) SetCommands(commands Commands) {
	r.commands = commands
}
func (r *Room) Close() {
	r.closeOnce.Do(func() {
		r.closed = true
		r.Members.Each(func(_ string, item set.Item) error {
			item.Value().(*Member).Close()
			return nil
		})
		r.Members.Clear()
		close(r.broadcast)
	})
}
func (r *Room) SetLogging(out io.Writer) {
	r.history.SetOutput(out)
}