tkellem 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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