def send_message(kind, server, user, target, message): message = colon(message) if target[0] == '#': chan = server.find_chan(target) if not chan: server.send_reply(user, 'ERR_NOSUCHCHANNEL', target) return # it's actually ok to send a message across connections if both # are authenticated and with the same nick user_data = server.chan_nick(chan, user['nick']) if not user_data: server.send_reply(user, 'ERR_NOTONCHANNEL', target) return if 'm' in chan['modes']: modes = user_data['modes'] can_talk = is_op(user_data) or 'v' in modes if not can_talk: server.send_reply(user, 'ERR_CANNOTSENDTOCHAN', chan['name']) return server.send_chan(user, kind, chan, message, others_only=True) else: tags = server.find_nick(target) if not tags: server.send_reply(user, 'ERR_NOSUCHNICK', target) return server.send_command(tags, user, kind, target, message)
def cmd_topic(server, user, chan, topic): if not topic: send_topic(server, user, chan) return user_data = server.chan_nick(chan, user['nick']) if not is_op(user_data): server.send_reply(user, 'ERR_CHANOPRIVSNEEDED', chan['name']) return chan['topic'] = decolon(topic) server.save_chan(chan) server.send_chan(user, 'TOPIC', chan, ':%s' % chan['topic'])
def cmd_kick(server, user, chan, target, message): user_data = server.chan_nick(chan, user['nick']) if not is_op(user_data): server.send_reply(user, 'ERR_CHANOPRIVSNEEDED', chan['name']) return target_data = server.chan_nick(chan, target) if not target_data: server.send_reply(user, 'ERR_USERNOTINCHANNEL', target, chan['name']) return # +o can't kick +q if 'q' not in user_data['modes'] and 'q' in target_data['modes']: server.send_reply(user, 'ERR_CHANOPRIVSNEEDED', chan['name']) return # ok to kick server.send_chan(user, 'KICK', chan, '%s %s' % (target, colon(message))) target_user = server.load_user(target_data['tag']) server.part_chan(target_user, chan)
def mode_chan(server, user, target, args): chan = server.find_chan(target) if not chan: server.send_reply(user, 'ERR_NOSUCHCHANNEL', target) return # parameterless mode: show current modes if not args: server.send_reply(user, 'RPL_CHANNELMODEIS', chan['name'], chan['modes']) return # special case for banlist if args == 'b' or args == '+b': # users should use ACCESS instead server.send_reply(user, 'RPL_ENDOFBANLIST', chan['name']) return # all modes require op status user_data = server.chan_nick(chan, user['nick']) if not is_op(user_data): server.send_reply(user, 'ERR_CHANOPRIVSNEEDED', chan['name']) return chars, rest = split(args, 1) adding = True for c in chars: if c in '+-': adding = c == '+' # op/voice elif c in 'qov': target, rest = split(rest, 1) if not target: # no target supplied continue # only owners are allowed to +q/-q if c == 'q' and 'q' not in user_data['modes']: continue target_data = server.chan_nick(chan, target) if target_data is None: server.send_reply( user, 'ERR_USERNOTINCHANNEL', target, chan['name']) continue target_modes = target_data['modes'] # check if it's necessary to add or remove the mode if not ((c in target_modes) ^ adding): continue if adding: target_modes += c else: target_modes = target_modes.replace(c, '') target_data['modes'] = target_modes server.set_chan_nick(chan, target, target_data) args = '%s%s %s' % ('+' if adding else '-', c, target) server.send_chan(user, 'MODE', chan, args) elif c in 'm': chan_modes = chan['modes'] if not ((c in chan_modes) ^ adding): continue if adding: chan_modes += c else: chan_modes = chan_modes.replace(c, '') chan['modes'] = chan_modes server.save_chan(chan) args = '%s%s' % ('+' if adding else '-', c) server.send_chan(user, 'MODE', chan, args) else: server.send_reply(user, 'ERR_UNKNOWNMODE', c)
def cmd_access(server, user, chan, action, level, mask, timeout, reason): user_data = server.chan_nick(chan, user['nick']) if not is_op(user_data): server.send_reply(user, 'ERR_CHANOPRIVSNEEDED', chan['name']) return action = action.upper() level = level.upper() if level not in levels: server.send_reply(user, 'ERR_BADLEVEL', 'ACCESS') return is_owner_ = is_owner(user_data) if action in ['ADD', 'DELETE', 'CLEAR']: if level == 'OWNER' and not is_owner_: server.send_reply(user, 'ERR_NOACCESS', 'ACCESS') return if action == 'ADD': if not mask: server.send_reply(user, 'ERR_NEEDMOREPARAMS', 'ACCESS') return mask = parse_mask(mask) timeout = parse_timeout(timeout) reason = decolon(reason) server.access_list_add(chan, level, mask, timeout, user, reason) timeout = timeout_minutes(timeout) server.send_reply(user, 'RPL_ACCESSADD', chan['name'], level, mask, timeout, user['id'], reason) elif action == 'DELETE': mask = parse_mask(mask) server.access_list_del(chan, level, mask) server.send_reply(user, 'RPL_ACCESSDELETE', chan['name'], level, mask) elif action == 'CLEAR': for level_, mask, _, _, _ in get_access_list(server, chan): if level and level != level_: continue if level_ == 'OWNER' and not is_owner_: continue server.access_list_del(chan, level_, mask) server.send_reply(user, 'RPL_ACCESSCLEAR', chan['name'], level) elif action == 'LIST': server.send_reply(user, 'RPL_ACCESSSTART', chan['name']) acl = get_access_list(server, chan) for level_, mask, timeout, userid, reason in acl: if level and level != level_: continue timeout = timeout_minutes(timeout) server.send_reply(user, 'RPL_ACCESSLIST', chan['name'], level_, mask, timeout, userid, reason) server.send_reply(user, 'RPL_ACCESSEND', chan['name']) else: server.send_reply(user, 'ERR_BADCOMMAND', 'ACCESS') return
def cmd_access(server, user, chan, action, level, mask, timeout, reason): user_data = server.chan_nick(chan, user['nick']) if not is_op(user_data): server.send_reply(user, 'ERR_CHANOPRIVSNEEDED', chan['name']) return action = action.upper() level = level.upper() if level not in levels: server.send_reply(user, 'ERR_BADLEVEL', 'ACCESS') return is_owner_ = is_owner(user_data) if action in ['ADD', 'DELETE', 'CLEAR']: if level == 'OWNER' and not is_owner_: server.send_reply(user, 'ERR_NOACCESS', 'ACCESS') return if action == 'ADD': if not mask: server.send_reply(user, 'ERR_NEEDMOREPARAMS', 'ACCESS') return if server.access_list_count(chan) >= server.config.max_acl_entries: server.send_reply(user, 'ERR_TOOMANYACCESSES') return mask = parse_mask(mask) timeout = parse_timeout(timeout) reason = decolon(reason) server.access_list_add(chan, level, mask, timeout, user, reason) timeout = timeout_minutes(timeout) server.send_reply(user, 'RPL_ACCESSADD', chan['name'], level, mask, timeout, user['id'], reason) elif action == 'DELETE': mask = parse_mask(mask) server.access_list_del(chan, level, mask) server.send_reply(user, 'RPL_ACCESSDELETE', chan['name'], level, mask) elif action == 'CLEAR': for level_, mask, _, _, _ in get_access_list(server, chan): if level and level != level_: continue if level_ == 'OWNER' and not is_owner_: continue server.access_list_del(chan, level_, mask) server.send_reply(user, 'RPL_ACCESSCLEAR', chan['name'], level) elif action == 'LIST': server.send_reply(user, 'RPL_ACCESSSTART', chan['name']) acl = get_access_list(server, chan) for level_, mask, timeout, userid, reason in acl: if level and level != level_: continue timeout = timeout_minutes(timeout) server.send_reply(user, 'RPL_ACCESSLIST', chan['name'], level_, mask, timeout, userid, reason) server.send_reply(user, 'RPL_ACCESSEND', chan['name']) else: server.send_reply(user, 'ERR_BADCOMMAND', 'ACCESS') return