tkellem 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +4 -0
  3. data/README.md +28 -6
  4. data/Rakefile +14 -5
  5. data/bin/tkellem +2 -107
  6. data/debian/changelog +5 -0
  7. data/debian/compat +1 -0
  8. data/debian/control +18 -0
  9. data/debian/copyright +42 -0
  10. data/debian/docs +1 -0
  11. data/debian/examples +1 -0
  12. data/debian/install +3 -0
  13. data/debian/manpages +1 -0
  14. data/debian/rules +13 -0
  15. data/debian/source/format +1 -0
  16. data/debian/tkellem.1 +11 -0
  17. data/examples/config.yml +2 -29
  18. data/lib/tkellem/bouncer.rb +196 -31
  19. data/lib/tkellem/bouncer_connection.rb +90 -85
  20. data/lib/tkellem/daemon.rb +155 -0
  21. data/lib/tkellem/irc_message.rb +58 -0
  22. data/lib/tkellem/irc_server.rb +8 -121
  23. data/lib/tkellem/migrations/001_init_db.rb +33 -0
  24. data/lib/tkellem/models/host.rb +11 -0
  25. data/lib/tkellem/models/listen_address.rb +12 -0
  26. data/lib/tkellem/models/network.rb +15 -0
  27. data/lib/tkellem/models/network_user.rb +12 -0
  28. data/lib/tkellem/models/user.rb +56 -0
  29. data/lib/tkellem/plugins/backlog.rb +160 -0
  30. data/lib/tkellem/plugins/push_service.rb +152 -0
  31. data/lib/tkellem/socket_server.rb +29 -0
  32. data/lib/tkellem/tkellem_bot.rb +318 -0
  33. data/lib/tkellem/tkellem_server.rb +114 -0
  34. data/lib/tkellem/version.rb +3 -0
  35. data/lib/tkellem.rb +7 -10
  36. data/resources/bot_command_descriptions.yml +36 -0
  37. data/spec/irc_message_spec.rb +47 -0
  38. data/spec/irc_server_spec.rb +60 -0
  39. data/spec/spec_helper.rb +0 -2
  40. data/tkellem.gemspec +20 -47
  41. metadata +118 -22
  42. data/VERSION +0 -1
  43. data/lib/tkellem/backlog.rb +0 -85
  44. data/lib/tkellem/irc_line.rb +0 -58
