xmpp-agent 0.2.2 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cc18c3e39574543fd3941ec362455ad1de84f879
4
- data.tar.gz: 0814d2fd8695a4b085495ea7423a1f3f97e7d4f6
2
+ SHA256:
3
+ metadata.gz: 577bb2cc12f813639ee3d0b732b0809f26a0acb38fe23d4bcfc7a3b56966adbb
4
+ data.tar.gz: 8a35a77d8e4d593d1cda6b7d7d881011bfffef1a323f57a52afb0300c692e06f
5
5
  SHA512:
6
- metadata.gz: 8cc44846f6d4fe645e779602a6ec18ecc31d68d3dfe8b09e4eb20ee81504063696c33b68ddbd96168d92363f5584c7b17566f162eb9211d8e76256b36fad2bee
7
- data.tar.gz: 00819f6dc86d2739d5c787cf471787e8c2b82f0ec3766af63ab766f96354b3f836dbd12cd15d9e5fe3c64b0fd9d652586c0d41e05b8f69d418aaca29ab01da72
6
+ metadata.gz: 7db481786756250f1dc7b60bb6be95c73d337860db32dc27f120d6b38504b681e68650c77547905df7482b7ce964936a896b9f98a29b354f92f5fe189fc3dfbf
7
+ data.tar.gz: 5a25264b3e434b5c30b73f7e1331f0041dfe107d5058e62153f9c5dd319f84b10fc86d6f6439c05608b524a2874e7b33aecd2d3f0df74538749541bd35ac0ef6
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/lib/xmpp-agent.rb CHANGED
@@ -2,62 +2,98 @@
2
2
 
3
3
  # file: xmpp-agent.rb
4
4
 
5
- require 'em-xmpp'
5
+ require "xrc"
6
6
  require 'app-routes'
7
7
 
8
+
8
9
  class XMPPAgent
9
10
  include AppRoutes
10
11
 
11
- def initialize()
12
- @routes = {}; @params = {}; @conn = nil; @ctx = nil
13
- super()
14
- end
12
+ attr_reader :client
15
13
 
16
- def received(conn,ctx)
14
+ def initialize(jid: '', password: '', port: 5222, host: nil, debug: false, callback: nil)
15
+
16
+ @routes = {}; @params = {}; msg = nil
17
+ @debug = debug
18
+
19
+ super()
20
+
21
+ h = {
22
+ jid: @jid = jid,
23
+ password: password,
24
+ port: port
25
+ }
26
+
27
+ h.merge!({hosts: [ host ]}) if host
17
28
 
18
- @conn = conn
19
- @ctx = ctx
20
- messages(@params, @conn, @ctx)
21
- run_route ctx.body.strip
22
- end
29
+ @client = client = Xrc::Client.new(h)
30
+
31
+ @client.on_private_message do |message|
32
+
33
+ messages(@params, client, message)
34
+ run_route message.body.strip
35
+
36
+ end
37
+
38
+ @client.on_connection_established do
39
+
40
+ on_connected()
23
41
 
24
- def messages(params, conn, ctx)
42
+ end
43
+
44
+ @client.on_event do |e|
45
+
46
+ if e.name.to_s == 'presence' then
47
+ on_presence_update(show=e.text('show'), status=e.text('status'), user=e.attributes['from'] )
48
+ end
49
+
50
+ end
51
+
52
+
53
+ end
54
+
55
+ def connect()
56
+ @client.connect
57
+ end
58
+
59
+ protected
60
+
61
+ def on_connected()
62
+ end
63
+
64
+ def on_presence_update(show, status, user)
65
+ end
66
+
67
+ private
68
+
69
+ def messages(params, client, msg)
25
70
 
26
71
  message %r{(send_to|send2)\s+([^\s]+)\s+(.*)} do
27
72
 
28
- user, message = params[:captures].values_at 1,2
29
- data = conn.message_stanza('to' => user) {|xml| xml.body(message) }
30
- conn.send_stanza data
73
+ user, msgout = params[:captures].values_at 1,2
74
+
75
+ client.say(body: msgout, from: @jid, to: user, type: "chat")
31
76
  end
32
77
 
33
78
  message 'help' do
34
- data = conn.message_stanza('to' => ctx.from) do |xml|
35
- xml.body('available commands: help, send_to')
36
- end
37
- conn.send_stanza data
79
+ msgout = 'available commands: help, send_to'
80
+ client.reply(body: msgout, to: msg)
38
81
  end
