2012-08-14 03:55:48 +00:00
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
# Nemubot is a modulable IRC bot, built around XML configuration files.
|
|
|
|
|
# Copyright (C) 2012 Mercier Pierre-Olivier
|
|
|
|
|
#
|
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU Affero General Public License as published by
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
# (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
2014-07-17 09:58:24 +00:00
|
|
|
|
import traceback
|
|
|
|
|
import sys
|
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
from hooks import hook
|
2014-10-09 05:37:52 +00:00
|
|
|
|
from message import TextMessage
|
|
|
|
|
from networkbot import NetworkBot
|
2012-08-27 22:27:02 +00:00
|
|
|
|
|
2014-08-13 13:53:55 +00:00
|
|
|
|
nemubotversion = 3.4
|
2012-08-14 03:55:48 +00:00
|
|
|
|
NODATA = True
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2012-08-27 22:27:02 +00:00
|
|
|
|
def getserver(toks, context, prompt):
|
|
|
|
|
"""Choose the server in toks or prompt"""
|
|
|
|
|
if len(toks) > 1 and toks[0] in context.servers:
|
|
|
|
|
return (context.servers[toks[0]], toks[1:])
|
|
|
|
|
elif prompt.selectedServer is not None:
|
|
|
|
|
return (prompt.selectedServer, toks)
|
|
|
|
|
else:
|
|
|
|
|
return (None, toks)
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "close")
|
2012-08-14 03:55:48 +00:00
|
|
|
|
def close(data, toks, context, prompt):
|
|
|
|
|
"""Disconnect and forget (remove from the servers list) the server"""
|
|
|
|
|
if len(toks) > 1:
|
|
|
|
|
for s in toks[1:]:
|
|
|
|
|
if s in servers:
|
2014-11-14 13:25:52 +00:00
|
|
|
|
context.servers[s].close()
|
2012-08-14 03:55:48 +00:00
|
|
|
|
del context.servers[s]
|
|
|
|
|
else:
|
|
|
|
|
print ("close: server `%s' not found." % s)
|
|
|
|
|
elif prompt.selectedServer is not None:
|
2014-11-14 13:25:52 +00:00
|
|
|
|
prompt.selectedServer.close()
|
2012-08-14 03:55:48 +00:00
|
|
|
|
del prompt.servers[selectedServer.id]
|
|
|
|
|
prompt.selectedServer = None
|
|
|
|
|
return
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "connect")
|
2012-08-14 03:55:48 +00:00
|
|
|
|
def connect(data, toks, context, prompt):
|
|
|
|
|
"""Make the connexion to a server"""
|
|
|
|
|
if len(toks) > 1:
|
|
|
|
|
for s in toks[1:]:
|
|
|
|
|
if s in context.servers:
|
2014-11-14 13:25:52 +00:00
|
|
|
|
context.servers[s].open()
|
2012-08-14 03:55:48 +00:00
|
|
|
|
else:
|
|
|
|
|
print ("connect: server `%s' not found." % s)
|
|
|
|
|
|
|
|
|
|
elif prompt.selectedServer is not None:
|
2014-11-14 13:25:52 +00:00
|
|
|
|
prompt.selectedServer.open()
|
2012-08-14 03:55:48 +00:00
|
|
|
|
else:
|
|
|
|
|
print (" Please SELECT a server or give its name in argument.")
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "disconnect")
|
2012-08-14 03:55:48 +00:00
|
|
|
|
def disconnect(data, toks, context, prompt):
|
|
|
|
|
"""Close the connection to a server"""
|
|
|
|
|
if len(toks) > 1:
|
|
|
|
|
for s in toks[1:]:
|
|
|
|
|
if s in context.servers:
|
2014-11-14 13:25:52 +00:00
|
|
|
|
if not context.servers[s].close():
|
2012-08-14 03:55:48 +00:00
|
|
|
|
print ("disconnect: server `%s' already disconnected." % s)
|
|
|
|
|
else:
|
|
|
|
|
print ("disconnect: server `%s' not found." % s)
|
|
|
|
|
elif prompt.selectedServer is not None:
|
2014-11-14 13:25:52 +00:00
|
|
|
|
if not prompt.selectedServer.close():
|
2012-08-14 03:55:48 +00:00
|
|
|
|
print ("disconnect: server `%s' already disconnected."
|
|
|
|
|
% prompt.selectedServer.id)
|
|
|
|
|
else:
|
|
|
|
|
print (" Please SELECT a server or give its name in argument.")
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "discover")
|
2012-08-27 22:27:02 +00:00
|
|
|
|
def discover(data, toks, context, prompt):
|
|
|
|
|
"""Discover a new bot on a server"""
|
|
|
|
|
(srv, toks) = getserver(toks, context, prompt)
|
|
|
|
|
if srv is not None:
|
|
|
|
|
for name in toks[1:]:
|
|
|
|
|
if "!" in name:
|
|
|
|
|
bot = context.add_networkbot(srv, name)
|
|
|
|
|
bot.connect()
|
|
|
|
|
else:
|
2014-11-13 01:51:49 +00:00
|
|
|
|
print (" %s is not a valid fullname, for example: "
|
|
|
|
|
"nemubot!nemubotV3@bot.nemunai.re")
|
2012-08-27 22:27:02 +00:00
|
|
|
|
else:
|
|
|
|
|
print (" Please SELECT a server or give its name in first argument.")
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "hotswap")
|
2012-08-14 03:55:48 +00:00
|
|
|
|
def hotswap(data, toks, context, prompt):
|
|
|
|
|
"""Reload a server class"""
|
|
|
|
|
if len(toks) > 1:
|
|
|
|
|
print ("hotswap: apply only on selected server")
|
|
|
|
|
elif prompt.selectedServer is not None:
|
|
|
|
|
del context.servers[prompt.selectedServer.id]
|
|
|
|
|
srv = server.Server(selectedServer.node, selectedServer.nick,
|
|
|
|
|
selectedServer.owner, selectedServer.realname,
|
|
|
|
|
selectedServer.s)
|
|
|
|
|
context.servers[srv.id] = srv
|
|
|
|
|
prompt.selectedServer.kill()
|
|
|
|
|
prompt.selectedServer = srv
|
|
|
|
|
prompt.selectedServer.start()
|
|
|
|
|
else:
|
|
|
|
|
print (" Please SELECT a server or give its name in argument.")
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "join")
|
2014-09-28 18:34:49 +00:00
|
|
|
|
@hook("prompt_cmd", "leave")
|
|
|
|
|
@hook("prompt_cmd", "part")
|
2012-08-14 03:55:48 +00:00
|
|
|
|
def join(data, toks, context, prompt):
|
|
|
|
|
"""Join or leave a channel"""
|
|
|
|
|
rd = 1
|
|
|
|
|
if len(toks) <= rd:
|
|
|
|
|
print ("%s: not enough arguments." % toks[0])
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if toks[rd] in context.servers:
|
|
|
|
|
srv = context.servers[toks[rd]]
|
|
|
|
|
rd += 1
|
|
|
|
|
elif prompt.selectedServer is not None:
|
|
|
|
|
srv = prompt.selectedServer
|
|
|
|
|
else:
|
|
|
|
|
print (" Please SELECT a server or give its name in argument.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if len(toks) <= rd:
|
2014-11-13 01:51:49 +00:00
|
|
|
|
print("%s: not enough arguments." % toks[0])
|
2012-08-14 03:55:48 +00:00
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if toks[0] == "join":
|
|
|
|
|
if len(toks) > rd + 1:
|
2014-09-28 18:34:49 +00:00
|
|
|
|
srv.write("JOIN %s %s" % (toks[rd], toks[rd + 1]))
|
2012-08-14 03:55:48 +00:00
|
|
|
|
else:
|
2014-09-28 18:34:49 +00:00
|
|
|
|
srv.write("JOIN %s" % toks[rd])
|
2012-08-14 03:55:48 +00:00
|
|
|
|
elif toks[0] == "leave" or toks[0] == "part":
|
2014-09-28 18:34:49 +00:00
|
|
|
|
srv.write("PART %s" % toks[rd])
|
2012-08-14 03:55:48 +00:00
|
|
|
|
return
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "save")
|
2013-03-20 08:56:12 +00:00
|
|
|
|
def save_mod(data, toks, context, prompt):
|
|
|
|
|
"""Force save module data"""
|
|
|
|
|
if len(toks) < 2:
|
|
|
|
|
print ("save: not enough arguments.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
for mod in toks[1:]:
|
|
|
|
|
if mod in context.modules:
|
|
|
|
|
context.modules[mod].save()
|
|
|
|
|
print ("save: module `%s´ saved successfully" % mod)
|
|
|
|
|
else:
|
|
|
|
|
print ("save: no module named `%s´" % mod)
|
|
|
|
|
return
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "send")
|
2012-08-14 03:55:48 +00:00
|
|
|
|
def send(data, toks, context, prompt):
|
|
|
|
|
"""Send a message on a channel"""
|
|
|
|
|
rd = 1
|
|
|
|
|
if len(toks) <= rd:
|
|
|
|
|
print ("send: not enough arguments.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if toks[rd] in context.servers:
|
|
|
|
|
srv = context.servers[toks[rd]]
|
|
|
|
|
rd += 1
|
|
|
|
|
elif prompt.selectedServer is not None:
|
|
|
|
|
srv = prompt.selectedServer
|
|
|
|
|
else:
|
|
|
|
|
print (" Please SELECT a server or give its name in argument.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if len(toks) <= rd:
|
|
|
|
|
print ("send: not enough arguments.")
|
|
|
|
|
return
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
# Check the server is connected
|
2012-08-14 03:55:48 +00:00
|
|
|
|
if not srv.connected:
|
|
|
|
|
print ("send: server `%s' not connected." % srv.id)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if toks[rd] in srv.channels:
|
|
|
|
|
chan = toks[rd]
|
|
|
|
|
rd += 1
|
|
|
|
|
else:
|
|
|
|
|
print ("send: channel `%s' not authorized in server `%s'."
|
|
|
|
|
% (toks[rd], srv.id))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if len(toks) <= rd:
|
|
|
|
|
print ("send: not enough arguments.")
|
|
|
|
|
return
|
|
|
|
|
|
2014-10-09 05:37:52 +00:00
|
|
|
|
srv.send_response(TextMessage(" ".join(toks[rd:]), server=None, to=[chan]))
|
2012-08-14 03:55:48 +00:00
|
|
|
|
return "done"
|
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "zap")
|
2012-08-14 03:55:48 +00:00
|
|
|
|
def zap(data, toks, context, prompt):
|
|
|
|
|
"""Hard change connexion state"""
|
|
|
|
|
if len(toks) > 1:
|
|
|
|
|
for s in toks[1:]:
|
|
|
|
|
if s in context.servers:
|
|
|
|
|
context.servers[s].connected = not context.servers[s].connected
|
|
|
|
|
else:
|
|
|
|
|
print ("zap: server `%s' not found." % s)
|
|
|
|
|
elif prompt.selectedServer is not None:
|
|
|
|
|
prompt.selectedServer.connected = not prompt.selectedServer.connected
|
|
|
|
|
else:
|
|
|
|
|
print (" Please SELECT a server or give its name in argument.")
|
2014-07-17 09:58:24 +00:00
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "top")
|
2014-07-17 09:58:24 +00:00
|
|
|
|
def top(data, toks, context, prompt):
|
|
|
|
|
"""Display consumers load information"""
|
2014-11-13 01:51:49 +00:00
|
|
|
|
print("Queue size: %d, %d thread(s) running (counter: %d)" %
|
|
|
|
|
(context.cnsr_queue.qsize(),
|
|
|
|
|
len(context.cnsr_thrd),
|
|
|
|
|
context.cnsr_thrd_size))
|
2014-07-17 09:58:24 +00:00
|
|
|
|
if len(context.events) > 0:
|
2014-11-13 01:51:49 +00:00
|
|
|
|
print("Events registered: %d, next in %d seconds" %
|
|
|
|
|
(len(context.events),
|
|
|
|
|
context.events[0].time_left.seconds))
|
2014-07-17 09:58:24 +00:00
|
|
|
|
else:
|
|
|
|
|
print("No events registered")
|
|
|
|
|
|
|
|
|
|
for th in context.cnsr_thrd:
|
|
|
|
|
if th.is_alive():
|
2014-11-13 01:51:49 +00:00
|
|
|
|
print(("#" * 15 + " Stack trace for thread %u " + "#" * 15) %
|
|
|
|
|
th.ident)
|
2014-07-17 09:58:24 +00:00
|
|
|
|
traceback.print_stack(sys._current_frames()[th.ident])
|
2014-07-23 14:32:42 +00:00
|
|
|
|
|
2014-11-13 01:51:49 +00:00
|
|
|
|
|
2014-08-28 10:26:02 +00:00
|
|
|
|
@hook("prompt_cmd", "netstat")
|
2014-07-23 14:32:42 +00:00
|
|
|
|
def netstat(data, toks, context, prompt):
|
|
|
|
|
"""Display sockets in use and many other things"""
|
|
|
|
|
if len(context.network) > 0:
|
|
|
|
|
print("Distant bots connected: %d:" % len(context.network))
|
|
|
|
|
for name, bot in context.network.items():
|
|
|
|
|
print("# %s:" % name)
|
|
|
|
|
print(" * Declared hooks:")
|
|
|
|
|
lvl = 0
|
|
|
|
|
for hlvl in bot.hooks:
|
|
|
|
|
lvl += 1
|
2014-11-13 01:51:49 +00:00
|
|
|
|
for hook in (hlvl.all_pre + hlvl.all_post + hlvl.cmd_rgxp +
|
|
|
|
|
hlvl.cmd_default + hlvl.ask_rgxp +
|
|
|
|
|
hlvl.ask_default + hlvl.msg_rgxp +
|
|
|
|
|
hlvl.msg_default):
|
2014-07-23 14:32:42 +00:00
|
|
|
|
print(" %s- %s" % (' ' * lvl * 2, hook))
|
2014-11-13 01:51:49 +00:00
|
|
|
|
for kind in ["irc_hook", "cmd_hook", "ask_hook", "msg_hook"]:
|
|
|
|
|
print(" %s- <%s> %s" % (' ' * lvl * 2, kind,
|
|
|
|
|
", ".join(hlvl.__dict__[kind].keys())))
|
2014-07-23 14:32:42 +00:00
|
|
|
|
print(" * My tag: %d" % bot.my_tag)
|
|
|
|
|
print(" * Tags in use (%d):" % bot.inc_tag)
|
|
|
|
|
for tag, (cmd, data) in bot.tags.items():
|
|
|
|
|
print(" - %11s: %s « %s »" % (tag, cmd, data))
|
|
|
|
|
else:
|
|
|
|
|
print("No distant bot connected")
|