@@ -0,0 +1,114 @@
1
+ require 'eventmachine'
2
+ require 'active_record'
3
+
4
+ require 'tkellem/bouncer_connection'
5
+ require 'tkellem/bouncer'
6
+
7
+ require 'tkellem/models/user'
8
+ require 'tkellem/models/network'
9
+ require 'tkellem/models/host'
10
+ require 'tkellem/models/network_user'
11
+ require 'tkellem/models/listen_address'
12
+
13
+ require 'tkellem/plugins/push_service'
14
+ require 'tkellem/plugins/backlog'
15
+
16
+ module Tkellem
17
+
18
+ class TkellemServer
19
+ include Tkellem::EasyLogger
20
+
21
+ def initialize
22
+ @listeners = {}
23
+ @bouncers = {}
24
+
25
+ ActiveRecord::Base.establish_connection({
26
+ :adapter => 'sqlite3',
27
+ :database => File.expand_path("~/.tkellem/tkellem.sqlite3"),
28
+ })
29
+ ActiveRecord::Migrator.migrate(File.expand_path("../migrations", __FILE__), nil)
30
+
31
+ ListenAddress.all.each { |a| listen(a) }
32
+ NetworkUser.find_each { |nu| add_bouncer(Bouncer.new(nu)) }
33
+ Observer.forward_to << self
34
+ end
35
+
36
+ # callbacks for AR observer events
37
+ def after_create(obj)
38
+ case obj
39
+ when ListenAddress
40
+ listen(obj)
41
+ when NetworkUser
42
+ add_bouncer(Bouncer.new(obj))
43
+ end
44
+ end
45
+
46
+ def after_destroy(obj)
47
+ case obj
48
+ when ListenAddress
49
+ stop_listening(obj)
50
+ # TODO: remove bouncer on NetworkUser.destroy
51
+ end
52
+ end
53
+
54
+ def listen(listen_address)
55
+ address = listen_address.address
56
+ port = listen_address.port
57
+ ssl = listen_address.ssl
58
+
59
+ info "Listening on #{listen_address}"
60
+
61
+ @listeners[listen_address.id] = EM.start_server(listen_address.address,
62
+ listen_address.port,
63
+ BouncerConnection,
64
+ self,
65
+ listen_address.ssl)
66
+ end
67
+
68
+ def stop_listening(listen_address)
69
+ listener = @listeners[listen_address.id]
70
+ return unless listener
71
+ EM.stop_server(listener)
72
+ info "No longer listening on #{listen_address}"
73
+ end
74
+
75
+ def add_bouncer(bouncer)
76
+ key = [bouncer.user.id, bouncer.network.name]
77
+ raise("bouncer already exists: #{key}") if @bouncers.include?(key)
78
+ @bouncers[key] = bouncer
79
+ end
80
+
81
+ def find_bouncer(user, network_name)
82
+ key = [user.id, network_name]
83
+ bouncer = @bouncers[key]
84
+ if !bouncer
85
+ # find the public network with this name, and attempt to auto-add this user to it
86
+ network = Network.first(:conditions => { :user_id => nil, :name => network_name })
87
+ if network
88
+ nu = NetworkUser.create!(:user => user, :network => network)
89
+ # AR callback should create the bouncer in sync
90
+ bouncer = @bouncers[key]
91
+ end
92
+ end
93
+ bouncer
94
+ end
95
+
96
+ class Observer < ActiveRecord::Observer
97
+ observe 'Tkellem::ListenAddress', 'Tkellem::NetworkUser'
98
+ cattr_accessor :forward_to
99
+ self.forward_to = []
100
+
101
+ def after_create(obj)
102
+ forward_to.each { |f| f.after_create(obj) }
103
+ end
104
+
105
+ def after_destroy(obj)
106
+ forward_to.each { |f| f.after_destroy(obj) }
107
+ end
108
+ end
109
+
110
+ ActiveRecord::Base.observers = Observer
111
+ ActiveRecord::Base.instantiate_observers
112
+ end
113
+
114
+ end
@@ -0,0 +1,3 @@
1
+ module Tkellem
2
+ VERSION = "0.8.0"
3
+ end
data/lib/tkellem.rb CHANGED
@@ -1,11 +1,3 @@
1
- begin
2
- require 'rubygems'
3
- rescue LoadError
4
- end
5
-
6
- pathname = File.expand_path(File.dirname(__FILE__))
7
- $LOAD_PATH.push(pathname) unless $LOAD_PATH.include?(pathname)
8
-
9
1
  module Tkellem
10
2
  module EasyLogger
11
3
  require 'logger'
@@ -24,7 +16,11 @@ module Tkellem
24
16
  @trace = val
25
17
  end
26
18
  def self.trace
27
- @trace || @trace = false
19
+ @trace || @trace = true
20
+ end
21
+
22
+ def log_name
23
+ ""
28
24
  end
29
25
 
30
26
  def trace(msg)
@@ -42,4 +38,5 @@ module Tkellem
42
38
  end
43
39
  end
44
40
 