39
82
 
40
83
  message '.*' do
41
84
 
42
- data = conn.message_stanza('to' => ctx.from) do |xml|
43
- xml.body('need some help? type help')
44
- end
45
- conn.send_stanza data
85
+ msgout = 'need some help? type help'
86
+ client.reply(body: msgout, to: msg)
46
87
  end
47
88
 
48
89
  end
49
90
 
50
91
  def add_route(arg)
51
- get(arg) {yield(@params, @conn, @ctx)}
92
+ get(arg) {yield(@params, @client, @msg)}
52
93
  end
53
94
 
54
95
  def message(route, &blk)
55
96
  get(route, &blk)
56
- end
57
-
58
- def conn() @conn end
59
-
60
- def presence_update(ctx)
61
- end
97
+ end
62
98
 
63
99
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xmpp-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -10,65 +10,80 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDljCCAn6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBIMRIwEAYDVQQDDAlnZW1t
14
- YXN0ZXIxHjAcBgoJkiaJk/IsZAEZFg5qYW1lc3JvYmVydHNvbjESMBAGCgmSJomT
15
- 8ixkARkWAmV1MB4XDTE0MDQwNTE5MjM1OVoXDTE1MDQwNTE5MjM1OVowSDESMBAG
16
- A1UEAwwJZ2VtbWFzdGVyMR4wHAYKCZImiZPyLGQBGRYOamFtZXNyb2JlcnRzb24x
17
- EjAQBgoJkiaJk/IsZAEZFgJldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
18
- ggEBAL0Uq28c4pfHfHXtX03cuOL4svrytTcBVcAT0CMrQLWkp9exVzFEic6sK6w1
19
- Gjfycf39ij1yFLEvR5rhZSL8qB+U+C7mjM5O2d1O4RB1sTQzs2bsEHx5Xvt9gY6b
20
- 4icqnJNfDpWdN4dCchhinYVet+MSOfwTrk6cSdeupKkLAJqzn7ckOLS6YGjvChGd
21
- slsFgEO3Di50HGpYbky9AwfSrRtps6MjsOl/uedr+FPLT/nP894HAXJt5HHwj79j
22
- tLHHM8FrWQokPBf2cVgWC2Rn5LghEo3IHD3En4nZKqJRJkd2zGkK03L2KSj1e2jN
23
- aVQYzv8ARVXkg6NhmIIbkXjYKO8CAwEAAaOBijCBhzAJBgNVHRMEAjAAMAsGA1Ud
24
- DwQEAwIEsDAdBgNVHQ4EFgQUHNdoeObmaJOyyCZrjWBargjqkiowJgYDVR0RBB8w
25
- HYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0c29uLmV1MCYGA1UdEgQfMB2BG2dlbW1h
26
- c3RlckBqYW1lc3JvYmVydHNvbi5ldTANBgkqhkiG9w0BAQUFAAOCAQEARN5IbndL
27
- vLnc2DlGh2kB9tcTSamlUM4bGke+GmItqk1IHfHFIvnCQU6WasCvi5sz2IifrBJ0
28
- gAQGclMgasc/5YiRVRbLxTk8Cf9iJ39YpCk6xwVc2py/0g+B9k7ahk/Y0/QBYJug
29
- VhnqZ064ebat8mLAHP+dL44SoMFsKGScYR5/RnjhQnONvg5xPuOg7wpXv9dz9TzL
30
- Xq/YKsl9GmhmsDj/Wy9ugRxGupRi4CaUo2ZWz6YAjE7u3Y4x2AuYPFSmKPFg4WpJ
31
- dK8nOI/ggrVJPOIbhAfE35/0QJ5Jec4k2Z1lGL+tzA//Tl8XlGDhTqcfVqnPwPxM
32
- GiPYMZ7fiR8BAw==
13
+ MIIEXjCCAsagAwIBAgIBATANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDDCFnZW1t
14
+ YXN0ZXIvREM9amFtZXNyb2JlcnRzb24vREM9ZXUwHhcNMTkwOTIxMjMxNzMxWhcN
15
+ MjAwOTIwMjMxNzMxWjAsMSowKAYDVQQDDCFnZW1tYXN0ZXIvREM9amFtZXNyb2Jl
16
+ cnRzb24vREM9ZXUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDtgFiq
17
+ +G7z+lIkbabWI1SzgWk9rBl8iI85tELX3YFvz4ayg7DX+NuHC/X720NBXTEppcf8
18
+ NWNtopq2XXCHlPerLKQFa4InW2O+AvOyTtitCR+Sza3zKxk3gUw2ToddLvwWk6cD
19
+ ZP+FCorucGhDhGCGABM9BEGMSkJG9Lod3MvHXVS/oLHhPvqaYAaZECH1khWL7RWM
20
+ jAqBvU/A00xN7jOJVBkH+UA9EyVL2lk7830P8D+5jhERAc/XLX2q+I2sdsFn6Wor
21
+ wxkfCTU/rL+eDS/gOPeigMlYg1Mt4vjmEwK+8QNKqmONa2AYB3o15ejP0TrsZR72
22
+ 3W1XFw2OIQG/01l89BgtaFRb4ylMGbHFpYNpNqEJumwksKgsTSZC5JeJyS9BnCeV
23
+ gcjV+DxwN+smzXrEeV8d3vr0u6tgVQPjF+qvy4rRvJ9lqZUAiml69Izd2oFEHXKo
24
+ kgwxCMzMFOW3xa9J6g0j7rkhz9GJxKeEaM2eL33cE/LhUcAC/ifbkQxzBQECAwEA
25
+ AaOBijCBhzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU/0itzTBw
26
+ 3QvdhrAlvTjNB+5tAVkwJgYDVR0RBB8wHYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0
27
+ c29uLmV1MCYGA1UdEgQfMB2BG2dlbW1hc3RlckBqYW1lc3JvYmVydHNvbi5ldTAN
28
+ BgkqhkiG9w0BAQsFAAOCAYEAAxdl3NXLewgOSwPtfdtQqhRDMoFlziIB0es/atjt
29
+ Hn7M7sV0rXG46qNiAuS33aoSI3lxf+ylHFonhwnyO8I0wfAq46pRxyEA4Xswmhzz
30
+ Nk4lRCJym7DGrPuciNZKJt8EEMLny9UBZUQGPlAnayqcLYWhTWCLU9G/xbka2chI
31
+ wM5OZO2ubW1HN1kqvLzh8zAxJKAxxuwkGAlQczmbnatp+ZpTLJ2jRMCK/d+G0yos
32
+ j8lmbAVbxD+f1fB1+P4/DvpKlN2h8HxdDirdbWjE+6QvgSE9cymnhz5Qgc1EwbR+
33
+ HrlBlt200+/DSQvjwXFY3+T+NPT4ESPe1cHPtkce8xNPbNLgKu7Qr9GZP/XqUGJn
34
+ 71RBgFbe7Wp4fFf1dj6v8xgG+uqxCVtK4LbHgCYqnmWvCfD9x3jhBTfwzPUJHQSR
35
+ 9Eg9Gbw3IF8iMcIPwTT7WTzb3vLw4+o6hP8oRi2CD1KB4KMDSxn4li5v8VuGdZ1o
36
+ ZPG6kphiEV/Pdc0QAh4qYhIN
33
37
  -----END CERTIFICATE-----
