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
17 -- object metatable {{{
18 -- TODO: this <br /> shouldn't be necessary - bug in luadoc
20 -- An object of the Channel class represents a single joined channel. It has
21 -- several table fields, and can be used in string contexts (returning the
22 -- channel name).<br />
25 -- @field name Name of the channel (read only)
26 -- @field topic Channel topic, if set (read/write, writing to this sends a
27 -- topic change request to the server for this channel)
28 -- @field chanmode Channel mode (public/private/secret) (read only)
29 -- @field members Array of all members of this channel
32 __index = function(self, key)
35 elseif key == "topic" then
37 elseif key == "chanmode" then
45 __newindex = function(self, key, value)
48 elseif key == "topic" then
49 irc.send("TOPIC", self._name, value)
50 elseif key == "chanmode" then
53 base.rawset(self, key, value)
58 __concat = function(first, second)
59 local first_str, second_str
61 if base.type(first) == "table" then
62 first_str = first._name
66 if base.type(second) == "table" then
67 second_str = second._name
72 return first_str .. second_str
76 __tostring = function(self)
83 -- private methods {{{
86 -- Sets a no-arg mode on a channel.
87 -- @name chan:set_basic_mode
88 -- @param self Channel object
89 -- @param set True to set the mode, false to unset it
90 -- @param letter Letter of the mode
91 local function set_basic_mode(self, set, letter)
93 irc.send("MODE", self.name, "+" .. letter)
95 irc.send("MODE", self.name, "-" .. letter)
103 -- Creates a new Channel object.
104 -- @param chan Name of the new channel
105 -- @return The new channel instance
107 return base.setmetatable({_name = chan, _topic = {}, _chanmode = "",
112 -- public methods {{{
116 -- Iterator over the ops in the channel
117 -- @param self Channel object
118 function each_op(self)
119 return function(state, arg)
120 return misc.value_iter(state, arg,
122 return v:sub(1, 1) == "@"
132 -- Iterator over the voiced users in the channel
133 -- @param self Channel object
134 function each_voice(self)
135 return function(state, arg)
136 return misc.value_iter(state, arg,
138 return v:sub(1, 1) == "+"
148 -- Iterator over the normal users in the channel
149 -- @param self Channel object
150 function each_user(self)
151 return function(state, arg)
152 return misc.value_iter(state, arg,
154 return v:sub(1, 1) ~= "@" and
165 -- Iterator over all users in the channel
166 -- @param self Channel object
167 function each_member(self)
168 return misc.value_iter, self._members, nil
173 -- return tables of users {{{
176 -- Gets an array of all the ops in the channel.
177 -- @param self Channel object
178 -- @return Array of channel ops
181 for nick in self:each_op() do
182 table.insert(ret, nick)
190 -- Gets an array of all the voiced users in the channel.
191 -- @param self Channel object
192 -- @return Array of channel voiced users
193 function voices(self)
195 for nick in self:each_voice() do
196 table.insert(ret, nick)
204 -- Gets an array of all the normal users in the channel.
205 -- @param self Channel object
206 -- @return Array of channel normal users
209 for nick in self:each_user() do
210 table.insert(ret, nick)
218 -- Gets an array of all the users in the channel.
219 -- @param self Channel object
220 -- @return Array of channel users
221 function members(self)
223 -- not just returning self._members, since the return value shouldn't be
225 for nick in self:each_member() do
226 table.insert(ret, nick)
235 -- TODO: hmmm, this probably needs an appropriate mask, rather than a nick
237 -- Ban a user from a channel.
238 -- @param self Channel object
239 -- @param name User to ban
240 function ban(self, name)
241 irc.send("MODE", self.name, "+b", name)
248 -- Remove a ban on a user.
249 -- @param self Channel object
250 -- @param name User to unban
251 function unban(self, name)
252 irc.send("MODE", self.name, "-b", name)
258 -- Give a user voice on a channel.
259 -- @param self Channel object
260 -- @param name User to give voice to
261 function voice(self, name)
262 irc.send("MODE", self.name, "+v", name)
268 -- Remove voice from a user.
269 -- @param self Channel object
270 -- @param name User to remove voice from
271 function devoice(self, name)
272 irc.send("MODE", self.name, "-v", name)
278 -- Give a user ops on a channel.
279 -- @param self Channel object
280 -- @param name User to op
281 function op(self, name)
282 irc.send("MODE", self.name, "+o", name)
288 -- Remove ops from a user.
289 -- @param self Channel object
290 -- @param name User to remove ops from
291 function deop(self, name)
292 irc.send("MODE", self.name, "-o", name)
298 -- Set a channel limit.
299 -- @param self Channel object
300 -- @param new_limit New value for the channel limit (optional; limit is unset
301 -- if this argument isn't passed)
302 function set_limit(self, new_limit)
304 irc.send("MODE", self.name, "+l", new_limit)
306 irc.send("MODE", self.name, "-l")
313 -- Set a channel password.
314 -- @param self Channel object
315 -- @param key New channel password (optional; password is unset if this
316 -- argument isn't passed)
317 function set_key(self, key)
319 irc.send("MODE", self.name, "+k", key)
321 irc.send("MODE", self.name, "-k")
328 -- Set the private state of a channel.
329 -- @param self Channel object
330 -- @param set True to set the channel as private, false to unset it
331 function set_private(self, set)
332 set_basic_mode(self, set, "p")
338 -- Set the secret state of a channel.
339 -- @param self Channel object
340 -- @param set True to set the channel as secret, false to unset it
341 function set_secret(self, set)
342 set_basic_mode(self, set, "s")
346 -- set_invite_only {{{
348 -- Set whether joining the channel requires an invite.
349 -- @param self Channel object
350 -- @param set True to set the channel invite only, false to unset it
351 function set_invite_only(self, set)
352 set_basic_mode(self, set, "i")
356 -- set_topic_lock {{{
358 -- If true, the topic can only be changed by an op.
359 -- @param self Channel object
360 -- @param set True to lock the topic, false to unlock it
361 function set_topic_lock(self, set)
362 set_basic_mode(self, set, "t")
366 -- set_no_outside_messages {{{
368 -- If true, users must be in the channel to send messages to it.
369 -- @param self Channel object
370 -- @param set True to require users to be in the channel to send messages to
371 -- it, false to remove this restriction
372 function set_no_outside_messages(self, set)
373 set_basic_mode(self, set, "n")
379 -- Set whether voice is required to speak.
380 -- @param self Channel object
381 -- @param set True to set the channel as moderated, false to unset it
382 function set_moderated(self, set)
383 set_basic_mode(self, set, "m")
391 -- Test if a user is in the channel.
392 -- @param self Channel object
393 -- @param nick Nick to search for
394 -- @return True if the nick is in the channel, false otherwise
395 function contains(self, nick)
396 for member in self:each_member() do
397 local member_nick = member:gsub('@+', '')
398 if member_nick == nick then
406 -- TODO: these four need to be made private at minimum (they are here for the
407 -- main irc module to access things), but they really should probably be
408 -- refactored out or something. definitely shouldn't be part of the public
411 function add_user(self, user, mode)
413 self._members[user] = mode .. user
418 function remove_user(self, user)
419 self._members[user] = nil
423 -- change_status() {{{
424 function change_status(self, user, on, mode)
427 self._members[user] = '@' .. user
428 elseif mode == 'v' then
429 self._members[user] = '+' .. user
432 if (mode == 'o' and self._members[user]:sub(1, 1) == '@') or
433 (mode == 'v' and self._members[user]:sub(1, 1) == '+') then
434 self._members[user] = user
441 function change_nick(self, old_nick, new_nick)
442 for member in self:each_member() do
443 local member_nick = member:gsub('@+', '')
444 if member_nick == old_nick then
445 local mode = self._members[old_nick]:sub(1, 1)
446 if mode ~= '@' and mode ~= '+' then mode = "" end
447 self._members[old_nick] = nil
448 self._members[new_nick] = mode .. new_nick