blather 0.1

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 (45) hide show
  1. data/CHANGELOG +1 -0
  2. data/LICENSE +20 -0
  3. data/Manifest +43 -0
  4. data/README.rdoc +78 -0
  5. data/Rakefile +16 -0
  6. data/blather.gemspec +41 -0
  7. data/examples/echo.rb +22 -0
  8. data/examples/shell_client.rb +28 -0
  9. data/lib/autotest/discover.rb +1 -0
  10. data/lib/autotest/spec.rb +60 -0
  11. data/lib/blather.rb +46 -0
  12. data/lib/blather/callback.rb +24 -0
  13. data/lib/blather/client.rb +81 -0
  14. data/lib/blather/core/errors.rb +24 -0
  15. data/lib/blather/core/jid.rb +101 -0
  16. data/lib/blather/core/roster.rb +84 -0
  17. data/lib/blather/core/roster_item.rb +92 -0
  18. data/lib/blather/core/stanza.rb +116 -0
  19. data/lib/blather/core/stanza/iq.rb +27 -0
  20. data/lib/blather/core/stanza/iq/query.rb +42 -0
  21. data/lib/blather/core/stanza/iq/roster.rb +96 -0
  22. data/lib/blather/core/stanza/message.rb +55 -0
  23. data/lib/blather/core/stanza/presence.rb +35 -0
  24. data/lib/blather/core/stanza/presence/status.rb +77 -0
  25. data/lib/blather/core/stanza/presence/subscription.rb +73 -0
  26. data/lib/blather/core/stream.rb +181 -0
  27. data/lib/blather/core/stream/parser.rb +74 -0
  28. data/lib/blather/core/stream/resource.rb +51 -0
  29. data/lib/blather/core/stream/sasl.rb +135 -0
  30. data/lib/blather/core/stream/session.rb +43 -0
  31. data/lib/blather/core/stream/tls.rb +29 -0
  32. data/lib/blather/core/sugar.rb +150 -0
  33. data/lib/blather/core/xmpp_node.rb +132 -0
  34. data/lib/blather/extensions.rb +4 -0
  35. data/lib/blather/extensions/last_activity.rb +55 -0
  36. data/lib/blather/extensions/version.rb +85 -0
  37. data/spec/blather/core/jid_spec.rb +78 -0
  38. data/spec/blather/core/roster_item_spec.rb +80 -0
  39. data/spec/blather/core/roster_spec.rb +79 -0
  40. data/spec/blather/core/stanza_spec.rb +95 -0
  41. data/spec/blather/core/stream_spec.rb +263 -0
  42. data/spec/blather/core/xmpp_node_spec.rb +130 -0
  43. data/spec/build_safe.rb +20 -0
  44. data/spec/spec_helper.rb +49 -0
  45. metadata +172 -0
