blather 0.2.1 → 0.2.2

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