blather 0.2.1 → 0.2.2

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 (84) hide show
  1. data/LICENSE +2 -0
  2. data/README.rdoc +54 -29
  3. data/Rakefile +94 -13
  4. data/VERSION.yml +4 -0
  5. data/examples/drb_client.rb +2 -4
  6. data/examples/echo.rb +13 -8
  7. data/examples/pubsub/cli.rb +64 -0
  8. data/examples/pubsub/ping_pong.rb +18 -0
  9. data/examples/pubsub/pubsub_dsl.rb +52 -0
  10. data/examples/pubsub_client.rb +39 -0
  11. data/examples/rosterprint.rb +14 -0
  12. data/examples/xmpp4r/echo.rb +35 -0
  13. data/ext/extconf.rb +65 -0
  14. data/lib/blather.rb +18 -121
  15. data/lib/blather/client.rb +13 -0
  16. data/lib/blather/client/client.rb +165 -0
  17. data/lib/blather/client/dsl.rb +99 -0
  18. data/lib/blather/client/pubsub.rb +53 -0
  19. data/lib/blather/client/pubsub/node.rb +27 -0
  20. data/lib/blather/core_ext/active_support.rb +1 -0
  21. data/lib/blather/core_ext/libxml.rb +7 -1
  22. data/lib/blather/errors.rb +39 -18
  23. data/lib/blather/errors/sasl_error.rb +87 -0
  24. data/lib/blather/errors/stanza_error.rb +262 -0
  25. data/lib/blather/errors/stream_error.rb +253 -0
  26. data/lib/blather/jid.rb +9 -16
  27. data/lib/blather/roster.rb +9 -0
  28. data/lib/blather/roster_item.rb +7 -4
  29. data/lib/blather/stanza.rb +19 -25
  30. data/lib/blather/stanza/disco.rb +9 -0
  31. data/lib/blather/stanza/disco/disco_info.rb +84 -0
  32. data/lib/blather/stanza/disco/disco_items.rb +59 -0
  33. data/lib/blather/stanza/iq.rb +16 -4
  34. data/lib/blather/stanza/iq/query.rb +6 -4
  35. data/lib/blather/stanza/iq/roster.rb +38 -38
  36. data/lib/blather/stanza/pubsub.rb +33 -0
  37. data/lib/blather/stanza/pubsub/affiliations.rb +52 -0
  38. data/lib/blather/stanza/pubsub/errors.rb +9 -0
  39. data/lib/blather/stanza/pubsub/event.rb +21 -0
  40. data/lib/blather/stanza/pubsub/items.rb +59 -0
  41. data/lib/blather/stanza/pubsub/owner.rb +9 -0
  42. data/lib/blather/stanza/pubsub/subscriptions.rb +57 -0
  43. data/lib/blather/stream.rb +125 -57
  44. data/lib/blather/stream/client.rb +26 -0
  45. data/lib/blather/stream/component.rb +34 -0
  46. data/lib/blather/stream/parser.rb +17 -27
  47. data/lib/blather/stream/resource.rb +21 -24
  48. data/lib/blather/stream/sasl.rb +60 -37
  49. data/lib/blather/stream/session.rb +12 -19
  50. data/lib/blather/stream/stream_handler.rb +39 -0
  51. data/lib/blather/stream/tls.rb +22 -18
  52. data/lib/blather/xmpp_node.rb +91 -17
  53. data/spec/blather/core_ext/libxml_spec.rb +58 -0
  54. data/spec/blather/errors/sasl_error_spec.rb +56 -0
  55. data/spec/blather/errors/stanza_error_spec.rb +148 -0
  56. data/spec/blather/errors/stream_error_spec.rb +114 -0
  57. data/spec/blather/errors_spec.rb +40 -0
  58. data/spec/blather/jid_spec.rb +0 -7
  59. data/spec/blather/roster_item_spec.rb +5 -0
  60. data/spec/blather/roster_spec.rb +6 -6
  61. data/spec/blather/stanza/discos/disco_info_spec.rb +207 -0
  62. data/spec/blather/stanza/discos/disco_items_spec.rb +136 -0
  63. data/spec/blather/stanza/iq/query_spec.rb +9 -2
  64. data/spec/blather/stanza/iq/roster_spec.rb +117 -1
  65. data/spec/blather/stanza/iq_spec.rb +29 -0
  66. data/spec/blather/stanza/presence/subscription_spec.rb +12 -1
  67. data/spec/blather/stanza/presence_spec.rb +29 -0
  68. data/spec/blather/stanza/pubsub/affiliations_spec.rb +46 -0
  69. data/spec/blather/stanza/pubsub/items_spec.rb +59 -0
  70. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +63 -0
  71. data/spec/blather/stanza/pubsub_spec.rb +26 -0
  72. data/spec/blather/stanza_spec.rb +13 -1
  73. data/spec/blather/stream/client_spec.rb +787 -0
  74. data/spec/blather/stream/component_spec.rb +86 -0
  75. data/spec/blather/xmpp_node_spec.rb +75 -22
  76. data/spec/fixtures/pubsub.rb +157 -0
  77. data/spec/spec_helper.rb +6 -14
  78. metadata +86 -74
  79. data/CHANGELOG +0 -5
  80. data/Manifest +0 -47
  81. data/blather.gemspec +0 -41
  82. data/lib/blather/stanza/error.rb +0 -31
  83. data/spec/blather/stream_spec.rb +0 -462
  84. data/spec/build_safe.rb +0 -20
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Prints out each roster entry
4
+
5
+ require 'blather/client'
6
+
7
+ when_ready do
8
+ roster.grouped.each do |group, items|
9
+ puts "#{'*'*3} #{group || 'Ungrouped'} #{'*'*3}"
10
+ items.each { |item| puts "- #{item.name} (#{item.jid})" }
11
+ puts
12
+ end
13
+ shutdown
14
+ end
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # This bot will reply to every message it receives. To end the game, send 'exit'
4
+
5
+ require 'xmpp4r/client'
6
+ include Jabber
7
+
8
+ # settings
9
+ if ARGV.length != 2
10
+ puts "Run with ./echo_thread.rb user@server/resource password"
11
+ exit 1
12
+ end
13
+ myJID = JID.new(ARGV[0])
14
+ myPassword = ARGV[1]
15
+ cl = Client.new(myJID)
16
+ cl.connect
17
+ cl.auth(myPassword)
18
+ cl.send(Presence.new)
19
+ puts "Connected ! send messages to #{myJID.strip.to_s}."
20
+ mainthread = Thread.current
21
+ cl.add_message_callback do |m|
22
+ if m.type != :error
23
+ m2 = Message.new(m.from, "You sent: #{m.body}")
24
+ m2.type = m.type
25
+ cl.send(m2)
26
+ if m.body == 'exit'
27
+ m2 = Message.new(m.from, "Exiting ...")
28
+ m2.type = m.type
29
+ cl.send(m2)
30
+ mainthread.wakeup
31
+ end
32
+ end
33
+ end
34
+ Thread.stop
35
+ cl.close
@@ -0,0 +1,65 @@
1
+ require 'mkmf'
2
+
3
+ flags = []
4
+
5
+ case RUBY_PLATFORM.split('-',2)[1]
6
+ when 'mswin32', 'mingw32', 'bccwin32'
7
+ unless have_header('windows.h') and
8
+ have_header('winsock.h') and
9
+ have_library('kernel32') and
10
+ have_library('rpcrt4') and
11
+ have_library('gdi32')
12
+ exit
13
+ end
14
+
15
+ flags << "-D OS_WIN32"
16
+ flags << '-D BUILD_FOR_RUBY'
17
+ flags << "-EHs"
18
+ flags << "-GR"
19
+
20
+ dir_config('xml2')
21
+ exit unless have_library('xml2') && have_header('libxml/parser.h')
22
+
23
+ when /solaris/
24
+ unless have_library('pthread') and
25
+ have_library('nsl') and
26
+ have_library('socket')
27
+ exit
28
+ end
29
+
30
+ flags << '-D OS_UNIX'
31
+ flags << '-D OS_SOLARIS8'
32
+ flags << '-D BUILD_FOR_RUBY'
33
+
34
+ dir_config('xml2')
35
+ exit unless have_library('xml2') && find_header('libxml/parser.h', '/usr/include/libxml2')
36
+
37
+ # on Unix we need a g++ link, not gcc.
38
+ #CONFIG['LDSHARED'] = "$(CXX) -shared"
39
+
40
+ when /darwin/
41
+ flags << '-DOS_UNIX'
42
+ flags << '-DBUILD_FOR_RUBY'
43
+
44
+ dir_config('xml2')
45
+ exit unless have_library('xml2') && find_header('libxml/parser.h', '/usr/include/libxml2')
46
+ # on Unix we need a g++ link, not gcc.
47
+ #CONFIG['LDSHARED'] = "$(CXX) " + CONFIG['LDSHARED'].split[1..-1].join(' ')
48
+
49
+ else
50
+ unless have_library('pthread')
51
+ exit
52
+ end
53
+
54
+ flags << '-DOS_UNIX'
55
+ flags << '-DBUILD_FOR_RUBY'
56
+
57
+ dir_config('xml2')
58
+ exit unless have_library('xml2') && find_header('libxml/parser.h', '/usr/include/libxml2')
59
+ # on Unix we need a g++ link, not gcc.
60
+ #CONFIG['LDSHARED'] = "$(CXX) -shared"
61
+ end
62
+
63
+ $CFLAGS += ' ' + flags.join(' ')
64
+
65
+ create_makefile "push_parser"
@@ -1,10 +1,12 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
+ $:.unshift File.join(File.dirname(__FILE__), '..')
2
3
 
