jabber4r-revive 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,160 @@
1
+ # coding: utf-8
2
+
3
+ # License: see LICENSE
4
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
5
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
6
+
7
+ module Jabber::Protocol
8
+ ##
9
+ # The presence class is used to construct presence messages to
10
+ # send to the Jabber service.
11
+ #
12
+ class Presence
13
+ attr_accessor :to, :from, :id, :type
14
+
15
+ # The state to show (chat, xa, dnd, away)
16
+ attr_accessor :show
17
+
18
+ # The status message
19
+ attr_accessor :status
20
+ attr_accessor :priority
21
+
22
+ ##
23
+ # Constructs a Presence object w/the supplied id
24
+ #
25
+ # id:: [String] The message ID
26
+ # show:: [String] The state to show
27
+ # status:: [String] The status message
28
+ #
29
+ def initialize(id, show=nil, status=nil)
30
+ @id = id
31
+ @show = show if show
32
+ @status = status if status
33
+ end
34
+
35
+ ##
36
+ # Generate a presence object for initial presence notification
37
+ #
38
+ # id:: [String] The message ID
39
+ # show:: [String] The state to show
40
+ # status:: [String] The status message
41
+ # return:: [Jabber::Protocol::Presence] The newly created Presence object
42
+ #
43
+ def self.gen_initial(id, show=nil, status=nil)
44
+ Presence.new(id, show, status)
45
+ end
46
+
47
+ ##
48
+ # Generate a presence object w/show="normal" (normal availability)
49
+ #
50
+ # id:: [String] The message ID
51
+ # status:: [String=nil] The status message
52
+ # return:: [Jabber::Protocol::Presence] The newly created Presence object
53
+ #
54
+ def self.gen_normal(id, status=nil)
55
+ Presence.new(id, "normal", status)
56
+ end
57
+
58
+ ##
59
+ # Generate a presence object w/show="chat" (free for chat)
60
+ #
61
+ # id:: [String] The message ID
62
+ # status:: [String=nil] The status message
63
+ # return:: [Jabber::Protocol::Presence] The newly created Presence object
64
+ #
65
+ def self.gen_chat(id, status=nil)
66
+ Presence.new(id, "chat", status)
67
+ end
68
+
69
+ ##
70
+ # Generate a presence object w/show="xa" (extended away)
71
+ #
72
+ # id:: [String] The message ID
73
+ # status:: [String=nil] The status message
74
+ # return:: [Jabber::Protocol::Presence] The newly created Presence object
75
+ #
76
+ def self.gen_xa(id, status=nil)
77
+ Presence.new(id, "xa", status)
78
+ end
79
+
80
+ ##
81
+ # Generate a presence object w/show="dnd" (do not disturb)
82
+ #
83
+ # id:: [String] The message ID
84
+ # status:: [String=nil] The status message
85
+ # return:: [Jabber::Protocol::Presence] The newly created Presence object
86
+ #
87
+ def self.gen_dnd(id, status=nil)
88
+ Presence.new(id, "dnd", status)
89
+ end
90
+
91
+ ##
92
+ # Generate a presence object w/show="away" (away from resource)
93
+ #
94
+ # id:: [String] The message ID
95
+ # status:: [String=nil] The status message
96
+ # return:: [Jabber::Protocol::Presence] The newly created Presence object
97
+ #
98
+ def self.gen_away(id, status=nil)
99
+ Presence.new(id, "away", status)
100
+ end
101
+
102
+ ##
103
+ # Generate a presence object w/show="unavailable" (not free for chat)
104
+ #
105
+ # id:: [String] The message ID
106
+ # status:: [String=nil] The status message
107
+ # return:: [Jabber::Protocol::Presence] The newly created Presence object
108
+ #
109
+ def self.gen_unavailable(id, status=nil)
110
+ p = Presence.new(id)
111
+ p.type="unavailable"
112
+ p
113
+ end
114
+
115
+ def self.gen_new_subscription(to)
116
+ p = Presence.new(Jabber.gen_random_id)
117
+ p.type = "subscribe"
118
+ p.to = to
119
+ p
120
+ end
121
+
122
+ def self.gen_accept_subscription(id, jid)
123
+ p = Presence.new(id)
124
+ p.type = "subscribed"
125
+ p.to = jid
126
+ p
127
+ end
128
+
129
+ def self.gen_accept_unsubscription(id, jid)
130
+ p = Presence.new(id)
131
+ p.type = "unsubscribed"
132
+ p.to = jid
133
+ p
134
+ end
135
+
136
+ ##
137
+ # Generates the xml representation of this Presence object
138
+ #
139
+ # return:: [String] The presence XML message to send the Jabber service
140
+ #
141
+ def to_xml
142
+ e = XMLElement.new("presence")
143
+ e.add_attribute("id", @id) if @id
144
+ e.add_attribute("from", @from) if @from
145
+ e.add_attribute("to", @to) if @to
146
+ e.add_attribute("type", @type) if @type
147
+ e.add_child("show").add_data(@show) if @show
148
+ e.add_child("status").add_data(@status) if @status
149
+ e.add_child("priority") if @priority
150
+ e.to_s
151
+ end
152
+
153
+ ##
154
+ # see _to_xml
155
+ #
156
+ def to_s
157
+ to_xml
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,144 @@
1
+ # coding: utf-8
2
+
3
+ # License: see LICENSE
4
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
5
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
6
+
7
+ module Jabber::Protocol
8
+ ##
9
+ # Utility class to create valid XML strings
10
+ #
11
+ class XMLElement
12
+
13
+ # The parent XMLElement
14
+ attr_accessor :parent
15
+
16
+ ##
17
+ # Construct an XMLElement for the supplied tag and attributes
18
+ #
19
+ # tag:: [String] XML tag
20
+ # attributes:: [Hash = {}] The attribute hash[attribute]=value
21
+ def initialize(tag, attributes={})
22
+ @tag = tag
23
+ @elements = []
24
+ @attributes = attributes
25
+ @data = ""
26
+ end
27
+
28
+ ##
29
+ # Adds an attribute to this element
30
+ #
31
+ # attrib:: [String] The attribute name
32
+ # value:: [String] The attribute value
33
+ # return:: [Jabber::Protocol::XMLElement] self for chaining
34
+ #
35
+ def add_attribute(attrib, value)
36
+ @attributes[attrib]=value
37
+ self
38
+ end
39
+
40
+ ##
41
+ # Adds data to this element
42
+ #
43
+ # data:: [String] The data to add
44
+ # return:: [Jabber::Protocol::XMLElement] self for chaining
45
+ #
46
+ def add_data(data)
47
+ @data += data.to_s
48
+ self
49
+ end
50
+
51
+ ##
52
+ # Sets the namespace for this tag
53
+ #
54
+ # ns:: [String] The namespace
55
+ # return:: [Jabber::Protocol::XMLElement] self for chaining
56
+ #
57
+ def set_namespace(ns)
58
+ @tag+=":#{ns}"
59
+ self
60
+ end
61
+
62
+ ##
63
+ # Adds cdata to this element
64
+ #
65
+ # cdata:: [String] The cdata to add
66
+ # return:: [Jabber::Protocol::XMLElement] self for chaining
67
+ #
68
+ def add_cdata(cdata)
69
+ @data += "<![CDATA[#{cdata.to_s}]]>"
70
+ self
71
+ end
72
+
73
+ ##
74
+ # Returns the parent element
75
+ #
76
+ # return:: [Jabber::Protocol::XMLElement] The parent XMLElement
77
+ #
78
+ def to_parent
79
+ @parent
80
+ end
81
+
82
+ ##
83
+ # Adds a child to this element of the supplied tag
84
+ #
85
+ # tag:: [String] The element tag
86
+ # attributes:: [Hash = {}] The attributes hash[attribute]=value
87
+ # return:: [Jabber::Protocol::XMLElement] newly created child element
88
+ #
89
+ def add_child(tag, attributes={})
90
+ child = XMLElement.new(tag, attributes)
91
+ child.parent = self
92
+ @elements << child
93
+ return child
94
+ end
95
+
96
+ ##
97
+ # Adds arbitrary XML data to this object
98
+ #
99
+ # xml:: [String] the xml to add
100
+ #
101
+ def add_xml(xml)
102
+ @xml = xml
103
+ end
104
+
105
+ ##
106
+ # Recursively builds the XML string by traversing this element's
107
+ # children.
108
+ #
109
+ # format:: [Boolean] True to pretty-print (format) the output string
110
+ # indent:: [Integer = 0] The indent level (recursively more)
111
+ #
112
+ def to_xml(format, indent=0)
113
+ result = ""
114
+ result += " "*indent if format
115
+ result += "<#{@tag}"
116
+ @attributes.each {|attrib, value| result += (' '+attrib.to_s+'="'+value.to_s+'"') }
117
+ if @data=="" and @elements.size==0
118
+ result +="/>"
119
+ result +="\n" if format
120
+ return result
121
+ end
122
+ result += ">"
123
+ result += "\n" if format and @data==""
124
+ result += @data if @data!=""
125
+ @elements.each {|element| result+=element.to_xml(format, indent+4)}
126
+ result += @xml if not @xml.nil?
127
+ result += " "*indent if format and @data==""
128
+ result+="</#{@tag}>"
129
+ result+="\n" if format
130
+ return result
131
+ end
132
+
133
+ ##
134
+ # Climbs to the top of this elements parent tree and then returns
135
+ # the to_xml XML string.
136
+ #
137
+ # return:: [String] The XML string of this element (from the topmost parent).
138
+ #
139
+ def to_s
140
+ return @parent.to_s if @parent
141
+ return to_xml(true)
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,257 @@
1
+ # coding: utf-8
2
+
3
+ # License: see LICENSE
4
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
5
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
6
+
7
+ require "singleton"
8
+ require "socket"
9
+
10
+ module Jabber
11
+ class JabberConnectionException < RuntimeError
12
+ attr_reader :data
13
+
14
+ def initialize(writing, data)
15
+ @writing = writing
16
+ @data = data
17
+ end
18
+
19
+ def writing?
20
+ @writing
21
+ end
22
+ end
23
+
24
+ ##
25
+ # The Protocol module contains helper methods for constructing
26
+ # Jabber protocol elements and classes that implement protocol
27
+ # elements.
28
+ #
29
+ module Protocol
30
+
31
+ USE_PARSER = :rexml # either :rexml or :xmlparser
32
+
33
+ ##
34
+ # The parser to use for stream processing. The current
35
+ # available parsers are:
36
+ #
37
+ # * Jabber::Protocol::ExpatJabberParser uses XMLParser
38
+ # * Jabber::Protocol::REXMLJabberParser uses REXML
39
+ #
40
+ # return:: [Class] The parser class
41
+ #
42
+ def Protocol.Parser
43
+ if USE_PARSER==:xmlparser
44
+ Jabber::Protocol::ExpatJabberParser
45
+ else
46
+ Jabber::Protocol::REXMLJabberParser
47
+ end
48
+ end
49
+
50
+ ##
51
+ # Generates an open stream XML element
52
+ #
53
+ # host:: [String] The host being connected to
54
+ # return:: [String] The XML data to send
55
+ #
56
+ def self.gen_open_stream(host)
57
+ return ('<?xml version="1.0" encoding="UTF-8" ?><stream:stream to="'+host+'" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">')
58
+ end
59
+
60
+ ##
61
+ # Generates an close stream XML element
62
+ #
63
+ # return:: [String] The XML data to send
64
+ #
65
+ def self.gen_close_stream
66
+ return "</stream:stream>"
67
+ end
68
+
69
+ if USE_PARSER == :xmlparser
70
+ require 'xmlparser'
71
+ ##
72
+ # The ExpatJabberParser uses XMLParser (expat) to parse the incoming XML stream
73
+ # of the Jabber protocol and fires ParsedXMLElements at the Connection
74
+ # instance.
75
+ #
76
+ class ExpatJabberParser
77
+
78
+ # status if the parser is started
79
+ attr_reader :started
80
+
81
+ ##
82
+ # Constructs a parser for the supplied stream (socket input)
83
+ #
84
+ # stream:: [IO] Socket input stream
85
+ # listener:: [#receive(ParsedXMLElement)] The listener (usually a Jabber::Protocol::Connection instance
86
+ #
87
+ def initialize(stream, listener)
88
+ @stream = stream
89
+ def @stream.gets
90
+ super(">")
91
+ end
92
+ @listener = listener
93
+ end
94
+
95
+ ##
96
+ # Begins parsing the XML stream and does not return until
97
+ # the stream closes.
98
+ #
99
+ def parse
100
+ @started = false
101
+
102
+ parser = XMLParser.new("UTF-8")
103
+ def parser.unknownEncoding(e)
104
+ raise "Unknown encoding #{e.to_s}"
105
+ end
106
+ def parser.default
107
+ end
108
+
109
+ begin
110
+ parser.parse(@stream) do |type, name, data|
111
+ begin
112
+ case type
113
+ when XMLParser::START_ELEM
114
+ case name
115
+ when "stream:stream"
116
+ openstream = ParsedXMLElement.new(name)
117
+ data.each {|key, value| openstream.add_attribute(key, value)}
118
+ @listener.receive(openstream)
119
+ @started = true
120
+ else
121
+ if @current.nil?
122
+ @current = ParsedXMLElement.new(name.clone)
123
+ else
124
+ @current = @current.add_child(name.clone)
125
+ end
126
+ data.each {|key, value| @current.add_attribute(key.clone, value.clone)}
127
+ end
128
+ when XMLParser::CDATA
129
+ @current.append_data(data.clone) if @current
130
+ when XMLParser::END_ELEM
131
+ case name
132
+ when "stream:stream"
133
+ @started = false
134
+ else
135
+ @listener.receive(@current) unless @current.element_parent
136
+ @current = @current.element_parent
137
+ end
138
+ end
139
+ rescue
140
+ puts "Error #{$!}"
141
+ end
142
+ end
143
+ rescue XMLParserError
144
+ line = parser.line
145
+ print "XML Parsing error(#{line}): #{$!}\n"
146
+ end
147
+ end
148
+ end
149
+ else # USE REXML
150
+ require 'rexml/document'
151
+ require 'rexml/parsers/sax2parser'
152
+ require 'rexml/source'
153
+
154
+ ##
155
+ # The REXMLJabberParser uses REXML to parse the incoming XML stream
156
+ # of the Jabber protocol and fires ParsedXMLElements at the Connection
157
+ # instance.
158
+ #
159
+ class REXMLJabberParser
160
+ # status if the parser is started
161
+ attr_reader :started
162
+
163
+ ##
164
+ # Constructs a parser for the supplied stream (socket input)
165
+ #
166
+ # stream:: [IO] Socket input stream
167
+ # listener:: [Object.receive(ParsedXMLElement)] The listener (usually a Jabber::Protocol::Connection instance
168
+ #
169
+ def initialize(stream, listener)
170
+ @stream = stream
171
+
172
+ # this hack fixes REXML version "2.7.3" and "2.7.4"
173
+ if REXML::Version=="2.7.3" || REXML::Version=="2.7.4"
174
+ def @stream.read(len=nil)
175
+ len = 100 unless len
176
+ super(len)
177
+ end
178
+ def @stream.gets(char=nil)
179
+ super(">")
180
+ end
181
+ def @stream.readline(char=nil)
182
+ super(">")
183
+ end
184
+ def @stream.readlines(char=nil)
185
+ super(">")
186
+ end
187
+ end
188
+
189
+ @listener = listener
190
+ @current = nil
191
+ end
192
+
193
+ ##
194
+ # Begins parsing the XML stream and does not return until
195
+ # the stream closes.
196
+ #
197
+ def parse
198
+ #puts "PARSE"
199
+ @started = false
200
+ begin
201
+ parser = REXML::Parsers::SAX2Parser.new @stream
202
+
203
+ parser.listen(:end_document) do
204
+ raise Jabber::ConnectionForceCloseError
205
+ end
206
+
207
+ parser.listen( :start_element ) do |uri, localname, qname, attributes|
208
+ puts "START ELEMENT"
209
+ case qname
210
+ when "stream:stream"
211
+ openstream = ParsedXMLElement.new(qname)
212
+ attributes.each { |attr, value| openstream.add_attribute(attr, value) }
213
+ @listener.receive(openstream)
214
+ @started = true
215
+ else
216
+ if @current.nil?
217
+ @current = ParsedXMLElement.new(qname)
218
+ else
219
+ @current = @current.add_child(qname)
220
+ end
221
+ attributes.each { |attr, value| @current.add_attribute(attr, value) }
222
+ end
223
+ end
224
+ parser.listen( :end_element ) do |uri, localname, qname|
225
+ puts "END ELEMENT"
226
+ case qname
227
+ when "stream:stream"
228
+ @started = false
229
+ else
230
+ @listener.receive(@current) unless @current.element_parent
231
+ @current = @current.element_parent
232
+ end
233
+ end
234
+ parser.listen( :characters ) do | text |
235
+ puts "CHARACTERS"
236
+ @current.append_data(text) if @current
237
+ end
238
+ parser.listen( :cdata ) do | text |
239
+ puts "CDATA"
240
+ @current.append_data(text) if @current
241
+ end
242
+ parser.parse
243
+ rescue REXML::ParseException => e
244
+ puts "FAIL"
245
+
246
+ puts e.backtrace.join "\n"
247
+ puts e.message
248
+ @listener.parse_failure
249
+ rescue Jabber::ConnectionForceCloseError => e
250
+ @listener.parse_failure(e)
251
+ end
252
+ end
253
+ end
254
+ end # USE_PARSER
255
+ end
256
+ end
257
+