34
- date: 2014-04-05 00:00:00.000000000 Z
38
+ date: 2019-09-21 00:00:00.000000000 Z
35
39
  dependencies:
36
40
  - !ruby/object:Gem::Dependency
37
- name: em-xmpp
41
+ name: xrc
38
42
  requirement: !ruby/object:Gem::Requirement
39
43
  requirements:
40
- - - '='
44
+ - - "~>"
41
45
  - !ruby/object:Gem::Version
42
- version: 0.0.11
46
+ version: '0.1'
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 0.1.8
43
50
  type: :runtime
44
51
  prerelease: false
45
52
  version_requirements: !ruby/object:Gem::Requirement
46
53
  requirements:
47
- - - '='
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '0.1'
57
+ - - ">="
48
58
  - !ruby/object:Gem::Version
49
- version: 0.0.11
59
+ version: 0.1.8
50
60
  - !ruby/object:Gem::Dependency
51
61
  name: app-routes
52
62
  requirement: !ruby/object:Gem::Requirement
53
63
  requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '0.1'
54
67
  - - ">="
55
68
  - !ruby/object:Gem::Version
56
- version: '0'
69
+ version: 0.1.19
57
70
  type: :runtime
58
71
  prerelease: false
59
72
  version_requirements: !ruby/object:Gem::Requirement
