2 -- Implementation of the Channel class
6 local irc = require 'irc'
7 local misc = require 'irc.misc'
8 local socket = require 'socket'
9 local table = require 'table'
13 -- This module implements a channel object representing a single channel we
18 -- object metatable {{{
19 -- TODO: this <br /> shouldn't be necessary - bug in luadoc
21 -- An object of the Channel class represents a single joined channel. It has
22 -- several table fields, and can be used in string contexts (returning the
23 -- channel name).<br />
26 -- @field name Name of the channel (read only)
27 -- @field topic Channel topic, if set (read/write, writing to this sends a
28 -- topic change request to the server for this channel)
29 -- @field chanmode Channel mode (public/private/secret) (read only)
30 -- @field members Array of all members of this channel
33 __index = function(self, key)
36 elseif key == "topic" then
38 elseif key == "chanmode" then
46 __newindex = function(self, key, value)
49 elseif key == "topic" then
50 irc.send("TOPIC", self._name, value)
51 elseif key == "chanmode" then
54 base.rawset(self, key, value)
59 __concat = function(first, second)
60 local first_str, second_str
62 if base.type(first) == "table" then
63 first_str = first._name
67 if base.type(second) == "table" then
68 second_str = second._name
73 return first_str .. second_str
77 __tostring = function(self)
84 -- private methods {{{
87 -- Sets a no-arg mode on a channel.
88 -- @name chan:set_basic_mode
89 -- @param self Channel object
90 -- @param set True to set the mode, false to unset it
91 -- @param letter Letter of the mode
92 local function set_basic_mode(self, set, letter)
94 irc.send("MODE", self.name, "+" .. letter)
96 irc.send("MODE", self.name, "-" .. letter)
104 -- Creates a new Channel object.
105 -- @param chan Name of the new channel
106 -- @return The new channel instance
108 return base.setmetatable({_name = chan, _topic = {}, _chanmode = "",
113 -- public methods {{{
117 -- Iterator over the ops in the channel
118 -- @param self Channel object
119 function each_op(self)
120 return function(state, arg)
121 return misc.value_iter(state, arg,
123 return v:sub(1, 1) == "@"
133 -- Iterator over the voiced users in the channel
134 -- @param self Channel object
135 function each_voice(self)
136 return function(state, arg)
137 return misc.value_iter(state, arg,
139 return v:sub(1, 1) == "+"
149 -- Iterator over the normal users in the channel
150 -- @param self Channel object
151 function each_user(self)
152 return function(state, arg)
153 return misc.value_iter(state, arg,
155 return v:sub(1, 1) ~= "@" and
166 -- Iterator over all users in the channel
167 -- @param self Channel object
168 function each_member(self)
169 return misc.value_iter, self._members, nil
174 -- return tables of users {{{
177 -- Gets an array of all the ops in the channel.
178 -- @param self Channel object
179 -- @return Array of channel ops
182 for nick in self:each_op() do
183 table.insert(ret, nick)
191 -- Gets an array of all the voiced users in the channel.
192 -- @param self Channel object
193 -- @return Array of channel voiced users
194 function voices(self)
196 for nick in self:each_voice() do
197 table.insert(ret, nick)
205 -- Gets an array of all the normal users in the channel.
206 -- @param self Channel object
207 -- @return Array of channel normal users
210 for nick in self:each_user() do
211 table.insert(ret, nick)
219 -- Gets an array of all the users in the channel.
220 -- @param self Channel object
221 -- @return Array of channel users
222 function members(self)
224 -- not just returning self._members, since the return value shouldn't be
226 for nick in self:each_member() do
227 table.insert(ret, nick)
235 -- ban() - ban a user from a channel {{{
236 -- TODO: hmmm, this probably needs an appropriate mask, rather than a nick
237 function ban(self, name)
238 irc.send("MODE", self.name, "+b", name)
242 -- unban() - remove a ban on a user {{{
244 function unban(self, name)
245 irc.send("MODE", self.name, "-b", name)
249 -- voice() - give a user voice on a channel {{{
250 function voice(self, name)
251 irc.send("MODE", self.name, "+v", name)
255 -- devoice() - remove voice from a user {{{
256 function devoice(self, name)
257 irc.send("MODE", self.name, "-v", name)
261 -- op() - give a user ops on a channel {{{
262 function op(self, name)
263 irc.send("MODE", self.name, "+o", name)
267 -- deop() - remove ops from a user {{{
268 function deop(self, name)
269 irc.send("MODE", self.name, "-o", name)
273 -- set_limit() - set a channel limit {{{
274 function set_limit(self, new_limit)
276 irc.send("MODE", self.name, "+l", new_limit)
278 irc.send("MODE", self.name, "-l")
283 -- set_key() - set a channel password {{{
284 function set_key(self, key)
286 irc.send("MODE", self.name, "+k", key)
288 irc.send("MODE", self.name, "-k")
293 -- set_private() - set the private state of a channel {{{
294 function set_private(self, set)
295 set_basic_mode(self, set, "p")
299 -- set_secret() - set the secret state of a channel {{{
300 function set_secret(self, set)
301 set_basic_mode(self, set, "s")
305 -- set_invite_only() - set whether joining the channel requires an invite {{{
306 function set_invite_only(self, set)
307 set_basic_mode(self, set, "i")
311 -- set_topic_lock() - if true, the topic can only be changed by an op {{{
312 function set_topic_lock(self, set)
313 set_basic_mode(self, set, "t")
317 -- set_no_outside_messages() - if true, users must be in the channel to send messages to it {{{
318 function set_no_outside_messages(self, set)
319 set_basic_mode(self, set, "n")
323 -- set moderated() - set whether voice is required to speak {{{
324 function set_moderated(self, set)
325 set_basic_mode(self, set, "m")
332 function add_user(self, user, mode)
334 self._members[user] = mode .. user
339 function remove_user(self, user)
340 self._members[user] = nil
344 -- change_status() {{{
345 function change_status(self, user, on, mode)
348 self._members[user] = '@' .. user
349 elseif mode == 'v' then
350 self._members[user] = '+' .. user
353 if (mode == 'o' and self._members[user]:sub(1, 1) == '@') or
354 (mode == 'v' and self._members[user]:sub(1, 1) == '+') then
355 self._members[user] = user
362 function contains(self, nick)
363 for member in self:each_member() do
364 local member_nick = member:gsub('@+', '')
365 if member_nick == nick then
374 function change_nick(self, old_nick, new_nick)
375 for member in self:each_member() do
376 local member_nick = member:gsub('@+', '')
377 if member_nick == old_nick then
378 local mode = self._members[old_nick]:sub(1, 1)
379 if mode ~= '@' and mode ~= '+' then mode = "" end
380 self._members[old_nick] = nil
381 self._members[new_nick] = mode .. new_nick