agent_xmpp 0.1.0

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