@@ -0,0 +1 @@
1
+ v0.1 Initial release (birth!)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Jeff Smick
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+ CHANGELOG
2
+ examples/echo.rb
3
+ examples/shell_client.rb
4
+ lib/autotest/discover.rb
5
+ lib/autotest/spec.rb
6
+ lib/blather/callback.rb
7
+ lib/blather/client.rb
8
+ lib/blather/core/errors.rb
9
+ lib/blather/core/jid.rb
10
+ lib/blather/core/roster.rb
11
+ lib/blather/core/roster_item.rb
12
+ lib/blather/core/stanza/iq/query.rb
13
+ lib/blather/core/stanza/iq/roster.rb
14
+ lib/blather/core/stanza/iq.rb
15
+ lib/blather/core/stanza/message.rb
16
+ lib/blather/core/stanza/presence/status.rb
17
+ lib/blather/core/stanza/presence/subscription.rb
18
+ lib/blather/core/stanza/presence.rb
19
+ lib/blather/core/stanza.rb
20
+ lib/blather/core/stream/parser.rb
21
+ lib/blather/core/stream/resource.rb
22
+ lib/blather/core/stream/sasl.rb
23
+ lib/blather/core/stream/session.rb
24
+ lib/blather/core/stream/tls.rb
25
+ lib/blather/core/stream.rb
26
+ lib/blather/core/sugar.rb
27
+ lib/blather/core/xmpp_node.rb
28
+ lib/blather/extensions/last_activity.rb
29
+ lib/blather/extensions/version.rb
30
+ lib/blather/extensions.rb
31
+ lib/blather.rb
32
+ LICENSE
33
+ Rakefile
34
+ README.rdoc
35
+ spec/blather/core/jid_spec.rb
36
+ spec/blather/core/roster_item_spec.rb
37
+ spec/blather/core/roster_spec.rb
38
+ spec/blather/core/stanza_spec.rb
39
+ spec/blather/core/stream_spec.rb
40
+ spec/blather/core/xmpp_node_spec.rb
41
+ spec/build_safe.rb
42
+ spec/spec_helper.rb
43
+ Manifest
@@ -0,0 +1,78 @@
1
+ = Blather
2
+
3
+ An evented XMPP library
4
+
5
+ == Features
6
+
7
+ * evented architecture
8
+ * uses libxml
9
+ * simplified starting point
10
+
11
+ == Project Pages
12
+
13
+ GitHub:: https://github.com/sprsquish/blather
14
+
15
+ RubyForge:: http://rubyforge.org/projects/squishtech/
16
+
17
+ Lighthouse:: http://squishtech.lighthouseapp.com/projects/20652-blather
18
+
19
+ == Author
20
+
21
+ Jeff Smick <sprsquish@gmail.com>
22
+
23
+ = Usage
24
+
25
+ == Installation
26
+
27
+ sudo gem install blather
28
+
29
+ == Example
30
+
31
+ See the /examples directory for more advanced examples.
32
+
33
+ This will auto-accept any subscription requests and echo back any messages or presence notifications.
34
+
35
+ require 'lib/blather/client'
36
+
37
+ class Echo < Blather::Client
38
+ # Auto-approve subscription requests
39
+ def receive_subscription(s)
40
+ send_data(s.approve!) and true if s.request?
41
+ end
42
+
43
+ # Echo presence
44
+ def receive_status(status)
45
+ set_status(status.state, status.message, status.from) if roster[status.from]
46
+ end
47
+
48
+ # Echo message
49
+ def receive_message(message)
50
+ send_data(message.reply) if message.type == :chat
51
+ end
52
+ end
53
+
54
+ Blather.run 'echo@jabber.local', 'echo', Echo.new
55
+
56
+
57
+ = License
58
+
59
+ Copyright (c) 2008 Jeff Smick
60
+
61
+ Permission is hereby granted, free of charge, to any person obtaining
62
+ a copy of this software and associated documentation files (the
63
+ "Software"), to deal in the Software without restriction, including
64
+ without limitation the rights to use, copy, modify, merge, publish,
65
+ distribute, sublicense, and/or sell copies of the Software, and to
66
+ permit persons to whom the Software is furnished to do so, subject to
67
+ the following conditions:
68
+
69
+ The above copyright notice and this permission notice shall be
70
+ included in all copies or substantial portions of the Software.
71
+
72
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
73
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
74
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
75
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
76
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
77
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
78
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,16 @@
1
+ require 'echoe'
2
+ require 'lib/blather'
3
+ require 'hanna/rdoctask'
4
+
5
+ Echoe.new('blather') do |p|
6
+ p.author = 'Jeff Smick'
7
+ p.email = 'sprsquish@gmail.com'
8
+
9
+ p.project = 'squishtech'
10
+ p.version = Blather::VERSION
11
+ p.summary = 'An evented XMPP library written on EventMachine and libxml-ruby'
12
+
13
+ p.runtime_dependencies = ['eventmachine', 'libxml >=1.0.11']
14
+ p.rdoc_options += %w[-S -T hanna --main README.rdoc --exclude autotest]
15
+ p.test_pattern = 'spec/**/*_spec.rb'
16
+ end
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{blather}
5
+ s.version = "0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Jeff Smick"]
9
+ s.date = %q{2008-11-27}
10
+ s.description = %q{An evented XMPP library written on EventMachine and libxml-ruby}
11
+ s.email = %q{sprsquish@gmail.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/autotest/discover.rb", "lib/autotest/spec.rb", "lib/blather/callback.rb", "lib/blather/client.rb", "lib/blather/core/errors.rb", "lib/blather/core/jid.rb", "lib/blather/core/roster.rb", "lib/blather/core/roster_item.rb", "lib/blather/core/stanza/iq/query.rb", "lib/blather/core/stanza/iq/roster.rb", "lib/blather/core/stanza/iq.rb", "lib/blather/core/stanza/message.rb", "lib/blather/core/stanza/presence/status.rb", "lib/blather/core/stanza/presence/subscription.rb", "lib/blather/core/stanza/presence.rb", "lib/blather/core/stanza.rb", "lib/blather/core/stream/parser.rb", "lib/blather/core/stream/resource.rb", "lib/blather/core/stream/sasl.rb", "lib/blather/core/stream/session.rb", "lib/blather/core/stream/tls.rb", "lib/blather/core/stream.rb", "lib/blather/core/sugar.rb", "lib/blather/core/xmpp_node.rb", "lib/blather/extensions/last_activity.rb", "lib/blather/extensions/version.rb", "lib/blather/extensions.rb", "lib/blather.rb", "LICENSE", "README.rdoc"]
13
+ s.files = ["CHANGELOG", "examples/echo.rb", "examples/shell_client.rb", "lib/autotest/discover.rb", "lib/autotest/spec.rb", "lib/blather/callback.rb", "lib/blather/client.rb", "lib/blather/core/errors.rb", "lib/blather/core/jid.rb", "lib/blather/core/roster.rb", "lib/blather/core/roster_item.rb", "lib/blather/core/stanza/iq/query.rb", "lib/blather/core/stanza/iq/roster.rb", "lib/blather/core/stanza/iq.rb", "lib/blather/core/stanza/message.rb", "lib/blather/core/stanza/presence/status.rb", "lib/blather/core/stanza/presence/subscription.rb", "lib/blather/core/stanza/presence.rb", "lib/blather/core/stanza.rb", "lib/blather/core/stream/parser.rb", "lib/blather/core/stream/resource.rb", "lib/blather/core/stream/sasl.rb", "lib/blather/core/stream/session.rb", "lib/blather/core/stream/tls.rb", "lib/blather/core/stream.rb", "lib/blather/core/sugar.rb", "lib/blather/core/xmpp_node.rb", "lib/blather/extensions/last_activity.rb", "lib/blather/extensions/version.rb", "lib/blather/extensions.rb", "lib/blather.rb", "LICENSE", "Rakefile", "README.rdoc", "spec/blather/core/jid_spec.rb", "spec/blather/core/roster_item_spec.rb", "spec/blather/core/roster_spec.rb", "spec/blather/core/stanza_spec.rb", "spec/blather/core/stream_spec.rb", "spec/blather/core/xmpp_node_spec.rb", "spec/build_safe.rb", "spec/spec_helper.rb", "Manifest", "blather.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Blather", "--main", "README.rdoc", "-S", "-T", "hanna", "--main", "README.rdoc", "--exclude", "autotest"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{squishtech}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{An evented XMPP library written on EventMachine and libxml-ruby}
21
+ s.test_files = ["spec/blather/core/jid_spec.rb", "spec/blather/core/roster_item_spec.rb", "spec/blather/core/roster_spec.rb", "spec/blather/core/stanza_spec.rb", "spec/blather/core/stream_spec.rb", "spec/blather/core/xmpp_node_spec.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
29
+ s.add_runtime_dependency(%q<libxml>, [">= 1.0.11"])
30
+ s.add_development_dependency(%q<echoe>, [">= 0"])
31
+ else
32
+ s.add_dependency(%q<eventmachine>, [">= 0"])
33
+ s.add_dependency(%q<libxml>, [">= 1.0.11"])
34
+ s.add_dependency(%q<echoe>, [">= 0"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<eventmachine>, [">= 0"])
38
+ s.add_dependency(%q<libxml>, [">= 1.0.11"])
39
+ s.add_dependency(%q<echoe>, [">= 0"])
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ require 'lib/blather/client'
2
+ include Blather
3
+
4
+ class Echo < Client
5
+ # Auto-approve subscription requests
6
+ def receive_subscription(s)
7
+ send_data(s.approve!) and true if s.request?
8
+ end
9
+
10
+ # Echo presence
11
+ def receive_status(status)
12
+ set_status(status.state, status.message, status.from) if roster[status.from]
13
+ end
14
+
15
+ # Echo message
16
+ def receive_message(message)
17
+ send_data(message.reply) if message.type == :chat
18
+ end
19
+ end
20
+
21
+ #handle :version do run Extensions::VersionHandler.new('Echo', '1.0'); end
22
+ run 'sprsquish@jabber.local/Blather', 'iq150150', Echo.new
@@ -0,0 +1,28 @@
1
+ require 'lib/blather/client'
2
+ include Blather
3
+
4
+ class ShellClient < Client
5
+ def receive_roster(roster)
6
+ super
7
+ if roster.type == :result
8
+ start_highline
9
+ end
10
+ end
11
+
12
+ def receive_message(msg)
13
+
14
+ end
15
+
16
+ def start_highline
17
+ end
18
+
19
+ end
20
+
21
+ EM.run {
22
+ shell = Shell.new
23
+
24
+ #shell
25
+ EM.spawn { shell.start }
26
+
27
+ Blather.run 'orthie@jabber.local/Blather', 'orthie', shell
28
+ }
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { 'spec' }
@@ -0,0 +1,60 @@
1
+ require 'autotest'
2
+
3
+ Autotest.add_hook :initialize do |at|
4
+ at.clear_mappings
5
+ # watch out: Ruby bug (1.8.6):
6
+ # %r(/) != /\//
7
+ at.add_mapping(%r%^spec/.*_spec.rb$%) { |filename, _|
8
+ filename
9
+ }
10
+ at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m|
11
+ ["spec/#{m[1]}_spec.rb"]
12
+ }
13
+ at.add_mapping(%r%^spec/(spec_helper|shared/.*)\.rb$%) {
14
+ at.files_matching %r%^spec/.*_spec\.rb$%
15
+ }
16
+ end
17
+
18
+ BAR = "=" * 78
19
+ REDCODE = 31
20
+ GREENCODE = 32
21
+
22
+ Autotest.add_hook :ran_command do |at|
23
+ at.results.last =~ /^.* (\d+) failures, (\d+) errors/
24
+
25
+ code = ($1 == "0" and $2 == "0") ? GREENCODE : REDCODE
26
+ puts "\e[#{ code }m#{ BAR }\e[0m\n\n"
27
+ end
28
+
29
+ class Autotest::Spec < Autotest
30
+ def path_to_classname(s)
31
+ sep = File::SEPARATOR
32
+ f = s.sub(/spec#{sep}/, '').sub(/(spec)?\.rb$/, '').split(sep)
33
+ f = f.map { |path| path.split(/_|(\d+)/).map { |seg| seg.capitalize }.join }
34
+ f = f.delete_if { |path| path == 'Core' }
35
+ f.join
36
+ end
37
+
38
+ ##
39
+ # Returns a hash mapping a file name to the known failures for that
40
+ # file.
41
+
42
+ def consolidate_failures(failed)
43
+ filters = new_hash_of_arrays
44
+
45
+ class_map = Hash[*self.find_order.grep(/^spec/).map { |f| # TODO: ugly
46
+ [path_to_classname(f), f]
47
+ }.flatten]
48
+ class_map.merge!(self.extra_class_map)
49
+
50
+ failed.each do |method, klass|
51
+ if class_map.has_key? klass then
52
+ filters[class_map[klass]] << method
53
+ else
54
+ output.puts "Unable to map class #{klass} to a file"
55
+ end
56
+ end
57
+
58
+ return filters
59
+ end
60
+ end
@@ -0,0 +1,46 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ %w[
4
+ rubygems
5
+ xml/libxml
6
+ eventmachine
7
+ digest/md5
8
+ logger
9
+
10
+ blather/callback
11
+
12
+ blather/core/errors
13
+ blather/core/jid
14
+ blather/core/roster
15
+ blather/core/roster_item
16
+ blather/core/sugar
17
+ blather/core/xmpp_node
18
+
19
+ blather/core/stanza
20
+ blather/core/stanza/iq
21
+ blather/core/stanza/iq/query
22
+ blather/core/stanza/iq/roster
23
+ blather/core/stanza/message
24
+ blather/core/stanza/presence
25
+ blather/core/stanza/presence/status
26
+ blather/core/stanza/presence/subscription
27
+
28
+ blather/core/stream
29
+ blather/core/stream/parser
30
+ blather/core/stream/resource
31
+ blather/core/stream/sasl
32
+ blather/core/stream/session
33
+ blather/core/stream/tls
34
+ ].each { |r| require r }
35
+
36
+ XML::Parser.indent_tree_output = false
37
+
38
+ module Blather
39
+ VERSION = '0.1'
40
+ LOG = Logger.new STDOUT
41
+
42
+ def run(jid, password, client, host = nil, port = 5222)
43
+ EM.run { Stream.start client, JID.new(jid), password, host, port }
44
+ end
45
+ module_function :run
46
+ end
@@ -0,0 +1,24 @@
1
+ module Blather
2
+
3
+ class Callback
4
+ include Comparable
5
+
6
+ attr_accessor :priority
7
+
8
+ def initialize(priority = 0, &callback)
9
+ @priority = priority
10
+ @callback = callback
11
+ end
12
+
13
+ def call(*args)
14
+ @callback.call(*args)
15
+ end
16
+
17
+ # Favor higher numbers
18
+ def <=>(o)
19
+ self.priority <=> o.priority
20
+ end
21
+
22
+ end #Callback
23
+
24
+ end
@@ -0,0 +1,81 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. blather])
2
+
3
+ module Blather
4
+
5
+ class Client
6
+ @@callbacks = {}
7
+ @@status = nil
8
+
9
+ attr_accessor :jid,
10
+ :roster
11
+
12
+ def send_data(data)
13
+ @stream.send data
14
+ end
15
+
16
+ def status
17
+ @@status
18
+ end
19
+
20
+ def set_status(state = nil, msg = nil, to = nil)
21
+ status = Presence::Status.new state, msg
22
+ status.to = to
23
+ @@status = status unless to
24
+
25
+ send_data status
26
+ end
27
+
28
+ def stream_started(stream)
29
+ @stream = stream
30
+ retreive_roster
31
+ end
32
+
33
+ def call(stanza)
34
+ stanza.callback_heirarchy.each { |type| break if callback(type, stanza) }
35
+ end
36
+
37
+ # Default response to an Iq 'get' or 'set' is 'service-unavailable'/'cancel'
38
+ def receive_iq(iq)
39
+ send_data(ErrorStanza.new_from(iq, 'service-unavailable', 'cancel').reply!) if [:set, :get].include?(iq.type)
40
+ end
41
+
42
+ def receive_roster(node)
43
+ if !@roster && node.type == :result
44
+ self.roster = Roster.new(@stream, node)
45
+ register_callback(:status, -128) { |_, status| roster[status.from].status = status if roster[status.from]; false }
46
+ set_status
47
+ elsif node.type == :set
48
+ roster.process node
49
+ end
50
+ end
51
+
52
+ def self.register_callback(type, priority = 0, &callback)
53
+ @@callbacks[type] ||= []
54
+ @@callbacks[type] << Callback.new(priority, &callback)
55
+ @@callbacks[type].sort!
56
+ end
57
+
58
+ def register_callback(type, priority = 0, &callback)
59
+ self.class.register_callback(type, priority = 0, &callback)
60
+ end
61
+
62
+ def self.status(state = nil, msg = nil)
63
+ @@status = Presence::Status.new state, msg
64
+ end
65
+
66
+ def callback(type, stanza)
67
+ complete = false
68
+ (@@callbacks[type] || []).each { |callback| break if complete = callback.call(self, stanza) }
69
+
70
+ method = "receive_#{type}"
71
+ complete = __send__(method, stanza) if !complete && respond_to?(method)
72
+ complete
73
+ end
74
+
75
+ def retreive_roster
76
+ send_data Iq::Roster.new
77
+ end
78
+
79
+ end #Client
80
+
81
+ end