60
73
  requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '0.1'
61
77
  - - ">="
62
78
  - !ruby/object:Gem::Version
63
- version: '0'
79
+ version: 0.1.19
64
80
  description:
65
- email: james@r0bertson.co.uk
81
+ email: james@jamesrobertson.eu
66
82
  executables: []
67
83
  extensions: []
68
84
  extra_rdoc_files: []
69
85
  files:
70
86
  - lib/xmpp-agent.rb
71
- - lib/xmpp4r-simple.rb
72
87
  homepage: https://github.com/jrobertson/xmpp-agent
73
88
  licenses:
74
89
  - MIT
@@ -81,16 +96,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
96
  requirements:
82
97
  - - ">="
83
98
  - !ruby/object:Gem::Version
84
- version: '0'
99
+ version: 2.1.2
85
100
  required_rubygems_version: !ruby/object:Gem::Requirement
86
101
  requirements:
87
102
  - - ">="
88
103
  - !ruby/object:Gem::Version
89
104
  version: '0'
90
105
  requirements: []
91
- rubyforge_project:
92
- rubygems_version: 2.0.14
106
+ rubygems_version: 3.0.3
93
107
  signing_key:
94
108
  specification_version: 4
95
- summary: xmpp-agent
109
+ summary: Uses the Xrc gem to build a simple XMPP client.
96
110
  test_files: []
