Kills oyoyo
This commit is contained in:
parent
99ca795df5
commit
3855ef20f5
8 changed files with 6 additions and 860 deletions
11
irc.py
11
irc.py
|
@ -19,9 +19,6 @@ from dataobjs import PesterProfile
|
|||
from generic import PesterList
|
||||
from version import _pcVersion
|
||||
|
||||
from oyoyo import services
|
||||
from oyoyo.ircevents import numeric_events
|
||||
|
||||
import scripts.irc.outgoing
|
||||
|
||||
PchumLog = logging.getLogger("pchumLogger")
|
||||
|
@ -871,7 +868,9 @@ class PesterIRC(QtCore.QThread):
|
|||
self.moodUpdated.emit(handle, Mood("chummy"))
|
||||
|
||||
def mode(self, op, channel, mode, *handles):
|
||||
PchumLog.debug("op=%s, channel=%s, mode=%s, handles=%s", op, channel, mode, handles)
|
||||
PchumLog.debug(
|
||||
"op=%s, channel=%s, mode=%s, handles=%s", op, channel, mode, handles
|
||||
)
|
||||
|
||||
if not handles:
|
||||
handles = [""]
|
||||
|
@ -1048,7 +1047,7 @@ class PesterIRC(QtCore.QThread):
|
|||
# # Channel name is not valid.
|
||||
# msg = ' '.join(args)
|
||||
# self.forbiddenchannel.emit(channel, msg)
|
||||
|
||||
|
||||
def forbiddenchannel(self, server, handle, channel, msg):
|
||||
# Channel is forbidden.
|
||||
self.signal_forbiddenchannel.emit(channel, msg)
|
||||
|
@ -1062,9 +1061,7 @@ class PesterIRC(QtCore.QThread):
|
|||
"""finds and runs a command"""
|
||||
PchumLog.debug("processCommand {}({})".format(command, args))
|
||||
try:
|
||||
print(f"command is {command}")
|
||||
f = self.commands[command]
|
||||
print(f" we r running {command}")
|
||||
except KeyError as e:
|
||||
PchumLog.info(e)
|
||||
self.__unhandled__(command, *args)
|
||||
|
|
|
@ -1,212 +0,0 @@
|
|||
# Copyright (c) 2008 Duncan Fordyce
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
import logging
|
||||
import inspect
|
||||
|
||||
from oyoyo import helpers
|
||||
from oyoyo.parse import parse_nick
|
||||
|
||||
PchumLog = logging.getLogger("pchumLogger")
|
||||
|
||||
|
||||
def protected(func):
|
||||
"""decorator to protect functions from being called"""
|
||||
func.protected = True
|
||||
return func
|
||||
|
||||
|
||||
class CommandError(Exception):
|
||||
def __init__(self, cmd):
|
||||
self.cmd = cmd
|
||||
|
||||
|
||||
class NoSuchCommandError(CommandError):
|
||||
def __str__(self):
|
||||
return 'No such command "%s"' % ".".join(self.cmd)
|
||||
|
||||
|
||||
class ProtectedCommandError(CommandError):
|
||||
def __str__(self):
|
||||
return 'Command "%s" is protected' % ".".join(self.cmd)
|
||||
|
||||
|
||||
class CommandHandler:
|
||||
"""The most basic CommandHandler"""
|
||||
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
|
||||
@protected
|
||||
def get(self, in_command_parts):
|
||||
PchumLog.debug("in_command_parts: %s" % in_command_parts)
|
||||
""" finds a command
|
||||
commands may be dotted. each command part is checked that it does
|
||||
not start with and underscore and does not have an attribute
|
||||
"protected". if either of these is true, ProtectedCommandError
|
||||
is raised.
|
||||
its possible to pass both "command.sub.func" and
|
||||
["command", "sub", "func"].
|
||||
"""
|
||||
if isinstance(in_command_parts, (str, bytes)):
|
||||
in_command_parts = in_command_parts.split(".")
|
||||
command_parts = in_command_parts[:]
|
||||
|
||||
p = self
|
||||
while command_parts:
|
||||
cmd = command_parts.pop(0)
|
||||
if cmd.startswith("_"):
|
||||
raise ProtectedCommandError(in_command_parts)
|
||||
|
||||
try:
|
||||
f = getattr(p, cmd)
|
||||
except AttributeError:
|
||||
raise NoSuchCommandError(in_command_parts)
|
||||
|
||||
if hasattr(f, "protected"):
|
||||
raise ProtectedCommandError(in_command_parts)
|
||||
|
||||
if isinstance(f, CommandHandler) and command_parts:
|
||||
return f.get(command_parts)
|
||||
p = f
|
||||
|
||||
return f
|
||||
|
||||
@protected
|
||||
def run(self, command, *args):
|
||||
"""finds and runs a command"""
|
||||
arguments_str = ""
|
||||
for x in args:
|
||||
arguments_str += str(x) + " "
|
||||
PchumLog.debug("processCommand {}({})".format(command, arguments_str.strip()))
|
||||
|
||||
try:
|
||||
f = self.get(command)
|
||||
except NoSuchCommandError as e:
|
||||
PchumLog.info(e)
|
||||
self.__unhandled__(command, *args)
|
||||
return
|
||||
|
||||
PchumLog.debug("f %s" % f)
|
||||
|
||||
try:
|
||||
f(*args)
|
||||
except TypeError as e:
|
||||
PchumLog.info(
|
||||
"Failed to pass command, did the server pass an unsupported paramater? "
|
||||
+ str(e)
|
||||
)
|
||||
except Exception as e:
|
||||
# logging.info("Failed to pass command, %s" % str(e))
|
||||
PchumLog.exception("Failed to pass command")
|
||||
|
||||
@protected
|
||||
def __unhandled__(self, cmd, *args):
|
||||
"""The default handler for commands. Override this method to
|
||||
apply custom behavior (example, printing) unhandled commands.
|
||||
"""
|
||||
PchumLog.debug("unhandled command {}({})".format(cmd, args))
|
||||
|
||||
|
||||
class DefaultCommandHandler(CommandHandler):
|
||||
"""CommandHandler that provides methods for the normal operation of IRC.
|
||||
If you want your bot to properly respond to pings, etc, you should subclass this.
|
||||
"""
|
||||
|
||||
def ping(self, prefix, server):
|
||||
self.client.send("PONG", server)
|
||||
|
||||
|
||||
class DefaultBotCommandHandler(CommandHandler):
|
||||
"""default command handler for bots. methods/attributes are made
|
||||
available as commands"""
|
||||
|
||||
@protected
|
||||
def getVisibleCommands(self, obj=None):
|
||||
test = (
|
||||
lambda x: isinstance(x, CommandHandler)
|
||||
or inspect.ismethod(x)
|
||||
or inspect.isfunction(x)
|
||||
)
|
||||
members = inspect.getmembers(obj or self, test)
|
||||
return [
|
||||
m
|
||||
for m, _ in members
|
||||
if (not m.startswith("_") and not hasattr(getattr(obj, m), "protected"))
|
||||
]
|
||||
|
||||
def help(self, sender, dest, arg=None):
|
||||
"""list all available commands or get help on a specific command"""
|
||||
PchumLog.info("help sender={} dest={} arg={}".format(sender, dest, arg))
|
||||
if not arg:
|
||||
commands = self.getVisibleCommands()
|
||||
commands.sort()
|
||||
helpers.msg(
|
||||
self.client, dest, "available commands: %s" % " ".join(commands)
|
||||
)
|
||||
else:
|
||||
try:
|
||||
f = self.get(arg)
|
||||
except CommandError as e:
|
||||
helpers.msg(self.client, dest, str(e))
|
||||
return
|
||||
|
||||
doc = f.__doc__.strip() if f.__doc__ else "No help available"
|
||||
|
||||
if not inspect.ismethod(f):
|
||||
subcommands = self.getVisibleCommands(f)
|
||||
if subcommands:
|
||||
doc += " [sub commands: %s]" % " ".join(subcommands)
|
||||
|
||||
helpers.msg(self.client, dest, "{}: {}".format(arg, doc))
|
||||
|
||||
|
||||
class BotCommandHandler(DefaultCommandHandler):
|
||||
"""complete command handler for bots"""
|
||||
|
||||
def __init__(self, client, command_handler):
|
||||
DefaultCommandHandler.__init__(self, client)
|
||||
self.command_handler = command_handler
|
||||
|
||||
def privmsg(self, prefix, dest, msg):
|
||||
self.tryBotCommand(prefix, dest, msg)
|
||||
|
||||
@protected
|
||||
def tryBotCommand(self, prefix, dest, msg):
|
||||
"""tests a command to see if its a command for the bot, returns True
|
||||
and calls self.processBotCommand(cmd, sender) if its is.
|
||||
"""
|
||||
|
||||
PchumLog.debug("tryBotCommand('{}' '{}' '{}')".format(prefix, dest, msg))
|
||||
|
||||
if dest == self.client.nick:
|
||||
dest = parse_nick(prefix)[0]
|
||||
elif msg.startswith(self.client.nick):
|
||||
msg = msg[len(self.client.nick) + 1 :]
|
||||
else:
|
||||
return False
|
||||
|
||||
msg = msg.strip()
|
||||
|
||||
parts = msg.split(" ", 1)
|
||||
command = parts[0]
|
||||
arg = parts[1:]
|
||||
|
||||
try:
|
||||
self.command_handler.run(command, prefix, dest, *arg)
|
||||
except CommandError as e:
|
||||
helpers.msg(self.client, dest, str(e))
|
||||
return True
|
156
oyoyo/helpers.py
156
oyoyo/helpers.py
|
@ -1,156 +0,0 @@
|
|||
# Copyright (c) 2008 Duncan Fordyce
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
""" contains helper functions for common irc commands """
|
||||
|
||||
import logging
|
||||
import random
|
||||
|
||||
PchumLog = logging.getLogger("pchumLogger")
|
||||
|
||||
|
||||
def msg(cli, user, msg):
|
||||
for line in msg.split("\n"):
|
||||
cli.send("PRIVMSG", user, ":%s" % line)
|
||||
|
||||
|
||||
def names(cli, *channels):
|
||||
tmp = __builtins__["list"](channels)
|
||||
msglist = []
|
||||
while len(tmp) > 0:
|
||||
msglist.append(tmp.pop())
|
||||
if len(",".join(msglist)) > 490:
|
||||
tmp.append(msglist.pop())
|
||||
cli.send("NAMES %s" % (",".join(msglist)))
|
||||
msglist = []
|
||||
if len(msglist) > 0:
|
||||
cli.send("NAMES %s" % (",".join(msglist)))
|
||||
|
||||
|
||||
def channel_list(cli):
|
||||
cli.send("LIST")
|
||||
|
||||
def ping(cli, token):
|
||||
"""Why is this called ping when it pongs.."""
|
||||
cli.send("PONG", token)
|
||||
|
||||
def kick(cli, handle, channel, reason=""):
|
||||
cli.send("KICK {} {} {}".format(channel, handle, reason))
|
||||
|
||||
|
||||
def mode(cli, channel, mode, options=None):
|
||||
PchumLog.debug("mode = " + str(mode))
|
||||
PchumLog.debug("options = " + str(options))
|
||||
cmd = "MODE {} {}".format(channel, mode)
|
||||
if options:
|
||||
cmd += " %s" % (options)
|
||||
cli.send(cmd)
|
||||
|
||||
|
||||
def ctcp(cli, handle, cmd, msg=""):
|
||||
# Space breaks protocol if msg is absent
|
||||
if msg == "":
|
||||
cli.send("PRIVMSG", handle, "\x01%s\x01" % (cmd))
|
||||
else:
|
||||
cli.send("PRIVMSG", handle, "\x01{} {}\x01".format(cmd, msg))
|
||||
|
||||
|
||||
def ctcp_reply(cli, handle, cmd, msg=""):
|
||||
notice(cli, str(handle), "\x01{} {}\x01".format(cmd.upper(), msg))
|
||||
|
||||
|
||||
def metadata(cli, target, subcommand, *params):
|
||||
# IRC metadata draft specification
|
||||
# https://gist.github.com/k4bek4be/92c2937cefd49990fbebd001faf2b237
|
||||
cli.send("METADATA", target, subcommand, *params)
|
||||
|
||||
|
||||
def cap(cli, subcommand, *params):
|
||||
# Capability Negotiation
|
||||
# https://ircv3.net/specs/extensions/capability-negotiation.html
|
||||
cli.send("CAP", subcommand, *params)
|
||||
|
||||
|
||||
def msgrandom(cli, choices, dest, user=None):
|
||||
o = "%s: " % user if user else ""
|
||||
o += random.choice(choices)
|
||||
msg(cli, dest, o)
|
||||
|
||||
|
||||
def _makeMsgRandomFunc(choices):
|
||||
def func(cli, dest, user=None):
|
||||
msgrandom(cli, choices, dest, user)
|
||||
|
||||
return func
|
||||
|
||||
def ns(cli, *args):
|
||||
msg(cli, "NickServ", " ".join(args))
|
||||
|
||||
|
||||
def cs(cli, *args):
|
||||
msg(cli, "ChanServ", " ".join(args))
|
||||
|
||||
|
||||
def identify(cli, passwd, authuser="NickServ"):
|
||||
msg(cli, authuser, "IDENTIFY %s" % passwd)
|
||||
|
||||
|
||||
def quit(cli, msg):
|
||||
cli.send("QUIT %s" % (msg))
|
||||
|
||||
|
||||
def nick(cli, nick):
|
||||
cli.send("NICK", nick)
|
||||
|
||||
|
||||
def user(cli, username, realname):
|
||||
cli.send("USER", username, "0", "*", ":" + realname)
|
||||
|
||||
|
||||
def join(cli, channel):
|
||||
"""Protocol potentially allows multiple channels or keys."""
|
||||
cli.send("JOIN", channel)
|
||||
|
||||
|
||||
def part(cli, channel):
|
||||
cli.send("PART", channel)
|
||||
|
||||
|
||||
def notice(cli, target, text):
|
||||
cli.send("NOTICE", target, text)
|
||||
|
||||
|
||||
def invite(cli, nick, channel):
|
||||
cli.send("INVITE", nick, channel)
|
||||
|
||||
|
||||
def _addNumerics():
|
||||
import sys
|
||||
from oyoyo import ircevents
|
||||
|
||||
def numericcmd(cmd_num, cmd_name):
|
||||
def f(cli, *args):
|
||||
cli.send(cmd_num, *args)
|
||||
|
||||
return f
|
||||
|
||||
m = sys.modules[__name__]
|
||||
for num, name in ircevents.numeric_events.items():
|
||||
setattr(m, name, numericcmd(num, name))
|
||||
|
||||
|
||||
#_addNumerics()
|
|
@ -1,232 +0,0 @@
|
|||
# Copyright (c) 2008 Duncan Fordyce
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# taken from python irclib.. who took it from...
|
||||
# Numeric table mostly stolen from the Perl IRC module (Net::IRC).
|
||||
numeric_events = {
|
||||
"001": "welcome",
|
||||
"002": "yourhost",
|
||||
"003": "created",
|
||||
"004": "myinfo",
|
||||
"005": "featurelist", # XXX
|
||||
"010": "toomanypeeps",
|
||||
"200": "tracelink",
|
||||
"201": "traceconnecting",
|
||||
"202": "tracehandshake",
|
||||
"203": "traceunknown",
|
||||
"204": "traceoperator",
|
||||
"205": "traceuser",
|
||||
"206": "traceserver",
|
||||
"207": "traceservice",
|
||||
"208": "tracenewtype",
|
||||
"209": "traceclass",
|
||||
"210": "tracereconnect",
|
||||
"211": "statslinkinfo",
|
||||
"212": "statscommands",
|
||||
"213": "statscline",
|
||||
"214": "statsnline",
|
||||
"215": "statsiline",
|
||||
"216": "statskline",
|
||||
"217": "statsqline",
|
||||
"218": "statsyline",
|
||||
"219": "endofstats",
|
||||
"221": "umodeis",
|
||||
"231": "serviceinfo",
|
||||
"232": "endofservices",
|
||||
"233": "service",
|
||||
"234": "servlist",
|
||||
"235": "servlistend",
|
||||
"241": "statslline",
|
||||
"242": "statsuptime",
|
||||
"243": "statsoline",
|
||||
"244": "statshline",
|
||||
"250": "luserconns",
|
||||
"251": "luserclient",
|
||||
"252": "luserop",
|
||||
"253": "luserunknown",
|
||||
"254": "luserchannels",
|
||||
"255": "luserme",
|
||||
"256": "adminme",
|
||||
"257": "adminloc1",
|
||||
"258": "adminloc2",
|
||||
"259": "adminemail",
|
||||
"261": "tracelog",
|
||||
"262": "endoftrace",
|
||||
"263": "tryagain",
|
||||
"265": "n_local",
|
||||
"266": "n_global",
|
||||
"300": "none",
|
||||
"301": "away",
|
||||
"302": "userhost",
|
||||
"303": "ison",
|
||||
"305": "unaway",
|
||||
"306": "nowaway",
|
||||
"311": "whoisuser",
|
||||
"312": "whoisserver",
|
||||
"313": "whoisoperator",
|
||||
"314": "whowasuser",
|
||||
"315": "endofwho",
|
||||
"316": "whoischanop",
|
||||
"317": "whoisidle",
|
||||
"318": "endofwhois",
|
||||
"319": "whoischannels",
|
||||
"321": "liststart",
|
||||
"322": "list",
|
||||
"323": "listend",
|
||||
"324": "channelmodeis",
|
||||
"329": "channelcreate",
|
||||
"331": "notopic",
|
||||
"332": "currenttopic",
|
||||
"333": "topicinfo",
|
||||
"341": "inviting",
|
||||
"342": "summoning",
|
||||
"346": "invitelist",
|
||||
"347": "endofinvitelist",
|
||||
"348": "exceptlist",
|
||||
"349": "endofexceptlist",
|
||||
"351": "version",
|
||||
"352": "whoreply",
|
||||
"353": "namreply",
|
||||
"361": "killdone",
|
||||
"362": "closing",
|
||||
"363": "closeend",
|
||||
"364": "links",
|
||||
"365": "endoflinks",
|
||||
"366": "endofnames",
|
||||
"367": "banlist",
|
||||
"368": "endofbanlist",
|
||||
"369": "endofwhowas",
|
||||
"371": "info",
|
||||
"372": "motd",
|
||||
"373": "infostart",
|
||||
"374": "endofinfo",
|
||||
"375": "motdstart",
|
||||
"376": "endofmotd",
|
||||
"377": "motd2", # 1997-10-16 -- tkil
|
||||
"381": "youreoper",
|
||||
"382": "rehashing",
|
||||
"384": "myportis",
|
||||
"391": "time",
|
||||
"392": "usersstart",
|
||||
"393": "users",
|
||||
"394": "endofusers",
|
||||
"395": "nousers",
|
||||
"396": "hosthidden",
|
||||
"401": "nosuchnick",
|
||||
"402": "nosuchserver",
|
||||
"403": "nosuchchannel",
|
||||
"404": "cannotsendtochan",
|
||||
"405": "toomanychannels",
|
||||
"406": "wasnosuchnick",
|
||||
"407": "toomanytargets",
|
||||
"409": "noorigin",
|
||||
"411": "norecipient",
|
||||
"412": "notexttosend",
|
||||
"413": "notoplevel",
|
||||
"414": "wildtoplevel",
|
||||
"421": "unknowncommand",
|
||||
"422": "nomotd",
|
||||
"423": "noadmininfo",
|
||||
"424": "fileerror",
|
||||
"431": "nonicknamegiven",
|
||||
"432": "erroneusnickname", # Thiss iz how its speld in thee RFC.
|
||||
"433": "nicknameinuse",
|
||||
"436": "nickcollision",
|
||||
"437": "unavailresource", # "Nick temporally unavailable"
|
||||
"441": "usernotinchannel",
|
||||
"442": "notonchannel",
|
||||
"443": "useronchannel",
|
||||
"444": "nologin",
|
||||
"445": "summondisabled",
|
||||
"446": "usersdisabled",
|
||||
"451": "notregistered",
|
||||
"461": "needmoreparams",
|
||||
"462": "alreadyregistered",
|
||||
"463": "nopermforhost",
|
||||
"464": "passwdmismatch",
|
||||
"465": "yourebannedcreep", # I love this one...
|
||||
"466": "youwillbebanned",
|
||||
"467": "keyset",
|
||||
"471": "channelisfull",
|
||||
"472": "unknownmode",
|
||||
"473": "inviteonlychan",
|
||||
"474": "bannedfromchan",
|
||||
"475": "badchannelkey",
|
||||
"476": "badchanmask",
|
||||
"477": "nochanmodes", # "Channel doesn't support modes"
|
||||
"478": "banlistfull",
|
||||
"481": "noprivileges",
|
||||
"482": "chanoprivsneeded",
|
||||
"483": "cantkillserver",
|
||||
"484": "restricted", # Connection is restricted
|
||||
"485": "uniqopprivsneeded",
|
||||
"491": "nooperhost",
|
||||
"492": "noservicehost",
|
||||
"501": "umodeunknownflag",
|
||||
"502": "usersdontmatch",
|
||||
}
|
||||
|
||||
# Unrealircd extras
|
||||
unrealircd_events = {
|
||||
"448": "forbiddenchannel",
|
||||
}
|
||||
numeric_events.update(unrealircd_events)
|
||||
|
||||
# IRC metadata draft specification
|
||||
# https://gist.github.com/k4bek4be/92c2937cefd49990fbebd001faf2b237
|
||||
metadata_numeric_events = {
|
||||
"761": "keyvalue",
|
||||
"762": "metadataend",
|
||||
"766": "nomatchingkey",
|
||||
"768": "keynotset",
|
||||
"769": "keynopermission",
|
||||
"770": "metadatasubok",
|
||||
}
|
||||
numeric_events.update(metadata_numeric_events)
|
||||
|
||||
generated_events = [
|
||||
# Generated events
|
||||
"dcc_connect",
|
||||
"dcc_disconnect",
|
||||
"dccmsg",
|
||||
"disconnect",
|
||||
"ctcp",
|
||||
"ctcpreply",
|
||||
]
|
||||
|
||||
protocol_events = [
|
||||
# IRC protocol events
|
||||
"error",
|
||||
"join",
|
||||
"kick",
|
||||
"mode",
|
||||
"part",
|
||||
"ping",
|
||||
"privmsg",
|
||||
"privnotice",
|
||||
"pubmsg",
|
||||
"pubnotice",
|
||||
"quit",
|
||||
"invite",
|
||||
"pong",
|
||||
"nick", # We can get svsnicked
|
||||
"metadata", # Metadata specification
|
||||
"tagmsg", # IRCv3 message tags extension
|
||||
"cap", # IRCv3 Client Capability Negotiation
|
||||
]
|
||||
|
||||
all_events = generated_events + protocol_events + list(numeric_events.values())
|
121
oyoyo/parse.py
121
oyoyo/parse.py
|
@ -1,121 +0,0 @@
|
|||
# Copyright (c) 2008 Duncan Fordyce
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
import logging
|
||||
|
||||
from oyoyo.ircevents import numeric_events
|
||||
|
||||
PchumLog = logging.getLogger("pchumLogger")
|
||||
|
||||
|
||||
def parse_raw_irc_command(element):
|
||||
"""
|
||||
This function parses a raw irc command and returns a tuple
|
||||
of (prefix, command, args).
|
||||
The following is a psuedo BNF of the input text:
|
||||
|
||||
<message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
|
||||
<prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
|
||||
<command> ::= <letter> { <letter> } | <number> <number> <number>
|
||||
<SPACE> ::= ' ' { ' ' }
|
||||
<params> ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
|
||||
|
||||
<middle> ::= <Any *non-empty* sequence of octets not including SPACE
|
||||
or NUL or CR or LF, the first of which may not be ':'>
|
||||
<trailing> ::= <Any, possibly *empty*, sequence of octets not including
|
||||
NUL or CR or LF>
|
||||
|
||||
<crlf> ::= CR LF
|
||||
"""
|
||||
"""
|
||||
When message-tags are enabled, the message pseudo-BNF,
|
||||
as defined in RFC 1459, section 2.3.1 is extended as follows:
|
||||
|
||||
<message> ::= ['@' <tags> <SPACE>] [':' <prefix> <SPACE> ] <command> [params] <crlf>
|
||||
<tags> ::= <tag> [';' <tag>]*
|
||||
<tag> ::= <key> ['=' <escaped_value>]
|
||||
<key> ::= [ <client_prefix> ] [ <vendor> '/' ] <key_name>
|
||||
<client_prefix> ::= '+'
|
||||
<key_name> ::= <non-empty sequence of ascii letters, digits, hyphens ('-')>
|
||||
<escaped_value> ::= <sequence of zero or more utf8 characters except NUL, CR, LF, semicolon (`;`) and SPACE>
|
||||
<vendor> ::= <host>
|
||||
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
element = element.decode("utf-8")
|
||||
except UnicodeDecodeError as e:
|
||||
PchumLog.debug("utf-8 error %s" % str(e))
|
||||
element = element.decode("latin-1", "replace")
|
||||
|
||||
parts = element.strip().split(" ")
|
||||
if parts[0].startswith(":"):
|
||||
tags = None
|
||||
prefix = parts[0][1:]
|
||||
command = parts[1]
|
||||
args = parts[2:]
|
||||
elif parts[0].startswith("@"):
|
||||
# Message tag
|
||||
tags = parts[0]
|
||||
prefix = parts[1][1:]
|
||||
command = parts[2]
|
||||
args = parts[3:]
|
||||
else:
|
||||
tags = None
|
||||
prefix = None
|
||||
command = parts[0]
|
||||
args = parts[1:]
|
||||
|
||||
if command.isdigit():
|
||||
try:
|
||||
command = numeric_events[command]
|
||||
except KeyError:
|
||||
PchumLog.info("unknown numeric event %s" % command)
|
||||
command = command.lower()
|
||||
|
||||
if args[0].startswith(":"):
|
||||
args = [" ".join(args)[1:]]
|
||||
else:
|
||||
for idx, arg in enumerate(args):
|
||||
if arg.startswith(":"):
|
||||
args = args[:idx] + [" ".join(args[idx:])[1:]]
|
||||
break
|
||||
|
||||
return (tags, prefix, command, args)
|
||||
|
||||
|
||||
def parse_nick(name):
|
||||
"""parse a nickname and return a tuple of (nick, mode, user, host)
|
||||
|
||||
<nick> [ '!' [<mode> = ] <user> ] [ '@' <host> ]
|
||||
"""
|
||||
|
||||
try:
|
||||
nick, rest = name.split("!")
|
||||
except ValueError:
|
||||
return (name, None, None, None)
|
||||
try:
|
||||
mode, rest = rest.split("=")
|
||||
except ValueError:
|
||||
mode, rest = None, rest
|
||||
try:
|
||||
user, host = rest.split("@")
|
||||
except ValueError:
|
||||
return (name, mode, rest, None)
|
||||
|
||||
return (name, mode, user, host)
|
|
@ -1,125 +0,0 @@
|
|||
# NickServ basic functions
|
||||
_nickservfuncs = (
|
||||
"register",
|
||||
"group",
|
||||
"glist",
|
||||
"identify",
|
||||
"access",
|
||||
"drop",
|
||||
"recover",
|
||||
"release",
|
||||
"sendpass",
|
||||
"ghost",
|
||||
"alist",
|
||||
"info",
|
||||
"list",
|
||||
"logout",
|
||||
"status",
|
||||
"update",
|
||||
)
|
||||
|
||||
# NickServ SET functions
|
||||
_nickservsetfuncs = (
|
||||
"display",
|
||||
"password",
|
||||
"language",
|
||||
"url",
|
||||
"email",
|
||||
"icq",
|
||||
"greet",
|
||||
"kill",
|
||||
"secure",
|
||||
"private",
|
||||
"hide",
|
||||
"msg",
|
||||
"autoop",
|
||||
)
|
||||
|
||||
# ChanServ basic functions
|
||||
_chanservfuncs = (
|
||||
"register",
|
||||
"identify",
|
||||
"sop",
|
||||
"aop",
|
||||
"hop",
|
||||
"vop",
|
||||
"access",
|
||||
"levels",
|
||||
"akick",
|
||||
"drop",
|
||||
"sendpass",
|
||||
"ban",
|
||||
"unban",
|
||||
"clear",
|
||||
"owner",
|
||||
"deowner",
|
||||
"protect",
|
||||
"deprotect",
|
||||
"op",
|
||||
"deop",
|
||||
"halfop",
|
||||
"dehalfop",
|
||||
"voice",
|
||||
"devoice",
|
||||
"getkey",
|
||||
"invite",
|
||||
"kick",
|
||||
"list",
|
||||
"logout",
|
||||
"topic",
|
||||
"info",
|
||||
"appendtopic",
|
||||
"enforce",
|
||||
)
|
||||
|
||||
_chanservsetfuncs = (
|
||||
"founder",
|
||||
"successor",
|
||||
"password",
|
||||
"desc",
|
||||
"url",
|
||||
"email",
|
||||
"entrymsg",
|
||||
"bantype",
|
||||
"mlock",
|
||||
"keeptopic",
|
||||
"opnotice",
|
||||
"peace",
|
||||
"private",
|
||||
"restricted",
|
||||
"secure",
|
||||
"secureops",
|
||||
"securefounder",
|
||||
"signkick",
|
||||
"topiclock",
|
||||
"xop",
|
||||
)
|
||||
|
||||
|
||||
def _addServ(serv, funcs, prefix=""):
|
||||
def simplecmd(cmd_name):
|
||||
if prefix:
|
||||
cmd_name = prefix.upper() + " " + cmd_name
|
||||
|
||||
def f(cli, *args):
|
||||
print(cmd_name, " ".join(args))
|
||||
# cli.send(cmd_name, serv.name, *args)
|
||||
|
||||
return f
|
||||
|
||||
for t in funcs:
|
||||
setattr(serv, t, simplecmd(t.upper()))
|
||||
|
||||
|
||||
class NickServ:
|
||||
def __init__(self, nick="NickServ"):
|
||||
self.name = nick
|
||||
_addServ(self, _nickservfuncs)
|
||||
_addServ(self, _nickservsetfuncs, "set")
|
||||
|
||||
|
||||
class ChanServ:
|
||||
def __init__(self, nick="ChanServ"):
|
||||
self.name = nick
|
||||
_addServ(self, _chanservfuncs)
|
||||
_addServ(self, _chanservsetfuncs, "set")
|
|
@ -429,9 +429,7 @@ def kxsplitMsg(lexed, ctx, fmt="pchum", maxlen=None, debug=False):
|
|||
curlen = 0
|
||||
# Maximum number of characters *to* use.
|
||||
if not maxlen:
|
||||
maxlen = _max_msg_len(
|
||||
None, None, ctx.mainwindow.profile().handle, "pcc31"
|
||||
)
|
||||
maxlen = _max_msg_len(None, None, ctx.mainwindow.profile().handle, "pcc31")
|
||||
elif maxlen < 0:
|
||||
# Subtract the (negative) length, giving us less leeway in this
|
||||
# function.
|
||||
|
@ -805,9 +803,7 @@ def kxhandleInput(ctx, text=None, flavor=None):
|
|||
# We'll use those later.
|
||||
|
||||
# Split the messages so we don't go over the buffer and lose text.
|
||||
maxlen = _max_msg_len(
|
||||
None, None, ctx.mainwindow.profile().handle, "pcc31"
|
||||
)
|
||||
maxlen = _max_msg_len(None, None, ctx.mainwindow.profile().handle, "pcc31")
|
||||
# ctx.mainwindow.profile().handle ==> Get handle
|
||||
# "pcc31" ==> Get ident (Same as realname in this case.)
|
||||
# Since we have to do some post-processing, we need to adjust the maximum
|
||||
|
|
|
@ -136,4 +136,3 @@ class SendIRC:
|
|||
def quit(self, reason=""):
|
||||
"""Send QUIT to terminate connection."""
|
||||
self.send("QUIT", text=reason)
|
||||
|
||||
|
|
Loading…
Reference in a new issue