agent_xmpp 0.1.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.
Files changed (73) hide show
  1. data/.document +5 -0
  2. data/.gitignore +11 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +417 -0
  5. data/Rakefile +75 -0
  6. data/VERSION +1 -0
  7. data/agent_xmpp.gemspec +144 -0
  8. data/lib/agent_xmpp.rb +22 -0
  9. data/lib/agent_xmpp/admin.rb +113 -0
  10. data/lib/agent_xmpp/client.rb +7 -0
  11. data/lib/agent_xmpp/client/boot.rb +83 -0
  12. data/lib/agent_xmpp/client/client.rb +64 -0
  13. data/lib/agent_xmpp/client/connection.rb +108 -0
  14. data/lib/agent_xmpp/client/controller.rb +394 -0
  15. data/lib/agent_xmpp/client/message_delegate.rb +720 -0
  16. data/lib/agent_xmpp/client/message_pipe.rb +193 -0
  17. data/lib/agent_xmpp/client/response.rb +102 -0
  18. data/lib/agent_xmpp/config.rb +48 -0
  19. data/lib/agent_xmpp/main.rb +175 -0
  20. data/lib/agent_xmpp/models.rb +7 -0
  21. data/lib/agent_xmpp/models/contact.rb +85 -0
  22. data/lib/agent_xmpp/models/message.rb +152 -0
  23. data/lib/agent_xmpp/models/publication.rb +53 -0
  24. data/lib/agent_xmpp/models/roster.rb +107 -0
  25. data/lib/agent_xmpp/models/service.rb +91 -0
  26. data/lib/agent_xmpp/models/subscription.rb +61 -0
  27. data/lib/agent_xmpp/models/table_definitions.rb +107 -0
  28. data/lib/agent_xmpp/patches.rb +7 -0
  29. data/lib/agent_xmpp/patches/array.rb +32 -0
  30. data/lib/agent_xmpp/patches/float.rb +10 -0
  31. data/lib/agent_xmpp/patches/hash.rb +13 -0
  32. data/lib/agent_xmpp/patches/object.rb +15 -0
  33. data/lib/agent_xmpp/patches/rexml.rb +69 -0
  34. data/lib/agent_xmpp/patches/string.rb +15 -0
  35. data/lib/agent_xmpp/xmpp.rb +18 -0
  36. data/lib/agent_xmpp/xmpp/element.rb +158 -0
  37. data/lib/agent_xmpp/xmpp/entry.rb +36 -0
  38. data/lib/agent_xmpp/xmpp/error_response.rb +189 -0
  39. data/lib/agent_xmpp/xmpp/iq.rb +90 -0
  40. data/lib/agent_xmpp/xmpp/iq_command.rb +54 -0
  41. data/lib/agent_xmpp/xmpp/iq_disco.rb +206 -0
  42. data/lib/agent_xmpp/xmpp/iq_pubsub.rb +270 -0
  43. data/lib/agent_xmpp/xmpp/iq_roster.rb +183 -0
  44. data/lib/agent_xmpp/xmpp/iq_version.rb +89 -0
  45. data/lib/agent_xmpp/xmpp/jid.rb +150 -0
  46. data/lib/agent_xmpp/xmpp/message.rb +82 -0
  47. data/lib/agent_xmpp/xmpp/presence.rb +127 -0
  48. data/lib/agent_xmpp/xmpp/sasl.rb +241 -0
  49. data/lib/agent_xmpp/xmpp/stanza.rb +107 -0
  50. data/lib/agent_xmpp/xmpp/x_data.rb +357 -0
  51. data/test/app/app.rb +339 -0
  52. data/test/cases/test_application_message_processing.rb +65 -0
  53. data/test/cases/test_errors.rb +24 -0
  54. data/test/cases/test_presence_management.rb +139 -0
  55. data/test/cases/test_roster_management.rb +214 -0
  56. data/test/cases/test_service_discovery.rb +168 -0
  57. data/test/cases/test_session_management.rb +120 -0
  58. data/test/cases/test_version_discovery.rb +67 -0
  59. data/test/helpers/matchers.rb +23 -0
  60. data/test/helpers/mocks.rb +82 -0
  61. data/test/helpers/test_case_extensions.rb +45 -0
  62. data/test/helpers/test_client.rb +44 -0
  63. data/test/helpers/test_delegate.rb +60 -0
  64. data/test/helpers/test_helper.rb +91 -0
  65. data/test/messages/application_messages.rb +206 -0
  66. data/test/messages/error_messages.rb +35 -0
  67. data/test/messages/presence_messages.rb +66 -0
  68. data/test/messages/roster_messages.rb +126 -0
  69. data/test/messages/service_discovery_messages.rb +201 -0
  70. data/test/messages/session_messages.rb +158 -0
  71. data/test/messages/version_discovery_messages.rb +69 -0
  72. data/test/peer/peer.rb +21 -0
  73. metadata +187 -0
