troystribling-agent_xmpp 0.0.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.
- data/.document +5 -0
- data/.gitignore +9 -0
- data/LICENSE +20 -0
- data/README.rdoc +7 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/agent_xmpp.gemspec +89 -0
- data/bin/agent_xmpp +56 -0
- data/lib/agent_xmpp/app/boot.rb +64 -0
- data/lib/agent_xmpp/app/chat_message_body_controller.rb +16 -0
- data/lib/agent_xmpp/app/controller.rb +44 -0
- data/lib/agent_xmpp/app/format.rb +41 -0
- data/lib/agent_xmpp/app/map.rb +45 -0
- data/lib/agent_xmpp/app/routes.rb +77 -0
- data/lib/agent_xmpp/app/view.rb +49 -0
- data/lib/agent_xmpp/app.rb +7 -0
- data/lib/agent_xmpp/client/client.rb +197 -0
- data/lib/agent_xmpp/client/connection.rb +314 -0
- data/lib/agent_xmpp/client/parser.rb +71 -0
- data/lib/agent_xmpp/client.rb +3 -0
- data/lib/agent_xmpp/patches/standard_library_patches/array.rb +40 -0
- data/lib/agent_xmpp/patches/standard_library_patches/float.rb +25 -0
- data/lib/agent_xmpp/patches/standard_library_patches/hash.rb +28 -0
- data/lib/agent_xmpp/patches/standard_library_patches/object.rb +30 -0
- data/lib/agent_xmpp/patches/standard_library_patches/string.rb +25 -0
- data/lib/agent_xmpp/patches/standard_library_patches.rb +5 -0
- data/lib/agent_xmpp/patches/xmpp4r_patches/command.rb +26 -0
- data/lib/agent_xmpp/patches/xmpp4r_patches/iq.rb +26 -0
- data/lib/agent_xmpp/patches/xmpp4r_patches/x_data.rb +116 -0
- data/lib/agent_xmpp/patches/xmpp4r_patches.rb +3 -0
- data/lib/agent_xmpp/patches.rb +3 -0
- data/lib/agent_xmpp/utils/logger.rb +24 -0
- data/lib/agent_xmpp/utils/roster.rb +23 -0
- data/lib/agent_xmpp/utils.rb +2 -0
- data/lib/agent_xmpp/version.rb +6 -0
- data/lib/agent_xmpp.rb +16 -0
- data/test/agent_xmpp_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +131 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module AgentXmpp
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
module Routing
|
6
|
+
|
7
|
+
#####-------------------------------------------------------------------------------------------------------
|
8
|
+
class Routes
|
9
|
+
|
10
|
+
#.........................................................................................................
|
11
|
+
@map = Map.new
|
12
|
+
#.........................................................................................................
|
13
|
+
|
14
|
+
####......................................................................................................
|
15
|
+
class << self
|
16
|
+
|
17
|
+
#.........................................................................................................
|
18
|
+
attr_reader :map
|
19
|
+
#.........................................................................................................
|
20
|
+
|
21
|
+
#.......................................................................................................
|
22
|
+
def draw
|
23
|
+
yield map
|
24
|
+
end
|
25
|
+
|
26
|
+
#.......................................................................................................
|
27
|
+
def invoke_command_response(connection, params)
|
28
|
+
route_path = "#{params[:node]}/#{params[:action]}"
|
29
|
+
field_path = fields(params)
|
30
|
+
route_path += "/#{field_path}" unless field_path.nil?
|
31
|
+
route = map[route_path]
|
32
|
+
unless route.nil?
|
33
|
+
begin
|
34
|
+
controller_class = eval("#{route[:controller].classify}Controller")
|
35
|
+
rescue NameError
|
36
|
+
AgentXmpp.logger.error "ROUTING ERROR: #{route[:controller].classify}Controller does not exist for route {:controller => '#{route[:controller]}', :node => '#{params[:node]}', :action => '#{params[:action]}'}."
|
37
|
+
else
|
38
|
+
controler_instance = controller_class.new
|
39
|
+
if controler_instance.respond_to?(route[:action])
|
40
|
+
controler_instance.handle_request(connection, route[:action], params)
|
41
|
+
else
|
42
|
+
AgentXmpp.logger.error "ROUTING ERROR: no action on #{controller_class.to_s} for route {:controller => '#{route[:controller]}', :node => '#{params[:node]}', :action => '#{params[:action]}'}."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
else
|
46
|
+
AgentXmpp.logger.error "ROUTING ERROR: no route for {:node => '#{params[:node]}', :action => '#{params[:action]}'}."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#.......................................................................................................
|
51
|
+
def invoke_chat_message_body_response(connection, params)
|
52
|
+
route = map.chat_message_body_route
|
53
|
+
begin
|
54
|
+
controller_class = eval("#{route[:controller].classify}Controller")
|
55
|
+
rescue ArgumentError
|
56
|
+
AgentXmpp.logger.error "ROUTING ERROR: #{params[:node].classify}Controller inavlid for node:#{params[:node]} action:#{params[:action]}."
|
57
|
+
else
|
58
|
+
controller_class.new.handle_request(connection, route[:action], params)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
#.......................................................................................................
|
63
|
+
def fields(params)
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
####......................................................................................................
|
69
|
+
|
70
|
+
#### Routes
|
71
|
+
end
|
72
|
+
|
73
|
+
#### Routing
|
74
|
+
end
|
75
|
+
|
76
|
+
#### AgentXmpp
|
77
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module AgentXmpp
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class View
|
6
|
+
|
7
|
+
#---------------------------------------------------------------------------------------------------------
|
8
|
+
attr_reader :connection, :format, :params
|
9
|
+
#---------------------------------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
#.........................................................................................................
|
12
|
+
def initialize(connection, format, params)
|
13
|
+
@connection = connection
|
14
|
+
@format = format
|
15
|
+
@params = params
|
16
|
+
end
|
17
|
+
|
18
|
+
#.........................................................................................................
|
19
|
+
def add_payload_to_container(payload)
|
20
|
+
container_type = case format.xmlns
|
21
|
+
when 'jabber:x:data' then :add_x_data_to_container
|
22
|
+
when 'message:chat' then :add_chat_message_body_container
|
23
|
+
end
|
24
|
+
container_type.nil? ? nil : send(container_type, payload)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
#.........................................................................................................
|
30
|
+
def add_x_data_to_container(payload)
|
31
|
+
iq = Jabber::Iq.new(:result, params[:from])
|
32
|
+
iq.id = params[:id] unless params[:id].nil?
|
33
|
+
iq.command = Jabber::Command::IqCommand.new(params[:node], 'completed')
|
34
|
+
iq.command << payload
|
35
|
+
iq
|
36
|
+
end
|
37
|
+
|
38
|
+
#.........................................................................................................
|
39
|
+
def add_chat_message_body_container(payload)
|
40
|
+
message = Jabber::Message.new(params[:from], payload)
|
41
|
+
message.type = :chat
|
42
|
+
message
|
43
|
+
end
|
44
|
+
|
45
|
+
#### View
|
46
|
+
end
|
47
|
+
|
48
|
+
#### AgentXmpp
|
49
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module AgentXmpp
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class Client
|
6
|
+
|
7
|
+
#---------------------------------------------------------------------------------------------------------
|
8
|
+
attr_reader :jid, :port, :password, :roster, :connection
|
9
|
+
#---------------------------------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
#.........................................................................................................
|
12
|
+
def initialize(config)
|
13
|
+
@password = config['password']
|
14
|
+
@port = config['port'] || 5222
|
15
|
+
resource = config['resource'] || Socket.gethostname
|
16
|
+
@jid = Jabber::JID.new("#{config['jid']}/#{resource}")
|
17
|
+
@roster = Roster.new(@jid, config['contacts'])
|
18
|
+
end
|
19
|
+
|
20
|
+
#.........................................................................................................
|
21
|
+
def connect
|
22
|
+
while (true)
|
23
|
+
EventMachine.run do
|
24
|
+
@connection = EventMachine.connect(jid.domain, port, Connection, self, jid, password, port)
|
25
|
+
end
|
26
|
+
sleep(10.0)
|
27
|
+
AgentXmpp.logger.warn "RESTARTING SERVER"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
#.........................................................................................................
|
32
|
+
def reconnect
|
33
|
+
AgentXmpp.logger.info "RECONNECTING"
|
34
|
+
connection.reconnect(jid.domain, port)
|
35
|
+
end
|
36
|
+
|
37
|
+
#.........................................................................................................
|
38
|
+
def connected?
|
39
|
+
connection and !connection.error?
|
40
|
+
end
|
41
|
+
|
42
|
+
#.........................................................................................................
|
43
|
+
def add_delegate(delegate)
|
44
|
+
connection.add_delegate(delegate)
|
45
|
+
end
|
46
|
+
|
47
|
+
#.........................................................................................................
|
48
|
+
def remove_delegate(delegate)
|
49
|
+
connection.remove_delegate(delegate)
|
50
|
+
end
|
51
|
+
|
52
|
+
#---------------------------------------------------------------------------------------------------------
|
53
|
+
# AgentXmpp::Connection delegate
|
54
|
+
#.........................................................................................................
|
55
|
+
# connection
|
56
|
+
#.........................................................................................................
|
57
|
+
def did_connect(client_connection)
|
58
|
+
AgentXmpp.logger.info "CONNECTED"
|
59
|
+
end
|
60
|
+
|
61
|
+
#.........................................................................................................
|
62
|
+
def did_disconnect(client_connection)
|
63
|
+
AgentXmpp.logger.warn "DISCONNECTED"
|
64
|
+
EventMachine::stop_event_loop
|
65
|
+
end
|
66
|
+
|
67
|
+
#.........................................................................................................
|
68
|
+
def did_not_connect(client_connection)
|
69
|
+
AgentXmpp.logger.warn "CONNECTION FAILED"
|
70
|
+
end
|
71
|
+
|
72
|
+
#.........................................................................................................
|
73
|
+
# authentication
|
74
|
+
#.........................................................................................................
|
75
|
+
def did_authenticate(client_connection, stanza)
|
76
|
+
AgentXmpp.logger.info "AUTHENTICATED"
|
77
|
+
end
|
78
|
+
|
79
|
+
#.........................................................................................................
|
80
|
+
def did_not_authenticate(client_connection, stanza)
|
81
|
+
AgentXmpp.logger.info "AUTHENTICATION FAILED"
|
82
|
+
end
|
83
|
+
|
84
|
+
#.........................................................................................................
|
85
|
+
def did_bind(client_connection, stanza)
|
86
|
+
AgentXmpp.logger.info "BIND ACKNOWLEDGED"
|
87
|
+
end
|
88
|
+
|
89
|
+
#.........................................................................................................
|
90
|
+
# presence
|
91
|
+
#.........................................................................................................
|
92
|
+
def did_receive_presence(client_connection, presence)
|
93
|
+
from_jid = presence.from.to_s
|
94
|
+
from_bare_jid = presence.from.bare.to_s
|
95
|
+
if roster.has_key?(from_bare_jid)
|
96
|
+
roster[from_bare_jid.to_s][:resources][from_jid] = {} if roster[from_bare_jid.to_s][:resources][from_jid].nil?
|
97
|
+
roster[from_bare_jid.to_s][:resources][from_jid][:presence] = presence
|
98
|
+
client_connection.get_client_version(from_jid) if not from_jid.eql?(client_connection.jid.to_s) and presence.type.nil?
|
99
|
+
AgentXmpp.logger.info "RECEIVED PRESENCE FROM: #{from_jid}"
|
100
|
+
else
|
101
|
+
AgentXmpp.logger.info "RECEIVED PRESENCE FROM JID NOT IN CONTACT LIST: #{from_jid}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
#.........................................................................................................
|
106
|
+
def did_receive_subscribe_request(client_connection, presence)
|
107
|
+
from_jid = presence.from.to_s
|
108
|
+
if roster.has_key?(presence.from.bare.to_s )
|
109
|
+
client_connection.accept_contact_request(from_jid)
|
110
|
+
AgentXmpp.logger.info "RECEIVED SUBSCRIBE REQUEST: #{from_jid}"
|
111
|
+
else
|
112
|
+
client_connection.reject_contact_request(from_jid)
|
113
|
+
AgentXmpp.logger.info "RECEIVED SUBSCRIBE REQUEST FROM JID NOT IN CONTACT LIST: #{from_jid}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
#.........................................................................................................
|
118
|
+
def did_receive_unsubscribed_request(client_connection, presence)
|
119
|
+
from_jid = presence.from.to_s
|
120
|
+
if roster.delete(presence.from.bare.to_s )
|
121
|
+
client_connection.remove_contact(presence.from)
|
122
|
+
AgentXmpp.logger.info "RECEIVED UNSUBSCRIBED REQUEST: #{from_jid}"
|
123
|
+
else
|
124
|
+
AgentXmpp.logger.warn "RECEIVED UNSUBSCRIBED REQUEST FROM JID NOT IN CONTACT LIST: #{from_jid}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
#.........................................................................................................
|
129
|
+
# roster management
|
130
|
+
#.........................................................................................................
|
131
|
+
def did_receive_roster_item(client_connection, roster_item)
|
132
|
+
AgentXmpp.logger.info "RECEIVED ROSTER ITEM"
|
133
|
+
roster_item_jid = roster_item.jid.to_s
|
134
|
+
if roster.has_key?(roster_item_jid)
|
135
|
+
roster[roster_item_jid][:activated] = true
|
136
|
+
roster[roster_item_jid][:roster_item] = roster_item
|
137
|
+
AgentXmpp.logger.info "ACTIVATING CONTACT: #{roster_item_jid}"
|
138
|
+
else
|
139
|
+
client_connection.remove_contact(roster_item.jid)
|
140
|
+
AgentXmpp.logger.info "REMOVING CONTACT: #{roster_item_jid}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
#.........................................................................................................
|
145
|
+
def did_remove_roster_item(client_connection, roster_item)
|
146
|
+
AgentXmpp.logger.info "REMOVE ROSTER ITEM"
|
147
|
+
roster_item_jid = roster_item.jid.to_s
|
148
|
+
if roster.has_key?(roster_item_jid)
|
149
|
+
roster.delete(roster_item_jid)
|
150
|
+
AgentXmpp.logger.info "REMOVED CONTACT: #{roster_item_jid}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
#.........................................................................................................
|
155
|
+
def did_receive_all_roster_items(client_connection)
|
156
|
+
AgentXmpp.logger.info "RECEIVED ALL ROSTER ITEMS"
|
157
|
+
roster.select{|j,r| not r[:activated]}.each do |j,r|
|
158
|
+
AgentXmpp.logger.info "ADDING CONTACT: #{j}"
|
159
|
+
client_connection.add_contact(Jabber::JID.new(j))
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
#.........................................................................................................
|
164
|
+
def did_acknowledge_add_contact(client_connection, response, contact_jid)
|
165
|
+
AgentXmpp.logger.info "CONTACT ADD ACKNOWLEDGED: #{contact_jid.to_s}"
|
166
|
+
end
|
167
|
+
|
168
|
+
#.........................................................................................................
|
169
|
+
def did_remove_contact(client_connection, response, contact_jid)
|
170
|
+
AgentXmpp.logger.info "CONTACT REMOVED: #{contact_jid.to_s}"
|
171
|
+
end
|
172
|
+
|
173
|
+
#.........................................................................................................
|
174
|
+
def did_add_contact(client_connection, roster_item)
|
175
|
+
AgentXmpp.logger.info "CONTACT ADDED: #{roster_item.jid.to_s}"
|
176
|
+
end
|
177
|
+
|
178
|
+
#.........................................................................................................
|
179
|
+
# service discovery management
|
180
|
+
#.........................................................................................................
|
181
|
+
def did_receive_client_version_result(client_connection, from, version)
|
182
|
+
roster[from.bare.to_s][:resources][from.to_s][:version] = version \
|
183
|
+
unless roster[from.bare.to_s][:resources][from.to_s].nil?
|
184
|
+
AgentXmpp.logger.info "RECEIVED CLIENT VERSION RESULT: #{from.to_s}, #{version.iname}, #{version.version}"
|
185
|
+
end
|
186
|
+
|
187
|
+
#.........................................................................................................
|
188
|
+
def did_receive_client_version_request(client_connection, request)
|
189
|
+
client_connection.send_client_version(request)
|
190
|
+
AgentXmpp.logger.info "RECEIVED CLIENT VERSION REQUEST: #{request.from.to_s}"
|
191
|
+
end
|
192
|
+
|
193
|
+
#### Client
|
194
|
+
end
|
195
|
+
|
196
|
+
#### AgentXmpp
|
197
|
+
end
|
@@ -0,0 +1,314 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module AgentXmpp
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class NotConnected < Exception; end
|
6
|
+
|
7
|
+
#####-------------------------------------------------------------------------------------------------------
|
8
|
+
class Connection < EventMachine::Connection
|
9
|
+
|
10
|
+
#---------------------------------------------------------------------------------------------------------
|
11
|
+
include Parser
|
12
|
+
#---------------------------------------------------------------------------------------------------------
|
13
|
+
|
14
|
+
#---------------------------------------------------------------------------------------------------------
|
15
|
+
attr_reader :client, :jid, :port, :password, :connection_status, :delegates, :keepalive
|
16
|
+
#---------------------------------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
#.........................................................................................................
|
19
|
+
def initialize(client, jid, password, port=5222)
|
20
|
+
@client, @jid, @password, @port = client, jid, password, port
|
21
|
+
@connection_status = :offline;
|
22
|
+
@id_callbacks = {}
|
23
|
+
@delegates = []
|
24
|
+
end
|
25
|
+
|
26
|
+
#.........................................................................................................
|
27
|
+
def add_delegate(delegate)
|
28
|
+
@delegates << delegate
|
29
|
+
end
|
30
|
+
|
31
|
+
#.........................................................................................................
|
32
|
+
def remove_delegate(delegate)
|
33
|
+
@delegates.delete(delegate)
|
34
|
+
end
|
35
|
+
|
36
|
+
#.........................................................................................................
|
37
|
+
def send(data, &blk)
|
38
|
+
raise NotConnected if error?
|
39
|
+
if block_given? and data.is_a? Jabber::XMPPStanza
|
40
|
+
if data.id.nil?
|
41
|
+
data.id = Jabber::IdGenerator.instance.generate_id
|
42
|
+
end
|
43
|
+
@id_callbacks[data.id] = blk
|
44
|
+
end
|
45
|
+
send_data(data.to_s)
|
46
|
+
AgentXmpp.logger.info "SEND: #{data.to_s}"
|
47
|
+
end
|
48
|
+
|
49
|
+
#---------------------------------------------------------------------------------------------------------
|
50
|
+
# EventMachine::Connection callbacks
|
51
|
+
#.........................................................................................................
|
52
|
+
def connection_completed
|
53
|
+
init_connection
|
54
|
+
@keepalive = EventMachine::PeriodicTimer.new(60) do
|
55
|
+
send_data("\n")
|
56
|
+
end
|
57
|
+
add_delegate(client)
|
58
|
+
AgentXmpp::Boot.call_after_connection_completed(self) if AgentXmpp::Boot.respond_to?(:call_after_connection_completed)
|
59
|
+
broadcast_to_delegates(:did_connect, self)
|
60
|
+
end
|
61
|
+
|
62
|
+
#.........................................................................................................
|
63
|
+
def receive_data(data)
|
64
|
+
AgentXmpp.logger.info "RECV: #{data.to_s}"
|
65
|
+
super(data)
|
66
|
+
end
|
67
|
+
|
68
|
+
#.........................................................................................................
|
69
|
+
def unbind
|
70
|
+
if @keepalive
|
71
|
+
@keepalive.cancel
|
72
|
+
@keepalive = nil
|
73
|
+
end
|
74
|
+
@connection_status = :off_line
|
75
|
+
broadcast_to_delegates(:did_disconnect, self)
|
76
|
+
end
|
77
|
+
|
78
|
+
#---------------------------------------------------------------------------------------------------------
|
79
|
+
# service discovery
|
80
|
+
#.........................................................................................................
|
81
|
+
def get_client_version(contact_jid)
|
82
|
+
iq = Jabber::Iq.new(:get, contact_jid)
|
83
|
+
iq.query = Jabber::Version::IqQueryVersion.new
|
84
|
+
send(iq) do |r|
|
85
|
+
if (r.type == :result) && r.query.kind_of?(Jabber::Version::IqQueryVersion)
|
86
|
+
broadcast_to_delegates(:did_receive_client_version_result, self, r.from, r.query)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
#.........................................................................................................
|
92
|
+
def send_client_version(request)
|
93
|
+
iq = Jabber::Iq.new(:result, request.from.to_s)
|
94
|
+
iq.id = request.id unless request.id.nil?
|
95
|
+
iq.query = Jabber::Version::IqQueryVersion.new
|
96
|
+
iq.query.set_iname(AgentXmpp::AGENT_XMPP_NAME).set_version(AgentXmpp::VERSION).set_os(AgentXmpp::OS_VERSION)
|
97
|
+
send(iq)
|
98
|
+
end
|
99
|
+
|
100
|
+
#---------------------------------------------------------------------------------------------------------
|
101
|
+
# roster management
|
102
|
+
#.........................................................................................................
|
103
|
+
def get_roster
|
104
|
+
send(Jabber::Iq.new_rosterget) do |r|
|
105
|
+
if r.type == :result and r.query.kind_of?(Jabber::Roster::IqQueryRoster)
|
106
|
+
r.query.each_element {|i| broadcast_to_delegates(:did_receive_roster_item, self, i)}
|
107
|
+
broadcast_to_delegates(:did_receive_all_roster_items, self)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
#.........................................................................................................
|
113
|
+
def add_contact(contact_jid)
|
114
|
+
request = Jabber::Iq.new_rosterset
|
115
|
+
request.query.add(Jabber::Roster::RosterItem.new(contact_jid))
|
116
|
+
send(request) do |r|
|
117
|
+
send(Jabber::Presence.new.set_type(:subscribe).set_to(contact_jid))
|
118
|
+
broadcast_to_delegates(:did_acknowledge_add_contact, self, r, contact_jid)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#.........................................................................................................
|
123
|
+
def remove_contact(contact_jid)
|
124
|
+
request = Jabber::Iq.new_rosterset
|
125
|
+
request.query.add(Jabber::Roster::RosterItem.new(contact_jid, nil, :remove))
|
126
|
+
send(request) do |r|
|
127
|
+
broadcast_to_delegates(:did_remove_contact, self, r, contact_jid)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
#.........................................................................................................
|
132
|
+
def accept_contact_request(contact_jid)
|
133
|
+
presence = Jabber::Presence.new.set_type(:subscribed)
|
134
|
+
presence.to = contact_jid
|
135
|
+
send(presence)
|
136
|
+
end
|
137
|
+
|
138
|
+
#.........................................................................................................
|
139
|
+
def reject_contact_request(contact_jid)
|
140
|
+
presence = Jabber::Presence.new.set_type(:unsubscribed)
|
141
|
+
presence.to = contact_jid
|
142
|
+
send(presence)
|
143
|
+
end
|
144
|
+
|
145
|
+
#---------------------------------------------------------------------------------------------------------
|
146
|
+
# process commands
|
147
|
+
#.........................................................................................................
|
148
|
+
def process_command(stanza)
|
149
|
+
command = stanza.command
|
150
|
+
unless command.x.nil?
|
151
|
+
params = {:xmlns => command.x.namespace, :action => command.action, :to => stanza.from.to_s,
|
152
|
+
:from => stanza.from.to_s, :node => command.node, :id => stanza.id, :fields => {}}
|
153
|
+
Routing::Routes.invoke_command_response(self, params)
|
154
|
+
AgentXmpp.logger.info "RECEIVED COMMAND: #{command.node}, FROM: #{stanza.from.to_s}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
#---------------------------------------------------------------------------------------------------------
|
159
|
+
# process messages
|
160
|
+
#.........................................................................................................
|
161
|
+
def process_chat_message_body(stanza)
|
162
|
+
params = {:xmlns => 'message:chat', :to => stanza.from.to_s, :from => stanza.from.to_s, :id => stanza.id,
|
163
|
+
:body => stanza.body}
|
164
|
+
Routing::Routes.invoke_chat_message_body_response(self, params)
|
165
|
+
AgentXmpp.logger.info "RECEIVED MESSAGE BODY: #{stanza.body}"
|
166
|
+
end
|
167
|
+
|
168
|
+
#---------------------------------------------------------------------------------------------------------
|
169
|
+
# AgentXmpp::Parser callbacks
|
170
|
+
#.........................................................................................................
|
171
|
+
def receive(stanza)
|
172
|
+
if stanza.kind_of?(Jabber::XMPPStanza) and stanza.id and blk = @id_callbacks[stanza.id]
|
173
|
+
@id_callbacks.delete(stanza.id)
|
174
|
+
blk.call(stanza)
|
175
|
+
return
|
176
|
+
end
|
177
|
+
|
178
|
+
case stanza.xpath
|
179
|
+
when 'stream:features'
|
180
|
+
@stream_features, @stream_mechanisms = {}, []
|
181
|
+
@current.each do |e|
|
182
|
+
if e.name == 'mechanisms' and e.namespace == 'urn:ietf:params:xml:ns:xmpp-sasl'
|
183
|
+
e.each_element('mechanism') {|mech| @stream_mechanisms.push(mech.text)}
|
184
|
+
else
|
185
|
+
@stream_features[e.name] = e.namespace
|
186
|
+
end
|
187
|
+
end
|
188
|
+
if @connection_status.eql?(:offline)
|
189
|
+
authenticate
|
190
|
+
elsif @connection_status.eql?(:authenticated)
|
191
|
+
bind(stanza)
|
192
|
+
end
|
193
|
+
when 'stream:stream'
|
194
|
+
when 'success'
|
195
|
+
case connection_status
|
196
|
+
when :offline
|
197
|
+
reset_parser
|
198
|
+
init_connection(false)
|
199
|
+
@connection_status = :authenticated
|
200
|
+
end
|
201
|
+
return
|
202
|
+
when 'failure'
|
203
|
+
case connection_status
|
204
|
+
when :offline
|
205
|
+
reset_parser
|
206
|
+
broadcast_to_delegates(:did_not_authenticate, self, stanza)
|
207
|
+
end
|
208
|
+
else
|
209
|
+
demux_channel(stanza)
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
#---------------------------------------------------------------------------------------------------------
|
215
|
+
protected
|
216
|
+
#---------------------------------------------------------------------------------------------------------
|
217
|
+
|
218
|
+
#---------------------------------------------------------------------------------------------------------
|
219
|
+
# Process XMPP messages
|
220
|
+
#.........................................................................................................
|
221
|
+
def authenticate
|
222
|
+
begin
|
223
|
+
Jabber::SASL.new(self, 'PLAIN').auth(password)
|
224
|
+
rescue
|
225
|
+
raise ClientAuthenticationFailure.new, $!.to_s
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
#.........................................................................................................
|
230
|
+
def bind(stanza)
|
231
|
+
if stream_features.has_key?('bind')
|
232
|
+
iq = Jabber::Iq.new(:set)
|
233
|
+
bind = iq.add(REXML::Element.new('bind'))
|
234
|
+
bind.add_namespace(stream_features['bind'])
|
235
|
+
resource = bind.add REXML::Element.new('resource')
|
236
|
+
resource.text = jid.resource
|
237
|
+
send(iq) do |r|
|
238
|
+
if r.type == :result and full_jid = r.first_element('//jid') and full_jid.text
|
239
|
+
@connection_status = :bind
|
240
|
+
jid = Jabber::JID.new(full_jid.text) unless jid.to_s.eql?(full_jid.text)
|
241
|
+
broadcast_to_delegates(:did_bind, self, stanza)
|
242
|
+
session(stanza)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
#.........................................................................................................
|
249
|
+
def session(stanza)
|
250
|
+
if stream_features.has_key?('session')
|
251
|
+
iq = Jabber::Iq.new(:set)
|
252
|
+
session = iq.add REXML::Element.new('session')
|
253
|
+
session.add_namespace stream_features['session']
|
254
|
+
send(iq) do |r|
|
255
|
+
if r.type == :result
|
256
|
+
@connection_status = :active
|
257
|
+
broadcast_to_delegates(:did_authenticate, self, stanza)
|
258
|
+
send(Jabber::Presence.new(nil, nil, 1))
|
259
|
+
get_roster
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
#.........................................................................................................
|
266
|
+
def init_connection(starting=true)
|
267
|
+
send("<?xml version='1.0' ?>") if starting
|
268
|
+
send("<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' to='#{jid.domain}'>" )
|
269
|
+
end
|
270
|
+
|
271
|
+
#.........................................................................................................
|
272
|
+
def demux_channel(stanza)
|
273
|
+
stanza_class = stanza.class.to_s
|
274
|
+
#### roster update
|
275
|
+
if stanza.type == :set and stanza.query.kind_of?(Jabber::Roster::IqQueryRoster)
|
276
|
+
stanza.query.each_element do |i|
|
277
|
+
method = case i.subscription
|
278
|
+
when :remove then :did_remove_roster_item
|
279
|
+
when :none then :did_receive_roster_item
|
280
|
+
when :to then :did_add_contact
|
281
|
+
end
|
282
|
+
broadcast_to_delegates(method, self, i) unless method.nil?
|
283
|
+
end
|
284
|
+
#### presence subscription request
|
285
|
+
elsif stanza.type.eql?(:subscribe) and stanza_class.eql?('Jabber::Presence')
|
286
|
+
broadcast_to_delegates(:did_receive_subscribe_request, self, stanza)
|
287
|
+
#### presence unsubscribe
|
288
|
+
elsif stanza.type.eql?(:unsubscribed) and stanza_class.eql?('Jabber::Presence')
|
289
|
+
broadcast_to_delegates(:did_receive_unsubscribed_request, self, stanza)
|
290
|
+
#### client version request
|
291
|
+
elsif stanza.type.eql?(:get) and stanza.query.kind_of?(Jabber::Version::IqQueryVersion)
|
292
|
+
broadcast_to_delegates(:did_receive_client_version_request, self, stanza)
|
293
|
+
#### received command
|
294
|
+
elsif stanza.type.eql?(:set) and stanza.command.kind_of?(Jabber::Command::IqCommand)
|
295
|
+
process_command(stanza)
|
296
|
+
#### chat message received
|
297
|
+
elsif stanza_class.eql?('Jabber::Message') and stanza.type.eql?(:chat) and stanza.respond_to?(:body)
|
298
|
+
process_chat_message_body(stanza)
|
299
|
+
else
|
300
|
+
method = ('did_receive_' + /.*::(.*)/.match(stanza_class).to_a.last.downcase).to_sym
|
301
|
+
broadcast_to_delegates(method, self, stanza)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
#.........................................................................................................
|
306
|
+
def broadcast_to_delegates(method, *args)
|
307
|
+
delegates.each{|d| d.send(method, *args) if d.respond_to?(method)}
|
308
|
+
end
|
309
|
+
|
310
|
+
#### Connection
|
311
|
+
end
|
312
|
+
|
313
|
+
#### AgentXmpp
|
314
|
+
end
|