xmpp4r 0.3
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.
- data/COPYING +340 -0
- data/ChangeLog +28 -0
- data/LICENSE +59 -0
- data/README +20 -0
- data/Rakefile +103 -0
- data/UPDATING +40 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/README +57 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/adventure.rb +23 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/adventuremuc.rb +136 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/cube.xml +15 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/tower.xml +69 -0
- data/data/doc/xmpp4r/examples/advanced/adventure/world.rb +425 -0
- data/data/doc/xmpp4r/examples/advanced/fileserve.conf +11 -0
- data/data/doc/xmpp4r/examples/advanced/fileserve.rb +344 -0
- data/data/doc/xmpp4r/examples/advanced/getonline.rb +56 -0
- data/data/doc/xmpp4r/examples/advanced/gtkmucclient.rb +315 -0
- data/data/doc/xmpp4r/examples/advanced/migrate.rb +89 -0
- data/data/doc/xmpp4r/examples/advanced/minimuc.rb +266 -0
- data/data/doc/xmpp4r/examples/advanced/recvfile.rb +83 -0
- data/data/doc/xmpp4r/examples/advanced/rosterdiscovery.rb +130 -0
- data/data/doc/xmpp4r/examples/advanced/sendfile.conf +10 -0
- data/data/doc/xmpp4r/examples/advanced/sendfile.rb +72 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr.rb +51 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_jabber.rb +43 -0
- data/data/doc/xmpp4r/examples/advanced/shellmgr/shellmgr_test.rb +10 -0
- data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +90 -0
- data/data/doc/xmpp4r/examples/advanced/xmpping.rb +134 -0
- data/data/doc/xmpp4r/examples/advanced/xmppingrc.sample +9 -0
- data/data/doc/xmpp4r/examples/basic/change_password.rb +41 -0
- data/data/doc/xmpp4r/examples/basic/client.rb +68 -0
- data/data/doc/xmpp4r/examples/basic/component.rb +11 -0
- data/data/doc/xmpp4r/examples/basic/echo_nonthreaded.rb +32 -0
- data/data/doc/xmpp4r/examples/basic/echo_threaded.rb +32 -0
- data/data/doc/xmpp4r/examples/basic/jabbersend.rb +41 -0
- data/data/doc/xmpp4r/examples/basic/mass_sender.rb +67 -0
- data/data/doc/xmpp4r/examples/basic/mucinfo.rb +39 -0
- data/data/doc/xmpp4r/examples/basic/mucsimplebot.rb +83 -0
- data/data/doc/xmpp4r/examples/basic/register.rb +25 -0
- data/data/doc/xmpp4r/examples/basic/remove_registration.rb +18 -0
- data/data/doc/xmpp4r/examples/basic/roster.rb +42 -0
- data/data/doc/xmpp4r/examples/basic/rosterprint.rb +50 -0
- data/data/doc/xmpp4r/examples/basic/rosterrename.rb +34 -0
- data/data/doc/xmpp4r/examples/basic/rosterwatch.rb +172 -0
- data/data/doc/xmpp4r/examples/basic/send_vcard.rb +68 -0
- data/data/doc/xmpp4r/examples/basic/versionbot.rb +75 -0
- data/data/doc/xmpp4r/examples/buggy/jabber2jabber/jabber2jabber.rb +18 -0
- data/data/doc/xmpp4r/examples/buggy/miniedgarr_cgi.rb +192 -0
- data/data/doc/xmpp4r/examples/buggy/miniedgarr_watch.rb +82 -0
- data/lib/callbacks.rb +122 -0
- data/lib/xmpp4r/authenticationfailure.rb +13 -0
- data/lib/xmpp4r/bytestreams/helper/filetransfer.rb +315 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/base.rb +256 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/initiator.rb +30 -0
- data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +46 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb +151 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb +85 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb +178 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb +56 -0
- data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +61 -0
- data/lib/xmpp4r/bytestreams/iq/bytestreams.rb +177 -0
- data/lib/xmpp4r/bytestreams/iq/si.rb +221 -0
- data/lib/xmpp4r/bytestreams.rb +11 -0
- data/lib/xmpp4r/client.rb +249 -0
- data/lib/xmpp4r/component.rb +103 -0
- data/lib/xmpp4r/connection.rb +166 -0
- data/lib/xmpp4r/dataforms/x/data.rb +248 -0
- data/lib/xmpp4r/dataforms.rb +1 -0
- data/lib/xmpp4r/debuglog.rb +34 -0
- data/lib/xmpp4r/delay/x/delay.rb +100 -0
- data/lib/xmpp4r/delay.rb +1 -0
- data/lib/xmpp4r/discovery/iq/discoinfo.rb +225 -0
- data/lib/xmpp4r/discovery/iq/discoitems.rb +162 -0
- data/lib/xmpp4r/discovery.rb +2 -0
- data/lib/xmpp4r/error.rb +230 -0
- data/lib/xmpp4r/errorexception.rb +32 -0
- data/lib/xmpp4r/feature_negotiation/iq/feature.rb +42 -0
- data/lib/xmpp4r/feature_negotiation.rb +1 -0
- data/lib/xmpp4r/idgenerator.rb +37 -0
- data/lib/xmpp4r/iq.rb +229 -0
- data/lib/xmpp4r/jid.rb +167 -0
- data/lib/xmpp4r/message.rb +171 -0
- data/lib/xmpp4r/muc/helper/mucbrowser.rb +107 -0
- data/lib/xmpp4r/muc/helper/mucclient.rb +382 -0
- data/lib/xmpp4r/muc/helper/simplemucclient.rb +222 -0
- data/lib/xmpp4r/muc/x/muc.rb +98 -0
- data/lib/xmpp4r/muc/x/mucuserinvite.rb +58 -0
- data/lib/xmpp4r/muc/x/mucuseritem.rb +148 -0
- data/lib/xmpp4r/muc.rb +6 -0
- data/lib/xmpp4r/presence.rb +255 -0
- data/lib/xmpp4r/query.rb +43 -0
- data/lib/xmpp4r/rexmladdons.rb +826 -0
- data/lib/xmpp4r/roster/helper/roster.rb +514 -0
- data/lib/xmpp4r/roster/iq/roster.rb +244 -0
- data/lib/xmpp4r/roster/x/roster.rb +155 -0
- data/lib/xmpp4r/roster.rb +4 -0
- data/lib/xmpp4r/sasl.rb +167 -0
- data/lib/xmpp4r/stream.rb +543 -0
- data/lib/xmpp4r/streamparser.rb +77 -0
- data/lib/xmpp4r/vcard/helper/vcard.rb +86 -0
- data/lib/xmpp4r/vcard/iq/vcard.rb +102 -0
- data/lib/xmpp4r/vcard.rb +3 -0
- data/lib/xmpp4r/version/helper/responder.rb +71 -0
- data/lib/xmpp4r/version/helper/simpleresponder.rb +44 -0
- data/lib/xmpp4r/version/iq/version.rb +118 -0
- data/lib/xmpp4r/version.rb +3 -0
- data/lib/xmpp4r/x.rb +43 -0
- data/lib/xmpp4r/xmlstanza.rb +174 -0
- data/lib/xmpp4r/xmpp4r.rb +16 -0
- data/lib/xmpp4r.rb +122 -0
- data/setup.rb +1360 -0
- data/test/bytestreams/tc_ibb.rb +186 -0
- data/test/bytestreams/tc_socks5bytestreams.rb +57 -0
- data/test/delay/tc_xdelay.rb +51 -0
- data/test/lib/clienttester.rb +110 -0
- data/test/muc/tc_muc_mucclient.rb +569 -0
- data/test/muc/tc_muc_simplemucclient.rb +72 -0
- data/test/roster/.tc_helper.rb.swp +0 -0
- data/test/roster/tc_helper.rb +389 -0
- data/test/roster/tc_iqqueryroster.rb +140 -0
- data/test/roster/tc_xroster.rb +70 -0
- data/test/tc_callbacks.rb +128 -0
- data/test/tc_class_names.rb +129 -0
- data/test/tc_client.rb +30 -0
- data/test/tc_error.rb +103 -0
- data/test/tc_idgenerator.rb +30 -0
- data/test/tc_iq.rb +109 -0
- data/test/tc_iqquery.rb +31 -0
- data/test/tc_jid.rb +202 -0
- data/test/tc_message.rb +114 -0
- data/test/tc_presence.rb +148 -0
- data/test/tc_stream.rb +182 -0
- data/test/tc_streamError.rb +87 -0
- data/test/tc_streamSend.rb +59 -0
- data/test/tc_streamThreaded.rb +168 -0
- data/test/tc_xmlstanza.rb +76 -0
- data/test/ts_xmpp4r.rb +34 -0
- data/test/vcard/tc_iqvcard.rb +52 -0
- data/test/version/tc_helper.rb +46 -0
- data/test/version/tc_iqqueryversion.rb +96 -0
- data/tools/doctoweb.bash +30 -0
- data/tools/gen_requires.bash +10 -0
- metadata +232 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
require 'world'
|
|
2
|
+
|
|
3
|
+
class AdventureMUC
|
|
4
|
+
def initialize(jid, secret, addr, port=5347)
|
|
5
|
+
@worlds = {}
|
|
6
|
+
|
|
7
|
+
@component = Jabber::Component::new(jid)
|
|
8
|
+
@component.connect(addr, port)
|
|
9
|
+
@component.auth(secret)
|
|
10
|
+
@component.on_exception { |e,|
|
|
11
|
+
puts "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@component.add_iq_callback { |iq|
|
|
15
|
+
handle_iq(iq)
|
|
16
|
+
}
|
|
17
|
+
@component.add_presence_callback { |pres|
|
|
18
|
+
handle_presence(pres)
|
|
19
|
+
}
|
|
20
|
+
@component.add_message_callback { |msg|
|
|
21
|
+
handle_message(msg)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
puts "Adventure component up and running"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def add_world(file)
|
|
28
|
+
print "Adding world from #{file}..."
|
|
29
|
+
begin
|
|
30
|
+
world = World.new_from_file(self, file)
|
|
31
|
+
rescue Exception => e
|
|
32
|
+
puts " #{e.to_s}"
|
|
33
|
+
exit
|
|
34
|
+
end
|
|
35
|
+
@worlds[world.node] = world
|
|
36
|
+
puts " #{world.iname}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def send(worldnode, worldresource, stanza)
|
|
40
|
+
stanza.from = Jabber::JID::new(worldnode, @component.jid.domain, worldresource)
|
|
41
|
+
@component.send(stanza)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def handle_iq(iq)
|
|
45
|
+
puts "iq: from #{iq.from} type #{iq.type} to #{iq.to}: #{iq.queryns}"
|
|
46
|
+
|
|
47
|
+
if iq.query.kind_of?(Jabber::Discovery::IqQueryDiscoInfo)
|
|
48
|
+
handle_disco_info(iq)
|
|
49
|
+
true
|
|
50
|
+
elsif iq.query.kind_of?(Jabber::Discovery::IqQueryDiscoItems)
|
|
51
|
+
handle_disco_items(iq)
|
|
52
|
+
true
|
|
53
|
+
else
|
|
54
|
+
false
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def handle_disco_info(iq)
|
|
59
|
+
if iq.type != :get
|
|
60
|
+
answer = Jabber::XMLStanza.answer(iq)
|
|
61
|
+
answer.type = :error
|
|
62
|
+
answer.add(Jabber::Error.new('bad-request'))
|
|
63
|
+
@component.send(answer) if iq.type != :error
|
|
64
|
+
return
|
|
65
|
+
end
|
|
66
|
+
answer = Jabber::XMLStanza.answer(iq)
|
|
67
|
+
answer.type = :result
|
|
68
|
+
if iq.to.node == nil
|
|
69
|
+
answer.query.add(Jabber::Discovery::Identity.new('conference', 'Adventure component', 'text'))
|
|
70
|
+
answer.query.add(Jabber::Discovery::Feature.new(Jabber::Discovery::IqQueryDiscoInfo.new.namespace))
|
|
71
|
+
answer.query.add(Jabber::Discovery::Feature.new(Jabber::Discovery::IqQueryDiscoItems.new.namespace))
|
|
72
|
+
else
|
|
73
|
+
world = @worlds[iq.to.node]
|
|
74
|
+
if world.nil?
|
|
75
|
+
answer.type = :error
|
|
76
|
+
answer.query.add(Jabber::Error.new('item-not-found', 'The world you are trying to reach is currently unavailable.'))
|
|
77
|
+
else
|
|
78
|
+
answer.query.add(Jabber::Discovery::Identity.new('conference', world.iname, 'text'))
|
|
79
|
+
answer.query.add(Jabber::Discovery::Feature.new(Jabber::Discovery::IqQueryDiscoInfo.new.namespace))
|
|
80
|
+
answer.query.add(Jabber::Discovery::Feature.new(Jabber::Discovery::IqQueryDiscoItems.new.namespace))
|
|
81
|
+
answer.query.add(Jabber::Discovery::Feature.new(Jabber::MUC::XMUC.new.namespace))
|
|
82
|
+
answer.query.add(Jabber::Discovery::Feature.new(Jabber::MUC::XMUCUser.new.namespace))
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
@component.send(answer)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def handle_disco_items(iq)
|
|
89
|
+
if iq.type != :get
|
|
90
|
+
answer = Jabber::XMLStanza.answer(iq)
|
|
91
|
+
answer.add(Jabber::Error.new('bad-request'))
|
|
92
|
+
@component.send(answer)
|
|
93
|
+
return
|
|
94
|
+
end
|
|
95
|
+
answer = Jabber::XMLStanza.answer(iq)
|
|
96
|
+
answer.type = :result
|
|
97
|
+
if iq.to.node == nil
|
|
98
|
+
@worlds.each { |node,world|
|
|
99
|
+
answer.query.add(Jabber::Discovery::Item.new(Jabber::JID::new(node, @component.jid.domain), world.iname))
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
@component.send(answer)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def handle_presence(pres)
|
|
106
|
+
puts "presence: from #{pres.from} type #{pres.type} to #{pres.to}"
|
|
107
|
+
|
|
108
|
+
world = @worlds[pres.to.node]
|
|
109
|
+
if world.nil?
|
|
110
|
+
answer = Jabber::XMLStanza.answer(pres)
|
|
111
|
+
answer.type = :error
|
|
112
|
+
answer.add(Jabber::Error.new('item-not-found', 'The world you are trying to reach is currently unavailable.'))
|
|
113
|
+
@component.send(answer)
|
|
114
|
+
else
|
|
115
|
+
world.handle_presence(pres)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
true
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def handle_message(msg)
|
|
122
|
+
puts "message: from #{msg.from} type #{msg.type} to #{msg.to}: #{msg.body.inspect}"
|
|
123
|
+
|
|
124
|
+
world = @worlds[msg.to.node]
|
|
125
|
+
if world.nil?
|
|
126
|
+
answer = Jabber::XMLStanza.answer(msg)
|
|
127
|
+
answer.type = :error
|
|
128
|
+
answer.add(Jabber::Error.new('item-not-found', 'The world you are trying to reach is currently unavailable.'))
|
|
129
|
+
@component.send(answer)
|
|
130
|
+
else
|
|
131
|
+
world.handle_message(msg)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
true
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<world node='cube' name='Cube - the movie' start='Room'>
|
|
2
|
+
|
|
3
|
+
<place name='Room'>
|
|
4
|
+
This is a big white room.
|
|
5
|
+
There are doors up, down, left, right, in the back and in front of you.
|
|
6
|
+
There's nothing else.
|
|
7
|
+
<go spec='up' place='Room'/>
|
|
8
|
+
<go spec='down' place='Room'/>
|
|
9
|
+
<go spec='left' place='Room'/>
|
|
10
|
+
<go spec='right' place='Room'/>
|
|
11
|
+
<go spec='back' place='Room'/>
|
|
12
|
+
<go spec='forward' place='Room'/>
|
|
13
|
+
</place>
|
|
14
|
+
|
|
15
|
+
</world>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<world node='tower' name='The mysterious tower' start='the garden'>
|
|
2
|
+
|
|
3
|
+
<place name='the garden'>
|
|
4
|
+
You are in a beautiful garden.
|
|
5
|
+
There's an impressive tower beneath. Its door is open.
|
|
6
|
+
<go spec='door' place='lower room'/>
|
|
7
|
+
<go spec='east' place='the well'/>
|
|
8
|
+
</place>
|
|
9
|
+
|
|
10
|
+
<place name='lower room'>
|
|
11
|
+
Welcome to the tower's lower room.
|
|
12
|
+
There's a ladder to upstairs.
|
|
13
|
+
<go spec='door' place='the garden'/>
|
|
14
|
+
<go spec='ladder' place='upper room'/>
|
|
15
|
+
</place>
|
|
16
|
+
|
|
17
|
+
<place name='upper room'>
|
|
18
|
+
This is the upper room.
|
|
19
|
+
There's only a bed here. A wizard is currently sleeping in it.
|
|
20
|
+
<go spec='ladder' place='lower room'/>
|
|
21
|
+
</place>
|
|
22
|
+
|
|
23
|
+
<place name='the well'>
|
|
24
|
+
There's a very beautiful well in the middle of this place.
|
|
25
|
+
A frog sits on the well's edge. It looks frightening happy.
|
|
26
|
+
<go spec='west' place='the garden'/>
|
|
27
|
+
</place>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
<thing name='Frog' place='the well'>
|
|
31
|
+
<on-enter>
|
|
32
|
+
<say>Hello great hero!</say>
|
|
33
|
+
<say>Welcome to %place%</say>
|
|
34
|
+
</on-enter>
|
|
35
|
+
<on-leave>
|
|
36
|
+
<tell>The %self% waves towards %actor%</tell>
|
|
37
|
+
</on-leave>
|
|
38
|
+
<on-command command='talk'>
|
|
39
|
+
<say>I would love to come with you, great hero. But I'm immobile due to the simple nature of this game. Would *YOU* like to /code/ me movable? So we could enjoy great adventures together...</say>
|
|
40
|
+
</on-command>
|
|
41
|
+
<on-command command='touch'>
|
|
42
|
+
<tell to='all'>%actor% touches the %self%</tell>
|
|
43
|
+
<say to='all'>Quaaack! That feels good.</say>
|
|
44
|
+
</on-command>
|
|
45
|
+
<presence>
|
|
46
|
+
<show>chat</show>
|
|
47
|
+
<status>Happy</status>
|
|
48
|
+
</presence>
|
|
49
|
+
</thing>
|
|
50
|
+
|
|
51
|
+
<thing name='Sleeping Wizard' place='upper room'>
|
|
52
|
+
<on-enter>
|
|
53
|
+
<say>*snork*</say>
|
|
54
|
+
</on-enter>
|
|
55
|
+
<presence>
|
|
56
|
+
<show>dnd</show>
|
|
57
|
+
<status>Sleeping... go bother my assistant, the frog.</status>
|
|
58
|
+
</presence>
|
|
59
|
+
</thing>
|
|
60
|
+
|
|
61
|
+
<thing name='Tower window' command-name='window' place='upper room'>
|
|
62
|
+
<on-command command='look'>
|
|
63
|
+
<say>You see a beautiful garden. There's a well behind the garden. But a huge green monster is sitting on it's edge.</say>
|
|
64
|
+
</on-command>
|
|
65
|
+
<presence>
|
|
66
|
+
<status>There's a great view from up here</status>
|
|
67
|
+
</presence>
|
|
68
|
+
</thing>
|
|
69
|
+
</world>
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
require 'rexml/document'
|
|
2
|
+
|
|
3
|
+
class World < REXML::Element
|
|
4
|
+
def initialize(muc)
|
|
5
|
+
super('world')
|
|
6
|
+
|
|
7
|
+
@muc = muc
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def send(resource, stanza)
|
|
11
|
+
# Avoid sending to things without JID
|
|
12
|
+
if stanza.to != nil
|
|
13
|
+
@muc.send(node, resource, stanza)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def World.new_from_file(muc, filename)
|
|
18
|
+
file = File.new(filename)
|
|
19
|
+
world = World.new(muc)
|
|
20
|
+
world.import(REXML::Document.new(file).root)
|
|
21
|
+
file.close
|
|
22
|
+
world
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def add(xmlelement)
|
|
26
|
+
if xmlelement.kind_of?(REXML::Element) && (xmlelement.name == 'place')
|
|
27
|
+
super(Place::new.import(xmlelement))
|
|
28
|
+
elsif xmlelement.kind_of?(REXML::Element) && (xmlelement.name == 'thing') && !xmlelement.kind_of?(Player)
|
|
29
|
+
super(Thing::new(self).import(xmlelement))
|
|
30
|
+
else
|
|
31
|
+
super(xmlelement)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def node
|
|
36
|
+
attributes['node']
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def iname
|
|
40
|
+
attributes['name']
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def place(placename)
|
|
44
|
+
pl = nil
|
|
45
|
+
each_element('place') { |place|
|
|
46
|
+
if place.iname == placename
|
|
47
|
+
pl = place
|
|
48
|
+
end
|
|
49
|
+
}
|
|
50
|
+
pl
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def each_thing_by_place(place, &block)
|
|
54
|
+
each_element('thing') { |t|
|
|
55
|
+
if t.place == place
|
|
56
|
+
yield(t)
|
|
57
|
+
end
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def move_thing(thing, newplace)
|
|
62
|
+
each_thing_by_place(thing.place) { |t|
|
|
63
|
+
# Call leave hooks
|
|
64
|
+
t.on_leave(thing, newplace)
|
|
65
|
+
|
|
66
|
+
# Broadcast unavailability presence to leaver
|
|
67
|
+
unless t.presence.nil?
|
|
68
|
+
pres = Jabber::Presence.import(t.presence)
|
|
69
|
+
pres.type = :unavailable
|
|
70
|
+
pres.to = thing.jid
|
|
71
|
+
send(t.iname, pres) unless t.jid == thing.jid
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Broadcast unavailability presence to all who are here
|
|
75
|
+
unless thing.presence.nil?
|
|
76
|
+
pres = Jabber::Presence.import(thing.presence)
|
|
77
|
+
pres.type = :unavailable
|
|
78
|
+
pres.to = t.jid
|
|
79
|
+
send(thing.iname, pres) unless thing.jid == t.jid
|
|
80
|
+
end
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Enter new place
|
|
84
|
+
oldplace = thing.place
|
|
85
|
+
thing.place = newplace
|
|
86
|
+
|
|
87
|
+
each_thing_by_place(thing.place) { |t|
|
|
88
|
+
# Broadcast availability presence to enterer
|
|
89
|
+
unless t.presence.nil?
|
|
90
|
+
pres = Jabber::Presence.import(t.presence)
|
|
91
|
+
pres.to = thing.jid
|
|
92
|
+
send(t.iname, pres)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Broadcast availability presence to all who are here
|
|
96
|
+
unless thing.presence.nil?
|
|
97
|
+
pres = Jabber::Presence.import(thing.presence)
|
|
98
|
+
pres.to = t.jid
|
|
99
|
+
send(thing.iname, pres)
|
|
100
|
+
end
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
thing.send_message(nil, " ")
|
|
104
|
+
subject = newplace.nil? ? " " : newplace.dup
|
|
105
|
+
subject[0] = subject[0,1].upcase
|
|
106
|
+
thing.send_message(nil, "Entering #{newplace}", subject)
|
|
107
|
+
thing.send_message(nil, " ")
|
|
108
|
+
thing.see(place(newplace))
|
|
109
|
+
|
|
110
|
+
each_thing_by_place(thing.place) { |t|
|
|
111
|
+
# Call enter hooks
|
|
112
|
+
t.on_enter(thing, oldplace)
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def handle_presence(pres)
|
|
117
|
+
# A help for the irritated first:
|
|
118
|
+
if pres.type == :subscribe
|
|
119
|
+
msg = Jabber::Message.new(pres.from)
|
|
120
|
+
msg.type = :normal
|
|
121
|
+
msg.subject = "Adventure component help"
|
|
122
|
+
msg.body = "You don't need to subscribe to my presence. Simply use your Jabber client to join the MUC or conference at #{pres.to.strip}"
|
|
123
|
+
send(nil, msg)
|
|
124
|
+
return(true)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Look if player is already known
|
|
128
|
+
player = nil
|
|
129
|
+
each_element('thing') { |thing|
|
|
130
|
+
if thing.kind_of?(Player) && pres.to.resource == thing.iname
|
|
131
|
+
player = thing
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Disallow nick changes
|
|
135
|
+
if thing.kind_of?(Player) && (pres.from == thing.jid) && (player != thing)
|
|
136
|
+
answer = Jabber::XMLStanza.answer(pres, false)
|
|
137
|
+
answer.type = :error
|
|
138
|
+
answer.add(Jabber::Error.new('not-acceptable', 'Nickchange not allowed'))
|
|
139
|
+
send(thing.iname, answer)
|
|
140
|
+
return(true)
|
|
141
|
+
end
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# Either nick-collission or empty nick
|
|
145
|
+
unless (player.nil? || pres.from == player.jid) && (pres.to.resource.to_s.size > 1)
|
|
146
|
+
answer = Jabber::XMLStanza.answer(pres)
|
|
147
|
+
answer.type = :error
|
|
148
|
+
if (pres.to.resource.to_s.size > 1)
|
|
149
|
+
answer.add(Jabber::Error::new('conflict', 'Nickname already used'))
|
|
150
|
+
else
|
|
151
|
+
answer.add(Jabber::Error::new('not-acceptable', 'Please use a nickname'))
|
|
152
|
+
end
|
|
153
|
+
send(nil, answer)
|
|
154
|
+
return(true)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Add the valid player
|
|
158
|
+
if player.nil?
|
|
159
|
+
player = add(Player.new(self, pres.to.resource, pres.from))
|
|
160
|
+
player.presence = pres
|
|
161
|
+
move_thing(player, attributes['start'])
|
|
162
|
+
player.send_message('Help!', 'Send "?" to get a list of available commands any time.')
|
|
163
|
+
# Or broadcast updated presence
|
|
164
|
+
else
|
|
165
|
+
player.presence = pres
|
|
166
|
+
|
|
167
|
+
each_thing_by_place(player.place) { |t|
|
|
168
|
+
# Broadcast presence to all who are here
|
|
169
|
+
pres = Jabber::Presence.import(player.presence)
|
|
170
|
+
pres.to = t.jid
|
|
171
|
+
send(player.iname, pres)
|
|
172
|
+
}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Remove the player instantly
|
|
176
|
+
if pres.type == :error || pres.type == :unavailable
|
|
177
|
+
move_thing(player, nil)
|
|
178
|
+
delete_element(player)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def handle_message(msg)
|
|
183
|
+
player = nil
|
|
184
|
+
each_element('thing') { |thing|
|
|
185
|
+
if thing.kind_of?(Player) && msg.to.resource == nil && msg.from == thing.jid
|
|
186
|
+
player = thing
|
|
187
|
+
end
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if player.nil?
|
|
191
|
+
answer = Jabber::XMLStanza.answer(msg)
|
|
192
|
+
answer.type = :error
|
|
193
|
+
answer.add(Jabber::Error::new('forbidden'))
|
|
194
|
+
send(msg.to.resource, answer)
|
|
195
|
+
return(true)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
unless command(player, msg.body)
|
|
199
|
+
each_thing_by_place(player.place) { |thing|
|
|
200
|
+
thing.send_message(player.iname, msg.body)
|
|
201
|
+
}
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def command(player, text)
|
|
206
|
+
if text == '?'
|
|
207
|
+
player.send_message(nil, "(Command) who")
|
|
208
|
+
place(player.place).each_element('go') { |go|
|
|
209
|
+
player.send_message(nil, "(Command) go #{go.attributes['spec']}")
|
|
210
|
+
}
|
|
211
|
+
each_thing_by_place(player.place) { |thing|
|
|
212
|
+
thing.each_element('on-command') { |c|
|
|
213
|
+
player.send_message(nil, "(Command) #{c.attributes['command']} #{thing.command_name}")
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return(true)
|
|
217
|
+
else
|
|
218
|
+
words = text.split(/ /)
|
|
219
|
+
cmd = words.shift
|
|
220
|
+
what = words.shift || ""
|
|
221
|
+
if cmd == 'go'
|
|
222
|
+
oldplace = place(player.place)
|
|
223
|
+
newplace = nil
|
|
224
|
+
|
|
225
|
+
oldplace.each_element('go') { |go|
|
|
226
|
+
if go.attributes['spec'] == what
|
|
227
|
+
newplace = go.attributes['place']
|
|
228
|
+
end
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if newplace.nil?
|
|
232
|
+
player.send_message(nil, 'You cannot go there')
|
|
233
|
+
else
|
|
234
|
+
move_thing(player, newplace)
|
|
235
|
+
end
|
|
236
|
+
return(true)
|
|
237
|
+
elsif cmd == 'who'
|
|
238
|
+
player.send_message(nil, "Players in \"#{iname}\":")
|
|
239
|
+
each_element('thing') { |thing|
|
|
240
|
+
if thing.kind_of?(Player)
|
|
241
|
+
player.send_message(nil, "#{thing.iname} is at/in #{thing.place}")
|
|
242
|
+
end
|
|
243
|
+
}
|
|
244
|
+
return(true)
|
|
245
|
+
else
|
|
246
|
+
handled = false
|
|
247
|
+
each_thing_by_place(player.place) { |thing|
|
|
248
|
+
if what.downcase == thing.command_name.downcase
|
|
249
|
+
thing.each_element('on-command') { |c|
|
|
250
|
+
if c.attributes['command'] == cmd
|
|
251
|
+
thing.command(player, c, words)
|
|
252
|
+
handled = true
|
|
253
|
+
end
|
|
254
|
+
}
|
|
255
|
+
end
|
|
256
|
+
}
|
|
257
|
+
return(true) if handled
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
false
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
class Place < REXML::Element
|
|
265
|
+
def initialize
|
|
266
|
+
super('place')
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def iname
|
|
270
|
+
attributes['name']
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
class Thing < REXML::Element
|
|
275
|
+
def initialize(world)
|
|
276
|
+
super('thing')
|
|
277
|
+
@world = world
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def add(xmlelement)
|
|
281
|
+
if xmlelement.kind_of?(REXML::Element) && (xmlelement.name == 'presence')
|
|
282
|
+
super(Jabber::Presence.import(xmlelement))
|
|
283
|
+
else
|
|
284
|
+
super(xmlelement)
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def iname
|
|
289
|
+
attributes['name']
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def command_name
|
|
293
|
+
attributes['command-name'].nil? ? iname : attributes['command-name']
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def place
|
|
297
|
+
attributes['place']
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def place=(p)
|
|
301
|
+
attributes['place'] = p
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def jid
|
|
305
|
+
nil
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def presence
|
|
309
|
+
xe = nil
|
|
310
|
+
each_element('presence') { |pres|
|
|
311
|
+
xe = Jabber::Presence.import(pres)
|
|
312
|
+
}
|
|
313
|
+
if self.kind_of?(Player)
|
|
314
|
+
xe.add(Jabber::MUC::XMUCUser.new).add(Jabber::MUC::XMUCUserItem.new(:none, :participant))
|
|
315
|
+
else
|
|
316
|
+
xe.add(Jabber::MUC::XMUCUser.new).add(Jabber::MUC::XMUCUserItem.new(:owner, :moderator))
|
|
317
|
+
end
|
|
318
|
+
xe
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def presence=(pres)
|
|
322
|
+
delete_elements('presence')
|
|
323
|
+
add(pres)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def see(place)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def send_message(fromresource, text, subject=nil)
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def send_message_to_place(fromresource, text)
|
|
333
|
+
@world.each_element('thing') { |thing|
|
|
334
|
+
if thing.place == place
|
|
335
|
+
thing.send_message(fromresource, text)
|
|
336
|
+
end
|
|
337
|
+
}
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def on_enter(thing, from)
|
|
341
|
+
each_element('on-enter') { |c|
|
|
342
|
+
command(thing, c, [from])
|
|
343
|
+
}
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def on_leave(thing, to)
|
|
347
|
+
each_element('on-leave') { |c|
|
|
348
|
+
command(thing, c, [to])
|
|
349
|
+
}
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def command(source, command, arguments)
|
|
353
|
+
command.each_element { |action|
|
|
354
|
+
text = action.text.nil? ? "" : action.text.dup
|
|
355
|
+
text.gsub!('%self%', iname)
|
|
356
|
+
text.gsub!('%actor%', source.iname)
|
|
357
|
+
text.gsub!('%place%', place)
|
|
358
|
+
if action.name == 'say' || action.name == 'tell'
|
|
359
|
+
sender = nil
|
|
360
|
+
sender = iname if action.name == 'say'
|
|
361
|
+
if action.attributes['to'] == 'all'
|
|
362
|
+
send_message_to_place(sender, text)
|
|
363
|
+
else
|
|
364
|
+
source.send_message(sender, text)
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
}
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
class Player < Thing
|
|
372
|
+
def initialize(world, iname, jid)
|
|
373
|
+
super(world)
|
|
374
|
+
attributes['name'] = iname
|
|
375
|
+
attributes['jid'] = jid.to_s
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def jid
|
|
379
|
+
attributes['jid'].nil? ? nil : Jabber::JID::new(attributes['jid'])
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def see(place)
|
|
383
|
+
return if place.nil?
|
|
384
|
+
|
|
385
|
+
place.text.strip.split(/\n/).each do |line|
|
|
386
|
+
send_message(nil, line.strip)
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
send_message(nil, " ")
|
|
390
|
+
|
|
391
|
+
directions = []
|
|
392
|
+
place.each_element('go') { |go|
|
|
393
|
+
directions.push(go.attributes['spec'])
|
|
394
|
+
}
|
|
395
|
+
send_message(nil, "You can go #{directions.join(', ')}")
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def send_message(fromresource, text, subject=nil)
|
|
399
|
+
msg = Jabber::Message.new(jid, text)
|
|
400
|
+
msg.type = :groupchat
|
|
401
|
+
msg.subject = subject unless subject.nil?
|
|
402
|
+
@world.send(fromresource, msg)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def on_enter(thing, from)
|
|
406
|
+
if thing != self
|
|
407
|
+
if from.nil?
|
|
408
|
+
send_message(nil, "#{thing.iname} spawns")
|
|
409
|
+
else
|
|
410
|
+
send_message(nil, "#{thing.iname} enters #{place} coming from #{from}")
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def on_leave(thing, to)
|
|
416
|
+
if thing != self
|
|
417
|
+
if to.nil?
|
|
418
|
+
send_message(nil, "#{thing.iname} disintegrates")
|
|
419
|
+
else
|
|
420
|
+
send_message(nil, "#{thing.iname} leaves #{place} going to #{to}")
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|