Browse Source

Merge pull request #31 from edmund-huber/theater_mode_cleanup

clean up /theater
tags/v0.1.0
Jeremy Latt 10 years ago
parent
commit
ec3fcc9151
8 changed files with 76 additions and 54 deletions
  1. 8
    12
      irc/channel.go
  2. 21
    26
      irc/client.go
  3. 1
    1
      irc/commands.go
  4. 1
    1
      irc/modes.go
  5. 4
    0
      irc/reply.go
  6. 9
    0
      irc/strings.go
  7. 23
    14
      irc/theater.go
  8. 9
    0
      irc/types.go

+ 8
- 12
irc/channel.go View File

6
 )
6
 )
7
 
7
 
8
 type Channel struct {
8
 type Channel struct {
9
-	flags       ChannelModeSet
10
-	lists       map[ChannelMode]*UserMaskSet
11
-	key         Text
12
-	members     MemberSet
13
-	name        Name
14
-	server      *Server
15
-	topic       Text
16
-	userLimit   uint64
17
-	theaterUser *Client
9
+	flags     ChannelModeSet
10
+	lists     map[ChannelMode]*UserMaskSet
11
+	key       Text
12
+	members   MemberSet
13
+	name      Name
14
+	server    *Server
15
+	topic     Text
16
+	userLimit uint64
18
 }
17
 }
19
 
18
 
20
 // NewChannel creates a new channel from a `Server` and a `name`
19
 // NewChannel creates a new channel from a `Server` and a `name`
406
 		return channel.applyModeMember(client, change.mode, change.op,
405
 		return channel.applyModeMember(client, change.mode, change.op,
407
 			NewName(change.arg))
406
 			NewName(change.arg))
408
 
407
 
409
-	case Theater:
410
-		client.ErrConfiguredMode(change.mode)
411
-
412
 	default:
408
 	default:
413
 		client.ErrUnknownMode(change.mode, channel)
409
 		client.ErrUnknownMode(change.mode, channel)
414
 	}
410
 	}

+ 21
- 26
irc/client.go View File

13
 )
13
 )
14
 
14
 
15
 type Client struct {
15
 type Client struct {
16
-	atime           time.Time
17
-	authorized      bool
18
-	awayMessage     Text
19
-	capabilities    CapabilitySet
20
-	capState        CapState
21
-	channels        ChannelSet
22
-	commands        chan Command
23
-	ctime           time.Time
24
-	flags           map[UserMode]bool
25
-	hasQuit         bool
26
-	hops            uint
27
-	hostname        Name
28
-	idleTimer       *time.Timer
29
-	loginTimer      *time.Timer
30
-	nick            Name
31
-	quitTimer       *time.Timer
32
-	realname        Text
33
-	registered      bool
34
-	server          *Server
35
-	socket          *Socket
36
-	username        Name
37
-	theaterChannels []*Channel
16
+	atime        time.Time
17
+	authorized   bool
18
+	awayMessage  Text
19
+	capabilities CapabilitySet
20
+	capState     CapState
21
+	channels     ChannelSet
22
+	commands     chan Command
23
+	ctime        time.Time
24
+	flags        map[UserMode]bool
25
+	hasQuit      bool
26
+	hops         uint
27
+	hostname     Name
28
+	idleTimer    *time.Timer
29
+	loginTimer   *time.Timer
30
+	nick         Name
31
+	quitTimer    *time.Timer
32
+	realname     Text
33
+	registered   bool
34
+	server       *Server
35
+	socket       *Socket
36
+	username     Name
38
 }
37
 }
39
 
38
 
40
 func NewClient(server *Server, conn net.Conn) *Client {
39
 func NewClient(server *Server, conn net.Conn) *Client {
260
 		return
259
 		return
261
 	}
260
 	}
262
 
261
 
263
-	for _, channel := range client.theaterChannels {
264
-		delete(channel.flags, Theater)
265
-	}
266
-
267
 	client.Reply(RplError("connection closed"))
262
 	client.Reply(RplError("connection closed"))
268
 	client.hasQuit = true
263
 	client.hasQuit = true
269
 	client.server.whoWas.Append(client)
264
 	client.server.whoWas.Append(client)

+ 1
- 1
irc/commands.go View File

966
 		return &TheaterActionCommand{
966
 		return &TheaterActionCommand{
967
 			channel: NewName(args[1]),
967
 			channel: NewName(args[1]),
968
 			asNick:  NewName(args[2]),
968
 			asNick:  NewName(args[2]),
969
-			action:  NewText(args[3]),
969
+			action:  NewCTCPText(args[3]),
970
 		}, nil
970
 		}, nil
971
 	} else {
971
 	} else {
972
 		return nil, ErrParseCommand
972
 		return nil, ErrParseCommand

+ 1
- 1
irc/modes.go View File

83
 	Quiet           ChannelMode = 'q' // flag
83
 	Quiet           ChannelMode = 'q' // flag
84
 	ReOp            ChannelMode = 'r' // flag
84
 	ReOp            ChannelMode = 'r' // flag
85
 	Secret          ChannelMode = 's' // flag, deprecated
85
 	Secret          ChannelMode = 's' // flag, deprecated
86
-	Theater         ChannelMode = 'T' // flag arg, nonstandard
86
+	Theater         ChannelMode = 'T' // flag, nonstandard
87
 	UserLimit       ChannelMode = 'l' // flag arg
87
 	UserLimit       ChannelMode = 'l' // flag arg
88
 	Voice           ChannelMode = 'v' // arg
88
 	Voice           ChannelMode = 'v' // arg
89
 )
