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)
101 -- internal methods {{{
102 -- TODO: is there a better way to do this? also, storing op/voice as initial
103 -- substrings of the username is just ugly
106 -- Add a user to the channel's internal user list.
107 -- @param self Channel object
108 -- @param user Nick of the user to add
109 -- @param mode Mode (op/voice) of the user, in symbolic form (@/+)
110 function _add_user(self, user, mode)
112 self._members[user] = mode .. user
118 -- Remove a user from the channel's internal user list.
119 -- @param self Channel object
120 -- @param user Nick of the user to remove
121 function _remove_user(self, user)
122 self._members[user] = nil
126 -- _change_status {{{
128 -- Change the op/voice status of a user in the channel's internal user list.
129 -- @param self Channel object
130 -- @param user Nick of the user to affect
131 -- @param on True if the mode is being set, false if it's being unset
132 -- @param mode 'o' for op, 'v' for voice
133 function _change_status(self, user, on, mode)
136 self._members[user] = '@' .. user
137 elseif mode == 'v' then
138 self._members[user] = '+' .. user
141 if (mode == 'o' and self._members[user]:sub(1, 1) == '@') or
142 (mode == 'v' and self._members[user]:sub(1, 1) == '+') then
143 self._members[user] = user
151 -- Change the nick of a user in the channel's internal user list.
152 -- @param self Channel object
153 -- @param old_nick User's old nick
154 -- @param new_nick User's new nick
155 function _change_nick(self, old_nick, new_nick)
156 for member in self:each_member() do
157 local member_nick = member:gsub('@+', '')
158 if member_nick == old_nick then
159 local mode = self._members[old_nick]:sub(1, 1)
160 if mode ~= '@' and mode ~= '+' then mode = "" end
161 self._members[old_nick] = nil
162 self._members[new_nick] = mode .. new_nick
172 -- Creates a new Channel object.
173 -- @param chan Name of the new channel
174 -- @return The new channel instance
176 return base.setmetatable({_name = chan, _topic = {}, _chanmode = "",
181 -- public methods {{{
185 -- Iterator over the ops in the channel
186 -- @param self Channel object
187 function each_op(self)
188 return function(state, arg)
189 return misc._value_iter(state, arg,
191 return v:sub(1, 1) == "@"
201 -- Iterator over the voiced users in the channel
202 -- @param self Channel object
203 function each_voice(self)
204 return function(state, arg)
205 return misc._value_iter(state, arg,
207 return v:sub(1, 1) == "+"
217 -- Iterator over the normal users in the channel
218 -- @param self Channel object
219 function each_user(self)
220 return function(state, arg)
221 return misc._value_iter(state, arg,
223 return v:sub(1, 1) ~= "@" and
234 -- Iterator over all users in the channel
235 -- @param self Channel object
236 function each_member(self)
237 return misc._value_iter, self._members, nil
242 -- return tables of users {{{
245 -- Gets an array of all the ops in the channel.
246 -- @param self Channel object
247 -- @return Array of channel ops
250 for nick in self:each_op() do
251 table.insert(ret, nick)
259 -- Gets an array of all the voiced users in the channel.
260 -- @param self Channel object
261 -- @return Array of channel voiced users
262 function voices(self)
264 for nick in self:each_voice() do
265 table.insert(ret, nick)
273 -- Gets an array of all the normal users in the channel.
274 -- @param self Channel object
275 -- @return Array of channel normal users
278 for nick in self:each_user() do
279 table.insert(ret, nick)
287 -- Gets an array of all the users in the channel.
288 -- @param self Channel object
289 -- @return Array of channel users
290 function members(self)
292 -- not just returning self._members, since the return value shouldn't be
294 for nick in self:each_member() do
295 table.insert(ret, nick)
304 -- TODO: hmmm, this probably needs an appropriate mask, rather than a nick
306 -- Ban a user from a channel.
307 -- @param self Channel object
308 -- @param name User to ban
309 function ban(self, name)
310 irc.send("MODE", self.name, "+b", name)
317 -- Remove a ban on a user.
318 -- @param self Channel object
319 -- @param name User to unban
320 function unban(self, name)
321 irc.send("MODE", self.name, "-b", name)
327 -- Give a user voice on a channel.
328 -- @param self Channel object
329 -- @param name User to give voice to
330 function voice(self, name)
331 irc.send("MODE", self.name, "+v", name)
337 -- Remove voice from a user.
338 -- @param self Channel object
339 -- @param name User to remove voice from
340 function devoice(self, name)
341 irc.send("MODE", self.name, "-v", name)
347 -- Give a user ops on a channel.
348 -- @param self Channel object
349 -- @param name User to op
350 function op(self, name)
351 irc.send("MODE", self.name, "+o", name)
357 -- Remove ops from a user.
358 -- @param self Channel object
359 -- @param name User to remove ops from
360 function deop(self, name)
361 irc.send("MODE", self.name, "-o", name)
367 -- Set a channel limit.
368 -- @param self Channel object
369 -- @param new_limit New value for the channel limit (optional; limit is unset
370 -- if this argument isn't passed)
371 function set_limit(self, new_limit)
373 irc.send("MODE", self.name, "+l", new_limit)
375 irc.send("MODE", self.name, "-l")
382 -- Set a channel password.
383 -- @param self Channel object
384 -- @param key New channel password (optional; password is unset if this
385 -- argument isn't passed)
386 function set_key(self, key)
388 irc.send("MODE", self.name, "+k", key)
390 irc.send("MODE", self.name, "-k")
397 -- Set the private state of a channel.
398 -- @param self Channel object
399 -- @param set True to set the channel as private, false to unset it
400 function set_private(self, set)
401 set_basic_mode(self, set, "p")
407 -- Set the secret state of a channel.
408 -- @param self Channel object
409 -- @param set True to set the channel as secret, false to unset it
410 function set_secret(self, set)
411 set_basic_mode(self, set, "s")
415 -- set_invite_only {{{
417 -- Set whether joining the channel requires an invite.
418 -- @param self Channel object
419 -- @param set True to set the channel invite only, false to unset it
420 function set_invite_only(self, set)
421 set_basic_mode(self, set, "i")
425 -- set_topic_lock {{{
427 -- If true, the topic can only be changed by an op.
428 -- @param self Channel object
429 -- @param set True to lock the topic, false to unlock it
430 function set_topic_lock(self, set)
431 set_basic_mode(self, set, "t")
435 -- set_no_outside_messages {{{
437 -- If true, users must be in the channel to send messages to it.
438 -- @param self Channel object
439 -- @param set True to require users to be in the channel to send messages to
440 -- it, false to remove this restriction
441 function set_no_outside_messages(self, set)
442 set_basic_mode(self, set, "n")
448 -- Set whether voice is required to speak.
449 -- @param self Channel object
450 -- @param set True to set the channel as moderated, false to unset it
451 function set_moderated(self, set)
452 set_basic_mode(self, set, "m")
460 -- Test if a user is in the channel.
461 -- @param self Channel object
462 -- @param nick Nick to search for
463 -- @return True if the nick is in the channel, false otherwise
464 function contains(self, nick)
465 for member in self:each_member() do
466 local member_nick = member:gsub('@+', '')
467 if member_nick == nick then