45
- require 'tkellem/bouncer'
41
+ require "tkellem/version"
42
+ require 'tkellem/tkellem_server'
@@ -0,0 +1,36 @@
1
+ ---
2
+ LISTEN:
3
+ banner: "Usage: LISTEN [--add|--remove|--list] <uri>"
4
+ help: |+
5
+ Manage the address/port combinations for tkellem to accept client
6
+ connections on.
7
+
8
+ Protocol is either `irc`, or `ircs` for an SSL listener.
9
+
10
+ Example:
11
+ LISTEN --add ircs://0.0.0.0:10001
12
+
13
+ USER:
14
+ banner: "Usage: USER [--add|--remove|--list] <username> [--admin]"
15
+ help: |+
16
+ Manage users.
17
+
18
+ Example:
19
+ USER --add joe admin
20
+
21
+ PASSWORD:
22
+ banner: "Usage: PASSWORD [--user <username>] <new-password>"
23
+ help: |+
24
+ Change password. If you are an admin, you can change other users passwords as well.
25
+
26
+ Example:
27
+ PASSWORD hunter2
28
+
29
+ NETWORK:
30
+ banner: "Usage: NETWORK [--add|--remove|--list] [--public] <network-name> <uri>"
31
+ help: |+
32
+ Manage networks. --add will add a new network, or a new connection host to an existing network. Public networks can only be created by admins, and can be joined by anybody.
33
+
34
+ Examples:
35
+ NETWORK --add --public freenode irc://irc.freenode.org:6667
36
+ NETWORK --add freenode ircs://irc.freenode.org:7000
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'tkellem/irc_message'
3
+
4
+ include Tkellem
5
+
6
+ describe IrcMessage, ".parse" do
7
+ it "should parse complex irc lines" do
8
+ orig = ":some_long_prefix COMMAND first second :long arg here"
9
+ line = IrcMessage.parse(orig)
10
+ line.command.should == 'COMMAND'
11
+ line.prefix.should == 'some_long_prefix'
12
+ line.args.size.should == 3
13
+ line.args.should == ['first', 'second', 'long arg here']
14
+ line.replay.should == orig
15
+ end
16
+
17
+ it "should parse messages with embedded colons" do
18
+ orig = "MSG #myroom http://google.com/"
19
+ line = IrcMessage.parse(orig)
20
+ line.command.should == "MSG"
21
+ line.args.should == ["#myroom", "http://google.com/"]
22
+ line.replay.should == orig
23
+ end
24
+ end
25
+
26
+ describe IrcMessage, "#with_timestamp" do
27
+ it "should prefix a timestamp to the last arg" do
28
+ line = IrcMessage.parse(":some_long_prefix COMMAND first second :long arg here")
29
+ require 'time'
30
+ timestamp = Time.parse("Thu Nov 29 14:33:20 2001")
31
+ ts_line = line.with_timestamp(timestamp)
32
+ ts_line.should be_a(IrcMessage)
33
+ ts_line.to_s.should == ":some_long_prefix COMMAND first second :14:33:20> long arg here"
34
+ end
35
+ end
36
+
37
+ describe IrcMessage do
38
+ it "should know how to find the last arg" do
39
+ line1 = IrcMessage.parse("TEST one two three")
40
+ line1.args.should == %w(one two three)
41
+ line1.args.last.should == "three"
42
+
43
+ line2 = IrcMessage.parse("TEST one two :three")
44
+ line2.args.should == %w(one two three)
45
+ line2.args.last.should == "three"
46
+ end
47
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'tkellem/irc_server'
3
+
4
+ include Tkellem
5
+
6
+ describe IrcServer, "connection" do
7
+ def make_server
8
+ Class.new do
9
+ include IrcServer
10
+
11
+ def send_data(*a); end
12
+ end.new(nil, "spec_server", false, "speccer")
13
+ end
14
+
15
+ def send_welcome(s, &just_before_last)
16
+ s.receive_line("001 blah blah")
17
+ s.receive_line("002 more blah")
18
+ s.receive_line("003 even more blah")
19
+ just_before_last && just_before_last.call
20
+ s.receive_line("376 :end of MOTD")
21
+ end
22
+
23
+ def connected_server
24
+ s = make_server
25
+ s.post_init
26
+ send_welcome(s)
27
+ s.connected?.should be_true
28
+ s
29
+ end
30
+
31
+ it "should connect to the server on creation" do
32
+ s = make_server
33
+ s.connected?.should_not be_true
34
+ s.should_receive(:send_data).with("USER speccer localhost blah :speccer\r\n")
35
+ s.should_receive(:send_data).with("NICK speccer\r\n")
36
+ s.post_init
37
+ end
38
+
39
+ it "should join pending rooms once the connection is established" do
40
+ s = make_server
41
+ s.post_init
42
+ s.connected?.should_not be_true # still haven't received the welcome
43
+
44
+ s.join_room "#test1"
45
+ # as soon as the end of MOTD is received, the IrcServer will consider itself
46
+ # connected and try to join the rooms.
47
+ s.should_receive(:send_data).with("JOIN #test1\r\n")
48
+ s.should_receive(:send_data).with("JOIN #test2\r\n")
49
+
50
+ send_welcome(s) { s.join_room "#test2" }
51
+
52
+ s.connected?.should be_true
53
+ end
54
+
55
+ it "should pong" do
56
+ s = connected_server
57
+ s.should_receive(:send_data).with("PONG speccer!tkellem :HAI\r\n")
58
+ s.receive_line(":speccer!test@host ping :HAI")
59
+ end
60
+ end
data/spec/spec_helper.rb CHANGED
@@ -6,5 +6,3 @@ require 'rspec'
6
6
 