89
 )

+ 4
- 0
irc/reply.go View File

99
 	return NewStringReply(source, PRIVMSG, "%s :%s", target.Nick(), message)
99
 	return NewStringReply(source, PRIVMSG, "%s :%s", target.Nick(), message)
100
 }
100
 }
101
 
101
 
102
+func RplCTCPAction(source Identifiable, target Identifiable, action CTCPText) string {
103
+	return RplPrivMsg(source, target, NewText(fmt.Sprintf("\x01ACTION %s\x01", action)))
104
+}
105
+
102
 func RplNotice(source Identifiable, target Identifiable, message Text) string {
106
 func RplNotice(source Identifiable, target Identifiable, message Text) string {
103
 	return NewStringReply(source, NOTICE, "%s :%s", target.Nick(), message)
107
 	return NewStringReply(source, NOTICE, "%s :%s", target.Nick(), message)
104
 }
108
 }

+ 9
- 0
irc/strings.go View File

64
 func (text Text) String() string {
64
 func (text Text) String() string {
65
 	return string(text)
65
 	return string(text)
66
 }
66
 }
67
+
68
+// CTCPText is text suitably escaped for CTCP.
69
+type CTCPText string
70
+
71
+var ctcpEscaper = strings.NewReplacer("\x00", "\x200", "\n", "\x20n", "\r", "\x20r")
72
+
73
+func NewCTCPText(str string) CTCPText {
74
+	return CTCPText(ctcpEscaper.Replace(str))
75
+}

+ 23
- 14
irc/theater.go View File

51
 		return
51
 		return
52
 	}
52
 	}
53
 
53
 
54
-	if channel.theaterUser == nil {
55
-		client.theaterChannels = append(client.theaterChannels, channel)
56
-		channel.flags[Theater] = true
57
-		channel.theaterUser = client
54
+	if channel.members.AnyHasMode(Theater) {
55
+		client.Reply(RplNotice(s, client, "someone else is +T in this channel"))
56
+		return
58
 	}
57
 	}
58
+
59
+	channel.members[client][Theater] = true
59
 }
60
 }
60
 
61
 
61
 type TheaterPrivMsgCommand struct {
62
 type TheaterPrivMsgCommand struct {
71
 }
72
 }
72
 func (m *TheaterPrivMsgCommand) HandleServer(s *Server) {
73
 func (m *TheaterPrivMsgCommand) HandleServer(s *Server) {
73
 	client := m.Client()
74
 	client := m.Client()
75
+
74
 	if !m.channel.IsChannel() {
76
 	if !m.channel.IsChannel() {
75
 		client.ErrNoSuchChannel(m.channel)
77
 		client.ErrNoSuchChannel(m.channel)
76
 		return
78
 		return
82
 		return
84
 		return
83
 	}
85
 	}
84
 
86
 
85
-	if channel.theaterUser == client {
86
-		for member := range channel.members {
87
-			member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, m.message))
88
-		}
87
+	if !channel.members.HasMode(client, Theater) {
88
+		client.Reply(RplNotice(s, client, "you are not +T"))
89
+		return
90
+	}
91
+
92
+	for member := range channel.members {
93
+		member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, m.message))
89
 	}
94
 	}
90
 }
95
 }
91
 
96
 
93
 	BaseCommand
98
 	BaseCommand
94
 	channel Name
99
 	channel Name
95
 	asNick  Name
100
 	asNick  Name
96
-	action  Text
101
+	action  CTCPText
97
 }
102
 }
98
 
103
 
99
 func (cmd *TheaterActionCommand) String() string {
104
 func (cmd *TheaterActionCommand) String() string {
102
 
107
 
103
 func (m *TheaterActionCommand) HandleServer(s *Server) {
108
 func (m *TheaterActionCommand) HandleServer(s *Server) {
104
 	client := m.Client()
109
 	client := m.Client()
105
-	if m.channel.IsChannel() {
110
+
111
+	if !m.channel.IsChannel() {
106
 		client.ErrNoSuchChannel(m.channel)
112
 		client.ErrNoSuchChannel(m.channel)
107
 		return
113
 		return
108
 	}
114
 	}
113
 		return
119
 		return
114
 	}
120
 	}
115
 
121
 
116
-	if channel.theaterUser == client {
117
-		for member := range channel.members {
118
-			member.Reply(RplPrivMsg(TheaterClient(m.asNick), channel, NewText(fmt.Sprintf("\001ACTION %s\001", m.action))))
119
-		}
122
+	if !channel.members.HasMode(client, Theater) {
123
+		client.Reply(RplNotice(s, client, "you are not +T"))
124
+		return
125
+	}
126
+
127
+	for member := range channel.members {
128
+		member.Reply(RplCTCPAction(TheaterClient(m.asNick), channel, m.action))
120
 	}
129
 	}
121
 }
130
 }

+ 9
- 0
irc/types.go View File

83
 	return modes[mode]
83
 	return modes[mode]
84
 }
84
 }
85
 
85
 
86
+func (members MemberSet) AnyHasMode(mode ChannelMode) bool {
87
+	for _, modes := range members {
88
+		if modes[mode] {
89
+			return true
90
+		}
91
+	}
92
+	return false
93
+}
94
+
86
 type ChannelSet map[*Channel]bool
95
 type ChannelSet map[*Channel]bool
87
 
96
 
88
 func (channels ChannelSet) Add(channel *Channel) {
97
 func (channels ChannelSet) Add(channel *Channel) {

Loading…
Cancel
Save