bump python-irclib to 0.6.4, the latest i care to merge right now
This commit is contained in:
parent
db0cfbc997
commit
17040c1cde
@ -1,6 +1,6 @@
|
|||||||
Python IRC library (python-irclib)
|
Python IRC library (python-irclib)
|
||||||
* http://python-irclib.sourceforge.net/
|
* http://python-irclib.sourceforge.net/
|
||||||
* 0.4.8
|
* 0.6.4
|
||||||
* LGPLv2
|
* LGPLv2
|
||||||
|
|
||||||
python-weather-api
|
python-weather-api
|
||||||
|
321
extlib/irclib.py
321
extlib/irclib.py
@ -1,4 +1,7 @@
|
|||||||
# Copyright (C) 1999--2002 Joel Rosdahl
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (C) 1999-2002 Joel Rosdahl
|
||||||
|
# Portions Copyright © 2011 Jason R. Coombs
|
||||||
#
|
#
|
||||||
# This library is free software; you can redistribute it and/or
|
# This library is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
@ -15,10 +18,9 @@
|
|||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
#
|
#
|
||||||
# keltus <keltus@users.sourceforge.net>
|
# keltus <keltus@users.sourceforge.net>
|
||||||
#
|
|
||||||
# $Id: irclib.py,v 1.47 2008/09/25 22:00:59 keltus Exp $
|
|
||||||
|
|
||||||
"""irclib -- Internet Relay Chat (IRC) protocol client library.
|
"""
|
||||||
|
irclib -- Internet Relay Chat (IRC) protocol client library.
|
||||||
|
|
||||||
This library is intended to encapsulate the IRC protocol at a quite
|
This library is intended to encapsulate the IRC protocol at a quite
|
||||||
low level. It provides an event-driven IRC client framework. It has
|
low level. It provides an event-driven IRC client framework. It has
|
||||||
@ -66,12 +68,19 @@ import re
|
|||||||
import select
|
import select
|
||||||
import socket
|
import socket
|
||||||
import string
|
import string
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
import types
|
import types
|
||||||
|
import ssl as ssl_mod
|
||||||
|
import datetime
|
||||||
|
|
||||||
VERSION = 0, 4, 8
|
try:
|
||||||
DEBUG = 0
|
import pkg_resources
|
||||||
|
_pkg = pkg_resources.require('python-irclib')[0]
|
||||||
|
VERSION = tuple(int(res) for res in re.findall('\d+', _pkg.version))
|
||||||
|
except Exception:
|
||||||
|
VERSION = ()
|
||||||
|
|
||||||
|
DEBUG = False
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
# ----
|
# ----
|
||||||
@ -93,7 +102,7 @@ class IRCError(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class IRC:
|
class IRC(object):
|
||||||
"""Class that handles one or several IRC server connections.
|
"""Class that handles one or several IRC server connections.
|
||||||
|
|
||||||
When an IRC object has been instantiated, it can be used to create
|
When an IRC object has been instantiated, it can be used to create
|
||||||
@ -112,12 +121,12 @@ class IRC:
|
|||||||
|
|
||||||
irc = irclib.IRC()
|
irc = irclib.IRC()
|
||||||
server = irc.server()
|
server = irc.server()
|
||||||
server.connect(\"irc.some.where\", 6667, \"my_nickname\")
|
server.connect("irc.some.where", 6667, "my_nickname")
|
||||||
server.privmsg(\"a_nickname\", \"Hi there!\")
|
server.privmsg("a_nickname", "Hi there!")
|
||||||
irc.process_forever()
|
irc.process_forever()
|
||||||
|
|
||||||
This will connect to the IRC server irc.some.where on port 6667
|
This will connect to the IRC server irc.some.where on port 6667
|
||||||
using the nickname my_nickname and send the message \"Hi there!\"
|
using the nickname my_nickname and send the message "Hi there!"
|
||||||
to the nickname a_nickname.
|
to the nickname a_nickname.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -157,7 +166,7 @@ class IRC:
|
|||||||
self.fn_to_add_timeout = fn_to_add_timeout
|
self.fn_to_add_timeout = fn_to_add_timeout
|
||||||
self.connections = []
|
self.connections = []
|
||||||
self.handlers = {}
|
self.handlers = {}
|
||||||
self.delayed_commands = [] # list of tuples in the format (time, function, arguments)
|
self.delayed_commands = [] # list of DelayedCommands
|
||||||
|
|
||||||
self.add_global_handler("ping", _ping_ponger, -42)
|
self.add_global_handler("ping", _ping_ponger, -42)
|
||||||
|
|
||||||
@ -187,13 +196,14 @@ class IRC:
|
|||||||
|
|
||||||
See documentation for IRC.__init__.
|
See documentation for IRC.__init__.
|
||||||
"""
|
"""
|
||||||
t = time.time()
|
|
||||||
while self.delayed_commands:
|
while self.delayed_commands:
|
||||||
if t >= self.delayed_commands[0][0]:
|
command = self.delayed_commands[0]
|
||||||
self.delayed_commands[0][1](*self.delayed_commands[0][2])
|
if not command.due():
|
||||||
del self.delayed_commands[0]
|
|
||||||
else:
|
|
||||||
break
|
break
|
||||||
|
command.function(*command.arguments)
|
||||||
|
if isinstance(command, PeriodicCommand):
|
||||||
|
self._schedule_command(command.next())
|
||||||
|
del self.delayed_commands[0]
|
||||||
|
|
||||||
def process_once(self, timeout=0):
|
def process_once(self, timeout=0):
|
||||||
"""Process data from connections once.
|
"""Process data from connections once.
|
||||||
@ -252,7 +262,7 @@ class IRC:
|
|||||||
|
|
||||||
The handler functions are called in priority order (lowest
|
The handler functions are called in priority order (lowest
|
||||||
number is highest priority). If a handler function returns
|
number is highest priority). If a handler function returns
|
||||||
\"NO MORE\", no more handlers will be called.
|
"NO MORE", no more handlers will be called.
|
||||||
"""
|
"""
|
||||||
if not event in self.handlers:
|
if not event in self.handlers:
|
||||||
self.handlers[event] = []
|
self.handlers[event] = []
|
||||||
@ -264,7 +274,6 @@ class IRC:
|
|||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
event -- Event type (a string).
|
event -- Event type (a string).
|
||||||
|
|
||||||
handler -- Callback function.
|
handler -- Callback function.
|
||||||
|
|
||||||
Returns 1 on success, otherwise 0.
|
Returns 1 on success, otherwise 0.
|
||||||
@ -281,28 +290,39 @@ class IRC:
|
|||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
at -- Execute at this time (standard \"time_t\" time).
|
at -- Execute at this time (standard "time_t" time).
|
||||||
|
|
||||||
function -- Function to call.
|
function -- Function to call.
|
||||||
|
|
||||||
arguments -- Arguments to give the function.
|
arguments -- Arguments to give the function.
|
||||||
"""
|
"""
|
||||||
self.execute_delayed(at-time.time(), function, arguments)
|
command = DelayedCommand.at_time(at, function, arguments)
|
||||||
|
self._schedule_command(command)
|
||||||
|
|
||||||
def execute_delayed(self, delay, function, arguments=()):
|
def execute_delayed(self, delay, function, arguments=()):
|
||||||
"""Execute a function after a specified time.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
|
|
||||||
delay -- How many seconds to wait.
|
|
||||||
|
|
||||||
function -- Function to call.
|
|
||||||
|
|
||||||
arguments -- Arguments to give the function.
|
|
||||||
"""
|
"""
|
||||||
bisect.insort(self.delayed_commands, (delay+time.time(), function, arguments))
|
Execute a function after a specified time.
|
||||||
|
|
||||||
|
delay -- How many seconds to wait.
|
||||||
|
function -- Function to call.
|
||||||
|
arguments -- Arguments to give the function.
|
||||||
|
"""
|
||||||
|
command = DelayedCommand(delay, function, arguments)
|
||||||
|
self._schedule_command(command)
|
||||||
|
|
||||||
|
def execute_every(self, period, function, arguments=()):
|
||||||
|
"""
|
||||||
|
Execute a function every 'period' seconds.
|
||||||
|
|
||||||
|
period -- How often to run (always waits this long for first).
|
||||||
|
function -- Function to call.
|
||||||
|
arguments -- Arguments to give the function.
|
||||||
|
"""
|
||||||
|
command = PeriodicCommand(period, function, arguments)
|
||||||
|
self._schedule_command(command)
|
||||||
|
|
||||||
|
def _schedule_command(self, command):
|
||||||
|
bisect.insort(self.delayed_commands, command)
|
||||||
if self.fn_to_add_timeout:
|
if self.fn_to_add_timeout:
|
||||||
self.fn_to_add_timeout(delay)
|
self.fn_to_add_timeout(total_seconds(command.delay))
|
||||||
|
|
||||||
def dcc(self, dcctype="chat"):
|
def dcc(self, dcctype="chat"):
|
||||||
"""Creates and returns a DCCConnection object.
|
"""Creates and returns a DCCConnection object.
|
||||||
@ -321,7 +341,8 @@ class IRC:
|
|||||||
def _handle_event(self, connection, event):
|
def _handle_event(self, connection, event):
|
||||||
"""[Internal]"""
|
"""[Internal]"""
|
||||||
h = self.handlers
|
h = self.handlers
|
||||||
for handler in h.get("all_events", []) + h.get(event.eventtype(), []):
|
th = sorted(h.get("all_events", []) + h.get(event.eventtype(), []))
|
||||||
|
for handler in th:
|
||||||
if handler[1](connection, event) == "NO MORE":
|
if handler[1](connection, event) == "NO MORE":
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -331,9 +352,48 @@ class IRC:
|
|||||||
if self.fn_to_remove_socket:
|
if self.fn_to_remove_socket:
|
||||||
self.fn_to_remove_socket(connection._get_socket())
|
self.fn_to_remove_socket(connection._get_socket())
|
||||||
|
|
||||||
|
class DelayedCommand(datetime.datetime):
|
||||||
|
"""
|
||||||
|
A command to be executed after some delay (seconds or timedelta).
|
||||||
|
"""
|
||||||
|
def __new__(cls, delay, function, arguments):
|
||||||
|
if not isinstance(delay, datetime.timedelta):
|
||||||
|
delay = datetime.timedelta(seconds=delay)
|
||||||
|
at = datetime.datetime.utcnow() + delay
|
||||||
|
cmd = datetime.datetime.__new__(DelayedCommand, at.year,
|
||||||
|
at.month, at.day, at.hour, at.minute, at.second,
|
||||||
|
at.microsecond, at.tzinfo)
|
||||||
|
cmd.delay = delay
|
||||||
|
cmd.function = function
|
||||||
|
cmd.arguments = arguments
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
def at_time(cls, at, function, arguments):
|
||||||
|
"""
|
||||||
|
Construct a DelayedCommand to come due at `at`, where `at` may be
|
||||||
|
a datetime or timestamp.
|
||||||
|
"""
|
||||||
|
if isinstance(at, int):
|
||||||
|
at = datetime.datetime.utcfromtimestamp(at)
|
||||||
|
delay = at - datetime.datetime.utcnow()
|
||||||
|
return cls(delay, function, arguments)
|
||||||
|
at_time = classmethod(at_time)
|
||||||
|
|
||||||
|
def due(self):
|
||||||
|
return datetime.datetime.utcnow() >= self
|
||||||
|
|
||||||
|
class PeriodicCommand(DelayedCommand):
|
||||||
|
"""
|
||||||
|
Like a deferred command, but expect this command to run every delay
|
||||||
|
seconds.
|
||||||
|
"""
|
||||||
|
def next(self):
|
||||||
|
return PeriodicCommand(self.delay, self.function,
|
||||||
|
self.arguments)
|
||||||
|
|
||||||
_rfc_1459_command_regexp = re.compile("^(:(?P<prefix>[^ ]+) +)?(?P<command>[^ ]+)( *(?P<argument> .+))?")
|
_rfc_1459_command_regexp = re.compile("^(:(?P<prefix>[^ ]+) +)?(?P<command>[^ ]+)( *(?P<argument> .+))?")
|
||||||
|
|
||||||
class Connection:
|
class Connection(object):
|
||||||
"""Base class for IRC connections.
|
"""Base class for IRC connections.
|
||||||
|
|
||||||
Must be overridden.
|
Must be overridden.
|
||||||
@ -342,7 +402,7 @@ class Connection:
|
|||||||
self.irclibobj = irclibobj
|
self.irclibobj = irclibobj
|
||||||
|
|
||||||
def _get_socket():
|
def _get_socket():
|
||||||
raise IRCError, "Not overridden"
|
raise IRCError("Not overridden")
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
### Convenience wrappers.
|
### Convenience wrappers.
|
||||||
@ -353,6 +413,8 @@ class Connection:
|
|||||||
def execute_delayed(self, delay, function, arguments=()):
|
def execute_delayed(self, delay, function, arguments=()):
|
||||||
self.irclibobj.execute_delayed(delay, function, arguments)
|
self.irclibobj.execute_delayed(delay, function, arguments)
|
||||||
|
|
||||||
|
def execute_every(self, period, function, arguments=()):
|
||||||
|
self.irclibobj.execute_every(period, function, arguments)
|
||||||
|
|
||||||
class ServerConnectionError(IRCError):
|
class ServerConnectionError(IRCError):
|
||||||
pass
|
pass
|
||||||
@ -373,7 +435,7 @@ class ServerConnection(Connection):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, irclibobj):
|
def __init__(self, irclibobj):
|
||||||
Connection.__init__(self, irclibobj)
|
super(ServerConnection, self).__init__(irclibobj)
|
||||||
self.connected = 0 # Not connected yet.
|
self.connected = 0 # Not connected yet.
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self.ssl = None
|
self.ssl = None
|
||||||
@ -432,11 +494,11 @@ class ServerConnection(Connection):
|
|||||||
self.socket.bind((self.localaddress, self.localport))
|
self.socket.bind((self.localaddress, self.localport))
|
||||||
self.socket.connect((self.server, self.port))
|
self.socket.connect((self.server, self.port))
|
||||||
if ssl:
|
if ssl:
|
||||||
self.ssl = socket.ssl(self.socket)
|
self.ssl = ssl_mod.wrap_socket(self.socket)
|
||||||
except socket.error, x:
|
except socket.error, x:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
self.socket = None
|
self.socket = None
|
||||||
raise ServerConnectionError, "Couldn't connect to socket: %s" % x
|
raise ServerConnectionError("Couldn't connect to socket: %s" % x)
|
||||||
self.connected = 1
|
self.connected = 1
|
||||||
if self.irclibobj.fn_to_add_socket:
|
if self.irclibobj.fn_to_add_socket:
|
||||||
self.irclibobj.fn_to_add_socket(self.socket)
|
self.irclibobj.fn_to_add_socket(self.socket)
|
||||||
@ -488,10 +550,10 @@ class ServerConnection(Connection):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if self.ssl:
|
if self.ssl:
|
||||||
new_data = self.ssl.read(2**14)
|
new_data = self.ssl.read(2 ** 14)
|
||||||
else:
|
else:
|
||||||
new_data = self.socket.recv(2**14)
|
new_data = self.socket.recv(2 ** 14)
|
||||||
except socket.error, x:
|
except socket.error:
|
||||||
# The server hung up.
|
# The server hung up.
|
||||||
self.disconnect("Connection reset by peer")
|
self.disconnect("Connection reset by peer")
|
||||||
return
|
return
|
||||||
@ -660,7 +722,7 @@ class ServerConnection(Connection):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
except socket.error, x:
|
except socket.error:
|
||||||
pass
|
pass
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self._handle_event(Event("disconnect", self.server, "", [message]))
|
self._handle_event(Event("disconnect", self.server, "", [message]))
|
||||||
@ -743,10 +805,13 @@ class ServerConnection(Connection):
|
|||||||
|
|
||||||
def part(self, channels, message=""):
|
def part(self, channels, message=""):
|
||||||
"""Send a PART command."""
|
"""Send a PART command."""
|
||||||
if type(channels) == types.StringType:
|
channels = always_iterable(channels)
|
||||||
self.send_raw("PART " + channels + (message and (" " + message)))
|
cmd_parts = [
|
||||||
else:
|
'PART',
|
||||||
self.send_raw("PART " + ",".join(channels) + (message and (" " + message)))
|
','.join(channels),
|
||||||
|
]
|
||||||
|
if message: cmd_parts.append(message)
|
||||||
|
self.send_raw(' '.join(cmd_parts))
|
||||||
|
|
||||||
def pass_(self, password):
|
def pass_(self, password):
|
||||||
"""Send a PASS command."""
|
"""Send a PASS command."""
|
||||||
@ -782,7 +847,7 @@ class ServerConnection(Connection):
|
|||||||
The string will be padded with appropriate CR LF.
|
The string will be padded with appropriate CR LF.
|
||||||
"""
|
"""
|
||||||
if self.socket is None:
|
if self.socket is None:
|
||||||
raise ServerNotConnectedError, "Not connected."
|
raise ServerNotConnectedError("Not connected.")
|
||||||
try:
|
try:
|
||||||
if self.ssl:
|
if self.ssl:
|
||||||
self.ssl.write(string + "\r\n")
|
self.ssl.write(string + "\r\n")
|
||||||
@ -790,7 +855,7 @@ class ServerConnection(Connection):
|
|||||||
self.socket.send(string + "\r\n")
|
self.socket.send(string + "\r\n")
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "TO SERVER:", string
|
print "TO SERVER:", string
|
||||||
except socket.error, x:
|
except socket.error:
|
||||||
# Ouch!
|
# Ouch!
|
||||||
self.disconnect("Connection reset by peer.")
|
self.disconnect("Connection reset by peer.")
|
||||||
|
|
||||||
@ -862,7 +927,7 @@ class DCCConnection(Connection):
|
|||||||
method on an IRC object.
|
method on an IRC object.
|
||||||
"""
|
"""
|
||||||
def __init__(self, irclibobj, dcctype):
|
def __init__(self, irclibobj, dcctype):
|
||||||
Connection.__init__(self, irclibobj)
|
super(DCCConnection, self).__init__(irclibobj)
|
||||||
self.connected = 0
|
self.connected = 0
|
||||||
self.passive = 0
|
self.passive = 0
|
||||||
self.dcctype = dcctype
|
self.dcctype = dcctype
|
||||||
@ -889,7 +954,7 @@ class DCCConnection(Connection):
|
|||||||
try:
|
try:
|
||||||
self.socket.connect((self.peeraddress, self.peerport))
|
self.socket.connect((self.peeraddress, self.peerport))
|
||||||
except socket.error, x:
|
except socket.error, x:
|
||||||
raise DCCConnectionError, "Couldn't connect to socket: %s" % x
|
raise DCCConnectionError("Couldn't connect to socket: %s" % x)
|
||||||
self.connected = 1
|
self.connected = 1
|
||||||
if self.irclibobj.fn_to_add_socket:
|
if self.irclibobj.fn_to_add_socket:
|
||||||
self.irclibobj.fn_to_add_socket(self.socket)
|
self.irclibobj.fn_to_add_socket(self.socket)
|
||||||
@ -914,7 +979,7 @@ class DCCConnection(Connection):
|
|||||||
self.localaddress, self.localport = self.socket.getsockname()
|
self.localaddress, self.localport = self.socket.getsockname()
|
||||||
self.socket.listen(10)
|
self.socket.listen(10)
|
||||||
except socket.error, x:
|
except socket.error, x:
|
||||||
raise DCCConnectionError, "Couldn't bind socket: %s" % x
|
raise DCCConnectionError("Couldn't bind socket: %s" % x)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def disconnect(self, message=""):
|
def disconnect(self, message=""):
|
||||||
@ -930,7 +995,7 @@ class DCCConnection(Connection):
|
|||||||
self.connected = 0
|
self.connected = 0
|
||||||
try:
|
try:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
except socket.error, x:
|
except socket.error:
|
||||||
pass
|
pass
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self.irclibobj._handle_event(
|
self.irclibobj._handle_event(
|
||||||
@ -955,8 +1020,8 @@ class DCCConnection(Connection):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_data = self.socket.recv(2**14)
|
new_data = self.socket.recv(2 ** 14)
|
||||||
except socket.error, x:
|
except socket.error:
|
||||||
# The server hung up.
|
# The server hung up.
|
||||||
self.disconnect("Connection reset by peer")
|
self.disconnect("Connection reset by peer")
|
||||||
return
|
return
|
||||||
@ -972,7 +1037,7 @@ class DCCConnection(Connection):
|
|||||||
|
|
||||||
# Save the last, unfinished line.
|
# Save the last, unfinished line.
|
||||||
self.previous_buffer = chunks[-1]
|
self.previous_buffer = chunks[-1]
|
||||||
if len(self.previous_buffer) > 2**14:
|
if len(self.previous_buffer) > 2 ** 14:
|
||||||
# Bad peer! Naughty peer!
|
# Bad peer! Naughty peer!
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
return
|
return
|
||||||
@ -1010,11 +1075,11 @@ class DCCConnection(Connection):
|
|||||||
self.socket.send("\n")
|
self.socket.send("\n")
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "TO PEER: %s\n" % string
|
print "TO PEER: %s\n" % string
|
||||||
except socket.error, x:
|
except socket.error:
|
||||||
# Ouch!
|
# Ouch!
|
||||||
self.disconnect("Connection reset by peer.")
|
self.disconnect("Connection reset by peer.")
|
||||||
|
|
||||||
class SimpleIRCClient:
|
class SimpleIRCClient(object):
|
||||||
"""A simple single-server IRC client class.
|
"""A simple single-server IRC client class.
|
||||||
|
|
||||||
This is an example of an object-oriented wrapper of the IRC
|
This is an example of an object-oriented wrapper of the IRC
|
||||||
@ -1044,6 +1109,9 @@ class SimpleIRCClient:
|
|||||||
|
|
||||||
def _dispatcher(self, c, e):
|
def _dispatcher(self, c, e):
|
||||||
"""[Internal]"""
|
"""[Internal]"""
|
||||||
|
if DEBUG:
|
||||||
|
print("irclib.py:_dispatcher:%s" % e.eventtype())
|
||||||
|
|
||||||
m = "on_" + e.eventtype()
|
m = "on_" + e.eventtype()
|
||||||
if hasattr(self, m):
|
if hasattr(self, m):
|
||||||
getattr(self, m)(c, e)
|
getattr(self, m)(c, e)
|
||||||
@ -1114,7 +1182,7 @@ class SimpleIRCClient:
|
|||||||
self.ircobj.process_forever()
|
self.ircobj.process_forever()
|
||||||
|
|
||||||
|
|
||||||
class Event:
|
class Event(object):
|
||||||
"""Class representing an IRC event."""
|
"""Class representing an IRC event."""
|
||||||
def __init__(self, eventtype, source, target, arguments=None):
|
def __init__(self, eventtype, source, target, arguments=None):
|
||||||
"""Constructor of Event objects.
|
"""Constructor of Event objects.
|
||||||
@ -1184,16 +1252,6 @@ def mask_matches(nick, mask):
|
|||||||
|
|
||||||
_special = "-[]\\`^{}"
|
_special = "-[]\\`^{}"
|
||||||
nick_characters = string.ascii_letters + string.digits + _special
|
nick_characters = string.ascii_letters + string.digits + _special
|
||||||
_ircstring_translation = string.maketrans(string.ascii_uppercase + "[]\\^",
|
|
||||||
string.ascii_lowercase + "{}|~")
|
|
||||||
|
|
||||||
def irc_lower(s):
|
|
||||||
"""Returns a lowercased string.
|
|
||||||
|
|
||||||
The definition of lowercased comes from the IRC specification (RFC
|
|
||||||
1459).
|
|
||||||
"""
|
|
||||||
return s.translate(_ircstring_translation)
|
|
||||||
|
|
||||||
def _ctcp_dequote(message):
|
def _ctcp_dequote(message):
|
||||||
"""[Internal] Dequote a message according to CTCP specifications.
|
"""[Internal] Dequote a message according to CTCP specifications.
|
||||||
@ -1229,14 +1287,14 @@ def _ctcp_dequote(message):
|
|||||||
|
|
||||||
messages = []
|
messages = []
|
||||||
i = 0
|
i = 0
|
||||||
while i < len(chunks)-1:
|
while i < len(chunks) - 1:
|
||||||
# Add message if it's non-empty.
|
# Add message if it's non-empty.
|
||||||
if len(chunks[i]) > 0:
|
if len(chunks[i]) > 0:
|
||||||
messages.append(chunks[i])
|
messages.append(chunks[i])
|
||||||
|
|
||||||
if i < len(chunks)-2:
|
if i < len(chunks) - 2:
|
||||||
# Aye! CTCP tagged data ahead!
|
# Aye! CTCP tagged data ahead!
|
||||||
messages.append(tuple(chunks[i+1].split(" ", 1)))
|
messages.append(tuple(chunks[i + 1].split(" ", 1)))
|
||||||
|
|
||||||
i = i + 2
|
i = i + 2
|
||||||
|
|
||||||
@ -1308,12 +1366,12 @@ def parse_nick_modes(mode_string):
|
|||||||
"""Parse a nick mode string.
|
"""Parse a nick mode string.
|
||||||
|
|
||||||
The function returns a list of lists with three members: sign,
|
The function returns a list of lists with three members: sign,
|
||||||
mode and argument. The sign is \"+\" or \"-\". The argument is
|
mode and argument. The sign is "+" or "-". The argument is
|
||||||
always None.
|
always None.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
>>> irclib.parse_nick_modes(\"+ab-c\")
|
>>> parse_nick_modes("+ab-c")
|
||||||
[['+', 'a', None], ['+', 'b', None], ['-', 'c', None]]
|
[['+', 'a', None], ['+', 'b', None], ['-', 'c', None]]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -1323,12 +1381,12 @@ def parse_channel_modes(mode_string):
|
|||||||
"""Parse a channel mode string.
|
"""Parse a channel mode string.
|
||||||
|
|
||||||
The function returns a list of lists with three members: sign,
|
The function returns a list of lists with three members: sign,
|
||||||
mode and argument. The sign is \"+\" or \"-\". The argument is
|
mode and argument. The sign is "+" or "-". The argument is
|
||||||
None if mode isn't one of \"b\", \"k\", \"l\", \"v\" or \"o\".
|
None if mode isn't one of "b", "k", "l", "v" or "o".
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
>>> irclib.parse_channel_modes(\"+ab-c foo\")
|
>>> parse_channel_modes("+ab-c foo")
|
||||||
[['+', 'a', None], ['+', 'b', 'foo'], ['-', 'c', None]]
|
[['+', 'a', None], ['+', 'b', 'foo'], ['-', 'c', None]]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -1354,7 +1412,7 @@ def _parse_modes(mode_string, unary_modes=""):
|
|||||||
if ch in "+-":
|
if ch in "+-":
|
||||||
sign = ch
|
sign = ch
|
||||||
elif ch == " ":
|
elif ch == " ":
|
||||||
collecting_arguments = 1
|
pass
|
||||||
elif ch in unary_modes:
|
elif ch in unary_modes:
|
||||||
if len(args) >= arg_count + 1:
|
if len(args) >= arg_count + 1:
|
||||||
modes.append([sign, ch, args[arg_count]])
|
modes.append([sign, ch, args[arg_count]])
|
||||||
@ -1494,7 +1552,7 @@ numeric_events = {
|
|||||||
"423": "noadmininfo",
|
"423": "noadmininfo",
|
||||||
"424": "fileerror",
|
"424": "fileerror",
|
||||||
"431": "nonicknamegiven",
|
"431": "nonicknamegiven",
|
||||||
"432": "erroneusnickname", # Thiss iz how its speld in thee RFC.
|
"432": "erroneusnickname", # Thiss iz how its speld in thee RFC.
|
||||||
"433": "nicknameinuse",
|
"433": "nicknameinuse",
|
||||||
"436": "nickcollision",
|
"436": "nickcollision",
|
||||||
"437": "unavailresource", # "Nick temporally unavailable"
|
"437": "unavailresource", # "Nick temporally unavailable"
|
||||||
@ -1509,7 +1567,7 @@ numeric_events = {
|
|||||||
"462": "alreadyregistered",
|
"462": "alreadyregistered",
|
||||||
"463": "nopermforhost",
|
"463": "nopermforhost",
|
||||||
"464": "passwdmismatch",
|
"464": "passwdmismatch",
|
||||||
"465": "yourebannedcreep", # I love this one...
|
"465": "yourebannedcreep", # I love this one...
|
||||||
"466": "youwillbebanned",
|
"466": "youwillbebanned",
|
||||||
"467": "keyset",
|
"467": "keyset",
|
||||||
"471": "channelisfull",
|
"471": "channelisfull",
|
||||||
@ -1559,3 +1617,104 @@ protocol_events = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
all_events = generated_events + protocol_events + numeric_events.values()
|
all_events = generated_events + protocol_events + numeric_events.values()
|
||||||
|
|
||||||
|
# from jaraco.util.itertools
|
||||||
|
def always_iterable(item):
|
||||||
|
"""
|
||||||
|
Given an object, always return an iterable. If the item is not
|
||||||
|
already iterable, return a tuple containing only the item.
|
||||||
|
|
||||||
|
>>> always_iterable([1,2,3])
|
||||||
|
[1, 2, 3]
|
||||||
|
>>> always_iterable('foo')
|
||||||
|
('foo',)
|
||||||
|
>>> always_iterable(None)
|
||||||
|
(None,)
|
||||||
|
>>> always_iterable(xrange(10))
|
||||||
|
xrange(10)
|
||||||
|
"""
|
||||||
|
if isinstance(item, basestring) or not hasattr(item, '__iter__'):
|
||||||
|
item = item,
|
||||||
|
return item
|
||||||
|
|
||||||
|
# from jaraco.util.string
|
||||||
|
class FoldedCase(str):
|
||||||
|
"""
|
||||||
|
A case insensitive string class; behaves just like str
|
||||||
|
except compares equal when the only variation is case.
|
||||||
|
>>> s = FoldedCase('hello world')
|
||||||
|
|
||||||
|
>>> s == 'Hello World'
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> 'Hello World' == s
|
||||||
|
True
|
||||||
|
|
||||||
|
>>> s.index('O')
|
||||||
|
4
|
||||||
|
|
||||||
|
>>> s.split('O')
|
||||||
|
['hell', ' w', 'rld']
|
||||||
|
|
||||||
|
>>> names = map(FoldedCase, ['GAMMA', 'alpha', 'Beta'])
|
||||||
|
>>> names.sort()
|
||||||
|
>>> names
|
||||||
|
['alpha', 'Beta', 'GAMMA']
|
||||||
|
"""
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.lower() < other.lower()
|
||||||
|
|
||||||
|
def __gt__(self, other):
|
||||||
|
return self.lower() > other.lower()
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.lower() == other.lower()
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.lower())
|
||||||
|
|
||||||
|
# cache lower since it's likely to be called frequently.
|
||||||
|
def lower(self):
|
||||||
|
self._lower = super(FoldedCase, self).lower()
|
||||||
|
self.lower = lambda: self._lower
|
||||||
|
return self._lower
|
||||||
|
|
||||||
|
def index(self, sub):
|
||||||
|
return self.lower().index(sub.lower())
|
||||||
|
|
||||||
|
def split(self, splitter=' ', maxsplit=0):
|
||||||
|
pattern = re.compile(re.escape(splitter), re.I)
|
||||||
|
return pattern.split(self, maxsplit)
|
||||||
|
|
||||||
|
class IRCFoldedCase(FoldedCase):
|
||||||
|
"""
|
||||||
|
A version of FoldedCase that honors the IRC specification for lowercased
|
||||||
|
strings (RFC 1459).
|
||||||
|
|
||||||
|
>>> IRCFoldedCase('Foo^').lower()
|
||||||
|
'foo~'
|
||||||
|
>>> IRCFoldedCase('[this]') == IRCFoldedCase('{THIS}')
|
||||||
|
True
|
||||||
|
"""
|
||||||
|
translation = string.maketrans(
|
||||||
|
string.ascii_uppercase + r"[]\^",
|
||||||
|
string.ascii_lowercase + r"{}|~",
|
||||||
|
)
|
||||||
|
|
||||||
|
def lower(self):
|
||||||
|
return self.translate(self.translation)
|
||||||
|
|
||||||
|
# for compatibility
|
||||||
|
def irc_lower(str):
|
||||||
|
return IRCFoldedCase(str).lower()
|
||||||
|
|
||||||
|
def total_seconds(td):
|
||||||
|
"""
|
||||||
|
Python 2.7 adds a total_seconds method to timedelta objects.
|
||||||
|
See http://docs.python.org/library/datetime.html#datetime.timedelta.total_seconds
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
result = td.total_seconds()
|
||||||
|
except AttributeError:
|
||||||
|
result = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
|
||||||
|
return result
|
||||||
|
Loading…
x
Reference in New Issue
Block a user