jabber4r-revive 0.9.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.
@@ -0,0 +1,42 @@
1
+ # License: see LICENSE.txt
2
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
3
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
4
+ #
5
+
6
+
7
+ module Jabber
8
+
9
+ ##
10
+ # The VCard class holds the parsed VCard data from the Jabber service.
11
+ #
12
+ class VCard
13
+ attr_accessor :given, :family, :middle, :nickname, :email
14
+
15
+ ##
16
+ # Factory to create the VCard from the ParsedXMLElement
17
+ #
18
+ # je:: [ParsedXMLElement] The VCard as an xml element.
19
+ # return:: [Jabber::VCard] The newly created VCard.
20
+ #
21
+ def VCard.from_element(je)
22
+ card = VCard.new
23
+ return card unless je
24
+ card.given = je.N.GIVEN.element_data
25
+ card.family = je.N.FAMILY.element_data
26
+ card.middle = je.N.MIDDLE.element_data
27
+ card.email = je.EMAIL.element_data
28
+ card.nickname = je.NICKNAME.element_data
29
+ return card
30
+ end
31
+
32
+ ##
33
+ # Dumps the attributes of the VCard
34
+ #
35
+ # return:: [String] The VCard as a string.
36
  #
37
+ def to_s
38
+ "VCARD: [first=#{@given} last=#{@family} nick=#{@nickname} email=#{@email}]"
39
+ end
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,3 @@
1
+ module Jabber
2
+ VERSION = "0.9.0"
3
+ end
data/lib/jabber4r.rb ADDED
@@ -0,0 +1,33 @@
1
+ # License: see LICENSE.txt
2
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
3
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
4
+
5
+
6
+ # The Jabber module is the main namespace for all Jabber modules
7
+ # and classes.
8
+ module Jabber
9
+ DEBUG = false
10
+
11
+ # Public: Should raise if connection was force closed
12
+ class ConnectionForceCloseError < StandardError; end
13
+
14
+ # Public: Should raise if received XML data is malformed
15
+ class XMLMalformedError < StandardError; end
16
+
17
+ # Public: Should raise if authentication failed
18
+ class AuthenticationError < StandardError; end
19
+ end
20
+
21
+ require "jabber4r/debugger"
22
+ require "jabber4r/session"
23
+ require "jabber4r/bosh_session"
24
+ require "jabber4r/protocol"
25
+ require "jabber4r/connection"
26
+ require "jabber4r/protocol/iq"
27
+ require "jabber4r/protocol/presence"
28
+ require "jabber4r/protocol/message"
29
+ require "jabber4r/protocol/xml_element"
30
+ require "jabber4r/protocol/parsed_xml_element"
31
+ require "jabber4r/roster"
32
+ require "jabber4r/jid"
33
+ require "jabber4r/vcard"
@@ -0,0 +1,150 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Jabber::BoshSession do
5
+ let(:successful_login) { '<body xmlns="http://jabber.org/protocol/httpbind"><iq type="result" xmlns="jabber:client" id="2034"/></body>' }
6
+ let(:successful_open_stream) do
7
+ [
8
+ '<body xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" xmlns:stream="http://etherx.jabber.org/streams"',
9
+ 'authid="3780309894" sid="ce21410" from="localhost"',
10
+ 'wait="60" requests="2" inactivity="30" maxpause="120" polling="2" ver="1.8" secure="true" />'
11
+ ].join " "
12
+ end
13
+ let(:is_open_stream?) { ->(data) { x = Ox.parse(data); ["1", "localhost"] == [x[:rid], x[:to]] } }
14
+ let(:is_login?) { ->(data) { x = Ox.parse(data); ["1", "ce21410"] == [x[:rid], x[:sid]] } }
15
+ let(:bosh_session) { described_class.bind("strech@localhost/resource", "password") }
16
+
17
+ before { Jabber::BoshSession.any_instance.stub(:generate_next_rid).and_return "1" }
18
+
19
+ describe "#bind" do
20
+ context "when session successfuly binded" do
21
+ before do
22
+ stub_request(:post, "http://localhost:5280/http-bind")
23
+ .with(body: is_open_stream?)
24
+ .to_return(body: successful_open_stream)
25
+
26
+ stub_request(:post, "http://localhost:5280/http-bind")
27
+ .with(body: is_login?)
28
+ .to_return(body: successful_login)
29
+ end
30
+
31
+ it { expect(bosh_session).to be_alive }
32
+ end
33
+
34
+ context "when couldn't open stream" do
35
+ context "when response body missed authid attribute" do
36
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind" sid="ce21410" />' }
37
+
38
+ before do
39
+ stub_request(:post, "http://localhost:5280/http-bind")
40
+ .with(body: is_open_stream?)
41
+ .to_return(body: malformed_body)
42
+
43
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
44
+ .with(body: is_login?)
45
+ end
46
+
47
+ it { expect { bosh_session }.to raise_error Jabber::XMLMalformedError, "Couldn't find <body /> attribute [authid]" }
48
+ end
49
+
50
+ context "when response body missed sid attribute" do
51
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind" authid="3780309894" />' }
52
+
53
+ before do
54
+ stub_request(:post, "http://localhost:5280/http-bind")
55
+ .with(body: is_open_stream?)
56
+ .to_return(body: malformed_body)
57
+
58
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
59
+ .with(body: is_login?)
60
+ end
61
+
62
+ it { expect { bosh_session }.to raise_error Jabber::XMLMalformedError, "Couldn't find <body /> attribute [sid]" }
63
+ end
64
+
65
+ context "when response was not 200 OK" do
66
+ before do
67
+ stub_request(:post, "http://localhost:5280/http-bind")
68
+ .with(body: is_open_stream?)
69
+ .to_return(body: "Foo", status: 401)
70
+
71
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
72
+ .with(body: is_login?)
73
+ end
74
+
75
+ it { expect { bosh_session }.to raise_error Net::HTTPBadResponse }
76
+ end
77
+ end
78
+
79
+ context "when couldn't login in opened stream" do
80
+ context "when response is a malformed xml without IQ tag" do
81
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind"></body>' }
82
+
83
+ before do
84
+ stub_request(:post, "http://localhost:5280/http-bind")
85
+ .with(body: is_open_stream?)
86
+ .to_return(body: successful_open_stream)
87
+
88
+ stub_request(:post, "http://localhost:5280/http-bind")
89
+ .with(body: is_login?)
90
+ .to_return(body: malformed_body)
91
+ end
92
+
93
+ it { expect { bosh_session }.to raise_error Jabber::XMLMalformedError, "Couldn't find xml tag <iq/>" }
94
+ end
95
+
96
+ context "when response has type not equal 'result'" do
97
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind"><iq type="error" xmlns="jabber:client" id="2034"/></body>' }
98
+
99
+ before do
100
+ stub_request(:post, "http://localhost:5280/http-bind")
101
+ .with(body: is_open_stream?)
102
+ .to_return(body: successful_open_stream)
103
+
104
+ stub_request(:post, "http://localhost:5280/http-bind")
105
+ .with(body: is_login?)
106
+ .to_return(body: malformed_body)
107
+ end
108
+
109
+ it { expect { bosh_session }.to raise_error Jabber::AuthenticationError, "Failed to login" }
110
+ end
111
+
112
+ context "when response was not 200 OK" do
113
+ before do
114
+ stub_request(:post, "http://localhost:5280/http-bind")
115
+ .with(body: is_open_stream?)
116
+ .to_return(body: successful_open_stream)
117
+
118
+ stub_request(:post, "http://localhost:5280/http-bind")
119
+ .with(body: is_login?)
120
+ .to_return(body: "Foo", status: 401)
121
+ end
122
+
123
+ it { expect { bosh_session }.to raise_error Net::HTTPBadResponse }
124
+ end
125
+ end
126
+ end
127
+
128
+ describe "#to_json" do
129
+ let(:json) { JSON.parse(bosh_session.to_json) }
130
+
131
+ before do
132
+ stub_request(:post, "http://localhost:5280/http-bind")
133
+ .with(body: is_open_stream?)
134
+ .to_return(body: successful_open_stream)
135
+
136
+
137
+ stub_request(:post, "http://localhost:5280/http-bind")
138
+ .with(body: is_login?)
139
+ .to_return(body: successful_login)
140
+ end
141
+
142
+ it { expect(json).to have_key "jid" }
143
+ it { expect(json).to have_key "rid" }
144
+ it { expect(json).to have_key "sid" }
145
+
146
+ it { expect(json["jid"]).to eq "strech@localhost/resource"}
147
+ it { expect(json["rid"]).to eq "1"}
148
+ it { expect(json["sid"]).to eq "ce21410"}
149
+ end
150
+ end
@@ -0,0 +1,174 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Jabber::Connection do
5
+ let(:socket) { TCPSocketMock.new }
6
+ let(:connection) { described_class.new "localhost" }
7
+
8
+ before { TCPSocket.stub(:new).and_return socket }
9
+
10
+ describe "#connect" do
11
+ before { connection.connect }
12
+
13
+ it { expect(connection).to be_connected }
14
+ it { expect(connection.poll_thread).to be_alive }
15
+ it { expect(connection.parser_thread).to be_alive }
16
+ it { expect(connection.socket).not_to be_closed }
17
+ end
18
+
19
+ describe "#close" do
20
+ before { connection.connect }
21
+ before { connection.close; sleep 0.01 }
22
+
23
+ it { expect(connection).to be_disconnected }
24
+ it { expect(connection.poll_thread).not_to be_alive }
25
+ it { expect(connection.parser_thread).not_to be_alive }
26
+ it { expect(connection.socket).to be_closed }
27
+ end
28
+
29
+ describe "#add_filter" do
30
+ context "when filter name and block is given" do
31
+ before { connection.add_filter("hello") { 1 } }
32
+
33
+ it { expect(connection.filters).to have_key "hello" }
34
+ end
35
+
36
+ context "when only filter name give" do
37
+ it { expect { connection.add_filter("hello") }.to raise_error ArgumentError }
38
+ end
39
+ end
40
+
41
+ describe "#remove_filter" do
42
+ before { connection.add_filter("hello") { 1 } }
43
+ it { expect(connection.filters).to have_key "hello" }
44
+
45
+ it "should remove filter" do
46
+ connection.remove_filter("hello")
47
+ expect(connection.filters).not_to have_key "hello"
48
+ end
49
+ end
50
+
51
+ describe "#send" do
52
+ let(:handler) { proc { 1 } }
53
+
54
+ before { connection.connect }
55
+ before { Thread.stub(:current).and_return "current" }
56
+
57
+ context "when own handler is given" do
58
+ before { connection.send("hello", handler) }
59
+
60
+ it { expect(connection.handlers).to have_key "current" }
61
+ it { expect(connection.handlers["current"]).to eq handler }
62
+
63
+ describe "socket" do
64
+ it { expect(socket.to_s).to eq "hello" }
65
+ end
66
+ end
67
+
68
+ context "when only block is given" do
69
+ before { connection.send("hello") { 1 } }
70
+
71
+ it { expect(connection.handlers).to have_key "current" }
72
+ end
73
+
74
+ context "when handler and block are given" do
75
+ before { connection.send("hello", handler) { 1 } }
76
+
77
+ it { expect(connection.handlers).to have_key "current" }
78
+ it { expect(connection.handlers["current"]).to eq handler }
79
+ end
80
+
81
+ context "when no handlers and block are given" do
82
+ before { connection.send("hello") }
83
+
84
+ it { expect(connection.handlers).to be_empty }
85
+ end
86
+ end
87
+
88
+ describe "#receive" do
89
+ let(:thread) { double("Pseudo thread", alive?: true) }
90
+ let(:element) { double("XML Element", element_consumed?: false) }
91
+
92
+ let(:consume) { ->(element) { element.stub(:element_consumed?).and_return true } }
93
+ let(:skip) { ->(element) { element.stub(:element_consumed?).and_return false } }
94
+
95
+ before { connection.stub :register_parsing_thread }
96
+ before { connection.stub :register_polling_thread }
97
+
98
+ context "when handlers are not empty" do
99
+ context "when filters are empty" do
100
+ before do
101
+ thread.should_receive(:wakeup)
102
+ connection.stub(:handlers).and_return({thread => consume})
103
+
104
+ connection.receive(element)
105
+ end
106
+
107
+ it { expect(connection.handlers).to be_empty }
108
+ it { expect(connection.filters).to be_empty }
109
+ end
110
+
111
+ context "when filters are not empty" do
112
+ context "when handler consume element" do
113
+ before do
114
+ thread.should_receive(:wakeup)
115
+ skip.should_not_receive(:call)
116
+
117
+ connection.stub(:handlers).and_return({thread => consume})
118
+ connection.stub(:filters).and_return({f1: skip})
119
+
120
+ connection.receive(element)
121
+ end
122
+
123
+ it { expect(connection.handlers).to be_empty }
124
+ it { expect(connection.filters).not_to be_empty }
125
+ end
126
+
127
+ context "when handler doesn't consume element" do
128
+ before do
129
+ thread.should_not_receive(:wakeup)
130
+ consume.should_receive(:call).and_call_original
131
+
132
+ connection.stub(:handlers).and_return({thread => skip})
133
+ connection.stub(:filters).and_return({f1: consume})
134
+
135
+ connection.receive(element)
136
+ end
137
+
138
+ it { expect(connection.handlers).not_to be_empty }
139
+ it { expect(connection.filters).not_to be_empty }
140
+ end
141
+ end
142
+ end
143
+
144
+ context "when handlers are empty" do
145
+ context "when filters are empty" do
146
+ before do
147
+ thread.should_not_receive(:wakeup)
148
+ connection.should_receive(:wait_for_consume?).and_return false
149
+
150
+ connection.receive(element)
151
+ end
152
+
153
+ it { expect(connection.handlers).to be_empty }
154
+ it { expect(connection.filters).to be_empty }
155
+ end
156
+
157
+ context "when filters are not empty" do
158
+ before do
159
+ thread.should_not_receive(:wakeup)
160
+ consume.should_receive(:call).and_call_original
161
+
162
+ connection.stub(:filters).and_return({f1: consume})
163
+
164
+ connection.receive(element)
165
+ end
166
+
167
+ it { expect(connection.handlers).to be_empty }
168
+ it { expect(connection.filters).not_to be_empty }
169
+ end
170
+ end
171
+
172
+ # TODO : When socket is empty?
173
+ end
174
+ end
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Jabber::Debugger do
5
+ let(:debugger) { described_class.clone.instance }
6
+ before { described_class.stub(:instance).and_return debugger }
7
+
8
+ describe "#initialize" do
9
+ it { expect(described_class).not_to be_enabled }
10
+ end
11
+
12
+ describe "#enable" do
13
+ before { described_class.enable! }
14
+
15
+ it { expect(described_class).to be_enabled }
16
+ end
17
+
18
+ describe "#disable" do
19
+ before { described_class.disable! }
20
+
21
+ it { expect(described_class).not_to be_enabled }
22
+ end
23
+
24
+ describe "#logger=" do
25
+ let(:logger) { double("Logger") }
26
+
27
+ before { described_class.logger = logger }
28
+ it { expect(debugger.logger).to eq logger }
29
+ end
30
+
31
+ describe "generated methods" do
32
+ it { expect(described_class).to respond_to :warn }
33
+ it { expect(described_class).to respond_to :info }
34
+ it { expect(described_class).to respond_to :debug }
35
+ end
36
+ end
@@ -0,0 +1,198 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Jabber::JID do
5
+ describe "#initialize" do
6
+ context "when need parse jid from string" do
7
+ context "when only node given" do
8
+ it { expect { described_class.new "user" }.to raise_error ArgumentError }
9
+ end
10
+
11
+ context "when node and host given" do
12
+ subject { described_class.new "user@localhost" }
13
+
14
+ its(:node) { should eq "user" }
15
+ its(:host) { should eq "localhost" }
16
+ its(:resource) { should be_nil }
17
+ end
18
+
19
+ context "when node, host and resource given" do
20
+ subject { described_class.new "user@localhost/attach" }
21
+
22
+ its(:node) { should eq "user" }
23
+ its(:host) { should eq "localhost" }
24
+ its(:resource) { should eq "attach" }
25
+ end
26
+
27
+ context "when empty string given" do
28
+ it { expect { described_class.new "" }.to raise_error ArgumentError }
29
+ end
30
+ end
31
+
32
+ context "when extra arguments given" do
33
+ context "when only host given" do
34
+ subject { described_class.new "user", "localhost" }
35
+
36
+ its(:node) { should eq "user" }
37
+ its(:host) { should eq "localhost" }
38
+ end
39
+
40
+ context "when host and resource given" do
41
+ subject { described_class.new "user", "localhost", "attach" }
42
+
43
+ its(:node) { should eq "user" }
44
+ its(:host) { should eq "localhost" }
45
+ its(:resource) { should eq "attach" }
46
+ end
47
+
48
+ context "when node is fully loaded and host, resource given" do
49
+ subject { described_class.new "user@example.com/bind", "localhost", "attach" }
50
+
51
+ its(:node) { should eq "user" }
52
+ its(:host) { should eq "localhost" }
53
+ its(:resource) { should eq "attach" }
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#strip" do
59
+ subject { described_class.new(args).strip }
60
+
61
+ context "when JID has no resource" do
62
+ let(:args) { "strech@localhost" }
63
+
64
+ its(:to_s) { should eq "strech@localhost" }
65
+ end
66
+
67
+ context "when JID has no resource" do
68
+ let(:args) { "strech@localhost/pewpew" }
69
+
70
+ its(:to_s) { should eq "strech@localhost" }
71
+ end
72
+ end
73
+
74
+ describe "#strip!" do
75
+ subject { described_class.new(args).strip! }
76
+
77
+ context "when JID has no resource" do
78
+ let(:args) { "strech@localhost" }
79
+
80
+ its(:to_s) { should eq "strech@localhost" }
81
+ its(:resource) { should be_nil }
82
+ end
83
+
84
+ context "when JID has no resource" do
85
+ let(:args) { "strech@localhost/pewpew" }
86
+
87
+ its(:to_s) { should eq "strech@localhost" }
88
+ its(:resource) { should be_nil }
89
+ end
90
+ end
91
+
92
+ describe "#hash" do
93
+ let(:hash) { "strech@pewpew/one".hash }
94
+ subject { described_class.new "strech@pewpew/one" }
95
+
96
+ its(:hash) { should eq hash }
97
+ end
98
+
99
+ describe "#to_s" do
100
+ context "when only host and domain exists" do
101
+ subject { described_class.new("strech", "localhost").to_s }
102
+
103
+ it { should eq "strech@localhost" }
104
+ end
105
+
106
+ context "when only host and domain exists" do
107
+ subject { described_class.new("strech", "localhost", "attach-resource").to_s }
108
+
109
+ it { should eq "strech@localhost/attach-resource" }
110
+ end
111
+ end
112
+
113
+ describe "#==" do
114
+ subject { jid1 == jid2 }
115
+
116
+ context "when jids are equal" do
117
+ let(:jid1) { described_class.new "strech@localhost" }
118
+ let(:jid2) { described_class.new "strech@localhost" }
119
+
120
+ it { should be_true }
121
+ end
122
+
123
+ context "when jids are not equal" do
124
+ let(:jid1) { described_class.new "strech@localhost" }
125
+ let(:jid2) { described_class.new "strech@localhost/resource1" }
126
+
127
+ it { should be_false }
128
+ end
129
+ end
130
+
131
+ describe "#same?" do
132
+ subject { jid1.same? jid2 }
133
+
134
+ context "when jids are equal" do
135
+ context "when jid1 and jid2 has no resource" do
136
+ let(:jid1) { described_class.new "strech@localhost" }
137
+ let(:jid2) { described_class.new "strech@localhost" }
138
+
139
+ it { should be_true }
140
+ end
141
+
142
+ context "when jid1 has resource, but jid2 not" do
143
+ let(:jid1) { described_class.new "strech@localhost/pewpew" }
144
+ let(:jid2) { described_class.new "strech@localhost" }
145
+
146
+ it { should be_true }
147
+ end
148
+
149
+ context "when jid1 and jid2 has resources" do
150
+ let(:jid1) { described_class.new "strech@localhost/pewpew" }
151
+ let(:jid2) { described_class.new "strech@localhost/hola" }
152
+
153
+ it { should be_true }
154
+ end
155
+ end
156
+
157
+ context "when jids are not equal" do
158
+ context "when jid1 and jid2 has no resource" do
159
+ let(:jid1) { described_class.new "strech@localhost" }
160
+ let(:jid2) { described_class.new "strech@gmail.com" }
161
+
162
+ it { should be_false }
163
+ end
164
+
165
+ context "when jid1 has resource, but jid2 not" do
166
+ let(:jid1) { described_class.new "strech@localhost/pewpew" }
167
+ let(:jid2) { described_class.new "strech@gmail.com" }
168
+
169
+ it { should be_false }
170
+ end
171
+
172
+ context "when jid1 and jid2 has resources" do
173
+ let(:jid1) { described_class.new "strech@localhost/pewpew" }
174
+ let(:jid2) { described_class.new "strech@gmail.com/hola" }
175
+
176
+ it { should be_false }
177
+ end
178
+ end
179
+ end
180
+
181
+ describe "::to_jid" do
182
+ subject { Jabber::JID.to_jid jid }
183
+
184
+ context "when jid is a Jabber::JID" do
185
+ let(:jid) { described_class.new "strech@localhost" }
186
+
187
+ its(:object_id) { should eq jid.object_id }
188
+ its(:to_s) { should eq "strech@localhost" }
189
+ end
190
+
191
+ context "when jid is a String" do
192
+ let(:jid) { "strech@localhost/resource" }
193
+
194
+ its(:object_id) { should_not eq jid.object_id }
195
+ its(:to_s) { should eq "strech@localhost/resource" }
196
+ end
197
+ end
198
+ end