def join(bot, id, chans, *args): for chan in chans.split(','): yield sign('SOME_JOIN', bot, id, chan) if (id.nick.lower() == bot.nick.lower()): yield sign('SELF_JOIN', bot, chan) else: yield sign('OTHER_JOIN', bot, id, chan)
def h_command(bot, id, target, event, body, full_msg, action): bot.activity = False #================================================================= # (This should be in bridge.py.) s_event = ('SIMPLE', 'ACTION', event) if action else \ ('SIMPLE', event) no_echo = [False] replies = [] def cmd_reply(rmsg=None, from_name=None, no_bridge=False, **kwds): if rmsg is not None or from_name is not None: if rmsg is None: rmsg = from_name(id.nick) replies.append(((bot, id, target, rmsg), kwds)) no_echo[0] = no_echo[0] or no_bridge yield sign(s_event, bot, id.nick, target, body, cmd_reply) if not no_echo[0]: cmsg = ('* %s %s' if action else '<%s> %s') % (id.nick, full_msg) yield sign('IRC', bot, target, cmsg) for rargs, rkwds in replies: reply(*rargs, **rkwds) #================================================================= if limit.mark_activity(bot, id, notify=target): return if action: event = ('ACTION', event) yield sign(event, bot, id, target, body, full_msg) if bot.activity: return yield sign('CMD_IGNORED', event, bot, id, target, body, full_msg)
def nick(bot, id, new_nick, *args): if id.nick.lower() == bot.nick.lower(): yield sign('SELF_NICK', bot, new_nick) bot.nick = new_nick else: yield sign('OTHER_NICK', bot, id, new_nick) yield sign('SOME_NICK', bot, id, new_nick)
def h_general(bot, *args, **kwds): e, id = kwds['e'], kwds['a'](*args) for chan, names in track_channels.iteritems(): if id and id.nick.lower() not in map(str.lower, names): continue eargs = args + (chan,) yield sign(e, bot, *eargs) yield sign(e + '_FINAL', bot, *eargs)
def kicked(bot, op_id, chan, other_nick, msg=None, *args): yield sign('SOME_KICKED', bot, other_nick, op_id, chan, msg) if (other_nick.lower() == bot.nick.lower()): yield sign('SELF_KICKED', bot, chan, op_id, msg) yield sign('SELF_KICKED_FINAL', bot, chan, op_id, msg) else: yield sign('OTHER_KICKED', bot, other_nick, op_id, chan, msg) yield sign('OTHER_KICKED_FINAL', bot, other_nick, op_id, chan, msg)
def privmsg(bot, source, target, msg, *args): if target.lower() == bot.nick.lower(): target = None if isinstance(source, tuple): bot.activity = False yield sign('MESSAGE', bot, source, target, msg) if bot.activity: return yield sign('MESSAGE_IGNORED', bot, source, target, msg) elif isinstance(source, str): yield sign('SMESSAGE', bot, source, target, msg)
def part(bot, id, chans, msg=None, *args): for chan in chans.split(','): yield sign('SOME_PART', bot, id, chan, msg) if (id.nick.lower() == bot.nick.lower()): yield sign('SELF_PART', bot, chan, msg) yield sign('SELF_PART_FINAL', bot, chan, msg) else: yield sign('OTHER_PART', bot, id, chan, msg) yield sign('OTHER_PART_FINAL', bot, id, chan, msg)
def privmsg(bot, nick, user, host, target, msg, *args): # msg = re.sub('^:', '', msg) # not needed since xirclib updated if target == bot.nick: target = None id = ID(nick, user, host) yield sign("MESSAGE", bot, id, target, msg) yield sign(("MESSAGE", target), bot, id, msg) match = re.match("(?P<cmd>!\S+)\s*(?P<arg>.*)$", msg) if match: cmd, arg = match.group("cmd", "arg") yield sign(cmd, bot, id, target, arg) yield sign((cmd, target), bot, id, arg)
def h_buffer(work, data): if work.terraria_protocol.version_number > 155: while len(data) > 2: length, type = struct.unpack('<hB', data[:3]) if len(data) < length: break yield sign('MESSAGE', work, type, data[:length][3:]) data = data[length:] else: while len(data) > 4: length, type = struct.unpack('<iB', data[:5]) if len(data) < length + 4: break yield sign('MESSAGE', work, type, data[4:][1:length]) data = data[4:][length:] work.stack = data
def h_url(bot, id, target, args, full_msg, reply): channel = (target or ('%s!%s@%s' % id)).lower() if args: dice = sys.modules.get('dice') match = re.match(r'!r(oll)?\s+(?P<args>.*)', args) if match and dice and bot in dice.link.installed_modes: args = match.group('args') args = dice.roll(bot, id, target, args, error_reply=reply) if args is None: return reply(args) urls = url_collect.extract_urls(args) yield sign('URL_CMD_URLS', bot, urls, target, id, full_msg) elif url_collect.history[channel]: urls = url_collect.history[channel].pop(-1) else: urls = None if not urls: reply('No URL found.') return for url in urls: try: result = get_title_proxy(url) reply(result['title']) # Generate a URL-suppressed proxy message for the basic component. btitle = result['title_bare'] p_target = '%s!%s@%s' % id if target is None else target if isinstance(btitle, unicode): btitle = btitle.encode('utf-8') yield later(sign('PROXY_MSG', bot, None, p_target, btitle, no_url=True)) if result.get('proxy'): # Generate a quiet proxy message for the parenthetical component. pmsg, fmsg = result['proxy'], result['proxy_full'] if isinstance(pmsg, unicode): pmsg = pmsg.encode('utf-8') if isinstance(fmsg, unicode): fmsg = fmsg.encode('utf-8') yield later(sign('PROXY_MSG', bot, None, p_target, pmsg, full_msg=fmsg, quiet=True, no_url=True)) yield runtime.sleep(0.01) except Exception as e: traceback.print_exc() url, is_nsfw = url_collect.url_nsfw(url) reply('Error: %s [%s%s]' % (e, abbrev_url(url), ' \2NSFW\2' if is_nsfw else ''))
def h_help(bot, name, target, args, reply, bridge): lines = [] callback = lambda *args: lines.append(args) def header(str): return '\2%s%s\2' % ('!' if bot.conf['bang_cmd'] else '', str) if args: # Display help for a particular command. cmd, args = re.match(r'!?(\S+)\s*(.*)', args).groups() cmd = cmd.lower() yield sign(('BRIDGE', 'HELP', cmd) if bridge else ('HELP', cmd), bot, callback, args) if not lines: reply('Error: no help is available for "%s".' % cmd, no_bridge=True) return for line in lines: if line[0]: reply(header(line[0]), prefix=False, no_bridge=True) for para in line[1:]: if para: reply(para, prefix=False, no_bridge=True) elif not bridge: # Display general help and a summary of all commands. reply( 'Commands are issued by saying%s "%s: !COMMAND",' ' where COMMAND is the command and its parameters.' ' The following commands are available:' % (' "!COMMAND" or' if bot.conf['bang_cmd'] else '', bot.nick), prefix=False, no_bridge=True) yield sign('HELP*', bot, callback, args) lines = map(lambda l: (header(l[0]),) + l[1:], lines) for line in util.align_table(lines): reply(line, prefix=False, no_bridge=True) del lines[:] yield sign('HELP', bot, callback, args) if lines: reply('Other commands: %s.' % ', '.join( '\2%s\2' % l[0].split()[0] for l in lines), prefix=False, no_bridge=True) else: yield sign(('BRIDGE', 'HELP*'), bot, callback, args) yield sign(('BRIDGE', 'HELP'), bot, callback, args) if lines: reply('Available commands: %s.' % ', '.join( '\2%s\2' % l[0].split()[0] for l in lines), prefix=False, no_bridge=True)
def te_chat(work, slot, colour, text): no_echo = [False] echo_lines = [] event_type = None agent = work.terraria.user if slot == 255: match = re.match(r'((?P<sn>\[\S+\])|\*(?P<an>\S+))\s*(?P<m>.*)', text) if match: event_type = 'MESSAGE' if match.group('sn') else 'ACTION' event_name = match.group('sn') or match.group('an') event_text = match.group('m') else: event_type = 'MESSAGE' event_name = work.terraria_protocol.players.get(slot, slot) event_text = text if event_type is not None: reply = bridge.substitute_reply( context = work.terraria.name, local_name = event_name, msg_local = lambda m: terraria_protocol.chat(work, strip_codes(m)), msg_bridge = lambda m: echo_lines.append('<%s> %s' % (agent, m)), cancel_bridge = lambda: operator.setitem(no_echo, 0, True)) yield util.msign(ab_mode, ('BRIDGE', event_type), ab_mode, event_name, work.terraria.name, event_text, reply) if not no_echo[0] and slot != work.terraria_protocol.slot: if slot != 255: text = '<%s> %s' % (name, text) echo_lines.insert(0, text) for line in echo_lines: line = bridge.substitute_text(work.terraria.name, line) yield sign('TERRARIA', work, line)
def message(bot, id, target, msg): while True: match = re.match(r'\x01ACTION (.*?)\x01?$', msg) if match: msg = match.group(1) action = True else: action = False # !CMD [ARGS...] if bot.conf['bang_cmd']: match = re.match(r'!(?P<head>\S*)\s*(?P<body>.*)', msg) if match: break # NICK: !CMD [ARGS...] match = re.match(r'(?P<addr>\S+):\s*!(?P<head>\S*)\s*(?P<body>.*)', msg) if match and match.group('addr').lower() == bot.nick.lower(): break return event = '!' + match.group('head').lower() body = match.group('body').strip() type = 'ACTION_COMMAND' if action else 'COMMAND' yield sign(type, bot, id, target, event, body, msg) bot.activity = True from untwisted.usual import Stop raise Stop
def refresh(self, bot): try: quotes, title = self.quotes_title() url_state = state.get(self.index_url, {}) chan_state = url_state.get(self.channel.lower(), {}) last_quote = chan_state.get('last_quote') quotes = sorted( (qid, quote) for (qid, quote) in quotes if qid > last_quote) sample = quotes if len(quotes) <= MAX_REPORT else \ quotes[:MAX_REPORT-1] for qid, quote in sample: quote_url = '%s?%s' % (self.remote_index_url, qid) fquote = format_quote(quote) msg = '%s: new quote added: %s "%s"' % (title, quote_url, fquote) bot.send_msg(self.channel, msg) yield later(sign('PROXY_MSG', bot, None, self.channel, fquote, quiet=True)) if len(quotes) > len(sample): msg = '%s: ...and %d others. See: <%s>.' % ( title, len(quotes)-len(sample), self.remote_index_url) bot.send_msg(self.channel, msg) if quotes: last_quote = max( last_quote, max(qid for (qid, quote) in quotes)) chan_state['last_quote'] = last_quote url_state[self.channel.lower()] = chan_state state[self.index_url] = url_state write_state(state) except: traceback.print_exc()
def refresh(self, bot): try: quotes = self.quotes() if not quotes: return url_state = state.get(self.admin_url, {}) name_state = url_state.get(self.access_name.lower(), {}) last_quote = name_state.get('last_quote') nicks = yield identity.enum_access(bot, self.access_name) if not nicks: return for nick in nicks: for qid, quote in sorted(quotes): if qid > last_quote: fquote = format_quote(quote) msg = '[QdbS] New quote #%d <%s>: "%s"' % ( qid, self.remote_admin_url, fquote) if type(msg) is unicode: msg = msg.encode('utf8') bot.send_msg(nick, msg) hm = yield identity.get_hostmask(bot, nick) yield later(sign('PROXY_MSG', bot, None, hm, fquote, quiet=True)) last_quote = max( last_quote, max(qid for (qid, quote) in quotes)) name_state['last_quote'] = last_quote url_state[self.access_name.lower()] = name_state state[self.admin_url] = url_state write_state(state) except: traceback.print_exc()
def h_bridge(bot, target_chan, msg, source, no_proxy=False, **kwds): if not target_chan.startswith('#'): return bot.send_msg(target_chan, msg, no_bridge=True) if isinstance(msg, unicode): msg = msg.encode('utf-8') if not no_proxy: yield later(sign('PROXY_MSG', bot, None, target_chan, msg, no_auto = source.startswith('#')))
def h_names(bot, chan, include_prefix): if chan.lower() in track_channels and chan.lower() in umode_channels: # Return the cached names if they exist. nicks = track_channels[chan.lower()] umode = umode_channels[chan.lower()] else: # Otherwise, retrieves the names from the server. bot.send_cmd('NAMES %s' % chan) while True: event, data = yield hold(bot, 'NAMES_SYNC') e_bot, e_chan, nicks, umode = data if e_chan.lower() == chan.lower(): break # Reconstruct the nick prefixes from the nicks and their modes. pre_ms, pre_cs = bot.isupport['PREFIX'] names = [] for nick in nicks: for pre_m, pre_c in izip(pre_ms, pre_cs): if pre_m in umode.get(nick.lower(), ''): prefix, sort_key = pre_c, (-pre_cs.index(pre_c), nick.lower()) break else: prefix, sort_key = '', (None, nick.lower()) names.append((sort_key, prefix+nick if include_prefix else nick)) names = [n for (_,n) in sorted(names, reverse=True)] yield sign(('channel.names', bot, chan, include_prefix), names)
def h_names(bot, chan, new_names): chan = chan.lower() track_names = track_channels[chan] umode_names = umode_channels[chan] pre_ms, pre_cs = bot.isupport['PREFIX'] for prefix, nick in (split_name(bot,n) for n in new_names): # Update track_channels if nick.lower() not in map(str.lower, track_names): track_names.append(nick) elif nick not in track_names: track_names = [n for n in track_names if n.lower() != nick.lower()] track_names.append(nick) # Update umode_channels if len(prefix)==1 and nick.lower() in umode_names and prefix in pre_cs: # Add the mode and remove all known higher modes. i = pre_cs.index(prefix) umode_names[nick.lower()] = pre_ms[i] + ''.join( m for m in umode_names[nick.lower()] if m not in pre_ms[:i]) else: # Set to exactly the given modes. umode_names[nick.lower()] = ''.join( m for c in prefix if c in pre_cs for i in [pre_cs.index(c)] for m in pre_ms[i:i+1]) track_channels[chan] = track_names umode_channels[chan] = umode_names yield sign('NAMES_SYNC', bot, chan, track_names, umode_names)
def h_message(work, head, body): if head == 0x02: yield sign('DISCONNECT', work, body) elif head == 0x03: slot, = struct.unpack('<B', body[:1]) yield sign('CONNECTION_APPROVED', work, slot) elif head == 0x04: slot, = struct.unpack('<B', body[:1]) if work.terraria_protocol.version_number < 156: name = body[25:] else: name = unpack_string(work, body[3:]) yield sign('PLAYER_APPEARANCE', work, slot, name) elif head == 0x09: count, = struct.unpack('<i', body[:4]) text = unpack_string(work, body[4:]) yield sign('STATUSBAR_TEXT', work, count, text) elif head == 0x0E: slot, active = struct.unpack('<B?', body) yield sign('SET_PLAYER_ACTIVITY', work, slot, active) # elif head == 0x0D: # slot, cflags, islot, x,y, dx,dy, flags \ # = struct.unpack('<BBBffffB', body) # yield sign('PLAYER_CONTROL', work, slot, (x, y)) elif head == 0x19: slot, = struct.unpack('<B', body[:1]) colour = struct.unpack('<BBB', body[1:4]) text = unpack_string(work, body[4:]) yield sign('CHAT', work, slot, colour, text) elif head == 0x31: yield sign('SPAWN', work) elif head == 0x07: if work.terraria_protocol.version_number < 69: spawn = struct.unpack('<ii', body[15:23]) world_name = body[36:] elif work.terraria_protocol.version_number < 156: spawn = struct.unpack('<ii', body[16:24]) world_name = body[91:] else: spawn = struct.unpack('<hh', body[10:14]) world_name = unpack_string(work, body[22:]) yield sign('WORLD_INFORMATION', work, spawn, world_name) elif head == 0x25: yield sign('REQUEST_PASSWORD', work) elif head not in (0x0a, 0x14, 0x17, 0x1a, 0x1b, 0x1c, 0x1d): yield sign('UNKNOWN', work, '$%02X' % head, body)
def kakasi(bot, id, target, msg, prefix=True, auto=False, **kwds): if auto and not kakasi_lib.is_ja(msg): return raw_reply = kakasi_lib.kakasi(msg) if auto and len(raw_reply) > 200: return reply = ('<%s> %s' % (id.nick, raw_reply)) if prefix and id else raw_reply bot.send_msg(target, reply) bot.drive('runtime.later', sign( 'PROXY_MSG', bot, id, target, raw_reply, **dict(kwds, no_kakasi=True)))
def h_msg(bot, source, msg, source_name=None): if source is None: return if type(msg) is unicode: msg = msg.encode('utf8') for source, target in targets(source): name = source_name or source yield sign('BRIDGE', bot, target, '%s: %s' % (name, msg))
def nickserv_notice(bot, id, msg): if conf('prompt') and conf('password') and msg.startswith(conf('prompt')): bot.send_msg(id.nick, 'IDENTIFY %s' % conf('password')) return final = conf('final') if final and msg.startswith(final): yield sign('NICKSERV_REGISTERED', bot) return
def tick(bot): global ping_sent elapsed = time.time() - last_ping if elapsed > bot.conf['timeout']/2 and not ping_sent: bot.dump('PING :%s\r\n' % bot.nick) ping_sent = True elif elapsed > bot.conf['timeout']: print '! ping timeout: %ss' % elapsed yield sign(CLOSE, bot)
def h_message(*args, **kwds): bot, nick, chan, msg = kwds['a'](*args) if chan is None: return match = re.match(r'\x01ACTION (?P<msg>.*)', msg) if match: cmsg = '* %s %s' % (nick, match.group('msg')) else: cmsg = '<%s> %s' % (nick, msg) yield sign('IRC', bot, chan, cmsg)
def notice(bot, id, target, msg): if target is not None: return if not conf('nickserv'): return nickserv = conf('nickserv') if id.nick.lower() != nickserv.nick.lower(): return if (id.user, id.host) != (nickserv.user, nickserv.host): raise Exception('%s is %s@%s; %s@%s expected.' % (id.nick, id.user, id.host, nickserv.user, nickserv.host)) yield sign('NICKSERV_NOTICE', bot, id, msg)
def further_fun(bot, id, target, args, full_msg): match = re.search(r'(?P<cmd>!\S+)\s*(?P<args>.*)', args) if match: scmd = match.group('cmd') sargs = match.group('args') args = args[:match.start()] cont = sign('COMMAND', bot, id, target, scmd, sargs, full_msg) return func(bot, id, target, args, full_msg, cont) else: return func(bot, id, target, args, full_msg, lambda *args: None)
def examine_message(bot, id, source, message, full_msg=None): if isinstance(source, tuple): source = '%s!%s@%s' % source source = source.lower() urls = extract_urls(message, full_msg=full_msg) if not urls: return history[source].append(urls) del history[source][:-HISTORY_SIZE] yield sign('URL_COLLECT_URLS', bot, urls, source, id, message)
def further_fun(bot, id, target, args, full_msg): match = re.search(r'(^|(?<=\s))(?P<cmd>!\S+)\s*(?P<args>.*)', args) if match: scmd = match.group('cmd').lower() if scmd in bot._base or ('SIMPLE', scmd) in bot._base: sargs = match.group('args') args = args[:match.start()] cont = sign('COMMAND', bot, id, target, scmd, sargs, full_msg) return func(bot, id, target, args, full_msg, cont) return func(bot, id, target, args, full_msg, lambda *args: None)
def h_spawn(work): if not hasattr(work, 'terraria_protocol'): return if work.terraria_protocol.stage != 2: return work.terraria_protocol.stage = 3 spawn = (0, 9999) send_spawn_player(work, work.terraria_protocol.slot, *spawn) for text in work.terraria_protocol.chat_queue: chat(work, text) work.terraria_protocol.chat_queue = [] yield sign('HEARTBEAT', work)
def h_message(*args, **kwds): bot, nick, id, chan, msg = kwds['a'](*args) if not chan or chan.lower() not in links: return chan = channel.capitalisation.get(chan.lower(), chan) p_nick = channel.prefix_nick(bot, nick, chan) match = re.match(r'\x01ACTION (?P<act>.*?)\x01?$', msg) msg = '%s: * %s %s' % (chan, nick, match.group('act')) if match else \ '%s: <%s> %s' % (chan, p_nick, msg) for lchan in links[chan.lower()]: bot.send_msg(lchan, msg, no_link=True) if id is not None: yield sign('PROXY_MSG', bot, id, lchan, msg, no_link=True)