3
4
  # Require the necessary files
4
5
  %w[
5
6
  rubygems
6
- xml/libxml
7
7
  eventmachine
8
+ ext/push_parser
9
+ xml/libxml
8
10
  digest/md5
9
11
  logger
10
12
 
@@ -12,22 +14,34 @@ $:.unshift File.dirname(__FILE__)
12
14
  blather/core_ext/libxml
13
15
 
14
16
  blather/errors
17
+ blather/errors/sasl_error
18
+ blather/errors/stanza_error
19
+ blather/errors/stream_error
15
20
  blather/jid
16
21
  blather/roster
17
22
  blather/roster_item
18
23
  blather/xmpp_node
19
24
 
20
25
  blather/stanza
21
- blather/stanza/error
22
26
  blather/stanza/iq
23
27
  blather/stanza/iq/query
24
28
  blather/stanza/iq/roster
29
+ blather/stanza/disco
30
+ blather/stanza/disco/disco_info
31
+ blather/stanza/disco/disco_items
25
32
  blather/stanza/message
26
33
  blather/stanza/presence
27
34
  blather/stanza/presence/status
28
35
  blather/stanza/presence/subscription
36
+ blather/stanza/pubsub
37
+ blather/stanza/pubsub/affiliations
38
+ blather/stanza/pubsub/subscriptions
39
+ blather/stanza/pubsub/items
29
40
 
30
41
  blather/stream
42
+ blather/stream/client
43
+ blather/stream/component
44
+ blather/stream/stream_handler
31
45
  blather/stream/parser
32
46
  blather/stream/resource
33
47
  blather/stream/sasl
@@ -38,123 +52,6 @@ $:.unshift File.dirname(__FILE__)
38
52
  XML.indent_tree_output = false
39
53
 
40
54
  module Blather
41
- LOG = Logger.new(STDOUT)
42
- Stream::Parser.debug = true
43
- # LOG.level = Logger::INFO
44
-
45
- class Client
46
- attr_accessor :jid,
47
- :roster
48
-
49
- def initialize
50
- @state = :initializing
51
-
52
- @status = Stanza::Presence::Status.new
53
- @handlers = Hash.new { |h,k| h[k] = [] }
54
- @roster = Roster.new self
55
-
56
- setup_initial_handlers
57
- end
58
-
59
- def register_handler(type, &handler)
60
- @handlers[type] << handler
61
- end
62
-
63
- def status
64
- @status.state
65
- end
66
-
67
- def status=(state)
68
- state, msg, to = state
69
-
70
- status = Stanza::Presence::Status.new state, msg
71
- status.to = to
72
- @status = status unless to
73
-
74
- write status
75
- end
76
-
77
- def write(data)
78
- @stream.send(data) if @stream
79
- end
80
-
81
- def stream_started(stream)
82
- @stream = stream
83
-
84
- #retreive roster
85
- write Stanza::Iq::Roster.new
86
- end
87
-
88
- def call(stanza)
89
- stanza.handler_heirarchy.each do |type|
90
- break if call_handler_for(type, stanza) && stanza.type == :iq
91
- end
92
- end
93
-
94
- def call_handler_for(type, stanza)
95
- if @handlers[type]
96
- @handlers[type].each { |handler| handler.call(stanza) }
97
- true
98
- end
99
- end
100
-
101
- protected
102
- def setup_initial_handlers
103
- register_handler :iq do |iq|
104
- write(Stanza::Error.new_from(iq, 'service-unavailable', 'cancel').reply!) if [:set, :get].include?(iq.type)
105
- end
106
-
107
- register_handler :status do |status|
108
- roster[status.from].status = status if roster[status.from]
109
- end
110
-
111
- register_handler :roster do |node|
112
- roster.process node
113
- if @state == :initializing
114
- @state = :ready
115
- write @status
116
- call_handler_for :ready, nil
117
- end
118
- end
119
- end
120
-
121
- end #Client
122
-
123
- module Application
124
- @@client = Blather::Client.new
125
-
126
- def setup(jid, password, host = nil, port = 5222)
127
- at_exit do
128
- trap(:INT) { EM.stop }
129
- EM.run { Blather::Stream.start @@client, Blather::JID.new(jid), password, host, port }
130
- end
131
- end
132
-
133
- def daemonize
134
- @daemonize = true
135
- end
136
-
137
- def handle(stanza_type, &block)
138
- @@client.register_handler stanza_type, &block
139
- end
140
-
141
- def status(state = nil, msg = nil)
142
- @@client.status = state, msg
143
- end
144
-
145
- def roster
146
- @@client.roster
147
- end
148
-
149
- def write(stanza)
150
- @@client.write(stanza)
151
- end
152
-
153
- def say(to, msg)
154
- @@client.write Blather::Stanza::Message.new(to, msg)
155
- end
156
- end #Application
157
-
55
+ LOG = Logger.new(STDOUT) unless const_defined?(:LOG)
56
+ LOG.level = Logger::INFO
158
57
  end
159
-
160
- include Blather::Application
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__), *%w[client dsl])
2
+
3
+ include Blather::DSL
4
+
5
+ at_exit do
6
+ unless client.setup?
7
+ if ARGV.length < 2
8
+ puts "Run with #{$0} user@server/resource password [host] [port]"
9
+ else
10
+ client.setup(*ARGV).run
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,165 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. .. blather])
2
+ require File.join(File.dirname(__FILE__), 'pubsub')
3
+
4
+ module Blather #:nodoc:
5
+
6
+ class Client #:nodoc:
7
+ attr_accessor :jid,
8
+ :roster
9
+
10
+ def initialize
11
+ @state = :initializing
12
+
13
+ @status = Stanza::Presence::Status.new
14
+ @handlers = {}
15
+ @tmp_handlers = {}
16
+ @roster = Roster.new self
17
+
18
+ setup_initial_handlers
19
+ end
20
+
21
+ def setup?
22
+ @setup.is_a? Array
23
+ end
24
+
25
+ def setup(jid, password, host = nil, port = nil)
26
+ @setup = [JID.new(jid), password]
27
+ @setup << host if host
28
+ @setup << port if port
29
+ self
30
+ end
31
+
32
+ def run
33
+ raise 'not setup!' unless setup?
34
+ trap(:INT) { EM.stop }
35
+ EM.run {
36
+ klass = @setup[0].node ? Blather::Stream::Client : Blather::Stream::Component
37
+ klass.start self, *@setup
38
+ }
39
+ end
40
+
41
+ def register_tmp_handler(id, &handler)
42
+ @tmp_handlers[id] = handler
43
+ end
44
+
45
+ def register_handler(type, *guards, &handler)
46
+ @handlers[type] ||= []
47
+ @handlers[type] << [guards, handler]
48
+ end
49
+
50
+ def status
51
+ @status.state
52
+ end
53
+
54
+ def status=(state)
55
+ state, msg, to = state
56
+
57
+ status = Stanza::Presence::Status.new state, msg
58
+ status.to = to
59
+ @status = status unless to
60
+
61
+ write status
62
+ end
63
+
64
+ def write(stanza)
65
+ stanza.from ||= jid if stanza.respond_to?(:from)
66
+ @stream.send(stanza) if @stream
67
+ end
68
+
69
+ def write_with_handler(stanza, &hanlder)
70
+ register_tmp_handler stanza.id, &handler
71
+ write stanza
72
+ end
73
+
74
+ def stream_started(stream)
75
+ @stream = stream
76
+
77
+ #retreive roster
78
+ if @stream.is_a?(Stream::Component)
79
+ @state = :ready
80
+ call_handler_for :ready, nil
81
+ else
82
+ r = Stanza::Iq::Roster.new
83
+ register_tmp_handler r.id do |node|
84
+ roster.process node
85
+ @state = :ready
86
+ write @status
87
+ call_handler_for :ready, nil
88
+ end
89
+ write r
90
+ end
91
+ end
92
+
93
+ def stop
94
+ @stream.close_connection_after_writing
95
+ end
96
+
97
+ def stopped
98
+ EM.stop
99
+ end
100
+
101
+ def call(stanza)
102
+ if handler = @tmp_handlers.delete(stanza.id)
103
+ handler.call stanza
104
+ else
105
+ stanza.handler_heirarchy.each do |type|
106
+ break if call_handler_for(type, stanza) && (stanza.is_a?(BlatherError) || stanza.type == :iq)
107
+ end
108
+ end
109
+ end
110
+
111
+ def call_handler_for(type, stanza)
112
+ if @handlers[type]
113
+ @handlers[type].find { |guards, handler| handler.call(stanza) unless guarded?(guards, stanza) }
114
+ true
115
+ end
116
+ end
117
+
118
+ protected
119
+ def setup_initial_handlers
120
+ register_handler :error do |err|
121
+ raise err
122
+ end
123
+
124
+ register_handler :iq do |iq|
125
+ write(StanzaError::ServiceUnavailable.new(iq, :cancel).to_node) if [:set, :get].include?(iq.type)
126
+ end
127
+
128
+ register_handler :status do |status|
129
+ roster[status.from].status = status if roster[status.from]
130
+ end
131
+
132
+ register_handler :roster do |node|
133
+ roster.process node
134
+ end
135
+ end
136
+
137
+ ##
138
+ # If any of the guards returns FALSE this returns true
139
+ def guarded?(guards, stanza)
140
+ guards.find do |guard|
141
+ case guard
142
+ when Symbol
143
+ !stanza.__send__(guard)
144
+ when Array
145
+ # return FALSE if any item is TRUE
146
+ !guard.detect { |condition| !guarded?([condition], stanza) }
147
+ when Hash
148
+ # return FALSE unless any inequality is found
149
+ guard.find do |method, value|
150
+ if value.is_a?(Regexp)
151
+ !stanza.__send__(method).to_s.match(value)
152
+ else
153
+ stanza.__send__(method) != value
154
+ end
155
+ end
156
+ when Proc
157
+ !guard.call(stanza)
158
+ else
159
+ raise "Bad guard: #{guard.inspect}"
160
+ end
161
+ end
162
+ end
163
+
164
+ end #Client
165
+ end #Blather