metadata.gz.sig CHANGED
Binary file
data/lib/xmpp4r-simple.rb DELETED
@@ -1,494 +0,0 @@
1
- # Jabber::Simple - An extremely easy-to-use Jabber client library.
2
- # Copyright 2006 Blaine Cook <blaine@obvious.com>, Obvious Corp.
3
- #
4
- # Jabber::Simple is free software; you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation; either version 2 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # Jabber::Simple is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with Jabber::Simple; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
-
18
- require 'rubygems'
19
- require 'xmpp4r'
20
- require 'xmpp4r/roster'
21
- require 'xmpp4r/vcard'
22
-
23
- module Jabber
24
-
25
- class ConnectionError < StandardError #:nodoc:
26
- end
27
-
28
- class Contact #:nodoc:
29
-
30
- include DRb::DRbUndumped if defined?(DRb::DRbUndumped)
31
-
32
- def initialize(client, jid)
33
- @jid = jid.respond_to?(:resource) ? jid : JID.new(jid)
34
- @client = client
35
- end
36
-
37
- def inspect
38
- "Jabber::Contact #{jid.to_s}"
39
- end
40
-
41
- def subscribed?
42
- [:to, :both].include?(subscription)
43
- end
44
-
45
- def subscription
46
- roster_item && roster_item.subscription
47
- end
48
-
49
- def ask_for_authorization!
50
- subscription_request = Presence.new.set_type(:subscribe)
51
- subscription_request.to = jid
52
- client.send!(subscription_request)
53
- end
54
-
55
- def unsubscribe!
56
- unsubscription_request = Presence.new.set_type(:unsubscribe)
57
- unsubscription_request.to = jid
58
- client.send!(unsubscription_request)
59
- client.send!(unsubscription_request.set_type(:unsubscribed))
60
- end
61
-
62
- def jid(bare=true)
63
- bare ? @jid.strip : @jid
64
- end
65
-
66
- private
67
-
68
- def roster_item
69
- client.roster.items[jid]
70
- end
71
-
72
- def client
73
- @client
74
- end
75
- end
76
-
77
- class Simple
78
-
79
- include DRb::DRbUndumped if defined?(DRb::DRbUndumped)
80
-
81
- # Create a new Jabber::Simple client. You will be automatically connected
82
- # to the Jabber server and your status message will be set to the string
83
- # passed in as the status_message argument.
84
- #
85
- # jabber = Jabber::Simple.new("me@example.com", "password", "Chat with me - Please!")
86
- def initialize(jid, password, status = nil, status_message = "Available")
87
- @jid = jid
88
- @password = password
89
- @disconnected = false
90
- status(status, status_message)
91
- start_deferred_delivery_thread
92
- end
93
-
94
- def inspect #:nodoc:
95
- "Jabber::Simple #{@jid}"
96
- end
97
-
98
- # Send a message to jabber user jid.
99
- #
100
- # Valid message types are:
101
- #
102
- # * :normal (default): a normal message.
103
- # * :chat: a one-to-one chat message.
104
- # * :groupchat: a group-chat message.
105
- # * :headline: a "headline" message.
106
- # * :error: an error message.
107
- #
108
- # If the recipient is not in your contacts list, the message will be queued
109
- # for later delivery, and the Contact will be automatically asked for
110
- # authorization (see Jabber::Simple#add).
111
- #
112
- # message should be a string or a valid Jabber::Message object. In either case,
113
- # the message recipient will be set to jid.
114
- def deliver(jid, message, type=:chat)
115
- contacts(jid) do |friend|
116
- unless subscribed_to? friend
117
- add(friend.jid)
118
- return deliver_deferred(friend.jid, message, type)
119
- end
120
- if message.kind_of?(Jabber::Message)
121
- msg = message
122
- msg.to = friend.jid
123
- else
124
- msg = Message.new(friend.jid)
125
- msg.type = type
126
- msg.body = message
127
- end
128
- send!(msg)
129
- end
130
- end
131
-
132
- # Set your presence, with a message.
133
- #
134
- # Available values for presence are:
135
- #
136
- # * nil: online.
137
- # * :chat: free for chat.
138
- # * :away: away from the computer.
139
- # * :dnd: do not disturb.
140
- # * :xa: extended away.
141
- #
142
- # It's not possible to set an offline status - to do that, disconnect! :-)
143
- def status(presence, message)
144
- @presence = presence
145
- @status_message = message
146
- stat_msg = Presence.new(@presence, @status_message)
147
- send!(stat_msg)
148
- end
149
-
150
- # Ask the users specified by jids for authorization (i.e., ask them to add
151
- # you to their contact list). If you are already in the user's contact list,
152
- # add() will not attempt to re-request authorization. In order to force
153
- # re-authorization, first remove() the user, then re-add them.
154
- #
155
- # Example usage:
156
- #
157
- # jabber_simple.add("friend@friendosaurus.com")
158
- #
159
- # Because the authorization process might take a few seconds, or might
160
- # never happen depending on when (and if) the user accepts your
161
- # request, results are placed in the Jabber::Simple#new_subscriptions queue.
162
- def add(*jids)
163
- contacts(*jids) do |friend|
164
- next if subscribed_to? friend
165
- friend.ask_for_authorization!
166
- end
167
- end
168
-
169
- # Remove the jabber users specified by jids from the contact list.
170
- def remove(*jids)
171
- contacts(*jids) do |unfriend|
172
- unfriend.unsubscribe!
173
- end
174
- end
175
-
176
- # Returns true if this Jabber account is subscribed to status updates for
177
- # the jabber user jid, false otherwise.
178
- def subscribed_to?(jid)
179
- contacts(jid) do |contact|
180
- return contact.subscribed?
181
- end
182
- end
183
-
184
- # If contacts is a single contact, returns a Jabber::Contact object
185
- # representing that user; if contacts is an array, returns an array of
186
- # Jabber::Contact objects.
187
- #
188
- # When called with a block, contacts will yield each Jabber::Contact object
189
- # in turn. This is mainly used internally, but exposed as an utility
190
- # function.
191
- def contacts(*contacts, &block)
192
- @contacts ||= {}
193
- contakts = []
194
- contacts.each do |contact|
195
- jid = contact.to_s
196
- unless @contacts[jid]
197
- @contacts[jid] = contact.respond_to?(:ask_for_authorization!) ? contact : Contact.new(self, contact)
198
- end
199
- yield @contacts[jid] if block_given?
200
- contakts << @contacts[jid]
201
- end
202
- contakts.size > 1 ? contakts : contakts.first
203
- end
204
-
205
- # Returns true if the Jabber client is connected to the Jabber server,
206
- # false otherwise.
207
- def connected?
208
- @client ||= nil
209
- connected = @client.respond_to?(:is_connected?) && @client.is_connected?
210
- return connected
211
- end
212
-
213
- # Returns an array of messages received since the last time
214
- # received_messages was called. Passing a block will yield each message in
215
- # turn, allowing you to break part-way through processing (especially
216
- # useful when your message handling code is not thread-safe (e.g.,
217
- # ActiveRecord).
218
- #
219
- # e.g.:
220
- #
221
- # jabber.received_messages do |message|
222
- # puts "Received message from #{message.from}: #{message.body}"
223
- # end
224
- def received_messages(&block)
225
- dequeue(:received_messages, &block)
226
- end
227
-
228
- # Returns true if there are unprocessed received messages waiting in the
229
- # queue, false otherwise.
230
- def received_messages?
231
- !queue(:received_messages).empty?
232
- end
233
-
234
- # Returns an array of presence updates received since the last time
235
- # presence_updates was called. Passing a block will yield each update in
236
- # turn, allowing you to break part-way through processing (especially
237
- # useful when your presence handling code is not thread-safe (e.g.,
238
- # ActiveRecord).
239
- #
240
- # e.g.:
241
- #
242
- # jabber.presence_updates do |friend, new_presence|
243
- # puts "Received presence update from #{friend}: #{new_presence}"
244
- # end
245
- def presence_updates(&block)
246
- updates = []
247
- @presence_mutex.synchronize do
248
- dequeue(:presence_updates) do |friend|
249
- presence = @presence_updates[friend]
250
- next unless presence
251
- new_update = [friend, presence[0], presence[1]]
252
- yield new_update if block_given?
253
- updates << new_update
254
- @presence_updates.delete(friend)
255
- end
256
- end
257
- return updates
258
- end
259
-
260
- # Returns true if there are unprocessed presence updates waiting in the
261
- # queue, false otherwise.
262
- def presence_updates?
263
- !queue(:presence_updates).empty?
264
- end
265
-
266
- # Returns an array of subscription notifications received since the last
267
- # time new_subscriptions was called. Passing a block will yield each update
268
- # in turn, allowing you to break part-way through processing (especially
269
- # useful when your subscription handling code is not thread-safe (e.g.,
270
- # ActiveRecord).
271
- #
272
- # e.g.:
273
- #
274
- # jabber.new_subscriptions do |friend, presence|
275
- # puts "Received presence update from #{friend.to_s}: #{presence}"
276
- # end
277
- def new_subscriptions(&block)
278
- dequeue(:new_subscriptions, &block)
279
- end
280
-
281
- # Returns true if there are unprocessed presence updates waiting in the
282
- # queue, false otherwise.
283
- def new_subscriptions?
284
- !queue(:new_subscriptions).empty?
285
- end
286
-
287
- # Returns an array of subscription notifications received since the last
288
- # time subscription_requests was called. Passing a block will yield each update
289
- # in turn, allowing you to break part-way through processing (especially
290
- # useful when your subscription handling code is not thread-safe (e.g.,
291
- # ActiveRecord).
292
- #
293
- # e.g.:
294
- #
295
- # jabber.subscription_requests do |friend, presence|
296
- # puts "Received presence update from #{friend.to_s}: #{presence}"
297
- # end
298
- def subscription_requests(&block)
299
- dequeue(:subscription_requests, &block)
300
- end
301
-
302
- # Returns true if auto-accept subscriptions (friend requests) is enabled
303
- # (default), false otherwise.
304
- def accept_subscriptions?
305
- @accept_subscriptions = true if @accept_subscriptions.nil?
306
- @accept_subscriptions
307
- end
308
-
309
- # Change whether or not subscriptions (friend requests) are automatically accepted.
310
- def accept_subscriptions=(accept_status)
311
- @accept_subscriptions = accept_status
312
- end
313
-
314
- # Direct access to the underlying Roster helper.
315
- def roster
316
- return @roster if @roster
317
- self.roster = Roster::Helper.new(client)
318
- end
319
-
320
- # Direct access to the underlying Jabber client.
321
- def client
322
- connect!() unless connected?
323
- @client
324
- end
325
-
326
- # Send a Jabber stanza over-the-wire.
327
- def send!(msg)
328
- attempts = 0
329
- begin
330
- attempts += 1
331
- client.send(msg)
332
- rescue Errno::EPIPE, IOError => e
333
- sleep 1
334
- disconnect
335
- reconnect
336
- retry unless attempts > 3
337
- raise e
338
- rescue Errno::ECONNRESET => e
339
- sleep (attempts^2) * 60 + 60
340
- disconnect
341
- reconnect
342
- retry unless attempts > 3
343
- raise e
344
- end
345
- end
346
-
347
- # Use this to force the client to reconnect after a force_disconnect.
348
- def reconnect
349
- @disconnected = false
350
- connect!
351
- end
352
-
353
- # Use this to force the client to disconnect and not automatically
354
- # reconnect.
355
- def disconnect
356
- disconnect!
357
- end
358
-
359
- # Queue messages for delivery once a user has accepted our authorization
360
- # request. Works in conjunction with the deferred delivery thread.
361
- #
362
- # You can use this method if you want to manually add friends and still
363
- # have the message queued for later delivery.
364
- def deliver_deferred(jid, message, type)
365
- msg = {:to => jid, :message => message, :type => type}
366
- queue(:pending_messages) << [msg]
367
- end
368
-
369
- private
370
-
371
- def client=(client)
372
- self.roster = nil # ensure we clear the roster, since that's now associated with a different client.
373
- @client = client
374
- end
375
-
376
- def roster=(new_roster)
377
- @roster = new_roster
378
- end
379
-
380
- def connect!
381
- raise ConnectionError, "Connections are disabled - use Jabber::Simple::force_connect() to reconnect." if @disconnected
382
- # Pre-connect
383
- @connect_mutex ||= Mutex.new
384
-
385
- # don't try to connect if another thread is already connecting.
386
- return if @connect_mutex.locked?
387
-
388
- @connect_mutex.lock
389
- disconnect!(false) if connected?
390
-
391
- # Connect
392
- jid = JID.new(@jid)
393
- my_client = Client.new(@jid)
394
- my_client.connect
395
- my_client.auth(@password)
396
- self.client = my_client
397
-
398
- # Post-connect
399
- register_default_callbacks
400
- status(@presence, @status_message)
401
- @connect_mutex.unlock
402
- end
403
-
404
- def disconnect!(auto_reconnect = true)
405
- if client.respond_to?(:is_connected?) && client.is_connected?
406
- begin
407
- client.close
408
- rescue Errno::EPIPE, IOError => e
409
- # probably should log this.
410
- nil
411
- end
412
- end
413
- client = nil
414
- @disconnected = auto_reconnect
415
- end
416
-
417
- def register_default_callbacks
418
- client.add_message_callback do |message|
419
- queue(:received_messages) << message unless message.body.nil?
420
- end
421
-
422
- roster.add_subscription_callback do |roster_item, presence|
423
- if presence.type == :subscribed
424
- queue(:new_subscriptions) << [roster_item, presence]
425
- end
426
- end
427
-
428
- roster.add_subscription_request_callback do |roster_item, presence|
429
- if accept_subscriptions?
430
- roster.accept_subscription(presence.from)
431
- else
432
- queue(:subscription_requests) << [roster_item, presence]
433
- end
434
- end
435
-
436
- @presence_updates = {}
437
- @presence_mutex = Mutex.new
438
- roster.add_presence_callback do |roster_item, old_presence, new_presence|
439
- simple_jid = roster_item.jid.strip.to_s
440
- presence = case new_presence.type
441
- when nil
442
- new_presence.show || :online
443
- when :unavailable
444
- :unavailable
445
- else
446
- nil
447
- end
448
-
449
- if presence && @presence_updates[simple_jid] != presence
450
- queue(:presence_updates) << simple_jid
451
- @presence_mutex.synchronize { @presence_updates[simple_jid] = [presence, new_presence.status] }
452
- end
453
- end
454
- end
455
-
456
- # This thread facilitates the delivery of messages to users who haven't yet
457
- # accepted an invitation from us. When we attempt to deliver a message, if
458
- # the user hasn't subscribed, we place the message in a queue for later
459
- # delivery. Once a user has accepted our authorization request, we deliver
460
- # any messages that have been queued up in the meantime.
461
- def start_deferred_delivery_thread #:nodoc:
462
- Thread.new {
463
- loop {
464
- messages = [queue(:pending_messages).pop].flatten
465
- messages.each do |message|
466
- if subscribed_to?(message[:to])
467
- deliver(message[:to], message[:message], message[:type])
468
- else
469
- queue(:pending_messages) << message
470
- end
471
- end
472
- }
473
- }
474
- end
475
-
476
- def queue(queue)
477
- @queues ||= Hash.new { |h,k| h[k] = Queue.new }
478
- @queues[queue]
479
- end
480
-
481
- def dequeue(queue, non_blocking = true, max_items = 100, &block)
482
- queue_items = []
483
- max_items.times do
484
- queue_item = queue(queue).pop(non_blocking) rescue nil
485
- break if queue_item.nil?
486
- queue_items << queue_item
487
- yield queue_item if block_given?
488
- end
489
- queue_items
490
- end
491
- end
492
- end
493
-
494
- true