tkellem 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/Gemfile +4 -0
- data/README.md +28 -6
- data/Rakefile +14 -5
- data/bin/tkellem +2 -107
- data/debian/changelog +5 -0
- data/debian/compat +1 -0
- data/debian/control +18 -0
- data/debian/copyright +42 -0
- data/debian/docs +1 -0
- data/debian/examples +1 -0
- data/debian/install +3 -0
- data/debian/manpages +1 -0
- data/debian/rules +13 -0
- data/debian/source/format +1 -0
- data/debian/tkellem.1 +11 -0
- data/examples/config.yml +2 -29
- data/lib/tkellem/bouncer.rb +196 -31
- data/lib/tkellem/bouncer_connection.rb +90 -85
- data/lib/tkellem/daemon.rb +155 -0
- data/lib/tkellem/irc_message.rb +58 -0
- data/lib/tkellem/irc_server.rb +8 -121
- data/lib/tkellem/migrations/001_init_db.rb +33 -0
- data/lib/tkellem/models/host.rb +11 -0
- data/lib/tkellem/models/listen_address.rb +12 -0
- data/lib/tkellem/models/network.rb +15 -0
- data/lib/tkellem/models/network_user.rb +12 -0
- data/lib/tkellem/models/user.rb +56 -0
- data/lib/tkellem/plugins/backlog.rb +160 -0
- data/lib/tkellem/plugins/push_service.rb +152 -0
- data/lib/tkellem/socket_server.rb +29 -0
- data/lib/tkellem/tkellem_bot.rb +318 -0
- data/lib/tkellem/tkellem_server.rb +114 -0
- data/lib/tkellem/version.rb +3 -0
- data/lib/tkellem.rb +7 -10
- data/resources/bot_command_descriptions.yml +36 -0
- data/spec/irc_message_spec.rb +47 -0
- data/spec/irc_server_spec.rb +60 -0
- data/spec/spec_helper.rb +0 -2
- data/tkellem.gemspec +20 -47
- metadata +118 -22
- data/VERSION +0 -1
- data/lib/tkellem/backlog.rb +0 -85
- data/lib/tkellem/irc_line.rb +0 -58
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -4,14 +4,36 @@ tkellem is an IRC bouncer, a proxy that keeps you permanently logged on to an
|
|
4
4
|
IRC server and stores all messages so that when your client next connects, you
|
5
5
|
can see the backlog of what happened while you were gone.
|
6
6
|
|
7
|
-
tkellem supports multiple device-independent backlogs
|
8
|
-
multiple IRC servers all from the same
|
7
|
+
tkellem supports multiple users, multiple device-independent backlogs
|
8
|
+
per-user, and connecting to multiple IRC servers all from the same
|
9
|
+
process.
|
9
10
|
|
10
11
|
## IMPORTANT
|
11
12
|
|
12
|
-
This is a
|
13
|
-
|
13
|
+
This is still a pretty early alpha. Expect bugs and missing
|
14
|
+
functionality.
|
14
15
|
|
15
|
-
##
|
16
|
+
## Getting Started
|
16
17
|
|
17
|
-
|
18
|
+
This will have to do as a quickstart guide, for now:
|
19
|
+
|
20
|
+
$ git clone git://github.com/codekitchen/tkellem.git
|
21
|
+
$ cd tkellem
|
22
|
+
$ bundle install
|
23
|
+
$ bundle exec bin/tkellem start
|
24
|
+
$ bundle exec bin/tkellem admin
|
25
|
+
> help
|
26
|
+
> listen ircs://0.0.0.0:8765
|
27
|
+
> user --add <my-name> --admin
|
28
|
+
> password --user <my-name> <my-new-password>
|
29
|
+
> network --add --public freenode ircs://irc.freenode.org:7000
|
30
|
+
|
31
|
+
Then connect to tkellem with an irc client:
|
32
|
+
|
33
|
+
server: localhost
|
34
|
+
port: 8765
|
35
|
+
ssl: yes
|
36
|
+
|
37
|
+
nickname: <my-name>
|
38
|
+
login: <my-name>@freenode
|
39
|
+
server password: <my-new-password>
|
data/Rakefile
CHANGED
@@ -1,12 +1,21 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
require 'rspec'
|
4
|
-
require 'rspec/core/rake_task'
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
5
3
|
|
6
4
|
task :default => :spec
|
7
5
|
|
6
|
+
require 'rspec/core/rake_task'
|
8
7
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
9
|
-
spec.pattern = 'spec
|
8
|
+
spec.pattern = 'spec/*_spec.rb'
|
9
|
+
end
|
10
|
+
RSpec::Core::RakeTask.new(:rcov) do |t|
|
11
|
+
t.rcov = true
|
12
|
+
t.rcov_opts = ["--exclude", "spec,gems/,rubygems/"]
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'yard'
|
16
|
+
YARD::Rake::YardocTask.new(:doc) do |t|
|
17
|
+
version = Tkellem::VERSION
|
18
|
+
t.options = ["--title", "tkellem #{version}", "--files", "LICENSE,README.md"]
|
10
19
|
end
|
11
20
|
|
12
21
|
begin
|
data/bin/tkellem
CHANGED
@@ -1,110 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
rescue LoadError
|
6
|
-
end
|
7
|
-
require 'yaml'
|
8
|
-
require 'optparse'
|
3
|
+
require 'tkellem/daemon'
|
9
4
|
|
10
|
-
|
11
|
-
opts.banner = <<BANNER
|
12
|
-
Usage: #{opts.program_name} PATH_TO_CONFIG
|
13
|
-
|
14
|
-
Start a tkellem instance using the specified configuration file (or ~/.tkellem/config.yml if none given)
|
15
|
-
BANNER
|
16
|
-
|
17
|
-
opts.on_tail("-h", "--help") { puts opts; exit }
|
18
|
-
|
19
|
-
rest = opts.parse(ARGV)
|
20
|
-
config_filename = rest.first || File.expand_path(ENV["HOME"]+'/.tkellem/config.yml')
|
21
|
-
|
22
|
-
config = YAML.load_file(config_filename)
|
23
|
-
|
24
|
-
$LOAD_PATH.push(File.expand_path(File.dirname(__FILE__)+'/../lib'))
|
25
|
-
require 'tkellem'
|
26
|
-
|
27
|
-
EM.run do
|
28
|
-
bouncer =
|
29
|
-
Tkellem::Bouncer.new(config['listen'] || '0.0.0.0',
|
30
|
-
config['port'] || 10001,
|
31
|
-
config['ssl'])
|
32
|
-
|
33
|
-
bouncer.max_backlog = config['max_backlog'].to_i
|
34
|
-
|
35
|
-
bouncer.on_authenticate do |username, password, irc_server|
|
36
|
-
server_config = config['connections'][irc_server.name]
|
37
|
-
if server_config && password_sha1 = server_config['password_sha1']
|
38
|
-
require 'openssl'
|
39
|
-
password_sha1 == OpenSSL::Digest::SHA1.hexdigest(password)
|
40
|
-
else
|
41
|
-
true
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def add_irc_server(bouncer, name, conn)
|
46
|
-
server = bouncer.add_irc_server(name,
|
47
|
-
conn['host'], conn['port'], conn['ssl'],
|
48
|
-
conn['nick'])
|
49
|
-
|
50
|
-
(conn['rooms'] || []).each { |room| server.join_room(room['name']) }
|
51
|
-
conn['clients'].each { |client| server.add_client(client['name']) }
|
52
|
-
end
|
53
|
-
|
54
|
-
config['connections'].each do |name, conn|
|
55
|
-
Tkellem::EasyLogger.logger.info("adding new connection #{name}")
|
56
|
-
add_irc_server(bouncer, name, conn)
|
57
|
-
end
|
58
|
-
|
59
|
-
Signal.trap('HUP') do
|
60
|
-
Tkellem::EasyLogger.logger.warn("got HUP, reloading #{config_filename}")
|
61
|
-
new_config = YAML.load_file(config_filename)
|
62
|
-
|
63
|
-
bouncer.max_backlog = new_config['max_backlog'].to_i
|
64
|
-
|
65
|
-
# find changed connections
|
66
|
-
to_delete = config['connections'].keys
|
67
|
-
|
68
|
-
new_config['connections'].each do |name, new_conn|
|
69
|
-
to_delete.delete(name)
|
70
|
-
conn = config['connections'][name]
|
71
|
-
if !conn
|
72
|
-
Tkellem::EasyLogger.logger.info("adding new connection #{name}")
|
73
|
-
add_irc_server(bouncer, name, new_conn)
|
74
|
-
else
|
75
|
-
if new_conn['host'] != conn['host'] || new_conn['port'] != conn['port'] || new_conn['ssl'] != conn['ssl']
|
76
|
-
Tkellem::EasyLogger.logger.info("server settings changed for #{name}, dropping clients and reconnecting")
|
77
|
-
bouncer.remove_irc_server(name)
|
78
|
-
add_irc_server(bouncer, name, new_conn)
|
79
|
-
elsif conn['clients'] != new_conn['clients']
|
80
|
-
irc_server = bouncer.get_irc_server(name)
|
81
|
-
|
82
|
-
# we don't have to reconnect, but maybe clients changed. we ignore
|
83
|
-
# changes to nick and rooms on HUP, since those are dynamic once tkellem
|
84
|
-
# connects. password change will be caught on the next client
|
85
|
-
# connect.
|
86
|
-
clients_to_delete = conn['clients'].map { |c| c['name'] }
|
87
|
-
new_conn['clients'].each do |new_client|
|
88
|
-
clients_to_delete.delete(new_client['name'])
|
89
|
-
# add -- if already exists, this is a no-op. this may change in the
|
90
|
-
# future though...
|
91
|
-
Tkellem::EasyLogger.logger.info("adding client #{new_client['name']} to server #{name}")
|
92
|
-
irc_server.add_client(new_client['name'])
|
93
|
-
end
|
94
|
-
clients_to_delete.each do |client_name|
|
95
|
-
Tkellem::EasyLogger.logger.info("removing client #{client_name} from server #{name}")
|
96
|
-
irc_server.remove_client(client_name) if irc_server
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
to_delete.each do |name|
|
103
|
-
Tkellem::EasyLogger.logger.info("deleting connection #{name}")
|
104
|
-
bouncer.remove_irc_server(name)
|
105
|
-
end
|
106
|
-
|
107
|
-
config = new_config
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
5
|
+
Tkellem::Daemon.new(ARGV).run()
|
data/debian/changelog
ADDED
data/debian/compat
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
7
|
data/debian/control
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Source: tkellem
|
2
|
+
Section: net
|
3
|
+
Priority: extra
|
4
|
+
Maintainer: paul cannon <pik@debian.org>
|
5
|
+
Build-Depends: debhelper (>= 7.0.50~)
|
6
|
+
Standards-Version: 3.9.1
|
7
|
+
Homepage: https://github.com/codekitchen/tkellem
|
8
|
+
|
9
|
+
Package: tkellem
|
10
|
+
Architecture: all
|
11
|
+
Depends: ${misc:Depends}, ruby, rubygems, libeventmachine-ruby
|
12
|
+
Description: IRC bouncer with multi-client support
|
13
|
+
tkellem is an IRC bouncer, a proxy that keeps you permanently logged on to an
|
14
|
+
IRC server and stores all messages so that when your client next connects, you
|
15
|
+
can see the backlog of what happened while you were gone.
|
16
|
+
.
|
17
|
+
tkellem supports multiple device-independent backlogs, and connecting to
|
18
|
+
multiple IRC servers all from the same process.
|
data/debian/copyright
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
This work was packaged for Debian by:
|
2
|
+
|
3
|
+
paul cannon <pik@debian.org> on Thu, 16 Dec 2010 11:58:18 -0600
|
4
|
+
|
5
|
+
It was downloaded from:
|
6
|
+
|
7
|
+
https://github.com/codekitchen/tkellem
|
8
|
+
|
9
|
+
Upstream Author(s):
|
10
|
+
|
11
|
+
Brian Palmer
|
12
|
+
|
13
|
+
Copyright:
|
14
|
+
|
15
|
+
Copyright (c) 2010 Brian Palmer <brian@codekitchen.net>
|
16
|
+
|
17
|
+
License:
|
18
|
+
|
19
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
20
|
+
copy of this software and associated documentation files (the "Software"),
|
21
|
+
to deal in the Software without restriction, including without limitation
|
22
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
23
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
24
|
+
Software is furnished to do so, subject to the following conditions:
|
25
|
+
|
26
|
+
The above copyright notice and this permission notice shall be included in
|
27
|
+
all copies or substantial portions of the Software.
|
28
|
+
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
30
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
31
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
32
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
33
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
34
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
35
|
+
DEALINGS IN THE SOFTWARE.
|
36
|
+
|
37
|
+
The Debian packaging is:
|
38
|
+
|
39
|
+
Copyright (C) 2010 paul cannon <pik@debian.org>
|
40
|
+
|
41
|
+
and may be distributed and used under the same terms as the underlying work
|
42
|
+
(see above).
|
data/debian/docs
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
README.md
|
data/debian/examples
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
examples/config.yml
|
data/debian/install
ADDED
data/debian/manpages
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
debian/tkellem.1
|
data/debian/rules
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/make -f
|
2
|
+
# -*- makefile -*-
|
3
|
+
# Sample debian/rules that uses debhelper.
|
4
|
+
# This file was originally written by Joey Hess and Craig Small.
|
5
|
+
# As a special exception, when this file is copied by dh-make into a
|
6
|
+
# dh-make output file, you may use that output file without restriction.
|
7
|
+
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
8
|
+
|
9
|
+
# Uncomment this to turn on verbose mode.
|
10
|
+
#export DH_VERBOSE=1
|
11
|
+
|
12
|
+
%:
|
13
|
+
dh $@
|
@@ -0,0 +1 @@
|
|
1
|
+
3.0 (quilt)
|
data/debian/tkellem.1
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2.
|
2
|
+
.TH TKELLEM "1" "December 2010" "Brian Palmer" "User Commands"
|
3
|
+
.SH NAME
|
4
|
+
tkellem \- tkellem
|
5
|
+
.SH SYNOPSIS
|
6
|
+
.B tkellem
|
7
|
+
\fIPATH_TO_CONFIG\fR
|
8
|
+
.SH DESCRIPTION
|
9
|
+
Start a tkellem instance using the specified configuration file (or ~/.tkellem/config.yml if none given)
|
10
|
+
.HP
|
11
|
+
\fB\-h\fR, \fB\-\-help\fR
|
data/examples/config.yml
CHANGED
@@ -1,29 +1,2 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
# to connect: connect to localhost port 10001, ssl enabled, "real name" set to
|
4
|
-
#
|
5
|
-
# <connection_name> <client_name>
|
6
|
-
#
|
7
|
-
# e.g.:
|
8
|
-
#
|
9
|
-
# freenode laptop
|
10
|
-
---
|
11
|
-
listen: 0.0.0.0
|
12
|
-
port: 10001
|
13
|
-
ssl: true
|
14
|
-
# max_backlog: 500
|
15
|
-
connections:
|
16
|
-
freenode:
|
17
|
-
host: irc.freenode.org
|
18
|
-
port: 6667
|
19
|
-
ssl: false
|
20
|
-
nick: tkellem_r0ck
|
21
|
-
# Uncomment to enable password auth (there's no auth by default, which
|
22
|
-
# means anybody can connect). You can generate a password_sha1 like so:
|
23
|
-
# echo -n 'tkellem_r0ck' | openssl sha1
|
24
|
-
# password_sha1: a4f4a3b97c7b8a028d4e3f3fee85d6e5626baba5
|
25
|
-
rooms:
|
26
|
-
- name: "#tkellem_test"
|
27
|
-
clients:
|
28
|
-
- name: laptop
|
29
|
-
- name: iphone
|
1
|
+
# this file is deprecated, settings are now stored in ~/.tkellem/tkellem.sqlite3
|
2
|
+
# more help to come
|
data/lib/tkellem/bouncer.rb
CHANGED
@@ -1,52 +1,217 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
2
2
|
|
3
3
|
require 'tkellem/irc_server'
|
4
|
+
require 'tkellem/bouncer_connection'
|
4
5
|
|
5
6
|
module Tkellem
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
|
8
|
+
class Bouncer
|
9
|
+
include Tkellem::EasyLogger
|
10
|
+
|
11
|
+
attr_reader :user, :network, :nick
|
12
|
+
cattr_accessor :plugins
|
13
|
+
self.plugins = []
|
14
|
+
|
15
|
+
def initialize(network_user)
|
16
|
+
@network_user = network_user
|
17
|
+
@user = network_user.user
|
18
|
+
@network = network_user.network
|
19
|
+
|
20
|
+
@nick = network_user.nick
|
21
|
+
# maps { client_conn => state_hash }
|
22
|
+
@active_conns = {}
|
23
|
+
@welcomes = []
|
24
|
+
@rooms = ['#tk']
|
25
|
+
# maps { client_conn => away_status_or_nil }
|
26
|
+
@away = {}
|
27
|
+
# plugin data
|
28
|
+
@data = {}
|
29
|
+
# clients waiting for us to connect to the irc server
|
30
|
+
@waiting_clients = []
|
31
|
+
|
32
|
+
connect!
|
33
|
+
end
|
34
|
+
|
35
|
+
def data(key)
|
36
|
+
@data[key] ||= {}
|
37
|
+
end
|
38
|
+
|
39
|
+
def active_conns
|
40
|
+
@active_conns.keys
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.add_plugin(plugin)
|
44
|
+
self.plugins << plugin
|
45
|
+
end
|
46
|
+
|
47
|
+
def connected?
|
48
|
+
!!@connected
|
49
|
+
end
|
50
|
+
|
51
|
+
def connect_client(client)
|
52
|
+
@active_conns[client] = {}
|
53
|
+
@away[client] = nil
|
54
|
+
|
55
|
+
if !connected?
|
56
|
+
@waiting_clients << client
|
57
|
+
client.say_as_tkellem("Connecting you to the IRC server. Please wait...")
|
58
|
+
return
|
59
|
+
end
|
60
|
+
|
61
|
+
send_welcome(client)
|
62
|
+
# make the client join all the rooms that we're in
|
63
|
+
@rooms.each { |room| client.simulate_join(room) }
|
64
|
+
|
65
|
+
plugins.each { |plugin| plugin.new_client_connected(self, client) }
|
66
|
+
check_away_status
|
67
|
+
end
|
68
|
+
|
69
|
+
def disconnect_client(client)
|
70
|
+
@away.delete(client)
|
71
|
+
check_away_status
|
72
|
+
@active_conns.delete(client)
|
73
|
+
end
|
74
|
+
|
75
|
+
def client_msg(client, msg)
|
76
|
+
return if plugins.any? do |plugin|
|
77
|
+
!plugin.client_msg(self, client, msg)
|
78
|
+
end
|
79
|
+
|
80
|
+
forward = case msg.command
|
81
|
+
when 'PING'
|
82
|
+
client.send_msg(":tkellem!tkellem PONG tkellem :#{msg.args.last}")
|
83
|
+
false
|
84
|
+
when 'AWAY'
|
85
|
+
@away[client] = msg.args.last
|
86
|
+
check_away_status
|
87
|
+
false
|
88
|
+
else
|
89
|
+
true
|
12
90
|
end
|
13
91
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
server.set_max_backlog(@max_backlog) if @max_backlog
|
18
|
-
server
|
92
|
+
if forward
|
93
|
+
# send to server
|
94
|
+
send_msg(msg)
|
19
95
|
end
|
96
|
+
end
|
20
97
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
server.close_connection(true)
|
25
|
-
end
|
98
|
+
def server_msg(msg)
|
99
|
+
return if plugins.any? do |plugin|
|
100
|
+
!plugin.server_msg(self, msg)
|
26
101
|
end
|
27
102
|
|
28
|
-
|
29
|
-
|
103
|
+
forward = case msg.command
|
104
|
+
when /0\d\d/, /2[56]\d/, /37[256]/
|
105
|
+
@welcomes << msg
|
106
|
+
ready! if msg.command == "376" # end of MOTD
|
107
|
+
false
|
108
|
+
when 'JOIN'
|
109
|
+
debug "#{msg.target_user} joined #{msg.args.last}"
|
110
|
+
@rooms << msg.args.last if msg.target_user == @nick
|
111
|
+
true
|
112
|
+
when 'PART'
|
113
|
+
debug "#{msg.target_user} left #{msg.args.last}"
|
114
|
+
@rooms.delete(msg.args.last) if msg.target_user == @nick
|
115
|
+
true
|
116
|
+
when 'PING'
|
117
|
+
send_msg("PONG tkellem!tkellem :#{msg.args.last}")
|
118
|
+
false
|
119
|
+
when 'PONG'
|
120
|
+
# swallow it, we handle ping-pong from clients separately, in
|
121
|
+
# BouncerConnection
|
122
|
+
false
|
123
|
+
else
|
124
|
+
true
|
30
125
|
end
|
31
126
|
|
32
|
-
|
33
|
-
|
34
|
-
@
|
127
|
+
if forward
|
128
|
+
# send to clients
|
129
|
+
@active_conns.each { |c,s| c.send_msg(msg) }
|
35
130
|
end
|
131
|
+
end
|
36
132
|
|
133
|
+
## Away Statuses
|
37
134
|
|
38
|
-
|
135
|
+
def check_away_status
|
136
|
+
# for now we pretty much randomly pick an away status if multiple are set
|
137
|
+
# by clients
|
138
|
+
if @away.any? { |k,v| !v }
|
139
|
+
# we have a client who isn't away
|
140
|
+
send_msg("AWAY")
|
141
|
+
else
|
142
|
+
message = @away.values.first || "Away"
|
143
|
+
send_msg("AWAY :#{message}")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
def name
|
149
|
+
"#{user.name}-#{network.name}"
|
150
|
+
end
|
151
|
+
alias_method :log_name, :name
|
152
|
+
|
153
|
+
def send_msg(msg)
|
154
|
+
trace "to server: #{msg}"
|
155
|
+
@conn.send_data("#{msg}\r\n")
|
156
|
+
end
|
157
|
+
|
158
|
+
def connection_established
|
159
|
+
# TODO: support sending a real username, realname, etc
|
160
|
+
send_msg("USER #{@nick} localhost blah :#{@nick}")
|
161
|
+
change_nick(@nick, true)
|
162
|
+
check_away_status
|
163
|
+
end
|
164
|
+
|
165
|
+
def disconnected!
|
166
|
+
debug "OMG we got disconnected."
|
167
|
+
@conn = nil
|
168
|
+
@connected = false
|
169
|
+
@active_conns.each { |c,s| c.unbind }
|
170
|
+
connect!
|
171
|
+
end
|
39
172
|
|
40
|
-
|
41
|
-
|
173
|
+
protected
|
174
|
+
|
175
|
+
def change_nick(new_nick, force = false)
|
176
|
+
return if !force && new_nick == @nick
|
177
|
+
@nick = new_nick
|
178
|
+
send_msg("NICK #{new_nick}")
|
179
|
+
end
|
180
|
+
|
181
|
+
def send_welcome(bouncer_conn)
|
182
|
+
@welcomes.each { |msg| bouncer_conn.send_msg(msg) }
|
183
|
+
end
|
184
|
+
|
185
|
+
def connect!
|
186
|
+
span = @last_connect ? Time.now - @last_connect : 1000
|
187
|
+
hosts = @network.hosts(true).map { |h| h }
|
188
|
+
|
189
|
+
if span < 5 || hosts.length < 1
|
190
|
+
EM.add_timer(5) { connect! }
|
191
|
+
return
|
192
|
+
end
|
193
|
+
@last_connect = Time.now
|
194
|
+
@cur_host = (@cur_host || 0) % hosts.length
|
195
|
+
host = hosts[@cur_host]
|
196
|
+
@conn = EM.connect(host.address, host.port, IrcServerConnection, self, host.ssl)
|
197
|
+
end
|
198
|
+
|
199
|
+
def ready!
|
200
|
+
return if @joined_rooms
|
201
|
+
@joined_rooms = true
|
202
|
+
@rooms.each do |room|
|
203
|
+
send_msg("JOIN #{room}")
|
42
204
|
end
|
43
205
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
206
|
+
# We're all initialized, allow connections
|
207
|
+
@connected = true
|
208
|
+
@waiting_clients.each do |client|
|
209
|
+
client.say_as_tkellem("Now connected.")
|
210
|
+
connect_client(client)
|
50
211
|
end
|
212
|
+
@waiting_clients.clear
|
51
213
|
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
52
217
|
end
|