xmpp_simple 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8858b299fa6fee57b4a9aea3453a603d2a8171bd
4
+ data.tar.gz: be8e82a09dd4f06cd6c19e07b1f28924d9c5cb68
5
+ SHA512:
6
+ metadata.gz: c1b3c60f6452814965902387d6d3e1639973f4ef6e6555db7e121ede4310c34ddea6525045892c74f9d6326d2f0482cfda93994d17b95f91b87fc604b311d710
7
+ data.tar.gz: 58d7bc1137044750b75a2f2713a1d5007dab973191ee84834b99cc5f9d5080f4a3c5960804cf835a1af5dabd6b5d0eea358cb030447b07e9b77581e52a3bccdb
@@ -0,0 +1,33 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /vendor/bundle
26
+ /lib/bundler/man/
27
+
28
+ Gemfile.lock
29
+ .ruby-version
30
+ .ruby-gemset
31
+
32
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
33
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,9 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'vendor/**/*'
4
+ LineLength:
5
+ Max: 120
6
+ MethodLength:
7
+ Max: 15
8
+ Documentation:
9
+ Enabled: false
@@ -0,0 +1 @@
1
+ SimpleCov.start
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,11 @@
1
+ guard :rspec, cmd: 'bundle exec rspec' do
2
+ # watch /lib/ files
3
+ watch(%r{^lib/(.+).rb$}) do |m|
4
+ "spec/#{m[1]}_spec.rb"
5
+ end
6
+
7
+ # watch /spec/ files
8
+ watch(%r{^spec/(.+).rb$}) do |m|
9
+ "spec/#{m[1]}.rb"
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 l3akage
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,59 @@
1
+ # XmppSimple
2
+
3
+ A simle xmpp implementation using celluloid
4
+ intended to work with https://github.com/pushwerk/ccs
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'xmpp_simple', git: 'https://github.com/pushwerk/xmpp_simple.git'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ ## Usage
17
+
18
+ ```
19
+ class XMPPConnection
20
+ def initialize
21
+ xmpp_params = {
22
+ handler: self,
23
+ username: 'foobar',
24
+ password: 's3cr3t',
25
+ host: 'jabber.example.com',
26
+ port: 5222
27
+ }
28
+ @xmpp_client = XMPPSimple::Client.new(xmpp_params).connect
29
+ end
30
+
31
+ def send(xml)
32
+ @xmpp_client.write_data(xml)
33
+ end
34
+
35
+ # methods called by XMPPSimple
36
+ def message(node)
37
+ puts "received #{node.inspect}"
38
+ end
39
+
40
+ def disconnected
41
+ puts 'disconnected'
42
+ end
43
+
44
+ def connected
45
+ puts 'connected'
46
+ end
47
+ end
48
+ ```
49
+
50
+ ## TODO
51
+ * Probably more tests
52
+
53
+ ## Contributing
54
+
55
+ 1. Fork it ( https://github.com/pushwerk/xmpp_simple/fork )
56
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
57
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
58
+ 4. Push to the branch (`git push origin my-new-feature`)
59
+ 5. Create a new Pull Request
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,30 @@
1
+ require 'celluloid/io'
2
+ require 'nokogiri'
3
+
4
+ require 'xmpp_simple/stanzas/base_stanza'
5
+ require 'xmpp_simple/stanzas/auth_mechanism'
6
+ require 'xmpp_simple/stanzas/plain_auth'
7
+ require 'xmpp_simple/stanzas/message'
8
+ require 'xmpp_simple/stanzas/iq'
9
+ require 'xmpp_simple/stanzas/bind'
10
+
11
+ require 'xmpp_simple/client'
12
+ require 'xmpp_simple/parser'
13
+ require 'xmpp_simple/node'
14
+ require 'xmpp_simple/jid'
15
+
16
+ require 'xmpp_simple/version'
17
+
18
+ module XMPPSimple
19
+ module_function
20
+
21
+ def logger=(value)
22
+ @logger = value
23
+ end
24
+
25
+ def logger
26
+ @logger ||= Logger.new($stdout).tap do |log|
27
+ log.level = Logger::ERROR
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,120 @@
1
+ module XMPPSimple
2
+ class Client
3
+ include Celluloid::IO
4
+ finalizer :finalize
5
+
6
+ def initialize(params = {})
7
+ unless [:username, :password, :host, :port].all? { |s| params.key?(s) && params[s] }
8
+ raise 'username, password, host and port must be set'
9
+ end
10
+ @username = Jid.new(params[:username], params[:host])
11
+ @password = params[:password]
12
+ @host = params[:host]
13
+ @port = params[:port]
14
+ @handler = params[:handler]
15
+ end
16
+
17
+ def connect
18
+ XMPPSimple.logger.info "Connecting to #{@host}:#{@port}"
19
+ raw_socket = Celluloid::IO::TCPSocket.new(@host, @port)
20
+ @socket = Celluloid::IO::SSLSocket.new(raw_socket).connect
21
+ start
22
+ async.run
23
+ self
24
+ end
25
+
26
+ def disconnect
27
+ write_data close_stream_xml
28
+ end
29
+
30
+ def start
31
+ @parser = Parser.new(self)
32
+ write_data open_stream_xml
33
+ end
34
+
35
+ def reconnect
36
+ finalize
37
+ connect
38
+ end
39
+
40
+ def process(node)
41
+ XMPPSimple.logger.debug "Process: #{node}"
42
+ return unless respond_to?(node.name)
43
+ return unless %w(features success message iq).include?(node.name)
44
+ send(node.name, node)
45
+ end
46
+
47
+ def write_data(xml)
48
+ xml = xml.respond_to?(:to_xml) ? xml.to_xml : xml
49
+ XMPPSimple.logger.debug "Sending: #{xml}"
50
+ @socket.write xml
51
+ end
52
+
53
+ def features(node)
54
+ XMPPSimple.logger.debug "Features: #{node.class}"
55
+ if node.at('/features/bind:bind', 'bind' => 'urn:ietf:params:xml:ns:xmpp-bind')
56
+ write_data Bind.create
57
+ elsif node.at('/features/sasl:mechanisms', 'sasl' => 'urn:ietf:params:xml:ns:xmpp-sasl')
58
+ authenticate(node)
59
+ end
60
+ end
61
+
62
+ def authenticate(node)
63
+ mechanisms = node.xpath('/features/sasl:mechanisms/sasl:mechanism',
64
+ 'sasl' => 'urn:ietf:params:xml:ns:xmpp-sasl')
65
+ if mechanisms.any? { |m| m.inner_text == 'PLAIN' }
66
+ write_data PlainAuth.create(@username, @password)
67
+ else
68
+ XMPPSimple.logger.info 'No authentication method provided'
69
+ disconnect
70
+ end
71
+ end
72
+
73
+ def success(_node)
74
+ start
75
+ end
76
+
77
+ def message(node)
78
+ @handler.message(node.to_xml) if @handler.respond_to? :message
79
+ end
80
+
81
+ def iq(node)
82
+ XMPPSimple.logger.debug "Iq: #{node.inspect}"
83
+ return unless node.at('/iq/bind:bind', 'bind' => 'urn:ietf:params:xml:ns:xmpp-bind')
84
+ XMPPSimple.logger.debug 'Connected!'
85
+ @handler.connected if @handler.respond_to? :connected
86
+ end
87
+
88
+ def run
89
+ loop { @parser << @socket.readpartial(4096) }
90
+ rescue EOFError
91
+ XMPPSimple.logger.debug 'Socket disconnected'
92
+ @handler.disconnected if @handler.respond_to? :disconnected
93
+ rescue => e
94
+ XMPPSimple.logger.debug "Error: #{e}"
95
+ @handler.disconnected if @handler.respond_to? :disconnected
96
+ end
97
+
98
+ def finalize
99
+ return unless defined? @socket
100
+ return if @socket.nil?
101
+ disconnect
102
+ @socket.close
103
+ end
104
+
105
+ def open_stream_xml
106
+ <<-XML
107
+ <stream:stream
108
+ xmlns:stream='http://etherx.jabber.org/streams'
109
+ xmlns='jabber:client'
110
+ to='#{@host}'
111
+ xml:lang='en'
112
+ version='1.0'>
113
+ XML
114
+ end
115
+
116
+ def close_stream_xml
117
+ '</stream>'
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,19 @@
1
+ module XMPPSimple
2
+ class Jid
3
+ attr_reader :username, :domain
4
+
5
+ def initialize(username, host = nil)
6
+ if username.to_s.include?('@')
7
+ @username, @domain = username.split('@')
8
+ else
9
+ raise 'set either host or username@host' if host.nil?
10
+ @username = username
11
+ @domain = host
12
+ end
13
+ end
14
+
15
+ def to_s
16
+ "#{@username}@#{@domain}"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module XMPPSimple
2
+ class Node < Nokogiri::XML::Node
3
+ def self.new(name = '', attrs = [], ns = [], doc = Nokogiri::XML::Document.new)
4
+ return if name.nil? || name.empty?
5
+ node = super(name, doc)
6
+ attrs.each { |a| node[a.localname] = a.value }
7
+ ns.each { |p, u| node.add_namespace(p, u) }
8
+ node
9
+ end
10
+
11
+ def at(*args)
12
+ document.root = self
13
+ document.at(*args)
14
+ end
15
+
16
+ def xpath(*args)
17
+ document.root = self
18
+ document.xpath(*args)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ module XMPPSimple
2
+ class Parser < Nokogiri::XML::SAX::Document
3
+ def initialize(client)
4
+ @parser = Nokogiri::XML::SAX::PushParser.new self
5
+ @client = client
6
+ @current = nil
7
+ end
8
+
9
+ def <<(data)
10
+ @parser << data
11
+ self
12
+ rescue Nokogiri::XML::SyntaxError => e
13
+ @parser = Nokogiri::XML::SAX::PushParser.new self
14
+ @current = nil
15
+ XMPPSimple.logger.error e.message
16
+ end
17
+
18
+ def start_element_namespace(name, attrs = [], prefix = nil, uri = nil, ns = [])
19
+ params = { name: name, attrs: attrs, prefix: prefix, uri: uri, ns: ns }
20
+ XMPPSimple.logger.debug "Parse start elem: #{params.inspect}"
21
+ return if name == 'stream'
22
+ doc = @current.nil? ? Nokogiri::XML::Document.new : @current.document
23
+ node = Node.new(name, attrs, ns, doc)
24
+ @current << node if @current
25
+ @current = node
26
+ end
27
+
28
+ def end_element_namespace(name, prefix = nil, uri = nil)
29
+ params = { name: name, prefix: prefix, uri: uri }
30
+ XMPPSimple.logger.debug "Parse end elem: #{params.inspect}"
31
+ return if name == 'stream'
32
+ if @current.parent
33
+ @current = @current.parent
34
+ return
35
+ end
36
+ process(@current)
37
+ end
38
+
39
+ def characters(chars = '')
40
+ XMPPSimple.logger.debug "Parse chars: #{chars}"
41
+ @current << Nokogiri::XML::Text.new(chars, @current.document) if @current
42
+ end
43
+
44
+ def process(node)
45
+ @current = nil
46
+ @client.process(node)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,12 @@
1
+ module XMPPSimple
2
+ class AuthMechanism < BaseStanza
3
+ NAME = 'auth'.freeze
4
+
5
+ def self.create
6
+ super()
7
+ @node.add_namespace(nil, 'urn:ietf:params:xml:ns:xmpp-sasl')
8
+ @node['mechanism'] = self::MECHANISM
9
+ @node
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module XMPPSimple
2
+ class BaseStanza
3
+ def self.create
4
+ @node = Node.new(self::NAME)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ module XMPPSimple
2
+ class Bind < Iq
3
+ def self.create
4
+ super()
5
+ bind = Nokogiri::XML::Node.new('bind', @node.document)
6
+ bind.add_namespace(nil, 'urn:ietf:params:xml:ns:xmpp-bind')
7
+ @node << bind
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module XMPPSimple
2
+ class Iq < BaseStanza
3
+ NAME = 'iq'.freeze
4
+
5
+ def self.create
6
+ super()
7
+ @node['id'] = 'bind_1'
8
+ @node['type'] = 'set'
9
+ @node
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module XMPPSimple
2
+ class Message < BaseStanza
3
+ NAME = 'message'.freeze
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module XMPPSimple
2
+ class PlainAuth < AuthMechanism
3
+ MECHANISM = 'PLAIN'.freeze
4
+
5
+ def self.create(jid, password)
6
+ super()
7
+ @node.content = ["\x00#{jid}\x00#{password}"].pack('m').tr("\n", '')
8
+ @node
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module XMPPSimple
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'xmpp_simple/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'xmpp_simple'
8
+ spec.version = XMPPSimple::VERSION
9
+ spec.authors = ['l3akage']
10
+ spec.email = ['info@l3akage.de']
11
+
12
+ spec.homepage = 'https://github.com/pushwerk/xmpp_simple'
13
+ spec.summary = 'Simple XMPP implementation'
14
+ spec.description = 'A simle xmpp implementation using celluloid'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(/^(test|spec|features)/)
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.required_ruby_version = '>= 2.0.0'
23
+
24
+ spec.add_dependency 'celluloid-io', '~> 0.17.3'
25
+ spec.add_dependency 'nokogiri', '~> 1.6'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1.11'
28
+ spec.add_development_dependency 'rake', '~> 11.1'
29
+ spec.add_development_dependency 'rspec', '~> 3.4'
30
+ spec.add_development_dependency 'equivalent-xml', '~> 0.6'
31
+ spec.add_development_dependency 'guard', '~> 2.13'
32
+ spec.add_development_dependency 'guard-rspec', '~> 4.6'
33
+ spec.add_development_dependency 'simplecov', '~> 0.11'
34
+ end
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xmpp_simple
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - l3akage
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: celluloid-io
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.17.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.17.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.11'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.11'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '11.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '11.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.4'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: equivalent-xml
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.6'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.13'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.13'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '4.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '4.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.11'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.11'
139
+ description: A simle xmpp implementation using celluloid
140
+ email:
141
+ - info@l3akage.de
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".rspec"
148
+ - ".rubocop.yml"
149
+ - ".simplecov"
150
+ - Gemfile
151
+ - Guardfile
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - lib/xmpp_simple.rb
156
+ - lib/xmpp_simple/client.rb
157
+ - lib/xmpp_simple/jid.rb
158
+ - lib/xmpp_simple/node.rb
159
+ - lib/xmpp_simple/parser.rb
160
+ - lib/xmpp_simple/stanzas/auth_mechanism.rb
161
+ - lib/xmpp_simple/stanzas/base_stanza.rb
162
+ - lib/xmpp_simple/stanzas/bind.rb
163
+ - lib/xmpp_simple/stanzas/iq.rb
164
+ - lib/xmpp_simple/stanzas/message.rb
165
+ - lib/xmpp_simple/stanzas/plain_auth.rb
166
+ - lib/xmpp_simple/version.rb
167
+ - xmpp_simple.gemspec
168
+ homepage: https://github.com/pushwerk/xmpp_simple
169
+ licenses:
170
+ - MIT
171
+ metadata: {}
172
+ post_install_message:
173
+ rdoc_options: []
174
+ require_paths:
175
+ - lib
176
+ required_ruby_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: 2.0.0
181
+ required_rubygems_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ requirements: []
187
+ rubyforge_project:
188
+ rubygems_version: 2.5.1
189
+ signing_key:
190
+ specification_version: 4
191
+ summary: Simple XMPP implementation
192
+ test_files: []