DevConsole: New IRC Client interface

This commit is contained in:
Eduardo Silva
2007-08-21 12:18:38 -04:00
parent 7215de2dfc
commit 2ed32d1a11
41 changed files with 5539 additions and 7 deletions
@@ -0,0 +1,16 @@
sugardir = $(pkgdatadir)/services/console/lib/purk/scripts
sugar_PYTHON = \
alias.py \
chaninfo.py \
clicks.py \
completion.py \
console.py \
history.py \
ignore.py \
irc_script.py \
keys.py \
theme.py \
timeout.py \
ui_script.py
+60
View File
@@ -0,0 +1,60 @@
import sys
import os
from conf import conf
aliases = conf.get("aliases",{
'op':'"mode "+window.id+" +"+"o"*len(args)+" "+" ".join(args)',
'deop':'"mode "+window.id+" -"+"o"*len(args)+" "+" ".join(args)',
'voice':'"mode "+window.id+" +"+"v"*len(args)+" "+" ".join(args)',
'devoice':'"mode "+window.id+" -"+"v"*len(args)+" "+" ".join(args)',
'umode':'"mode "+network.me+" "+" ".join(args)',
'clear':'window.output.clear()',
})
class CommandHandler:
__slots__ = ["command"]
def __init__(self, command):
self.command = command
def __call__(self, e):
loc = sys.modules.copy()
loc.update(e.__dict__)
result = eval(self.command,loc)
if isinstance(result,basestring):
core.events.run(result,e.window,e.network)
for name in aliases:
globals()['onCommand'+name.capitalize()] = CommandHandler(aliases[name])
def onCommandAlias(e):
if e.args and 'r' in e.switches:
name = e.args[0].lower()
command = aliases[name]
del aliases[name]
conf['aliases'] = aliases
e.window.write("* Deleted alias %s%s (was %s)" % (conf.get('command-prefix','/'),name,command))
core.events.load(__name__,reloading=True)
elif 'l' in e.switches:
e.window.write("* Current aliases:")
for i in aliases:
e.window.write("* %s%s: %s" % (conf.get('command-prefix','/'),i,aliases[i]))
elif len(e.args) >= 2:
name = e.args[0].lower()
command = ' '.join(e.args[1:])
aliases[name] = command
conf['aliases'] = aliases
e.window.write("* Created an alias %s%s to %s" % (conf.get('command-prefix','/'),name,command))
core.events.reload(__name__)
elif len(e.args) == 1:
name = e.args[0].lower()
if name in aliases:
e.window.write("* %s%s is an alias to %s" % (conf.get('command-prefix','/'),name,aliases[name]))
else:
e.window.write("* There is no alias %s%s" % (conf.get('command-prefix','/'),name))
else:
e.window.write(
"""Usage:
/alias \x02name\x02 \x02expression\x02 to create or replace an alias
/alias \x02name\x02 to look at an alias
/alias -r \x02name\x02 to remove an alias
/alias -l to see a list of aliases""")
@@ -0,0 +1,320 @@
import windows
def _justprefix(network, channel, nick):
fr, to = network.isupport["PREFIX"][1:].split(")")
for mode, prefix in zip(fr, to):
if mode in channel.nicks.get(nick, ''):
return prefix
return ''
def prefix(network, channelname, nick):
channel = getchan(network, channelname)
if channel:
nick = '%s%s' % (_justprefix(network, channel, nick), nick)
return nick
def escape(string):
for escapes in (('&','&amp;'), ('<','&lt;'), ('>','&gt;')):
string = string.replace(*escapes)
return string
def sortkey(network, channelname, nick):
chanmodes, dummy = network.isupport["PREFIX"][1:].split(")")
nickmodes = mode(network, channelname, nick)
return '%s%s' % (''.join(str(int(mode not in nickmodes)) for mode in chanmodes), network.norm_case(nick))
def nicklist_add(network, channel, nick):
window = windows.get(windows.ChannelWindow, network, channel.name, core)
#window = core.window
if window:
window.nicklist.append(nick, escape(prefix(network, channel.name, nick)), sortkey(network, channel.name, nick))
def nicklist_del(network, channel, nick):
window = windows.get(windows.ChannelWindow, network, channel.name, core)
#window = core.window
if window:
try:
window.nicklist.remove(nick)
except ValueError:
pass
def setupListRightClick(e):
if isinstance(e.window, windows.ChannelWindow):
#if isinstance(core.window, windows.ChannelWindow):
#if e.data[0] in e.window.network.isupport["PREFIX"].split(")")[1]:
if e.data[0] in core.window.network.isupport["PREFIX"].split(")")[1]:
e.nick = e.data[1:]
else:
e.nick = e.data
def setupSocketConnect(e):
e.network.channels = {}
def setdownDisconnect(e):
e.network.channels = {}
class Channel(object):
def __init__(self, name):
self.name = name
self.nicks = {}
self.normal_nicks = {} # mapping of normal nicks to actual nicks
self.getting_names = False #are we between lines in a /names reply?
self.mode = ''
self.special_mode = {} #for limits, keys, and anything similar
self.topic = ''
self.got_mode = False #did we get at least one mode reply?
self.got_names = False #did we get at least one names reply?
def getchan(network, channel):
return hasattr(network, 'channels') and network.channels.get(network.norm_case(channel))
#return a list of channels you're on on the given network
def channels(network):
if not hasattr(network, 'channels'):
network.channels = {}
return list(network.channels)
#return True if you're on the channel
def ischan(network, channel):
return bool(getchan(network, channel))
#return True if the nick is on the channel
def ison(network, channel, nickname):
channel = getchan(network, channel)
return channel and network.norm_case(nickname) in channel.normal_nicks
#return a list of nicks on the given channel
def nicks(network, channel):
channel = getchan(network, channel)
if channel:
return channel.nicks
else:
return {}
#return the mode on the given channel
def mode(network, channel, nickname=''):
channel = getchan(network, channel)
if channel:
if nickname:
realnick = channel.normal_nicks.get(network.norm_case(nickname))
if realnick:
return channel.nicks[realnick]
else:
result = channel.mode
for m in channel.mode:
if m in channel.special_mode:
result += ' '+channel.special_mode[m]
return result
return ''
#return the topic on the given channel
def topic(network, channel):
channel = getchan(network, channel)
if channel:
return channel.topic
else:
return ''
def setupJoin(e):
print e
if e.source == e.network.me:
e.network.channels[e.network.norm_case(e.target)] = Channel(e.target)
e.network.raw('MODE '+e.target)
#if we wanted to be paranoid, we'd account for not being on the channel
channel = getchan(e.network,e.target)
channel.nicks[e.source] = ''
channel.normal_nicks[e.network.norm_case(e.source)] = e.source
if e.source == e.network.me:
#If the channel window already existed, and we're joining, then we
#didn't clear out the nicklist when we left. That means we have to clear
#it out now.
window = windows.get(windows.ChannelWindow, e.network, e.target, core)
#window = core.window
#print core
if window:
window.nicklist.clear()
nicklist_add(e.network, channel, e.source)
def setdownPart(e):
if e.source == e.network.me:
del e.network.channels[e.network.norm_case(e.target)]
else:
channel = getchan(e.network,e.target)
nicklist_del(e.network, channel, e.source)
del channel.nicks[e.source]
del channel.normal_nicks[e.network.norm_case(e.source)]
def setdownKick(e):
if e.target == e.network.me:
del e.network.channels[e.network.norm_case(e.channel)]
else:
channel = getchan(e.network,e.channel)
nicklist_del(e.network, channel, e.target)
del channel.nicks[e.target]
del channel.normal_nicks[e.network.norm_case(e.target)]
def setdownQuit(e):
#if paranoid: check if e.source is me
for channame in channels(e.network):
channel = getchan(e.network,channame)
if e.source in channel.nicks:
nicklist_del(e.network, channel, e.source)
del channel.nicks[e.source]
del channel.normal_nicks[e.network.norm_case(e.source)]
def setupMode(e):
channel = getchan(e.network,e.channel)
if channel:
user_modes = e.network.isupport['PREFIX'].split(')')[0][1:]
(list_modes,
always_parm_modes,
set_parm_modes,
normal_modes) = e.network.isupport['CHANMODES'].split(',')
list_modes += user_modes
mode_on = True #are we reading a + section or a - section?
params = e.text.split(' ')
for char in params.pop(0):
if char == '+':
mode_on = True
elif char == '-':
mode_on = False
else:
if char in user_modes:
#these are modes like op and voice
nickname = params.pop(0)
nicklist_del(e.network, channel, nickname)
if mode_on:
channel.nicks[nickname] += char
else:
channel.nicks[nickname] = channel.nicks[nickname].replace(char, '')
nicklist_add(e.network, channel, nickname)
elif char in list_modes:
#things like ban/unban
#FIXME: We don't keep track of those lists here, but we know
# when they're changed and how. Scriptors should be able to
# take advantage of this
params.pop(0)
elif char in always_parm_modes:
#these always have a parameter
param = params.pop(0)
if mode_on:
channel.special_mode[char] = param
else:
#account for unsetting modes that aren't set
channel.special_mode.pop(char, None)
elif char in set_parm_modes:
#these have a parameter only if they're being set
if mode_on:
channel.special_mode[char] = params.pop(0)
else:
#account for unsetting modes that aren't set
channel.special_mode.pop(char, None)
if char not in list_modes:
if mode_on:
channel.mode = channel.mode.replace(char, '')+char
else:
channel.mode = channel.mode.replace(char, '')
def setdownNick(e):
for channame in channels(e.network):
channel = getchan(e.network,channame)
if e.source in channel.nicks:
nicklist_del(e.network, channel, e.source)
del channel.normal_nicks[e.network.norm_case(e.source)]
channel.nicks[e.target] = channel.nicks[e.source]
del channel.nicks[e.source]
channel.normal_nicks[e.network.norm_case(e.target)] = e.target
nicklist_add(e.network, channel, e.target)
def setupTopic(e):
channel = getchan(e.network, e.target)
if channel:
channel.topic = e.text
def setupRaw(e):
if e.msg[1] == '353': #names reply
channel = getchan(e.network,e.msg[4])
if channel:
if not channel.getting_names:
channel.nicks.clear()
channel.normal_nicks.clear()
channel.getting_names = True
if not channel.got_names:
e.quiet = True
for nickname in e.msg[5].split(' '):
if nickname:
if not nickname[0].isalpha() and nickname[0] in e.network.prefixes:
n = nickname[1:]
channel.nicks[n] = e.network.prefixes[nickname[0]]
channel.normal_nicks[e.network.norm_case(n)] = n
else:
channel.nicks[nickname] = ''
channel.normal_nicks[e.network.norm_case(nickname)] = nickname
elif e.msg[1] == '366': #end of names reply
channel = getchan(e.network,e.msg[3])
if channel:
if not channel.got_names:
e.quiet = True
channel.got_names = True
channel.getting_names = False
window = windows.get(windows.ChannelWindow, e.network, e.msg[3], core)
if window:
window.nicklist.replace(
(nick, escape(prefix(e.network, channel.name, nick)), sortkey(e.network, channel.name, nick)) for nick in channel.nicks
)
elif e.msg[1] == '324': #channel mode is
channel = getchan(e.network,e.msg[3])
if channel:
if not channel.got_mode:
e.quiet = True
channel.got_mode = True
mode = e.msg[4]
params = e.msg[:4:-1]
list_modes, always_parm_modes, set_parm_modes, normal_modes = \
e.network.isupport['CHANMODES'].split(',')
parm_modes = always_parm_modes + set_parm_modes
channel.mode = e.msg[4]
channel.special_mode.clear()
for char in channel.mode:
if char in parm_modes:
channel.special_mode[char] = params.pop()
elif e.msg[1] == '331': #no topic
channel = getchan(e.network,e.msg[3])
if channel:
channel.topic = ''
elif e.msg[1] == '332': #channel topic is
channel = getchan(e.network,e.msg[3])
if channel:
channel.topic = e.text
#core.events.load(__name__)
+146
View File
@@ -0,0 +1,146 @@
import ui
import windows
import chaninfo
from conf import conf
def set_target(e):
target_l = e.target.lstrip('@+%.(<')
e._target_fr = e.target_fr + len(e.target) - len(target_l)
target_r = e.target.rstrip('>:,')
e._target_to = e.target_to - len(e.target) + len(target_r)
if target_r.endswith(')'):
e._target = e.text[e._target_fr:e._target_to]
open_parens = e._target.count('(') - e._target.count(')')
while open_parens < 0 and e.text[e._target_to-1] == ')':
e._target_to -= 1
open_parens += 1
e._target = e.text[e._target_fr:e._target_to]
def is_nick(e):
return isinstance(e.window, windows.ChannelWindow) and \
chaninfo.ison(e.window.network, e.window.id, e._target)
def is_url(e):
def starts(prefix, mindots=1):
def prefix_url(target):
return target.startswith(prefix) and target.count('.') >= mindots
return prefix_url
to_check = [starts(*x) for x in [
('http://', 1),
('https://', 1),
('ftp://', 1),
('www', 2),
]]
for check_url in to_check:
if check_url(e._target):
return True
return False
def is_chan(e):
# click on a #channel
return e.window.network and e._target and \
e._target[0] in e.window.network.isupport.get('CHANTYPES', '&#$+')
def get_autojoin_list(network):
perform = conf.get('networks',{}).get(network.name,{}).get('perform',())
channels = set()
for line in perform:
if line.startswith('join ') and ' ' not in line[5:]:
channels.update(line[5:].split(','))
return channels
def add_autojoin(network, channel):
if 'networks' not in conf:
conf['networks'] = {}
if network.name not in conf['networks']:
conf['networks'][network.name] = {'server': network.server}
conf['start_networks'] = conf.get('start_networks',[]) + [network.name]
if 'perform' in conf['networks'][network.name]:
perform = conf['networks'][network.name]['perform']
else:
perform = conf['networks'][network.name]['perform'] = []
for n, line in enumerate(perform):
if line.startswith('join ') and ' ' not in line[5:]:
perform[n] = "%s,%s" % (line, channel)
break
else:
perform.append('join %s' % channel)
def make_nick_menu(e, target):
def query():
core.events.run('query %s' % target, e.window, e.window.network)
def whois():
core.events.run('whois %s' % target, e.window, e.window.network)
e.menu += [
('Query', query),
('Whois', whois),
(),
]
def onHover(e):
set_target(e)
for is_check in (is_nick, is_url, is_chan):
if is_check(e):
e.tolink.add((e._target_fr, e._target_to))
break
def onClick(e):
set_target(e)
if is_nick(e):
core.events.run('query %s' % e._target, e.window, e.window.network)
# url of the form http://xxx.xxx or www.xxx.xxx
elif is_url(e):
if e._target.startswith('www'):
e._target = 'http://%s' % e._target
ui.open_file(e._target)
# click on a #channel
elif is_chan(e):
if not chaninfo.ischan(e.window.network, e._target):
e.window.network.join(e._target)
window = windows.get(windows.ChannelWindow, e.window.network, e._target)
if window:
window.activate()
def onRightClick(e):
set_target(e)
# nick on this channel
if is_nick(e):
make_nick_menu(e, e._target)
elif is_url(e):
if e._target.startswith('www'):
e._target = 'http://%s' % e._target
def copy_to():
# copy to clipboard
ui.set_clipboard(e._target)
e.menu += [('Copy', copy_to)]
elif is_chan(e):
e.channel = e._target
e.network = e.window.network
core.events.trigger('ChannelMenu', e)
def onListRightClick(e):
if isinstance(e.window, windows.ChannelWindow):
make_nick_menu(e, e.nick)
def onListDoubleClick(e):
if isinstance(e.window, windows.ChannelWindow):
core.events.run("query %s" % e.target, e.window, e.window.network)
@@ -0,0 +1,135 @@
import windows
import chaninfo
from conf import conf
def channel_completer(window, left, right, text):
if isinstance(window, windows.ChannelWindow):
yield window.id
for w in windows.get_with(wclass=windows.ChannelWindow, network=window.network):
if w is not window:
yield w.id
for w in windows.get_with(wclass=windows.ChannelWindow):
if w.network is not window.network:
yield w.id
# normal server commands
srv_commands = ('ping', 'join', 'part', 'mode', 'server', 'kick',
'quit', 'nick', 'privmsg', 'notice', 'topic')
def command_completer(window, left, right, text):
for c in srv_commands:
yield '/%s' % c
if 'CMDS' in window.network.isupport:
for c in window.network.isupport['CMDS'].split(','):
yield '/%s' % c.lower()
for c in core.events.all_events:
if c.startswith('Command') and c != 'Command':
yield '/%s' % c[7:].lower()
def nick_completer(window, left, right, text):
if type(window) == windows.QueryWindow:
yield window.id
recent_speakers = getattr(window, 'recent_speakers', ())
for nick in recent_speakers:
if chaninfo.ison(window.network, window.id, nick):
yield nick
for nick in chaninfo.nicks(window.network, window.id):
if nick not in recent_speakers:
yield nick
def script_completer(window, left, right, text):
return core.events.loaded.iterkeys()
def network_completer(window, left, right, text):
return conf.get('networks', {}).iterkeys()
def get_completer_for(window):
input = window.input
left, right = input.text[:input.cursor], input.text[input.cursor:]
text = left.split(' ')[-1]
while True:
suffix = ''
if text and text[0] in window.network.isupport.get('CHANTYPES', '#&+'):
candidates = channel_completer(window, left, right, text)
elif input.text.startswith('/reload '):
candidates = script_completer(window, left, right, text)
elif input.text.startswith('/edit '):
candidates = script_completer(window, left, right, text)
elif input.text.startswith('/server '):
candidates = network_completer(window, left, right, text)
elif text.startswith('/'):
candidates = command_completer(window, left, right, text)
suffix = ' '
else:
candidates = nick_completer(window, left, right, text)
if left == text:
suffix = ': '
else:
suffix = ' '
if text:
before = left[:-len(text)]
else:
before = left
insert_text = '%s%s%s%s' % (before, '%s', suffix, right)
cursor_pos = len(before + suffix)
original = window.input.text, window.input.cursor
for cand in candidates:
if cand.lower().startswith(text.lower()):
window.input.text, window.input.cursor = insert_text % cand, cursor_pos + len(cand)
yield None
window.input.text, window.input.cursor = original
yield None
# generator--use recent_completer.next() to continue cycling through whatever
recent_completer = None
def onKeyPress(e):
global recent_completer
if e.key == 'Tab':
if not recent_completer:
recent_completer = get_completer_for(e.window)
recent_completer.next()
else:
recent_completer = None
def onActive(e):
global recent_completer
recent_completer = None
def onText(e):
if chaninfo.ischan(e.network, e.target):
if not hasattr(e.window, 'recent_speakers'):
e.window.recent_speakers = []
for nick in e.window.recent_speakers:
if nick == e.source or not chaninfo.ison(e.network, e.target, nick):
e.window.recent_speakers.remove(nick)
e.window.recent_speakers.insert(0, e.source)
onAction = onText
+68
View File
@@ -0,0 +1,68 @@
import sys
import traceback
import windows
from conf import conf
class ConsoleWriter:
__slots__ = ['window']
def __init__(self, window):
self.window = window
def write(self, text):
try:
self.window.write(text, line_ending='')
except:
self.window.write(traceback.format_exc())
class ConsoleWindow(windows.SimpleWindow):
def __init__(self, network, id):
windows.SimpleWindow.__init__(self, network, id)
writer = ConsoleWriter(self)
sys.stdout = writer
sys.stderr = writer
self.globals = {'window': self}
self.locals = {}
#this prevents problems (and updates an open console window) on reload
#window = None
#for window in manager:
# if type(window).__name__ == "ConsoleWindow":
# window.mutate(ConsoleWindow, window.network, window.id)
#del window
def onClose(e):
if isinstance(e.window, ConsoleWindow):
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
def onCommandConsole(e):
windows.new(ConsoleWindow, None, "console").activate()
def onCommandSay(e):
if isinstance(e.window, ConsoleWindow):
import pydoc #fix nonresponsive help() command
old_pager, pydoc.pager = pydoc.pager, pydoc.plainpager
e.window.globals.update(sys.modules)
text = ' '.join(e.args)
try:
e.window.write(">>> %s" % text)
result = eval(text, e.window.globals, e.window.locals)
if result is not None:
e.window.write(repr(result))
e.window.globals['_'] = result
except SyntaxError:
try:
exec text in e.window.globals, e.window.locals
except:
traceback.print_exc()
except:
traceback.print_exc()
pydoc.pager = old_pager
else:
raise core.events.CommandError("There's no one here to speak to.")
def onStart(e):
if conf.get('start-console'):
windows.new(ConsoleWindow, None, "console")
@@ -0,0 +1,45 @@
def onKeyPress(e):
if not hasattr(e.window, 'history'):
e.window.history = [], -1
if e.key in ('Up', 'Down'):
h, i = e.window.history
if i == -1 and e.window.input.text:
h.insert(0, e.window.input.text)
i = 0
if e.key == 'Up':
i += 1
if i < len(h):
e.window.history = h, i
e.window.input.text = h[i]
e.window.input.cursor = -1
else: # e.key == 'Up'
i -= 1
if i > -1:
e.window.history = h, i
e.window.input.text = h[i]
e.window.input.cursor = -1
elif i == -1:
e.window.history = h, i
e.window.input.text = ''
e.window.input.cursor = -1
def onInput(e):
if not hasattr(e.window, 'history'):
e.window.history = [], -1
if e.text:
h, i = e.window.history
h.insert(0, e.text)
e.window.history = h, -1
+43
View File
@@ -0,0 +1,43 @@
from conf import conf
import irc
def preRaw(e):
if e.msg[1] in ('PRIVMSG','NOTICE'):
address = e.network.norm_case('%s!%s' % (e.source, e.address))
for mask in conf.get('ignore_masks',()):
if irc.match_glob(address, e.network.norm_case(mask)):
core.events.halt()
def onCommandIgnore(e):
if 'ignore_masks' not in conf:
conf['ignore_masks'] = []
if 'l' in e.switches:
for i in conf['ignore_masks']:
e.window.write('* %s' % i)
elif 'c' in e.switches:
del conf['ignore_masks']
e.window.write('* Cleared the ignore list.')
elif e.args:
if '!' in e.args[0] or '*' in e.args[0] or '?' in e.args[0]:
mask = e.args[0]
else:
mask = '%s!*' % e.args[0]
if 'r' in e.switches:
if mask in conf['ignore_masks']:
conf['ignore_masks'].remove(mask)
e.window.write('* Removed %s from the ignore list' % e.args[0])
else:
raise core.events.CommandError("Couldn't find %s in the ignore list" % e.args[0])
else:
if mask in conf['ignore_masks']:
e.window.write('* %s is already ignored' % e.args[0])
else:
conf['ignore_masks'].append(mask)
e.window.write('* Ignoring messages from %s' % e.args[0])
else:
e.window.write(
"""Usage:
/ignore \x02nick/mask\x02 to ignore a nickname or mask
/ignore -r \x02nick/mask\x02 to stop ignoring a nickname or mask
/ignore -l to view the ignore list
/ignore -c to clear the ignore list""")
@@ -0,0 +1,588 @@
import time
from conf import conf
import ui
import windows
import irc
COMMAND_PREFIX = conf.get('command_prefix', '/')
NICK_SUFFIX = r"`_-\|0123456789"
_hextochr = dict(('%02x' % i, chr(i)) for i in range(256))
def unquote(url, rurl=""):
while '%' in url:
url, char = url.rsplit('%', 1)
chars = char[:2].lower()
if chars in _hextochr:
rurl = '%s%s%s' % (_hextochr[chars], char[2:], rurl)
else:
rurl = "%s%s%s" % ('%', char, rurl)
return url + rurl
#for getting a list of alternative nicks to try on a network
def _nick_generator(network):
for nick in network.nicks[1:]:
yield nick
if network._nick_error:
nick = 'ircperson'
else:
nick = network.nicks[0]
import itertools
for i in itertools.count(1):
for j in xrange(len(NICK_SUFFIX)**i):
suffix = ''.join(NICK_SUFFIX[(j/(len(NICK_SUFFIX)**x))%len(NICK_SUFFIX)] for x in xrange(i))
if network._nick_max_length:
yield nick[0:network._nick_max_length-i]+suffix
else:
yield nick+suffix
def setdownRaw(e):
if not e.done:
if not e.network.got_nick:
if e.msg[1] in ('432','433','436','437'): #nickname unavailable
failednick = e.msg[3]
nicks = list(e.network.nicks)
if hasattr(e.network,'_nick_generator'):
if len(failednick) < len(e.network._next_nick):
e.network._nick_max_length = len(failednick)
e.network._next_nick = e.network._nick_generator.next()
e.network.raw('NICK %s' % e.network._next_nick)
e.network._nick_error |= (e.msg[1] == '432')
else:
e.network._nick_error = (e.msg[1] == '432')
if len(failednick) < len(e.network.nicks[0]):
e.network._nick_max_length = len(failednick)
else:
e.network._nick_max_length = 0
e.network._nick_generator = _nick_generator(e.network)
e.network._next_nick = e.network._nick_generator.next()
e.network.raw('NICK %s' % e.network._next_nick)
elif e.msg[1] == '431': #no nickname given--this shouldn't happen
pass
elif e.msg[1] == '001':
e.network.got_nick = True
if e.network.me != e.msg[2]:
core.events.trigger(
'Nick', network=e.network, window=e.window,
source=e.network.me, target=e.msg[2], address='',
text=e.msg[2]
)
e.network.me = e.msg[2]
if hasattr(e.network,'_nick_generator'):
del e.network._nick_generator, e.network._nick_max_length, e.network._next_nick
if e.msg[1] == "PING":
e.network.raw("PONG :%s" % e.msg[-1])
e.done = True
elif e.msg[1] == "JOIN":
e.channel = e.target
e.requested = e.network.norm_case(e.channel) in e.network.requested_joins
core.events.trigger("Join", e)
e.done = True
elif e.msg[1] == "PART":
e.channel = e.target
e.requested = e.network.norm_case(e.channel) in e.network.requested_parts
e.text = ' '.join(e.msg[3:])
core.events.trigger("Part", e)
e.done = True
elif e.msg[1] in "MODE":
e.channel = e.target
e.text = ' '.join(e.msg[3:])
core.events.trigger("Mode", e)
e.done = True
elif e.msg[1] == "QUIT":
core.events.trigger('Quit', e)
e.done = True
elif e.msg[1] == "KICK":
e.channel = e.msg[2]
e.target = e.msg[3]
core.events.trigger('Kick', e)
e.done = True
elif e.msg[1] == "NICK":
core.events.trigger('Nick', e)
if e.network.me == e.source:
e.network.me = e.target
e.done = True
elif e.msg[1] == "PRIVMSG":
core.events.trigger('Text', e)
e.done = True
elif e.msg[1] == "NOTICE":
core.events.trigger('Notice', e)
e.done = True
elif e.msg[1] == "TOPIC":
core.events.trigger('Topic', e)
e.done = True
elif e.msg[1] in ("376", "422"): #RPL_ENDOFMOTD
if e.network.status == irc.INITIALIZING:
e.network.status = irc.CONNECTED
core.events.trigger('Connect', e)
e.done = True
elif e.msg[1] == "470": #forwarded from channel X to channel Y
if e.network.norm_case(e.msg[3]) in e.network.requested_joins:
e.network.requested_joins.discard(e.network.norm_case(e.msg[3]))
e.network.requested_joins.add(e.network.norm_case(e.msg[4]))
elif e.msg[1] == "005": #RPL_ISUPPORT
for arg in e.msg[3:]:
if ' ' not in arg: #ignore "are supported by this server"
if '=' in arg:
name, value = arg.split('=', 1)
if value.isdigit():
value = int(value)
else:
name, value = arg, ''
#Workaround for broken servers (bahamut on EnterTheGame)
if name == 'PREFIX' and value[0] != '(':
continue
#in theory, we're supposed to replace \xHH with the
# corresponding ascii character, but I don't think anyone
# really does this
e.network.isupport[name] = value
if name == 'PREFIX':
new_prefixes = {}
modes, prefixes = value[1:].split(')')
for mode, prefix in zip(modes, prefixes):
new_prefixes[mode] = prefix
new_prefixes[prefix] = mode
e.network.prefixes = new_prefixes
def setupSocketConnect(e):
e.network.got_nick = False
e.network.isupport = {
'NETWORK': e.network.server,
'PREFIX': '(ohv)@%+',
'CHANMODES': 'b,k,l,imnpstr',
}
e.network.prefixes = {'o':'@', 'h':'%', 'v':'+', '@':'o', '%':'h', '+':'v'}
e.network.connect_timestamp = time.time()
e.network.requested_joins.clear()
e.network.requested_parts.clear()
e.network.on_channels.clear()
if hasattr(e.network,'_nick_generator'):
del e.network._nick_generator, e.network._nick_max_length, e.network._next_nick
if not e.done:
#this needs to be tested--anyone have a server that uses PASS?
if e.network.password:
e.network.raw("PASS :%s" % e.network.password)
e.network.raw("NICK %s" % e.network.nicks[0])
e.network.raw("USER %s %s %s :%s" %
(e.network.username, "8", "*", e.network.fullname))
#per rfc2812 these are username, user mode flags, unused, realname
#e.network.me = None
e.done = True
def onDisconnect(e):
if hasattr(e.network,'_reconnect_source'):
e.network._reconnect_source.unregister()
del e.network._reconnect_source
if hasattr(e.network,'connect_timestamp'):
if e.error and conf.get('autoreconnect',True):
delay = time.time() - e.network.connect_timestamp > 30 and 30 or 120
def do_reconnect():
if not e.network.status:
server(network=e.network)
def do_announce_reconnect():
if not e.network.status:
windows.get_default(e.network).write("* Will reconnect in %s seconds.." % delay)
e.network._reconnect_source = ui.register_timer(delay*1000,do_reconnect)
e.network._reconnect_source = ui.register_idle(do_announce_reconnect)
def onCloseNetwork(e):
e.network.quit()
if hasattr(e.network,'_reconnect_source'):
e.network._reconnect_source.unregister()
del e.network._reconnect_source
def setdownDisconnect(e):
if hasattr(e.network,'connect_timestamp'):
del e.network.connect_timestamp
def setupInput(e):
if not e.done:
if e.text.startswith(COMMAND_PREFIX) and not e.ctrl:
command = e.text[len(COMMAND_PREFIX):]
else:
command = 'say - %s' % e.text
core.events.run(command, e.window, e.network)
e.done = True
def onCommandSay(e):
if isinstance(e.window, windows.ChannelWindow) or isinstance(e.window, windows.QueryWindow):
e.network.msg(e.window.id, ' '.join(e.args))
else:
raise core.events.CommandError("There's no one here to speak to.")
def onCommandMsg(e):
e.network.msg(e.args[0], ' '.join(e.args[1:]))
def onCommandNotice(e):
e.network.notice(e.args[0], ' '.join(e.args[1:]))
def onCommandQuery(e):
windows.new(windows.QueryWindow, e.network, e.args[0], core).activate()
if len(e.args) > 1:
message = ' '.join(e.args[1:])
if message: #this is false if you do "/query nickname "
e.network.msg(e.args[0], ' '.join(e.args[1:]))
def setupJoin(e):
if e.source == e.network.me:
chan = e.network.norm_case(e.channel)
e.network.on_channels.add(chan)
e.network.requested_joins.discard(chan)
def setdownPart(e):
if e.source == e.network.me:
chan = e.network.norm_case(e.channel)
e.network.on_channels.discard(chan)
e.network.requested_parts.discard(chan)
def setdownKick(e):
if e.target == e.network.me:
chan = e.network.norm_case(e.channel)
e.network.on_channels.discard(chan)
def ischan(network, channel):
return network.norm_case(channel) in network.on_channels
# make /nick work offline
def change_nick(network, nick):
if not network.status:
core.events.trigger(
'Nick',
network=network, window=windows.get_default(network),
source=network.me, target=nick, address='', text=nick
)
network.nicks[0] = nick
network.me = nick
else:
network.raw('NICK :%s' % nick)
def onCommandNick(e):
default_nick = irc.default_nicks()[0]
if 't' not in e.switches and e.network.me == default_nick:
conf['nick'] = e.args[0]
import conf as _conf
_conf.save()
for network in set(w.network for w in core.manager):
if network.me == default_nick:
change_nick(network, e.args[0])
else:
change_nick(e.network, e.args[0])
def setdownNick(e):
if e.source != e.network.me:
window = windows.get(windows.QueryWindow, e.network, e.source)
if window:
window.id = e.target
# make /quit always disconnect us
def onCommandQuit(e):
if e.network.status:
e.network.quit(' '.join(e.args))
else:
raise core.events.CommandError("We're not connected to a network.")
def onCommandRaw(e):
if e.network.status >= irc.INITIALIZING:
e.network.raw(' '.join(e.args))
else:
raise core.events.CommandError("We're not connected to a network.")
onCommandQuote = onCommandRaw
def onCommandJoin(e):
if e.args:
if e.network.status >= irc.INITIALIZING:
e.network.join(' '.join(e.args), requested = 'n' not in e.switches)
else:
raise core.events.CommandError("We're not connected.")
elif isinstance(e.window, windows.ChannelWindow):
e.window.network.join(e.window.id, requested = 'n' not in e.switches)
else:
raise core.events.CommandError("You must supply a channel.")
def onCommandPart(e):
if e.args:
if e.network.status >= irc.INITIALIZING:
e.network.part(' '.join(e.args), requested = 'n' not in e.switches)
else:
raise core.events.CommandError("We're not connected.")
elif isinstance(e.window, windows.ChannelWindow):
e.window.network.part(e.window.id, requested = 'n' not in e.switches)
else:
raise core.events.CommandError("You must supply a channel.")
def onCommandHop(e):
if e.args:
if e.network.status >= irc.INITIALIZING:
e.network.part(e.args[0], requested = False)
e.network.join(' '.join(e.args), requested = False)
else:
raise core.events.CommandError("We're not connected.")
elif isinstance(e.window, windows.ChannelWindow):
e.window.network.part(e.window.id, requested = False)
e.window.network.join(e.window.id, requested = False)
else:
raise core.events.CommandError("You must supply a channel.")
#this should be used whereever a new irc.Network may need to be created
def server(server=None,port=6667,network=None,connect=True):
network_info = {}
if server:
network_info["name"] = server
network_info["server"] = server
if port:
network_info["port"] = port
get_network_info(server, network_info)
if not network:
network = irc.Network(**network_info)
windows.new(windows.StatusWindow, network, "status").activate()
else:
if "server" in network_info:
network.name = network_info['name']
network.server = network_info['server']
if not network.status:
#window = windows.get_default(network)
window = core.window
if window:
window.update()
if "port" in network_info:
network.port = network_info["port"]
if network.status:
network.quit()
if connect:
network.connect()
core.window.write("* Connecting to %s on port %s" % (network.server, network.port))
#windows.get_default(network).write(
# "* Connecting to %s on port %s" % (network.server, network.port)
# )
return network
def onCommandServer(e):
host = port = None
if e.args:
host = e.args[0]
if ':' in host:
host, port = host.rsplit(':', 1)
port = int(port)
elif len(e.args) > 1:
port = int(e.args[1])
else:
port = 6667
if 'm' in e.switches:
network = None
else:
network = e.network
server(server=host, port=port, network=network, connect='o' not in e.switches)
#see http://www.w3.org/Addressing/draft-mirashi-url-irc-01.txt
def onCommandIrcurl(e):
url = e.args[0]
if url.startswith('irc://'):
url = url[6:]
if not url.startswith('/'):
host, target = url.rsplit('/',1)
if ':' in host:
host, port = host.rsplit(':',1)
else:
port = 6667
else:
host = None
port = 6667
target = url
if host:
if e.network and e.network.server == host:
network = e.network
else:
for w in list(windows.manager):
if w.network and w.network.server == host:
network = w.network
break
else:
for w in list(windows.manager):
if w.network and w.network.server == 'irc.default.org':
network = server(host,port,w.network)
break
else:
network = server(host,port)
if ',' in target:
target, modifiers = target.split(',',1)
action = ''
else:
target = unquote(target)
if target[0] not in '#&+':
target = '#'+target
action = 'join %s' % target
if network.status == irc.CONNECTED:
core.events.run(action, windows.get_default(network), network)
else:
if not hasattr(network,'temp_perform'):
network.temp_perform = [action]
else:
network.temp_perform.append(action)
#commands that we need to add a : to but otherwise can send unchanged
#the dictionary contains the number of arguments we take without adding the :
trailing = {
'away':0,
'cnotice':2,
'cprivmsg':2,
'kick':2,
'kill':1,
'part':1,
'squery':1,
'squit':1,
'topic':1,
'wallops':0,
}
needschan = {
'topic':0,
'invite':1,
'kick':0,
# 'mode':0, #this is commonly used for channels, but can apply to users
# 'names':0, #with no parameters, this is supposed to give a list of all users; we may be able to safely ignore that.
}
def setupCommand(e):
if not e.done:
if e.name in needschan and isinstance(e.window, windows.ChannelWindow):
valid_chan_prefixes = e.network.isupport.get('CHANTYPES', '#&+')
chan_pos = needschan[e.name]
if len(e.args) > chan_pos:
if not e.args[chan_pos] or e.args[chan_pos][0] not in valid_chan_prefixes:
e.args.insert(chan_pos, e.window.id)
else:
e.args.append(e.window.id)
if e.name in trailing:
trailing_pos = trailing[e.name]
if len(e.args) > trailing_pos:
e.args[trailing_pos] = ':%s' % e.args[trailing_pos]
e.text = '%s %s' % (e.name, ' '.join(e.args))
def setdownCommand(e):
if not e.done and e.network.status >= irc.INITIALIZING:
e.network.raw(e.text)
e.done = True
def get_network_info(name, network_info):
conf_info = conf.get('networks', {}).get(name)
if conf_info:
network_info['server'] = name
network_info.update(conf_info)
def onStart(e):
for network in conf.get('start_networks', []):
server(server=network)
def onConnect(e):
network_info = conf.get('networks', {}).get(e.network.name, {})
for command in network_info.get('perform', []):
while command.startswith(COMMAND_PREFIX):
command = command[len(COMMAND_PREFIX):]
core.events.run(command, e.window, e.network)
tojoin = ','.join(network_info.get('join', []))
if tojoin:
core.events.run('join -n %s' % tojoin, e.window, e.network)
if hasattr(e.network,'temp_perform'):
for command in e.network.temp_perform:
core.events.run(command, e.window, e.network)
del e.network.temp_perform
def isautojoin(network, channel):
try:
joinlist = conf['networks'][network.name]['join']
except KeyError:
return False
normchannel = network.norm_case(channel)
for chan in joinlist:
if normchannel == network.norm_case(chan):
return True
return False
def setautojoin(network, channel):
if 'networks' not in conf:
conf['networks'] = networks = {}
else:
networks = conf['networks']
if network.name not in networks:
networks[network.name] = network_settings = {}
if 'start_networks' not in conf:
conf['start_networks'] = []
conf['start_networks'].append(network.name)
else:
network_settings = networks[network.name]
if 'join' not in network_settings:
network_settings['join'] = [channel]
else:
network_settings['join'].append(channel)
def unsetautojoin(network, channel):
try:
joinlist = conf['networks'][network.name]['join']
except KeyError:
return False
normchannel = network.norm_case(channel)
for i, chan in enumerate(joinlist[:]):
if normchannel == network.norm_case(chan):
joinlist.pop(i)
def onChannelMenu(e):
def toggle_join():
if isautojoin(e.network, e.channel):
unsetautojoin(e.network, e.channel)
else:
setautojoin(e.network, e.channel)
e.menu.append(('Autojoin', isautojoin(e.network, e.channel), toggle_join))
+70
View File
@@ -0,0 +1,70 @@
import windows
import widgets
import irc
shortcuts = {
'^b': '\x02',
'^u': '\x1F',
'^r': '\x16',
'^k': '\x03',
'^l': '\x04',
'^o': '\x0F',
}
def onKeyPress(e):
if e.key in shortcuts:
e.window.input.insert(shortcuts[e.key])
elif e.key == '!c':
e.window.output.copy()
elif e.key == 'Page_Up':
e.window.output.y = e.window.output.y - e.window.output.height / 2
elif e.key == 'Page_Down':
e.window.output.y = e.window.output.y + e.window.output.height / 2
elif e.key == '^Home':
e.window.output.y = 0
elif e.key == '^End':
e.window.output.y = e.window.output.ymax
elif e.key in ('^Page_Up', '^Page_Down'):
winlist = list(windows.manager)
index = winlist.index(e.window) + ((e.key == '^Page_Down') and 1 or -1)
if 0 <= index < len(winlist):
winlist[index].activate()
elif e.key == '!a':
winlist = list(windows.manager)
winlist = winlist[winlist.index(e.window):]+winlist
w = [w for w in winlist if widgets.HILIT in w.activity]
if not w:
w = [w for w in winlist if widgets.TEXT in w.activity]
if w:
windows.manager.set_active(w[0])
# tabbed browsing
elif e.key == '^t':
windows.new(windows.StatusWindow, irc.Network(), 'status').activate()
elif e.key == '^w':
windows.manager.get_active().close()
elif e.key == '^f':
window = windows.manager.get_active()
find = widgets.FindBox(window)
window.pack_start(find, expand=False)
find.textbox.grab_focus()
elif len(e.key) == 2 and e.key.startswith('!') and e.key[1].isdigit():
n = int(e.key[1])
if n and n <= len(core.manager):
list(core.manager)[n-1].activate()
#else e.key == "!0"
+366
View File
@@ -0,0 +1,366 @@
import time
import windows
import widgets
import chaninfo
from conf import conf
textareas = {}
if 'font' in conf:
textareas['font'] = conf['font']
if 'bg_color' in conf:
textareas['bg'] = conf['bg_color']
if 'fg_color' in conf:
textareas['fg'] = conf['fg_color']
widgets.set_style("view", textareas)
widgets.set_style("nicklist", textareas)
#copied pretty directly from something that was probably copied from wine sources
def RGBtoHSL(r, g, b):
maxval = max(r, g, b)
minval = min(r, g, b)
luminosity = ((maxval + minval) * 240 + 255) // 510
if maxval == minval:
saturation = 0
hue = 160
else:
delta = maxval - minval
if luminosity <= 120:
saturation = ((maxval+minval)//2 + delta*240) // (maxval + minval)
else:
saturation = ((150-maxval-minval)//2 + delta*240) // (150-maxval-minval)
#sigh..
rnorm = (delta//2 + maxval*40 - r*40)//delta
gnorm = (delta//2 + maxval*40 - g*40)//delta
bnorm = (delta//2 + maxval*40 - b*40)//delta
if r == maxval:
hue = bnorm-gnorm
elif g == maxval:
hue = 80+rnorm-bnorm
else:
hue = 160+gnorm-rnorm
hue = hue % 240
return hue, saturation, luminosity
#copied from the same place
def huetoRGB(hue, mid1, mid2):
hue = hue % 240
if hue > 160:
return mid1
elif hue > 120:
hue = 160 - hue
elif hue > 40:
return mid2
return ((hue * (mid2 - mid1) + 20) // 40) + mid1
#this too
def HSLtoRGB(hue, saturation, luminosity):
if saturation != 0:
if luminosity > 120:
mid2 = saturation + luminosity - (saturation * luminosity + 120)//240
else:
mid2 = ((saturation + 240) * luminosity + 120)//240
mid1 = luminosity * 2 - mid2
return tuple((huetoRGB(hue+x, mid1, mid2) * 255 + 120) // 240 for x in (80,0,-80))
else:
value = luminosity * 255 // 240
return value, value, value
def gethashcolor(string):
h = hash(string)
rgb = HSLtoRGB(h%241, 100-h//241%61, 90)
return "%02x%02x%02x" % rgb
#take an event e and trigger the highlight event if necessary
def hilight_text(e):
if not hasattr(e, 'Highlight'):
e.Highlight = []
core.events.trigger('Highlight', e)
#hilight own nick
def onHighlight(e):
lowertext = e.text.lower()
for word in conf.get('highlight_words', []) + [e.network.me] + e.network.nicks:
lowerword = word.lower()
pos = lowertext.find(lowerword, 0)
while pos != -1:
e.Highlight.append((pos, pos+len(word)))
pos = lowertext.find(lowerword, pos+1)
def prefix(e):
return time.strftime(conf.get('timestamp', ''))
def getsourcecolor(e):
address = getattr(e, "address", "")
if address:
if e.network.me == e.source:
e.network._my_address = address
elif e.network.me == e.source:
address = getattr(e.network, "_my_address", "")
if '@' in address:
address = address.split('@')[1]
if not address:
address = e.source
return "\x04%s" % gethashcolor(address)
def format_source(e):
highlight = getattr(e, "Highlight", "") and '\x02' or ''
return "%s\x04%s%s" % (highlight, getsourcecolor(e), e.source)
def format_info_source(e):
if e.source == e.network.me:
return "\x04%sYou" % (getsourcecolor(e))
else:
return "\x04%s%s" % (getsourcecolor(e), e.source)
def address(e):
#if e.source != e.network.me:
# return "%s " % info_in_brackets(e.address)
#else:
# return ""
return ""
def text(e):
if e.text:
#return " %s" % info_in_brackets(e.text)
return ": \x0F%s" % e.text
else:
return ""
def info_in_brackets(text):
return "(\x044881b6%s\x0F)" % text
def pretty_time(secs):
times = (
#("years", "year", 31556952),
("weeks", "week", 604800),
("days", "day", 86400),
("hours", "hour", 3600),
("minutes", "minute", 60),
("seconds", "second", 1),
)
if secs == 0:
return "0 seconds"
result = ""
for plural, singular, amount in times:
n, secs = divmod(secs, amount)
if n == 1:
result = result + " %s %s" % (n, singular)
elif n:
result = result + " %s %s" % (n, plural)
return result[1:]
def onText(e):
hilight_text(e)
color = getsourcecolor(e)
to_write = prefix(e)
if e.network.me == e.target: # this is a pm
if e.window.id == e.network.norm_case(e.source):
to_write += "\x02<\x0F%s\x0F\x02>\x0F " % (format_source(e))
else:
to_write += "\x02*\x0F%s\x0F\x02*\x0F " % (format_source(e))
else:
if e.window.id == e.network.norm_case(e.target):
to_write += "\x02<\x0F%s\x0F\x02>\x0F " % (format_source(e))
else:
to_write += "\x02<\x0F%s:%s\x0F\x02>\x0F " % (format_source(e), e.target)
to_write += e.text
if e.Highlight:
e.window.write(to_write, widgets.HILIT)
else:
e.window.write(to_write, widgets.TEXT)
def onOwnText(e):
color = getsourcecolor(e)
to_write = prefix(e)
if e.window.id == e.network.norm_case(e.target):
to_write += "\x02<\x0F%s\x0F\x02>\x0F %s" % (format_source(e), e.text)
else:
to_write += "%s->\x0F \x02*\x0F%s\x0F\x02*\x0F %s" % (color, e.target, e.text)
e.window.write(to_write)
def onAction(e):
hilight_text(e)
color = color = getsourcecolor(e)
to_write = "%s\x02*\x0F %s\x0F %s" % (prefix(e), format_source(e), e.text)
if e.Highlight:
e.window.write(to_write, widgets.HILIT)
else:
e.window.write(to_write, widgets.TEXT)
def onOwnAction(e):
color = getsourcecolor(e)
to_write = "%s\x02*\x0F %s\x0F %s" % (prefix(e), format_source(e), e.text)
e.window.write(to_write)
def onNotice(e):
hilight_text(e)
color = getsourcecolor(e)
to_write = prefix(e)
if e.network.me == e.target: # this is a pm
to_write += "\x02-\x0F%s\x0F\x02-\x0F " % (format_source(e))
else:
to_write += "\x02-\x0F%s:%s\x0F\x02-\x0F " % (format_source(e), e.target)
to_write += e.text
e.window.write(to_write, (e.Highlight and widgets.HILIT) or widgets.TEXT)
def onOwnNotice(e):
color = getsourcecolor(e)
to_write = "%s-> \x02-\x02%s\x0F\x02-\x0F %s" % (prefix(e), e.target, e.text)
e.window.write(to_write)
def onCtcp(e):
color = getsourcecolor(e)
to_write = "%s\x02[\x02%s\x0F\x02]\x0F %s" % (prefix(e), format_source(e), e.text)
if not e.quiet:
e.window.write(to_write)
def onCtcpReply(e):
color = getsourcecolor(e)
to_write = "%s%s--- %s reply from %s:\x0F %s" % (prefix(e), color, e.name.capitalize(), format_source(e), ' '.join(e.args))
window = windows.manager.get_active()
if window.network != e.network:
window = windows.get_default(e.network)
window.write(to_write, widgets.TEXT)
def onJoin(e):
if e.source == e.network.me:
to_write = "%s%s %sjoin %s" % (prefix(e), format_info_source(e), address(e), e.target)
else:
to_write = "%s%s %sjoins %s" % (prefix(e), format_info_source(e), address(e), e.target)
e.window.write(to_write)
def onPart(e):
if e.source == e.network.me:
to_write = "%s%s leave %s%s" % (prefix(e), format_info_source(e), e.target, text(e))
else:
to_write = "%s%s leaves %s%s" % (prefix(e), format_info_source(e), e.target, text(e))
e.window.write(to_write)
def onKick(e):
if e.source == e.network.me:
to_write = "%s%s kick %s%s" % (prefix(e), format_info_source(e), e.target, text(e))
else:
to_write = "%s%s kicks %s%s" % (prefix(e), format_info_source(e), e.target, text(e))
e.window.write(to_write, (e.target == e.network.me and widgets.HILIT) or widgets.EVENT)
def onMode(e):
if e.source == e.network.me:
to_write = "%s%s set mode:\x0F %s" % (prefix(e), format_info_source(e), e.text)
else:
to_write = "%s%s sets mode:\x0F %s" % (prefix(e), format_info_source(e), e.text)
e.window.write(to_write)
def onQuit(e):
to_write = "%s%s leaves%s" % (prefix(e), format_info_source(e), text(e))
for channame in chaninfo.channels(e.network):
if chaninfo.ison(e.network, channame, e.source):
window = windows.get(windows.ChannelWindow, e.network, channame, core)
if window:
window.write(to_write)
def onNick(e):
color = getsourcecolor(e)
if e.source == e.network.me:
to_write = "%s%sYou are now known as %s" % (prefix(e), color, e.target)
else:
to_write = "%s%s%s is now known as %s" % (prefix(e), color, e.source, e.target)
if e.source == e.network.me:
for window in windows.get_with(core.manager, network=e.network):
window.write(to_write)
else:
for channame in chaninfo.channels(e.network):
if chaninfo.ison(e.network,channame,e.source):
window = windows.get(windows.ChannelWindow, e.network, channame)
if window:
window.write(to_write)
def onTopic(e):
if e.source == e.network.me:
to_write = "%s%s set topic:\x0F %s" % (prefix(e), format_info_source(e), e.text)
else:
to_write = "%s%s sets topic:\x0F %s" % (prefix(e), format_info_source(e), e.text)
e.window.write(to_write)
def onRaw(e):
if not e.quiet:
if e.msg[1].isdigit():
if e.msg[1] == '332':
window = windows.get(windows.ChannelWindow, e.network, e.msg[3], core) or e.window
window.write(
"%sTopic on %s is: %s" %
(prefix(e), e.msg[3], e.text)
)
elif e.msg[1] == '333':
window = windows.get(windows.ChannelWindow, e.network, e.msg[3], core) or e.window
window.write(
"%sTopic on %s set by %s at time %s" %
(prefix(e), e.msg[3], e.msg[4], time.ctime(int(e.msg[5])))
)
elif e.msg[1] == '329': #RPL_CREATIONTIME
pass
elif e.msg[1] == '311': #RPL_WHOISUSER
e.window.write("* %s is %s@%s * %s" % (e.msg[3], e.msg[4], e.msg[5], e.msg[7]))
elif e.msg[1] == '312': #RPL_WHOISSERVER
e.window.write("* %s on %s (%s)" % (e.msg[3], e.msg[4], e.msg[5]))
elif e.msg[1] == '317': #RPL_WHOISIDLE
e.window.write("* %s has been idle for %s" % (e.msg[3], pretty_time(int(e.msg[4]))))
if e.msg[5].isdigit():
e.window.write("* %s signed on %s" % (e.msg[3], time.ctime(int(e.msg[5]))))
elif e.msg[1] == '319': #RPL_WHOISCHANNELS
e.window.write("* %s on channels: %s" % (e.msg[3], e.msg[4]))
elif e.msg[1] == '330': #RPL_WHOISACCOUNT
#this appears to conflict with another raw, so if there's anything weird about it,
# we fall back on the default
if len(e.msg) == 6 and not e.msg[4].isdigit() and not e.msg[5].isdigit():
e.window.write("* %s %s %s" % (e.msg[3], e.msg[5], e.msg[4]))
else:
e.window.write("* %s" % ' '.join(e.msg[3:]))
else:
e.window.write("* %s" % ' '.join(e.msg[3:]))
elif e.msg[1] == 'ERROR':
e.window.write("Error: %s" % e.text)
def onDisconnect(e):
to_write = '%s* Disconnected' % prefix(e)
if e.error:
to_write += ' (%s)' % e.error
for window in windows.get_with(network=e.network):
if isinstance(window, windows.StatusWindow):
window.write(to_write, widgets.TEXT)
else:
window.write(to_write, widgets.EVENT)
+45
View File
@@ -0,0 +1,45 @@
import time
import ui
from conf import conf
def setupRaw(e):
e.network._message_timeout = False
def onSocketConnect(e):
timeout = conf.get("server_traffic_timeout", 120)*1000
e.network._message_timeout = False
if timeout:
e.network._message_timeout_source = ui.register_timer(timeout, check_timeout, e.network)
else:
e.network._message_timeout_source = None
def check_timeout(network):
if network._message_timeout:
network.raw("PING %s" % network.me)
timeout = conf.get("server_death_timeout", 240)*1000
network._message_timeout_source = ui.register_timer(timeout, check_death_timeout, network)
return False
else:
network._message_timeout = True
return True # call this function again
def check_death_timeout(network):
if network._message_timeout:
network.raw("QUIT :Server missing, presumed dead")
network.disconnect(error="The server seems to have stopped talking to us")
else:
network._message_timeout = False
timeout = conf.get("server_traffic_timeout", 120)*1000
if timeout:
network._message_timeout_source = ui.register_timer(timeout, check_timeout, network)
else:
network._message_timeout_source = None
def onDisconnect(e):
try:
if e.network._message_timeout_source:
e.network._message_timeout_source.unregister()
e.network._message_timeout_source = None
except AttributeError:
pass
@@ -0,0 +1,132 @@
import irc
import ui
import windows
import irc_script
from conf import conf
# FIXME: meh still might want rid of these, I'm not sure yet
def onActive(e):
e.window.activity = None
ui.register_idle(windows.manager.set_title)
def setupNick(e):
if e.source == e.network.me:
for w in windows.get_with(core.manager, network=e.network):
try:
w.nick_label.update(e.target)
except AttributeError:
pass
def onExit(e):
for n in set(w.network for w in windows.manager):
if n:
n.quit()
def setupJoin(e):
if e.source == e.network.me:
window = windows.get(windows.StatusWindow, e.network, 'status', core)
if window and not conf.get('status'):
window.mutate(windows.ChannelWindow, e.network, e.target)
else:
window = windows.new(windows.ChannelWindow, e.network, e.target, core)
if e.requested:
window.activate()
e.window = windows.get(windows.ChannelWindow, e.network, e.target, core) or e.window
def setupText(e):
if e.target == e.network.me:
e.window = windows.new(windows.QueryWindow, e.network, e.source, core)
else:
e.window = \
windows.get(windows.ChannelWindow, e.network, e.target, core) or \
windows.get(windows.QueryWindow, e.network, e.source, core) or \
e.window
setupAction = setupText
def setupNotice(e):
if e.target != e.network.me:
e.window = \
windows.get(windows.ChannelWindow, e.network, e.target, core) or e.window
def setupOwnText(e):
e.window = \
windows.get(windows.ChannelWindow, e.network, e.target, core) or \
windows.get(windows.QueryWindow, e.network, e.target, core) or \
e.window
setupOwnAction = setupOwnText
def setdownPart(e):
if e.source == e.network.me:
window = windows.get(windows.ChannelWindow, e.network, e.target, core)
if window:
cwindows = list(windows.get_with(
network=window.network,
wclass=windows.ChannelWindow
))
if len(cwindows) == 1 and not list(windows.get_with(network=window.network, wclass=windows.StatusWindow)):
window.mutate(windows.StatusWindow, e.network, 'status')
if e.requested:
window.activate()
elif e.requested:
window.close()
def onClose(e):
nwindows = list(windows.get_with(core.manager, network=e.window.network))
if isinstance(e.window, windows.ChannelWindow):
cwindows = list(windows.get_with(core.manager,
network=e.window.network,
wclass=windows.ChannelWindow
))
#if we only have one window for the network, don't bother to part as
# we'll soon be quitting anyway
if len(nwindows) != 1 and irc_script.ischan(e.window.network, e.window.id):
e.window.network.part(e.window.id)
if len(nwindows) == 1:
core.events.trigger("CloseNetwork", window=e.window, network=e.window.network)
elif isinstance(e.window, windows.StatusWindow) and conf.get('status'):
core.events.trigger("CloseNetwork", window=e.window, network=e.window.network)
for window in nwindows:
if window != e.window:
window.close()
if len(core.manager) == 1:
windows.new(windows.StatusWindow, irc.Network(), "status", core)
def onConnecting(e):
return
window = windows.get_default(e.network)
if window:
window.update()
onDisconnect = onConnecting
def setupPart(e):
e.window = windows.get(windows.ChannelWindow, e.network, e.target, core) or e.window
setupTopic = setupPart
def setupKick(e):
e.window = windows.get(windows.ChannelWindow, e.network, e.channel, core) or e.window
def setupMode(e):
if e.target != e.network.me:
e.window = windows.get(windows.ChannelWindow, e.network, e.target, core) or e.window
def onWindowMenu(e):
if isinstance(e.window, windows.ChannelWindow):
e.channel = e.window.id
e.network = e.window.network
core.events.trigger('ChannelMenu', e)