Source code for hanyuu.ircbot.irclib.utils
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import absolute_import
import re
import string
#: The character used for low level CTCP quoting
_LOW_LEVEL_QUOTE = "\020"
#: Some kind of quoting char? No idea what this is for
_CTCP_LEVEL_QUOTE = "\134"
#: Signifies the start and end of a CTCP message
_CTCP_DELIMITER = "\001"
#: Regex used for separating lines in the IRC protocol
#: Some IRC servers seem to use \n only as the delimiter
_linesep_regexp = re.compile("\r?\n")
#: Regex used to split lines into their components, according to the IRC
#: specification. The regex groups are prefix, command and argument
_rfc_1459_command_regexp = re.compile("^(:(?P<prefix>[^ ]+) +)?(?P<command>[^ ]+)( *(?P<argument> .+))?", re.UNICODE)
#: Character mapping for special characters in low level CTCP quoting
_low_level_mapping = {
"0": "\000",
"n": "\n",
"r": "\r",
_LOW_LEVEL_QUOTE: _LOW_LEVEL_QUOTE
}
#: Regex used for dequoting CTCP quotes. I think
_low_level_regexp = re.compile(_LOW_LEVEL_QUOTE + "(.)", re.UNICODE)
_special = "-[]\\`^{}"
#: The characters that are permitted in IRC nicknames
nick_characters = string.ascii_letters + string.digits + _special
#: A translation map for translating IRC lowercase and uppercase
_ircstring_translation = string.maketrans(string.ascii_uppercase + "[]\\^",
string.ascii_lowercase + "{}|~")
[docs]def mask_matches(nick, mask):
"""Check if a nick matches a mask.
Returns True if the nick matches, otherwise False.
"""
nick = irc_lower(nick)
mask = irc_lower(mask)
mask = mask.replace("\\", "\\\\")
for ch in ".$|[](){}+":
mask = mask.replace(ch, "\\" + ch)
mask = mask.replace("?", ".")
mask = mask.replace("*", ".*")
r = re.compile(mask, re.IGNORECASE)
return r.match(nick)
[docs]def irc_lower(s):
"""Returns a lowercased string.
The definition of lowercased comes from the IRC specification (RFC
1459).
"""
if (type(s) == unicode):
s = s.encode('utf-8')
return s.translate(_ircstring_translation)
def _ctcp_dequote(message):
"""[Internal] Dequote a message according to CTCP specifications.
The function returns a list where each element can be either a
string (normal message) or a tuple of one or two strings (tagged
messages). If a tuple has only one element (ie is a singleton),
that element is the tag; otherwise the tuple has two elements: the
tag and the data.
:param message: The message to be decoded.
"""
def _low_level_replace(match_obj):
ch = match_obj.group(1)
# If low_level_mapping doesn't have the character as key, we
# should just return the character.
return _low_level_mapping.get(ch, ch)
if _LOW_LEVEL_QUOTE in message:
# Yup, there was a quote. Release the dequoter, man!
message = _low_level_regexp.sub(_low_level_replace, message)
if _CTCP_DELIMITER not in message:
return [message]
else:
# Split it into parts. (Does any IRC client actually *use*
# CTCP stacking like this?)
chunks = message.split(_CTCP_DELIMITER)
messages = []
i = 0
while i < len(chunks)-1:
# Add message if it's non-empty.
if len(chunks[i]) > 0:
messages.append(chunks[i])
if i < len(chunks)-2:
# Aye! CTCP tagged data ahead!
messages.append(tuple(chunks[i+1].split(" ", 1)))
i = i + 2
if len(chunks) % 2 == 0:
# Hey, a lonely _CTCP_DELIMITER at the end! This means
# that the last chunk, including the delimiter, is a
# normal message! (This is according to the CTCP
# specification.)
messages.append(_CTCP_DELIMITER + chunks[-1])
return messages
[docs]def ip_numstr_to_quad(num):
"""Convert an IP number as an integer given in ASCII
representation (e.g. '3232235521') to an IP address string
(e.g. '192.168.0.1')."""
n = long(num)
p = map(str, map(int, [n >> 24 & 0xFF, n >> 16 & 0xFF,
n >> 8 & 0xFF, n & 0xFF]))
return ".".join(p)
[docs]def ip_quad_to_numstr(quad):
"""Convert an IP address string (e.g. '192.168.0.1') to an IP
number as an integer given in ASCII representation
(e.g. '3232235521')."""
p = map(long, quad.split("."))
s = str((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
if s[-1] == "L":
s = s[:-1]
return s
[docs]def nm_to_n(s):
"""Get the nick part of a nickmask.
(The source of an :class:`connection.Event` is a nickmask.)
"""
return s.split("!")[0]
[docs]def nm_to_uh(s):
"""Get the userhost part of a nickmask.
(The source of an :class:`connection.Event` is a nickmask.)
"""
return s.split("!")[1]
[docs]def nm_to_h(s):
"""Get the host part of a nickmask.
(The source of an :class:`connection.Event` is a nickmask.)
"""
return s.split("@")[1]
[docs]def nm_to_u(s):
"""Get the user part of a nickmask.
(The source of an :class:`connection.Event` is a nickmask.)
"""
s = s.split("!")[1]
return s.split("@")[0]