summaryrefslogtreecommitdiff
path: root/server/channel/command.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/channel/command.go')
-rw-r--r--server/channel/command.go253
1 files changed, 253 insertions, 0 deletions
diff --git a/server/channel/command.go b/server/channel/command.go
new file mode 100644
index 0000000..94cf38f
--- /dev/null
+++ b/server/channel/command.go
@@ -0,0 +1,253 @@
+package channel
+
+import (
+ "citrons.xyz/talk/server/session"
+ "citrons.xyz/talk/server/user"
+ "citrons.xyz/talk/proto"
+)
+
+func (c *Channel) SendRequest(r session.Request) {
+ switch r.Cmd.Kind {
+
+ case "p":
+ if len(r.Cmd.Args) != 1 {
+ r.ReplyInvalid()
+ return
+ }
+ m := r.Cmd.Args[0]
+ switch m.Kind {
+ case "m":
+ for k, _ := range m.Fields {
+ switch k {
+ case "":
+ default:
+ r.ReplyInvalid()
+ return
+ }
+ }
+ default:
+ r.ReplyInvalid()
+ return
+ }
+
+ if !c.members[r.From.UserId].Put {
+ r.Reply(proto.Fail{"forbidden", "", nil}.Cmd())
+ return
+ }
+
+ m.Fields["f"] = r.From.UserId
+ err := c.Put(m)
+ if err != nil {
+ r.Reply(err.Cmd())
+ return
+ }
+ r.Reply(proto.NewCmd("p", c.id, m))
+
+ case "s":
+ r.From.Subscribe(&c.Stream)
+ r.Reply(proto.NewCmd("i", "", c.GetInfo()))
+
+ case "u":
+ r.From.Unsubscribe(&c.Stream)
+ r.Reply(proto.NewCmd("ok", ""))
+
+ case "join":
+ u := c.store.world.GetObject(r.From.UserId).(*user.User)
+ err := c.Join(u)
+ if err != nil {
+ r.Reply(err.Cmd())
+ } else {
+ r.Reply(proto.NewCmd("ok", ""))
+ }
+
+ case "leave":
+ u := c.store.world.GetObject(r.From.UserId).(*user.User)
+ err := c.Leave(u)
+ if err != nil {
+ r.Reply(err.Cmd())
+ } else {
+ r.Reply(proto.NewCmd("ok", ""))
+ }
+
+ case "delete":
+ if !c.members[r.From.UserId].Op {
+ r.Reply(proto.Fail{"forbidden", "", nil}.Cmd())
+ return
+ }
+ c.Delete()
+
+ case "update":
+ if len(r.Cmd.Args) != 1 {
+ r.ReplyInvalid()
+ return
+ }
+ upd := r.Cmd.Args[0]
+ if upd.Kind != "channel" {
+ r.ReplyInvalid()
+ return
+ }
+ name := c.name
+ for k, v := range upd.Fields {
+ switch k {
+ case "":
+ name = v
+ default:
+ r.ReplyInvalid()
+ return
+ }
+ }
+
+ if !c.members[r.From.UserId].Update {
+ r.Reply(proto.Fail{"forbidden", "", nil}.Cmd())
+ return
+ }
+ if name != c.name {
+ err := c.Rename(name)
+ if err != nil {
+ r.Reply(err.Cmd())
+ return
+ }
+ }
+ c.Stream.Event(r.Cmd)
+ r.Reply(proto.NewCmd("ok", ""))
+
+ case "list":
+ if !c.members[r.From.UserId].Yes {
+ r.Reply(proto.Fail{"forbidden", "", nil}.Cmd())
+ return
+ }
+ cmd := proto.NewCmd("list", c.Id())
+ for m, _ := range c.Members() {
+ u := c.store.world.GetObject(m).(*user.User)
+ cmd.Args = append(cmd.Args, u.GetInfo())
+ }
+ r.Reply(cmd)
+
+ case "history":
+ if len(r.Cmd.Args) != 1 {
+ r.ReplyInvalid()
+ return
+ }
+ h := r.Cmd.Args[0]
+ var min int
+ var max int
+ switch h.Kind {
+ case "latest":
+ max = len(c.messages)
+ min = max - 20
+ case "before", "around", "at":
+ var id string
+ for k, v := range h.Fields {
+ switch k {
+ case "":
+ id = v
+ default:
+ r.ReplyInvalid()
+ return
+ }
+ }
+ i, ok := c.byId[id]
+ if !ok {
+ r.Reply(proto.Fail{"bad-target", "", nil}.Cmd())
+ return
+ }
+ switch h.Kind {
+ case "before":
+ max = i
+ min = max - 20
+ case "around":
+ min = i - 9
+ max = i + 11
+ case "at":
+ min = i
+ max = i + 1
+ }
+ default:
+ r.ReplyInvalid()
+ return
+ }
+ if min < 0 {
+ min = 0
+ }
+ if max > len(c.messages) {
+ max = len(c.messages)
+ }
+
+ p := c.members[r.From.UserId]
+ if !p.History || !p.See {
+ r.Reply(proto.Fail{"forbidden", "", nil}.Cmd())
+ return
+ }
+ cmd := proto.NewCmd("history", c.id)
+ cmd.Args = c.messages[min:max]
+ r.Reply(cmd)
+
+ case "membership":
+ if len(r.Cmd.Args) != 1 {
+ r.ReplyInvalid()
+ return
+ }
+ m := r.Cmd.Args[0]
+ if m.Kind != "u" {
+ r.ReplyInvalid()
+ return
+ }
+
+ if !c.members[r.From.UserId].Yes {
+ r.Reply(proto.Fail{"forbidden", "", nil}.Cmd())
+ return
+ }
+
+ if !c.members[m.Id].Yes {
+ r.Reply(proto.Fail{
+ "not-in-channel", "", map[string]string {"": m.Id},
+ }.Cmd())
+ return
+ }
+ i := c.members[m.Id].GetInfo()
+ i.Fields[""] = m.Id
+ r.Reply(proto.NewCmd("i", "", i))
+
+ case "config":
+ if len(r.Cmd.Args) != 1 {
+ r.ReplyInvalid()
+ return
+ }
+ o := r.Cmd.Args[0]
+ switch o.Kind {
+ case "membership":
+ id := o.Fields[""]
+ if id == "" {
+ r.ReplyInvalid()
+ return
+ }
+ new, err := c.members[id].Change(o)
+ if err != nil {
+ r.Reply(err.Cmd())
+ return
+ }
+
+ if !c.members[r.From.UserId].Op {
+ r.Reply(proto.Fail{"forbidden", "", nil}.Cmd())
+ return
+ }
+ if !c.members[id].Yes {
+ r.Reply(proto.Fail{
+ "not-in-channel", "", map[string]string {"": id},
+ }.Cmd())
+ return
+ }
+ c.members[id] = new
+ c.Put(o)
+
+ i := new.GetInfo()
+ i.Fields[""] = id
+ r.Reply(proto.NewCmd("i", "", i))
+ default:
+ r.ReplyInvalid()
+ }
+
+ default:
+ r.ReplyInvalid()
+ }
+}