7
7
  RSpec.configure do |config|
8
8
  end
9
-
10
- puts "Yeah... not so much right now"
data/tkellem.gemspec CHANGED
@@ -1,57 +1,30 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
1
  # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "tkellem/version"
5
4
 
6
5
  Gem::Specification.new do |s|
7
- s.name = %q{tkellem}
8
- s.version = "0.7.1"
6
+ s.name = %q{tkellem}
7
+ s.version = Tkellem::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Brian Palmer"]
10
+ s.email = ["brian@codekitchen.net"]
11
+ s.homepage = %q{http://github.com/codekitchen/tkellem}
12
+ s.summary = %q{IRC bouncer with multi-client support}
9
13
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Brian Palmer"]
12
- s.date = %q{2010-11-18}
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
17
  s.default_executable = %q{tkellem}
14
- s.email = %q{brian@codekitchen.net}
15
- s.executables = ["tkellem"]
16
- s.extra_rdoc_files = [
17
- "LICENSE",
18
- "README.md"
19
- ]
20
- s.files = [
21
- "LICENSE",
22
- "README.md",
23
- "Rakefile",
24
- "VERSION",
25
- "bin/tkellem",
26
- "examples/config.yml",
27
- "lib/tkellem.rb",
28
- "lib/tkellem/backlog.rb",
29
- "lib/tkellem/bouncer.rb",
30
- "lib/tkellem/bouncer_connection.rb",
31
- "lib/tkellem/irc_line.rb",
32
- "lib/tkellem/irc_server.rb",
33
- "spec/spec_helper.rb",
34
- "tkellem.gemspec"
35
- ]
36
- s.homepage = %q{http://github.com/codekitchen/tkellem}
37
18
  s.require_paths = ["lib"]
38
- s.rubygems_version = %q{1.3.7}
39
- s.summary = %q{IRC bouncer with multi-client support}
40
- s.test_files = [
41
- "spec/spec_helper.rb"
42
- ]
43
19
 
44
- if s.respond_to? :specification_version then
45
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
- s.specification_version = 3
20
+ s.add_dependency "eventmachine", "~> 0.12.10"
21
+ s.add_dependency "daemons", "~> 1.1.0"
22
+ s.add_dependency "json"
23
+ s.add_dependency "activerecord", "~> 3.0.0"
24
+ s.add_dependency "sqlite3", "~> 1.3.3"
47
25
 
48
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
- s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
50
- else
51
- s.add_dependency(%q<eventmachine>, [">= 0"])
52
- end
53
- else
54
- s.add_dependency(%q<eventmachine>, [">= 0"])
55
- end
26
+ s.add_development_dependency "rspec", "~> 2.5"
27
+ s.add_development_dependency "rcov"
28
+ s.add_development_dependency "yard"
56
29
  end
57
30
 
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tkellem
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 7
8
- - 1
9
- version: 0.7.1
4
+ prerelease:
5
+ version: 0.8.0
10
6
  platform: ruby
11
7
  authors:
12
8
  - Brian Palmer
@@ -14,44 +10,146 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2010-11-18 00:00:00 -07:00
13
+ date: 2011-06-13 00:00:00 -06:00
18
14
  default_executable: tkellem
19
15
  dependencies:
20
16
  - !ruby/object:Gem::Dependency
21
17
  name: eventmachine
22
18
  prerelease: false
23
19
  requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 0.12.10
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: daemons
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 1.1.0
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: json
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
24
42
  none: false
25
43
  requirements:
26
44
  - - ">="
27
45
  - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
46
  version: "0"
31
47
  type: :runtime
32
- version_requirements: *id001
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: activerecord
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: 3.0.0
58
+ type: :runtime
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: sqlite3
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.3
69
+ type: :runtime
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ version: "2.5"
80
+ type: :development
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: rcov
84
+ prerelease: false
85
+ requirement: &id007 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ type: :development
92
+ version_requirements: *id007
93
+ - !ruby/object:Gem::Dependency
94
+ name: yard
95
+ prerelease: false
96
+ requirement: &id008 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: "0"
102
+ type: :development
103
+ version_requirements: *id008
33
104
  description:
34
- email: brian@codekitchen.net
105
+ email:
106
+ - brian@codekitchen.net
35
107
  executables:
36
108
  - tkellem
37
109
  extensions: []
38
110
 
39
- extra_rdoc_files:
40
- - LICENSE
41
- - README.md
111
+ extra_rdoc_files: []
112
+
42
113
  files:
114
+ - .gitignore
115
+ - Gemfile
43
116
  - LICENSE
44
117
  - README.md
45
118
  - Rakefile
46
- - VERSION
47
119
  - bin/tkellem
120
+ - debian/changelog
121
+ - debian/compat
122
+ - debian/control
123
+ - debian/copyright
124
+ - debian/docs
125
+ - debian/examples
126
+ - debian/install
127
+ - debian/manpages
128
+ - debian/rules
129
+ - debian/source/format
130
+ - debian/tkellem.1
48
131
  - examples/config.yml
49
132
  - lib/tkellem.rb
50
- - lib/tkellem/backlog.rb
51
133
  - lib/tkellem/bouncer.rb
52
134
  - lib/tkellem/bouncer_connection.rb
53
- - lib/tkellem/irc_line.rb
135
+ - lib/tkellem/daemon.rb
136
+ - lib/tkellem/irc_message.rb
54
137
  - lib/tkellem/irc_server.rb
138
+ - lib/tkellem/migrations/001_init_db.rb
139
+ - lib/tkellem/models/host.rb
140
+ - lib/tkellem/models/listen_address.rb
141
+ - lib/tkellem/models/network.rb
142
+ - lib/tkellem/models/network_user.rb
143
+ - lib/tkellem/models/user.rb
144
+ - lib/tkellem/plugins/backlog.rb
145
+ - lib/tkellem/plugins/push_service.rb
146
+ - lib/tkellem/socket_server.rb
147
+ - lib/tkellem/tkellem_bot.rb
148
+ - lib/tkellem/tkellem_server.rb
149
+ - lib/tkellem/version.rb
150
+ - resources/bot_command_descriptions.yml
151
+ - spec/irc_message_spec.rb
152
+ - spec/irc_server_spec.rb
55
153
  - spec/spec_helper.rb
56
154
  - tkellem.gemspec
57
155
  has_rdoc: true
@@ -68,23 +166,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
166
  requirements:
69
167
  - - ">="
70
168
  - !ruby/object:Gem::Version
71
- segments:
72
- - 0
73
169
  version: "0"
74
170
  required_rubygems_version: !ruby/object:Gem::Requirement
75
171
  none: false
76
172
  requirements:
77
173
  - - ">="
78
174
  - !ruby/object:Gem::Version
79
- segments:
80
- - 0
81
175
  version: "0"
82
176
  requirements: []
83
177
 
84
178
  rubyforge_project:
85
- rubygems_version: 1.3.7
179
+ rubygems_version: 1.6.2
86
180
  signing_key:
87
181
  specification_version: 3
88
182
  summary: IRC bouncer with multi-client support
89
183
  test_files:
184
+ - spec/irc_message_spec.rb
185
+ - spec/irc_server_spec.rb
90
186
  - spec/spec_helper.rb
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.7.1
@@ -1,85 +0,0 @@
1
- require 'tkellem/irc_line'
2
-
3
- module Tkellem
4
-
5
- # Normally there will be one client per backlog, but there can be more than one
6
- # connection for the same backlog, if two or more IRC clients connect with the
7
- # same client name. That situation is equivalent to how most multi-connection
8
- # bouncers like bip work.
9
-
10
- class Backlog
11
-
12
- class BacklogLine < Struct.new(:irc_line, :time)
13
- end
14
-
15
- def initialize(name, max_backlog = nil)
16
- @name = name
17
- @backlog = []
18
- @pm_backlogs = Hash.new { |h,k| h[k] = [] }
19
- @active_conns = []
20
- @max_backlog = max_backlog
21
- end
22
- attr_reader :name, :backlog, :active_conns, :pm_backlogs, :max_backlog
23
-
24
- def handle_message(msg)
25
- # TODO: only send back response messages like WHO, NAMES, etc. to the
26
- # BouncerConnection that requested it.
27
- if !active_conns.empty?
28
- case msg.command
29
- when /3\d\d/, /join/i, /part/i
30
- # transient response -- we want to forward these, but not backlog
31
- active_conns.each { |conn| conn.transient_response(msg) }
32
- when /privmsg/i
33
- active_conns.each { |conn| conn.send_msg(msg) }
34
- else
35
- # do nothing?
36
- end
37
- elsif msg.command.match(/privmsg/i)
38
- if msg.args.first.match(/^#/)
39
- # room privmsg always goes in a specific backlog
40
- pm_target = msg.args.first
41
- bl = pm_backlogs[pm_target]
42
- else
43
- # other messages go in the general backlog
44
- bl = backlog
45
- end
46
- bl.push(BacklogLine.new(msg, Time.now))
47
- limit_backlog(bl)
48
- end
49
- end
50
-
51
- def limit_backlog(bl)
52
- bl.shift until !max_backlog || bl.size <= max_backlog
53
- end
54
-
55
- def max_backlog=(new_val)
56
- @max_backlog = new_val
57
- limit_backlog(backlog)
58
- pm_backlogs.each { |k,bl| limit_backlog(bl) }
59
- end
60
-
61
- def add_conn(bouncer_conn)
62
- active_conns << bouncer_conn
63
- end
64
-
65
- def remove_conn(bouncer_conn)
66
- active_conns.delete(bouncer_conn)
67
- end
68
-
69
- def send_backlog(conn, pm_target = nil)
70
- if pm_target
71
- # send room-specific backlog
72
- msgs = pm_backlogs.key?(pm_target) ? pm_backlogs[pm_target] : []
73
- else
74
- # send the general backlog
75
- msgs = backlog
76
- end
77
-
78
- until msgs.empty?
79
- backlog_line = msgs.shift
80
- conn.send_msg(backlog_line.irc_line.with_timestamp(backlog_line.time))
81
- end
82
- end
83
- end
84
-
85
- end