Skip to content

Commit

Permalink
core: parse RPL_ISUPPORT into bot.server._isupport
Browse files Browse the repository at this point in the history
Parses one or more `RPL_ISUPPORT` messages from the IRC server for
parameters found in: https://modern.ircdocs.horse/.

While the documentation above does not explicitly list the parameters
mentioned in sopel-irc#1082, each parameter listed there would be parsed into
`bot.server._isupport`.
  • Loading branch information
HumorBaby committed Apr 23, 2019
1 parent 6caad9e commit b34dab5
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 1 deletion.
5 changes: 4 additions & 1 deletion sopel/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,13 @@ class _ServerInfo(object): # Eventually this can become a Python 3 data class
set.
hostname: A string containing 'servername' from RPL_MYINFO
_isupport: A dict containing parsed values from RPL_ISUPPORT.
"""
def __init__(self):
self.capabilities = {}
self.hostname = None # This attribute should be set only by the bot (not modules)
self.hostname = None
self._isupport = collections.defaultdict(lambda: None) # Will be falsy when parameter not in RPL_ISUPPORT


class Sopel(irc.Bot):
Expand Down
95 changes: 95 additions & 0 deletions sopel/coretasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,101 @@ def parse_reply_myinfo(bot, trigger):
bot.server.hostname = trigger.args[1]


@sopel.module.rule('.*')
@sopel.module.event(events.RPL_ISUPPORT)
@sopel.module.priority('high')
@sopel.module.thread(False)
@sopel.module.unblockable
def parse_reply_isupport(bot, trigger):
"""Parse RPL_ISUPPORT.
005 RPL_ISUPPORT "<client> <1-13 tokens> :are supported by this server"
"""
DEFAULT_VALUES = {
'EXCEPTS': 'e',
'INVEX': 'I',
}

CAST_TO = {
'AWAYLEN': int,
'CHANNELLEN': int,
'HOSTLEN': int,
'KICKLEN': int,
'MODES': int,
'NICKLEN': int,
'TOPICLEN': int,
'USERLEN': int,
}

def parse_value(key, value):
"""Parse the value in parameter[=value] from RPL_ISUPPORT.
Args:
key (string): used to determine parsed value type
value (string): format <value_type>:[limit] OR <value>
Returns:
object: a tuple of (value_type, limit (int)) if value argument has
':', a string of parsed value otherwise. If limit is not
provided after ":", None is returned to indicate no limit.
"""
if ':' in value:
parts = value.split(':')
return (parts[0], int(parts[1]) if parts[1] else None)

return value if key not in CAST_TO else CAST_TO[key](value)

def handle_value(key, value, is_single=True):
"""Properly store the value in the `bot.server._isupport` dict.
Args:
key (string): the ISUPPORT parameter name
value (string): the raw parameter value string
is_single (bool): is the parameter value a single entry, or not
(is a list of items)?
"""
# Single parameter value
parsed_value = parse_value(key, value)
if type(parsed_value) is tuple:
# A value_type:limit value
if key not in bot.server._isupport:
# Not using defaultdict here; don't assume no limit;
# explicitly check for limit, if needed.
bot.server._isupport[key] = {}
bot.server._isupport[key][parsed_value[0]] = parsed_value[1]
return

# Else, simple value
if not is_single:
# A value with multiple entries (e.g., CHANMODES)
if key not in bot.server._isupport:
bot.server._isupport[key] = []
bot.server._isupport[key].append(parsed_value)
return

# A value with a single entry (e.g., NETWORK)
bot.server._isupport[key] = parsed_value
return

# Last arg is the 'are supported by this server' string; first arg is the client.
parameters = trigger.args[1:-1]
for param in parameters:
if '=' not in param:
# Simple flag (e.g,. SAFELIST)
val = True if param not in DEFAULT_VALUES else DEFAULT_VALUES[param]
bot.server._isupport[param] = val # Default values should be correct type
continue

key, raw_value = param.split('=')
if ',' not in raw_value:
handle_value(key, raw_value)
continue

values = raw_value.split(',')
for val in values:
handle_value(key, val, is_single=False)


@sopel.module.rule('(.*)')
@sopel.module.event(events.RPL_NAMREPLY)
@sopel.module.priority('high')
Expand Down

0 comments on commit b34dab5

Please sign in to comment.