@@ -0,0 +1,720 @@
1
+ ##############################################################################################################
2
+ module AgentXmpp
3
+
4
+ #####-------------------------------------------------------------------------------------------------------
5
+ class MessageDelegate
6
+
7
+ #####-------------------------------------------------------------------------------------------------------
8
+ class << self
9
+
10
+ #.........................................................................................................
11
+ attr_reader :pubsub_service
12
+
13
+ #---------------------------------------------------------------------------------------------------------
14
+ # event flow delegate methods
15
+ #.........................................................................................................
16
+ # process command
17
+ #.........................................................................................................
18
+ def on_command_set(pipe, stanza)
19
+ command = stanza.command
20
+ params = {:xmlns => 'jabber:x:data', :action => command.action || :execute, :to => stanza.from.to_s,
21
+ :from => stanza.from.to_s, :node => command.node, :id => stanza.id,
22
+ :sessionid => command.sessionid}
23
+ (data = command.x) ? params.update(:data=>data.to_params, :x_data_type => data.type) : params.update(:data=>{})
24
+ AgentXmpp.logger.info "RECEIVED COMMAND NODE: #{command.node}, FROM: #{stanza.from.to_s}"
25
+ if BaseController.commands_list[params[:sessionid]]
26
+ BaseController.commands_list[params[:sessionid]][:controller].next(params).invoke_command_next
27
+ else
28
+ Controller.new(pipe, params).invoke_command
29
+ end
30
+ end
31
+
32
+ #.........................................................................................................
33
+ # process chat messages
34
+ #.........................................................................................................
35
+ def on_message_chat(pipe, stanza)
36
+ params = {:xmlns => 'message:chat', :to => stanza.from.to_s, :from => stanza.from.to_s,
37
+ :id => stanza.id, :body => stanza.body}
38
+ AgentXmpp.logger.info "RECEIVED CHAT MESSAGE FROM: #{stanza.from.to_s}"
39
+ Controller.new(pipe, params).invoke_chat
40
+ end
41
+
42
+ #.........................................................................................................
43
+ # process normal messages
44
+ #.........................................................................................................
45
+ def on_message_normal(pipe, stanza)
46
+ AgentXmpp.logger.info "RECEIVED NORMAL MESSAGE FROM: #{stanza.from.to_s}"
47
+ if event = stanza.event
48
+ on_pubsub_event(pipe, event, stanza.to.to_s, stanza.from.to_s)
49
+ else
50
+ on_unsupported_message(pipe, stanza)
51
+ end
52
+ end
53
+
54
+ #.........................................................................................................
55
+ # process headline messages
56
+ #.........................................................................................................
57
+ def on_message_headline(pipe, stanza)
58
+ AgentXmpp.logger.info "RECEIVED HEADLINE MESSAGE FROM: #{stanza.from.to_s}"
59
+ if event = stanza.event
60
+ on_pubsub_event(pipe, event, stanza.to.to_s, stanza.from.to_s)
61
+ else
62
+ on_unsupported_message(pipe, stanza)
63
+ end
64
+ end
65
+
66
+ #.........................................................................................................
67
+ # process events
68
+ #.........................................................................................................
69
+ def on_pubsub_event(pipe, event, to, from)
70
+ AgentXmpp.logger.info "RECEIVED EVENT FROM: #{from.to_s}"
71
+ event.items.each do |is|
72
+ src = is.node.split('/')
73
+ src_jid = "#{src[3]}@#{src[2]}"
74
+ is.item.each do |i|
75
+ if Message.update_received_event_item(i, from, is.node)
76
+ params = {
77
+ :xmlns => 'http://jabber.org/protocol/pubsub#event',
78
+ :to => to, :pubsub => from, :node => is.node, :from => src_jid, :id => i.id,
79
+ :resources => Roster.find_all_by_contact_jid_and_status(Xmpp::Jid.new(src_jid), :available)}
80
+ if data = i.x and data.type.eql?(:result)
81
+ params.update(:data => data.to_native)
82
+ Controller.new(pipe, params).invoke_event
83
+ elsif entry = i.entry
84
+ params.update(:data => entry.title)
85
+ Controller.new(pipe, params).invoke_event
86
+ else
87
+ on_unsupported_message(pipe, event)
88
+ end
89
+ else
90
+ on_unsupported_message(pipe, event)
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ #.........................................................................................................
97
+ # errors
98
+ #.........................................................................................................
99
+ def on_unsupported_message(pipe, stanza)
100
+ AgentXmpp.logger.info "RECEIVED UNSUPPORTED MESSAGE: #{stanza.to_s}"
101
+ if stanza.class.eql?(AgentXmpp::Xmpp::Iq)
102
+ Xmpp::ErrorResponse.feature_not_implemented(stanza)
103
+ end
104
+ end
105
+
106
+ #.........................................................................................................
107
+ # connection
108
+ #.........................................................................................................
109
+ def on_connect(pipe)
110
+ AgentXmpp.logger.info "CONNECTED"
111
+ end
112
+
113
+ #.........................................................................................................
114
+ def on_disconnect(pipe)
115
+ AgentXmpp.logger.warn "DISCONNECTED"
116
+ EventMachine::stop_event_loop
117
+ end
118
+
119
+ #.........................................................................................................
120
+ def on_did_not_connect(pipe)
121
+ AgentXmpp.logger.warn "CONNECTION FAILED"
122
+ end
123
+
124
+ #.........................................................................................................
125
+ # authentication
126
+ #.........................................................................................................
127
+ def on_bind(pipe)
128
+ AgentXmpp.logger.info "DID BIND TO RESOURCE: #{AgentXmpp.jid.resource}"
129
+ Xmpp::Iq.session(pipe) if pipe.stream_features.has_key?('session')
130
+ end
131
+
132
+ #.........................................................................................................
133
+ def on_preauthenticate_features(pipe)
134
+ AgentXmpp.logger.info "SESSION INITIALIZED"
135
+ Xmpp::SASL.authenticate(pipe.stream_mechanisms)
136
+ end
137
+
138
+ #.........................................................................................................
139
+ def on_authenticate(pipe)
140
+ AgentXmpp.logger.info "AUTHENTICATED"
141
+ end
142
+
143
+ #.........................................................................................................
144
+ def on_did_not_authenticate(pipe)
145
+ AgentXmpp.logger.info "AUTHENTICATION FAILED"
146
+ raise AgentXmppError, "authentication failed"
147
+ end
148
+
149
+ #.........................................................................................................
150
+ def on_postauthenticate_features(pipe)
151
+ AgentXmpp.logger.info "SESSION STARTED"
152
+ Xmpp::Iq.bind(pipe) if pipe.stream_features.has_key?('bind')
153
+ end
154
+
155
+ #.........................................................................................................
156
+ def on_start_session(pipe)
157
+ AgentXmpp.logger.info "SESSION STARTED"
158
+ add_send_command_request_method(pipe)
159
+ add_send_chat_method(pipe)
160
+ [Send(Xmpp::Presence.new(nil, nil, AgentXmpp.priority)), Xmpp::IqRoster.get(pipe),
161
+ Xmpp::IqDiscoInfo.get(pipe, AgentXmpp.jid.domain)]
162
+ end
163
+
164
+ #.........................................................................................................
165
+ # presence
166
+ #.........................................................................................................
167
+ def on_presence(pipe, presence)
168
+ from_jid = presence.from
169
+ if Contact.has_jid?(presence.from) or AgentXmpp.is_account_jid?(from_jid)
170
+ Roster.update(presence)
171
+ AgentXmpp.logger.info "RECEIVED PRESENCE FROM: #{from_jid.to_s}"
172
+ response = []
173
+ unless from_jid.to_s.eql?(AgentXmpp.jid.to_s)
174
+ Boot.call_if_implemented(:call_received_presence, from_jid.to_s, :available)
175
+ response << Xmpp::IqVersion.get(pipe, from_jid) unless Roster.has_version?(from_jid)
176
+ unless Service.has_jid?(from_jid)
177
+ response << Xmpp::IqDiscoInfo.get(pipe, from_jid)
178
+ response << Xmpp::IqDiscoItems.get(pipe, from_jid, 'http://jabber.org/protocol/commands')
179
+ end
180
+ end; response
181
+ else
182
+ AgentXmpp.logger.warn "RECEIVED PRESENCE FROM JID NOT IN ROSTER: #{from_jid}" unless from_jid.to_s.eql?(AgentXmpp.jid.to_s)
183
+ end
184
+ end
185
+
186
+ #.........................................................................................................
187
+ def on_presence_subscribe(pipe, presence)
188
+ from_jid = presence.from.to_s
189
+ if Contact.has_jid?(presence.from)
190
+ AgentXmpp.logger.info "RECEIVED SUBSCRIBE REQUEST: #{from_jid}"
191
+ Xmpp::Presence.accept(from_jid)
192
+ else
193
+ AgentXmpp.logger.warn "RECEIVED SUBSCRIBE REQUEST FROM JID NOT IN ROSTER: #{from_jid}"
194
+ Xmpp::Presence.decline(from_jid)
195
+ end
196
+ end
197
+
198
+ #.........................................................................................................
199
+ def on_presence_subscribed(pipe, presence)
200
+ AgentXmpp.logger.info "SUBSCRIPTION ACCEPTED: #{presence.from.to_s}"
201
+ end
202
+
203
+ #.........................................................................................................
204
+ def on_presence_unavailable(pipe, presence)
205
+ from_jid = presence.from
206
+ if Contact.has_jid?(from_jid) or AgentXmpp.is_account_jid?(from_jid)
207
+ Roster.update(presence)
208
+ Boot.call_if_implemented(:call_received_presence, from_jid.to_s, :unavailable)
209
+ AgentXmpp.logger.info "RECEIVED UNAVAILABLE PRESENCE FROM: #{from_jid.to_s }"
210
+ else
211
+ AgentXmpp.logger.warn "RECEIVED UNAVAILABLE PRESENCE FROM JID NOT IN ROSTER: #{from_jid}"
212
+ end
213
+ end
214
+
215
+ #.........................................................................................................
216
+ def on_presence_unsubscribed(pipe, presence)
217
+ from_jid = presence.from
218
+ if Contact.has_jid?(from_jid)
219
+ Contact.destroy_by_jid(from_jid)
220
+ AgentXmpp.logger.info "RECEIVED UNSUBSCRIBED REQUEST: #{from_jid.to_s}"
221
+ Xmpp::IqRoster.remove(pipe, from_jid)
222
+ else
223
+ AgentXmpp.logger.warn "RECEIVED UNSUBSCRIBED REQUEST FROM JID NOT IN ROSTER: #{from_jid.to_s}"
224
+ end
225
+ end
226
+
227
+ #.........................................................................................................
228
+ def on_presence_error(pipe, presence)
229
+ from_jid = presence.from
230
+ AgentXmpp.logger.warn "RECEIVED PRESENCE ERROR FROM: #{presence.from.to_s}"
231
+ if Contact.has_jid?(presence.from) or AgentXmpp.is_account_jid?(from_jid)
232
+ AgentXmpp.logger.warn "REMOVING '#{presence.from.to_s}' FROM ROSTER"
233
+ Xmpp::IqRoster.remove(pipe, from_jid.to_s)
234
+ end
235
+ end
236
+
237
+ #.........................................................................................................
238
+ # roster management
239
+ #.........................................................................................................
240
+ def on_roster_result(pipe, stanza)
241
+ process_roster_items(pipe, stanza)
242
+ end
243
+
244
+ #.........................................................................................................
245
+ def on_roster_set(pipe, stanza)
246
+ process_roster_items(pipe, stanza)
247
+ end
248
+
249
+ #.........................................................................................................
250
+ def on_roster_item(pipe, roster_item)
251
+ roster_item_jid = roster_item.jid
252
+ AgentXmpp.logger.info "RECEIVED ROSTER ITEM: #{roster_item_jid.to_s}"
253
+ if Contact.has_jid?(roster_item_jid)
254
+ case roster_item.subscription
255
+ when :none
256
+ if roster_item.ask.eql?(:subscribe)
257
+ AgentXmpp.logger.info "CONTACT SUBSCRIPTION PENDING: #{roster_item_jid.to_s}"
258
+ roster_item.subscription = :ask
259
+ else
260
+ AgentXmpp.logger.info "CONTACT ADDED TO ROSTER: #{roster_item_jid.to_s}"
261
+ roster_item.subscription = :added
262
+ end
263
+ when :to
264
+ AgentXmpp.logger.info "SUBSCRIBED TO CONTACT PRESENCE: #{roster_item_jid.to_s}"
265
+ when :from
266
+ AgentXmpp.logger.info "CONTACT SUBSCRIBED TO PRESENCE: #{roster_item_jid.to_s}"
267
+ when :both
268
+ AgentXmpp.logger.info "CONTACT SUBSCRIPTION BIDIRECTIONAL: #{roster_item_jid.to_s}"
269
+ end
270
+ Contact.update_with_roster_item(roster_item)
271
+ check_roster_item_group(pipe, roster_item)
272
+ else
273
+ AgentXmpp.logger.info "REMOVING ROSTER ITEM: #{roster_item_jid.to_s}"
274
+ Xmpp::IqRoster.remove(pipe, roster_item_jid)
275
+ end
276
+ end
277
+
278
+ #.........................................................................................................
279
+ def on_remove_roster_item(pipe, roster_item)
280
+ AgentXmpp.logger.info "REMOVE ROSTER ITEM"
281
+ roster_item_jid = roster_item.jid
282
+ if Contact.has_jid?(roster_item_jid)
283
+ AgentXmpp.logger.info "REMOVED ROSTER ITEM: #{roster_item_jid.to_s}"
284
+ Contact.destroy_by_jid(roster_item_jid)
285
+ end
286
+ end
287
+
288
+ #.........................................................................................................
289
+ def on_all_roster_items(pipe)
290
+ AgentXmpp.logger.info "RECEIVED ALL ROSTER ITEMS"
291
+ Contact.find_all_by_subscription(:new).map do |r|
292
+ AgentXmpp.logger.info "ADDING CONTACT: #{r[:jid]}"
293
+ [Xmpp::IqRoster.update(pipe, r[:jid], r[:groups].split(/,/)), Xmpp::Presence.subscribe(r[:jid])]
294
+ end
295
+ end
296
+
297
+ #.........................................................................................................
298
+ def on_update_roster_item_result(pipe, roster_item_jid)
299
+ AgentXmpp.logger.info "UPDATE ROSTER ITEM ACKNOWLEDEGED FROM: #{roster_item_jid}"
300
+ end
301
+
302
+ #.........................................................................................................
303
+ def on_update_roster_item_error(pipe, roster_item_jid)
304
+ AgentXmpp.logger.info "UPDATE ROSTER ITEM RECEIVED ERROR REMOVING: #{roster_item_jid}"
305
+ end
306
+
307
+ #.........................................................................................................
308
+ def on_remove_roster_item_result(pipe, roster_item_jid)
309
+ AgentXmpp.logger.info "REMOVE ROSTER ITEM ACKNOWLEDEGED FROM: #{roster_item_jid}"
310
+ end
311
+
312
+ #.........................................................................................................
313
+ def on_remove_roster_item_error(pipe, roster_item_jid)
314
+ AgentXmpp.logger.info "REMOVE ROSTER ITEM RECEIVED ERROR REMOVING: #{roster_item_jid}"
315
+ end
316
+
317
+ #.........................................................................................................
318
+ # service discovery management
319
+ #.........................................................................................................
320
+ def on_version_result(pipe, version)
321
+ from_jid, query = version.from, version.query
322
+ AgentXmpp.logger.info "RECEIVED VERSION RESULT: #{from_jid.to_s}, #{query.iname}, #{query.version}"
323
+ Roster.update(query, from_jid)
324
+ end
325
+
326
+ #.........................................................................................................
327
+ def on_version_get(pipe, request)
328
+ from_jid = request.from
329
+ if Contact.has_jid?(from_jid) or AgentXmpp.is_account_jid?(from_jid)
330
+ AgentXmpp.logger.info "RECEIVED VERSION REQUEST: #{request.from.to_s}"
331
+ Xmpp::IqVersion.result(pipe, request)
332
+ else
333
+ AgentXmpp.logger.warn "RECEIVED VERSION REQUEST FROM JID NOT IN ROSTER: #{request.from.to_s}"
334
+ Xmpp::ErrorResponse.service_unavailable(request)
335
+ end
336
+ end
337
+
338
+ #.........................................................................................................
339
+ def on_version_error(pipe, result)
340
+ from_jid = result.from
341
+ AgentXmpp.logger.warn "RECEIVED VERSION ERROR FROM: #{from_jid.to_s}"
342
+ end
343
+
344
+ #.........................................................................................................
345
+ def on_discoinfo_get(pipe, request)
346
+ from_jid = request.from
347
+ if Contact.has_jid?(from_jid) or AgentXmpp.is_account_jid?(from_jid)
348
+ if request.query.node.nil?
349
+ AgentXmpp.logger.info "RECEIVED DISCO INFO REQUEST FROM: #{from_jid.to_s}"
350
+ Xmpp::IqDiscoInfo.result(pipe, request)
351
+ else
352
+ AgentXmpp.logger.info "RECEIVED DISCO INFO REQUEST FOR UNSUPPORTED NODE FROM: #{from_jid.to_s}"
353
+ Xmpp::ErrorResponse.item_not_found(request)
354
+ end
355
+ else
356
+ AgentXmpp.logger.warn "RECEIVED DISCO INFO REQUEST FROM JID NOT IN ROSTER: #{from_jid.to_s}"
357
+ Xmpp::ErrorResponse.service_unavailable(request)
358
+ end
359
+ end
360
+
361
+ #.........................................................................................................
362
+ def on_discoinfo_result(pipe, discoinfo)
363
+ from_jid = discoinfo.from
364
+ do_discoitems = true
365
+ request = []
366
+ q = discoinfo.query
367
+ AgentXmpp.logger.info "RECEIVED DISCO INFO RESULT FROM: #{from_jid.to_s}" + (q.node.nil? ? '' : ", NODE: #{q.node}")
368
+ Service.update(discoinfo)
369
+ q.identities.each do |i|
370
+ AgentXmpp.logger.info " IDENTITY: NAME:#{i.iname}, CATEGORY:#{i.category}, TYPE:#{i.type}"
371
+ request << case i.category
372
+ when 'server' then Xmpp::IqDiscoItems.get(pipe, from_jid.to_s, q.node)
373
+ when 'pubsub' then process_pubsub_discoinfo(i.type, pipe, from_jid, q.node)
374
+ when 'conference'
375
+ when 'proxy'
376
+ when 'directory'
377
+ when 'client'
378
+ when 'automation'
379
+ when 'auth'
380
+ when 'collaboration'
381
+ when 'componenet'
382
+ when 'gateway'
383
+ when 'hierarchy'
384
+ when 'headline'
385
+ when 'store'
386
+ end
387
+ end
388
+ q.features.each do |f|
389
+ AgentXmpp.logger.info " FEATURE: #{f}"
390
+ end
391
+ request.smash
392
+ end
393
+
394
+ #.........................................................................................................
395
+ def on_discoinfo_error(pipe, result)
396
+ from_jid = result.from
397
+ AgentXmpp.logger.warn "RECEIVED DISCO INFO ERROR FROM: #{from_jid.to_s}, #{result.query.node}"
398
+ end
399
+
400
+ #.........................................................................................................
401
+ def on_discoitems_get(pipe, request)
402
+ from_jid = request.from
403
+ if Contact.has_jid?(from_jid) or AgentXmpp.is_account_jid?(from_jid)
404
+ if request.query.node.eql?('http://jabber.org/protocol/commands')
405
+ AgentXmpp.logger.info "RECEIVED COMMAND NODE DISCO ITEMS REQUEST FROM: #{from_jid.to_s}"
406
+ Xmpp::IqDiscoItems.result_command_nodes(pipe, request)
407
+ elsif request.query.node.nil?
408
+ AgentXmpp.logger.info "RECEIVED DISCO ITEMS REQUEST FROM: #{from_jid.to_s}"
409
+ Xmpp::IqDiscoItems.result(pipe, request)
410
+ else
411
+ AgentXmpp.logger.info "RECEIVED DISCO INFO REQUEST FOR UNSUPPORTED NODE FROM: #{from_jid.to_s}"
412
+ Xmpp::ErrorResponse.item_not_found(request)
413
+ end
414
+ else
415
+ AgentXmpp.logger.warn "RECEIVED DISCO ITEMS REQUEST FROM JID NOT IN ROSTER: #{from_jid.to_s}"
416
+ Xmpp::ErrorResponse.service_unavailable(request)
417
+ end
418
+ end
419
+
420
+ #.........................................................................................................
421
+ def on_discoitems_result(pipe, discoitems)
422
+ from_jid = discoitems.from
423
+ q = discoitems.query
424
+ AgentXmpp.logger.info "RECEIVED DISCO ITEMS RESULT FROM: #{from_jid.to_s}" + (q.node.nil? ? '' : ", NODE: #{q.node}")
425
+ Service.update(discoitems)
426
+ case q.node
427
+ when 'http://jabber.org/protocol/commands'
428
+ Boot.call_if_implemented(:call_discovered_command_nodes, from_jid.to_s, q.items.map{|i| i.node}) unless q.items.empty?
429
+ else
430
+ msgs = if from_jid.to_s.eql?(pubsub_service.to_s) and q.node.eql?(AgentXmpp.pubsub_root)
431
+ create_user_pubsub_root(pipe, from_jid, q.items)
432
+ else ; []; end
433
+ if from_jid.to_s.eql?(pubsub_service.to_s) and q.node.eql?(AgentXmpp.user_pubsub_root)
434
+ msgs += update_publish_nodes(pipe, from_jid, q.items)
435
+ end
436
+ q.items.inject(msgs) do |r,i|
437
+ AgentXmpp.logger.info " ITEM JID: #{i.jid}" + (i.node.nil? ? '' : ", NODE: #{i.node}")
438
+ r << Xmpp::IqDiscoInfo.get(pipe, i.jid, i.node)
439
+ end
440
+ end
441
+ end
442
+
443
+ #.........................................................................................................
444
+ def on_discoitems_error(pipe, result)
445
+ from_jid = result.from
446
+ AgentXmpp.logger.warn "RECEIVED DISCO ITEMS ERROR FROM: #{from_jid.to_s}"
447
+ end
448
+
449
+ #.........................................................................................................
450
+ # pubsub
451
+ #.........................................................................................................
452
+ def on_publish_result(pipe, result, node)
453
+ AgentXmpp.logger.info "PUBLISH TO NODE ACKNOWLEDEGED: #{node}, #{result.from.to_s}"
454
+ end
455
+
456
+ #.........................................................................................................
457
+ def on_publish_error(pipe, result, node)
458
+ AgentXmpp.logger.info "ERROR PUBLISING TO NODE: #{node}, #{result.from.to_s}"
459
+ end
460
+
461
+ #.........................................................................................................
462
+ def on_discovery_of_pupsub_service(pipe, jid)
463
+ AgentXmpp.logger.info "DISCOVERED PUBSUB SERVICE: #{jid}"
464
+ req = [Xmpp::IqPubSub.subscriptions(pipe, jid.to_s)]
465
+ if /#{AgentXmpp.jid.domain}/.match(jid.to_s)
466
+ add_publish_methods(pipe, jid)
467
+ @pubsub_service = jid
468
+ req += [Xmpp::IqDiscoItems.get(pipe, jid.to_s)] + init_remote_services(pipe)
469
+ end; req
470
+ end
471
+
472
+ #.........................................................................................................
473
+ def on_discovery_of_pupsub_collection(pipe, jid, node)
474
+ AgentXmpp.logger.info "DISCOVERED PUBSUB COLLECTION: #{jid}, #{node}"
475
+ Xmpp::IqDiscoItems.get(pipe, jid, node) if pubsub_service.eql?(jid)
476
+ end
477
+
478
+ #.........................................................................................................
479
+ def on_discovery_of_pupsub_leaf(pipe, jid, node)
480
+ AgentXmpp.logger.info "DISCOVERED PUBSUB LEAF: #{jid}, #{node}"
481
+ if node.eql?(AgentXmpp.pubsub_root) or node.eql?(AgentXmpp.user_pubsub_root)
482
+ Xmpp::IqDiscoItems.get(pipe, jid, node)
483
+ else
484
+ Boot.call_if_implemented(:call_discovered_pubsub_node, jid, node)
485
+ end
486
+ end
487
+
488
+ #.........................................................................................................
489
+ def on_discovery_of_user_pubsub_root(pipe, pubsub, node)
490
+ AgentXmpp.logger.info "DISCOVERED USER PUBSUB ROOT: #{pubsub.to_s}, #{node}"
491
+ end
492
+
493
+ #.........................................................................................................
494
+ def on_pubsub_subscriptions_result(pipe, result)
495
+ from_jid = result.from.to_s
496
+ AgentXmpp.logger.info "RECEIVED SUBSCRIPTIONS FROM: #{from_jid}"
497
+ app_subs = BaseController.subscriptions(result.from.domain)
498
+ srvr_subs = result.pubsub.subscriptions.map do |s|
499
+ AgentXmpp.logger.info "SUBSCRIBED TO NODE: #{from_jid}, #{s.node}"
500
+ Subscription.update(s, s.node, from_jid); s.node
501
+ end
502
+ reqs = app_subs.inject([]) do |r,s|
503
+ unless srvr_subs.include?(s)
504
+ AgentXmpp.logger.info "SUBSCRIBING TO NODE: #{from_jid}, #{s}"
505
+ r << Xmpp::IqPubSub.subscribe(pipe, from_jid, s)
506
+ end; r
507
+ end
508
+ srvr_subs.inject(reqs) do |r,s|
509
+ unless app_subs.include?(s)
510
+ AgentXmpp.logger.warn "UNSUBSCRIBING FROM NODE: #{from_jid}, #{s}"
511
+ r << Xmpp::IqPubSub.unsubscribe(pipe, from_jid, s)
512
+ end; r
513
+ end
514
+ end
515
+
516
+ #.........................................................................................................
517
+ def on_pubsub_subscriptions_error(pipe, result)
518
+ from_jid = result.from
519
+ AgentXmpp.logger.warn "RECEIVED ERROR ON SUBSCRIPTION REQUEST FROM: #{from_jid}"
520
+ end
521
+
522
+ #.........................................................................................................
523
+ def on_pubsub_affiliations_result(pipe, result)
524
+ from_jid = result.from
525
+ AgentXmpp.logger.info "RECEIVED AFFILIATIONS FROM: #{from_jid}"
526
+ end
527
+
528
+ #.........................................................................................................
529
+ def on_pubsub_affiliations_error(pipe, result)
530
+ from_jid = result.from
531
+ AgentXmpp.logger.info "RECEIVED ERROR ON AFFILIATIONS REQUEST FROM: #{from_jid}"
532
+ end
533
+
534
+ #.........................................................................................................
535
+ def on_pubsub_create_node_result(pipe, result, node)
536
+ from_jid = result.from
537
+ Publication.update_status(node, :active)
538
+ Boot.call_if_implemented(:call_discovered_pubsub_node, from_jid, node)
539
+ AgentXmpp.logger.info "RECEIVED CREATE NODE RESULT FROM: #{from_jid.to_s}, #{node}"
540
+ if node.eql?(AgentXmpp.user_pubsub_root)
541
+ [on_discovery_of_user_pubsub_root(pipe, from_jid, node), Xmpp::IqDiscoInfo.get(pipe, from_jid.to_s, node)]
542
+ end
543
+ end
544
+
545
+ #.........................................................................................................
546
+ def on_pubsub_create_node_error(pipe, result, node)
547
+ from_jid = result.from
548
+ Publication.update_status(node, :error)
549
+ AgentXmpp.logger.info "RECEIVED CREATE NODE ERROR FROM: #{from_jid.to_s}, #{node}"
550
+ end
551
+
552
+ #.........................................................................................................
553
+ def on_pubsub_delete_node_result(pipe, result, node)
554
+ from_jid = result.from
555
+ AgentXmpp.logger.info "RECEIVED DELETE NODE RESULT FROM: #{from_jid.to_s}, #{node}"
556
+ end
557
+
558
+ #.........................................................................................................
559
+ def on_pubsub_delete_node_error(pipe, result, node)
560
+ from_jid = result.from
561
+ AgentXmpp.logger.info "RECEIVED DELETE NODE ERROR FROM: #{from_jid.to_s}, #{node}"
562
+ end
563
+
564
+ #.........................................................................................................
565
+ def on_pubsub_subscribe_result(pipe, result, node)
566
+ from_jid = result.from.to_s
567
+ Subscription.update(result, node, from_jid)
568
+ AgentXmpp.logger.info "RECEIVED SUBSCRIBE RESULT FROM: #{from_jid}, #{node}"
569
+ end
570
+
571
+ #.........................................................................................................
572
+ def on_pubsub_subscribe_error(pipe, result, node)
573
+ from_jid = result.from
574
+ AgentXmpp.logger.warn "RECEIVED SUBSCRIBE ERROR FROM: #{from_jid.to_s}, #{node}"
575
+ on_pubsub_subscribe_error_item_not_found(pipe, result, node) if result.error.error.eql?('item-not-found')
576
+ end
577
+
578
+ #.........................................................................................................
579
+ def on_pubsub_subscribe_error_item_not_found(pipe, result, node)
580
+ from_jid = result.from
581
+ AgentXmpp.logger.warn "RECEIVED SUBSCRIBE ERROR ITEM-NOT-FOUND FROM: #{from_jid.to_s}, #{node}; " +
582
+ "RETRYING SUBSCRIPTION IN #{AgentXmpp::SUBSCRIBE_RETRY_PERIOD}s"
583
+ EventMachine::Timer.new(AgentXmpp::SUBSCRIBE_RETRY_PERIOD) do
584
+ pipe.send_resp(Xmpp::IqPubSub.subscribe(pipe, from_jid.to_s, node))
585
+ end
586
+ end
587
+
588
+ #.........................................................................................................
589
+ def on_pubsub_unsubscribe_result(pipe, result, node)
590
+ from_jid = result.from
591
+ Subscription.destroy_by_node(node)
592
+ AgentXmpp.logger.info "RECEIVED UNSUBSCRIBE RESULT FROM: #{from_jid.to_s}, #{node}"
593
+ end
594
+
595
+ #.........................................................................................................
596
+ def on_pubsub_unsubscribe_error(pipe, result, node)
597
+ from_jid = result.from
598
+ AgentXmpp.logger.info "RECEIVED UNSUBSCRIBE ERROR FROM: #{from_jid.to_s}, #{node}"
599
+ end
600
+
601
+ #.........................................................................................................
602
+ # private
603
+ #.........................................................................................................
604
+ def check_roster_item_group(pipe, roster_item)
605
+ roster_item_jid = roster_item.jid
606
+ roster_item_groups = Contact.find_by_jid(roster_item_jid)[:groups].split(/,/).sort
607
+ unless roster_item.groups.sort.eql?(roster_item_groups)
608
+ AgentXmpp.logger.info "CHANGE IN ROSTER ITEM GROUP FOUND UPDATING: #{roster_item_jid.to_s} to '#{roster_item_groups.join(', ')}'"
609
+ Xmpp::IqRoster.update(pipe, roster_item_jid.to_s, roster_item_groups)
610
+ end
611
+ end
612
+
613
+ #.........................................................................................................
614
+ def process_pubsub_discoinfo(type, pipe, from, node)
615
+ case type
616
+ when 'service' then pipe.broadcast_to_delegates(:on_discovery_of_pupsub_service, pipe, from)
617
+ when 'collection' then pipe.broadcast_to_delegates(:on_discovery_of_pupsub_collection, pipe, from, node)
618
+ when 'leaf' then pipe.broadcast_to_delegates(:on_discovery_of_pupsub_leaf, pipe, from, node)
619
+ end
620
+ end
621
+
622
+ #.........................................................................................................
623
+ def process_roster_items(pipe, stanza)
624
+ [stanza.query.inject([]) do |r, i|
625
+ method = i.subscription.eql?(:remove) ? :on_remove_roster_item : :on_roster_item
626
+ r.push(pipe.broadcast_to_delegates(method, pipe, i))
627
+ end, pipe.broadcast_to_delegates(:on_all_roster_items, pipe)].smash
628
+ end
629
+
630
+ #.........................................................................................................
631
+ def add_publish_methods(pipe, pubsub)
632
+ Publication.find_all.each do |pub|
633
+ if pub[:node]
634
+ meth = ("publish_" + pub[:node].gsub(/-/,'_')).to_sym
635
+ unless AgentXmpp.respond_to?(meth)
636
+ AgentXmpp.define_meta_class_method(meth) do |payload|
637
+ pipe.send_resp(Xmpp::IqPublish.set(pipe, :node => pub[:node], :to => pubsub, :payload => payload.to_x_data))
638
+ end
639
+ AgentXmpp.logger.info "ADDED PUBLISH METHOD FOR NODE: #{pub[:node]}, #{pubsub}"
640
+ Delegator.delegate(AgentXmpp, meth)
641
+ else
642
+ AgentXmpp.logger.warn "PUBLISH METHOD FOR NODE EXISTS: #{pub[:node]}, #{pubsub}"
643
+ end
644
+ else
645
+ AgentXmpp.logger.warn "NODE NOT SPECIFIED FOR PUBSUB PUBLISH CONFIGURATION"
646
+ end
647
+ end
648
+ end
649
+
650
+ #.........................................................................................................
651
+ def add_send_command_request_method(pipe)
652
+ AgentXmpp.define_meta_class_method(:send_command_request) do |args, &blk|
653
+ pipe.send_resp(Xmpp::IqCommand.send_command(:to=>args[:to], :node=>args[:node], :iq_type=>:set,
654
+ :action=>:execute, :payload=>args[:payload], &blk))
655
+ end
656
+ Delegator.delegate(AgentXmpp, :send_command_request)
657
+ AgentXmpp.logger.info "ADDED SEND_COMMAND_REQUEST METHOD"
658
+ end
659
+
660
+ #.........................................................................................................
661
+ def add_send_chat_method(pipe)
662
+ AgentXmpp.define_meta_class_method(:send_chat) do |args|
663
+ raise ArgmentError ':to and :body are required' unless args[:to] and args[:body]
664
+ message = Xmpp::Message.new(args[:to], args[:body])
665
+ message.type = args[:type] || :chat
666
+ pipe.send_resp(Send(message))
667
+ end
668
+ Delegator.delegate(AgentXmpp, :send_chat)
669
+ AgentXmpp.logger.info "ADDED MESSAGE METHOD"
670
+ end
671
+
672
+ #.........................................................................................................
673
+ def create_user_pubsub_root(pipe, pubsub, items)
674
+ if (roots = items.select{|i| i.node.eql?(AgentXmpp.user_pubsub_root)}).empty?
675
+ AgentXmpp.logger.info "USER PUBSUB ROOT NOT FOUND CREATING NODE: #{pubsub.to_s}, #{AgentXmpp.user_pubsub_root}"
676
+ [Xmpp::IqPubSub.create_node(pipe, pubsub.to_s, AgentXmpp.user_pubsub_root)]
677
+ else
678
+ AgentXmpp.logger.info "USER PUBSUB ROOT FOUND: #{pubsub.to_s}, #{AgentXmpp.user_pubsub_root}"
679
+ on_discovery_of_user_pubsub_root(pipe, pubsub, AgentXmpp.user_pubsub_root); []
680
+ end
681
+ end
682
+
683
+ #.........................................................................................................
684
+ def update_publish_nodes(pipe, pubsub, items)
685
+ disco_nodes = items.map{|i| i.node}
686
+ config_nodes = Publication.find_all.map{|pub| "#{AgentXmpp.user_pubsub_root}/#{pub[:node]}"}
687
+ updates = disco_nodes.inject([]) do |u,n|
688
+ unless config_nodes.include?(n)
689
+ AgentXmpp.logger.warn "DELETING PUBSUB NODE: #{pubsub.to_s}, #{n}"
690
+ u << Xmpp::IqPubSubOwner.delete_node(pipe, pubsub.to_s, n)
691
+ end; u
692
+ end
693
+ config_nodes.inject(updates) do |u,n|
694
+ unless disco_nodes.include?(n)
695
+ AgentXmpp.logger.info "ADDING PUBSUB NODE: #{pubsub.to_s}, #{n}"
696
+ u << Xmpp::IqPubSub.create_node(pipe, pubsub.to_s, n)
697
+ end; u
698
+ end
699
+ end
700
+
701
+ #.........................................................................................................
702
+ def init_remote_services(pipe)
703
+ (BaseController.event_domains-[AgentXmpp.jid.domain]).map do |d|
704
+ Xmpp::IqDiscoInfo.get(pipe, d)
705
+ end
706
+ end
707
+
708
+ #.........................................................................................................
709
+ private :init_remote_services, :update_publish_nodes, :create_user_pubsub_root, :add_send_chat_method,
710
+ :add_send_command_request_method, :add_publish_methods, :process_roster_items, :process_pubsub_discoinfo,
711
+ :check_roster_item_group
712
+
713
+ #### self
714
+ end
715
+
716
+ #### MessagePipe
717
+ end
718
+
719
+ #### AgentXmpp
720
+ end