Class Jabber::MUC::MUCClient
In: lib/xmpp4r/muc/helper/mucclient.rb
Parent: Object
XMLStanza Message Presence Iq REXML::Element X IqQuery Error StreamHost IqSiFileRange IqSiFile StreamHostUsed IqSi IqFeature XRosterItem RosterItem XMUCUserItem XMUCUserInvite XDataField XDataReported XDataTitle XDataInstructions Feature Identity Item IqVcard Singleton IdGenerator Connection Client Component Comparable JID RuntimeError AuthenticationFailure ErrorException SOCKS5Error Stream SOCKS5Bytestreams SOCKS5BytestreamsTarget SOCKS5BytestreamsInitiator SOCKS5BytestreamsServerStreamHost TCPSocket SOCKS5Socket IqQuery IqQueryBytestreams IqQueryVersion IqQueryRoster IqQueryDiscoItems IqQueryDiscoInfo IBB IBBTarget IBBInitiator Responder SimpleResponder X XRoster XMUCUser XMUC XDelay XData MUCClient SimpleMUCClient Base DigestMD5 Plain FileSource StreamParser SOCKS5BytestreamsPeer SOCKS5BytestreamsServer IBBQueueItem Helper MUCBrowser Helper Helper lib/xmpp4r/authenticationfailure.rb lib/xmpp4r/idgenerator.rb lib/xmpp4r/connection.rb lib/xmpp4r/iq.rb lib/xmpp4r/jid.rb lib/xmpp4r/xmlstanza.rb lib/xmpp4r/errorexception.rb lib/xmpp4r/stream.rb lib/xmpp4r/client.rb lib/xmpp4r/x.rb lib/xmpp4r/streamparser.rb lib/xmpp4r/error.rb lib/xmpp4r/component.rb lib/xmpp4r/query.rb lib/xmpp4r/message.rb lib/xmpp4r/presence.rb lib/xmpp4r/bytestreams/helper/ibb/initiator.rb lib/xmpp4r/bytestreams/iq/si.rb lib/xmpp4r/bytestreams/iq/bytestreams.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/base.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/server.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/socks5.rb lib/xmpp4r/bytestreams/helper/socks5bytestreams/initiator.rb lib/xmpp4r/bytestreams/helper/ibb/base.rb lib/xmpp4r/bytestreams/helper/ibb/target.rb Bytestreams lib/xmpp4r/version/iq/version.rb lib/xmpp4r/version/helper/responder.rb lib/xmpp4r/version/helper/simpleresponder.rb Version lib/xmpp4r/feature_negotiation/iq/feature.rb FeatureNegotiation lib/xmpp4r/roster/helper/roster.rb lib/xmpp4r/roster/iq/roster.rb lib/xmpp4r/roster/x/roster.rb Roster lib/xmpp4r/muc/x/muc.rb lib/xmpp4r/muc/helper/mucclient.rb lib/xmpp4r/muc/x/mucuseritem.rb lib/xmpp4r/muc/helper/mucbrowser.rb lib/xmpp4r/muc/x/mucuserinvite.rb lib/xmpp4r/muc/helper/simplemucclient.rb MUC lib/xmpp4r/sasl.rb SASL lib/xmpp4r/bytestreams/helper/filetransfer.rb TransferSource FileTransfer lib/xmpp4r/delay/x/delay.rb Delay lib/xmpp4r/dataforms/x/data.rb Dataforms lib/xmpp4r/discovery/iq/discoinfo.rb lib/xmpp4r/discovery/iq/discoitems.rb Discovery lib/xmpp4r/vcard/helper/vcard.rb lib/xmpp4r/vcard/iq/vcard.rb Vcard Jabber Module: Jabber

The MUCClient Helper handles low-level stuff of the Multi-User Chat (JEP 0045).

Use one instance per room.

Note that one client cannot join a single room multiple times. At least the clients’ resources must be different. This is a protocol design issue. But don’t consider it as a bug, it is just a clone-preventing feature.

Methods

Attributes

jid  [R]  MUC JID
jid:[JID] room@component/nick
my_jid  [RW]  Sender JID, set this to use MUCClient from Components
my_jid:[JID] Defaults to nil
roster  [R]  MUC room roster
roster:[Hash] of [String] Nick => [Presence]

Public Class methods

Initialize a MUCClient

Call MUCClient#join after you have registered your callbacks to avoid reception of stanzas after joining and before registration of callbacks.

stream:[Stream] to operate on

[Source]

    # File lib/xmpp4r/muc/helper/mucclient.rb, line 42
42:       def initialize(stream)
43:         # Attributes initialization
44:         @stream = stream
45:         @my_jid = nil
46:         @jid = nil
47:         @roster = {}
48:         @roster_lock = Mutex.new
49: 
50:         @active = false
51: 
52:         @join_cbs = CallbackList.new
53:         @leave_cbs = CallbackList.new
54:         @presence_cbs = CallbackList.new
55:         @message_cbs = CallbackList.new
56:         @private_message_cbs = CallbackList.new
57:       end

Public Instance methods

Is the MUC client active?

This is false after initialization, true after joining and false after exit/kick

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 153
153:       def active?
154:         @active
155:       end

Add a callback for <presence/> stanzas indicating availability of a MUC participant

This callback will not be called for initial presences when a client joins a room, but only for the presences afterwards.

The callback will be called from MUCClient#handle_presence with one argument: the <presence/> stanza. Note that this stanza will have been already inserted into MUCClient#roster.

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 260
260:       def add_join_callback(prio = 0, ref = nil, &block)
261:         @join_cbs.add(prio, ref, block)
262:       end

Add a callback for <presence/> stanzas indicating unavailability of a MUC participant

The callback will be called with one argument: the <presence/> stanza.

Note that this is called just before the stanza is removed from MUCClient#roster, so it is still possible to see the last presence in the given block.

If the presence’s origin is your MUC JID, the MUCClient will be deactivated afterwards.

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 276
276:       def add_leave_callback(prio = 0, ref = nil, &block)
277:         @leave_cbs.add(prio, ref, block)
278:       end

Add a callback for <message/> stanza directed to the whole room.

See MUCClient#add_private_message_callback for private messages between MUC participants.

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 293
293:       def add_message_callback(prio = 0, ref = nil, &block)
294:         @message_cbs.add(prio, ref, block)
295:       end

Add a callback for a <presence/> stanza which is neither a join nor a leave. This will be called when a room participant simply changes his status.

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 284
284:       def add_presence_callback(prio = 0, ref = nil, &block)
285:         @presence_cbs.add(prio, ref, block)
286:       end

Add a callback for <message/> stanza with type=’chat’.

These stanza are normally not broadcasted to all room occupants but are some sort of private messaging.

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 302
302:       def add_private_message_callback(prio = 0, ref = nil, &block)
303:         @private_message_cbs.add(prio, ref, block)
304:       end

Exit the room

  • Sends presence with type=’unavailable’ with an optional reason in <status/>,
  • then waits for a reply from the MUC component (will be processed by leave-callbacks),
  • then deletes callbacks from the stream.
reason:[String] Optional custom exit message

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 122
122:       def exit(reason=nil)
123:         unless active?
124:           raise "MUCClient hasn't yet joined"
125:         end
126: 
127:         pres = Presence.new
128:         pres.type = :unavailable
129:         pres.to = jid
130:         pres.from = @my_jid
131:         pres.status = reason if reason
132:         @stream.send(pres) { |r|
133:           Jabber::debuglog "exit: #{r.to_s.inspect}"
134:           if r.kind_of?(Presence) and r.type == :unavailable and r.from == jid
135:             @leave_cbs.process(r)
136:             true
137:           else
138:             false
139:           end
140:         }
141: 
142:         deactivate
143: 
144:         self
145:       end

Does this JID belong to that room?

jid:[JID]
result:[true] or [false]

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 310
310:       def from_room?(jid)
311:         @jid.strip == jid.strip
312:       end

Join a room

This registers its own callbacks on the stream provided to initialize and sends initial presence to the room. May throw ErrorException if joining fails.

jid:[JID] room@component/nick
password:[String] Optional password
return:[MUCClient] self (chain-able)

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 69
 69:       def join(jid, password=nil)
 70:         if active?
 71:           raise "MUCClient already active"
 72:         end
 73:         
 74:         @jid = (jid.kind_of?(JID) ? jid : JID.new(jid))
 75:         activate
 76: 
 77:         # Joining
 78:         pres = Presence.new
 79:         pres.to = @jid
 80:         pres.from = @my_jid
 81:         xmuc = XMUC.new
 82:         xmuc.password = password
 83:         pres.add(xmuc)
 84: 
 85:         # We don't use Stream#send_with_id here as it's unknown
 86:         # if the MUC component *always* uses our stanza id.
 87:         error = nil
 88:         @stream.send(pres) { |r|
 89:           if from_room?(r.from) and r.kind_of?(Presence) and r.type == :error
 90:             # Error from room
 91:             error = r.error
 92:             true
 93:           # type='unavailable' may occur when the MUC kills our previous instance,
 94:           # but all join-failures should be type='error'
 95:           elsif r.from == jid and r.kind_of?(Presence) and r.type != :unavailable
 96:             # Our own presence reflected back - success
 97:             handle_presence(r, false)
 98:             true
 99:           else
100:             # Everything else
101:             false
102:           end
103:         }
104: 
105:         if error
106:           deactivate
107:           raise ErrorException.new(error)
108:         end
109: 
110:         self
111:       end

The MUCClient’s own nick (= resource)

result:[String] Nickname

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 161
161:       def nick
162:         @jid ? @jid.resource : nil
163:       end

Change nick

Threading is, again, suggested. This method waits for two <presence/> stanzas, one indicating unavailabilty of the old transient JID, one indicating availability of the new transient JID.

If the service denies nick-change, ErrorException will be raisen.

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 174
174:       def nick=(new_nick)
175:         unless active?
176:           raise "MUCClient not active"
177:         end
178:         
179:         new_jid = JID.new(@jid.node, @jid.domain, new_nick)
180: 
181:         # Joining
182:         pres = Presence.new
183:         pres.to = new_jid
184:         pres.from = @my_jid
185: 
186:         error = nil
187:         # Keeping track of the two stanzas enables us to process stanzas
188:         # which don't arrive in the order specified by JEP-0045
189:         presence_unavailable = false
190:         presence_available = false
191:         # We don't use Stream#send_with_id here as it's unknown
192:         # if the MUC component *always* uses our stanza id.
193:         @stream.send(pres) { |r|
194:           if from_room?(r.from) and r.kind_of?(Presence) and r.type == :error
195:             # Error from room
196:             error = r.error
197:           elsif r.from == @jid and r.kind_of?(Presence) and r.type == :unavailable and
198:                 r.x and r.x.kind_of?(XMUCUser) and r.x.status_code == 303
199:             # Old JID is offline, but wait for the new JID and let stanza be handled
200:             # by the standard callback
201:             presence_unavailable = true
202:             handle_presence(r)
203:           elsif r.from == new_jid and r.kind_of?(Presence) and r.type != :unavailable
204:             # Our own presence reflected back - success
205:             presence_available = true
206:             handle_presence(r)
207:           end
208: 
209:           if error or (presence_available and presence_unavailable)
210:             true
211:           else
212:             false
213:           end
214:         }
215: 
216:         if error
217:           raise ErrorException.new(error)
218:         end
219: 
220:         # Apply new JID
221:         @jid = new_jid
222:       end

The room name (= node)

result:[String] Room name

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 228
228:       def room
229:         @jid ? @jid.node : nil
230:       end

Send a stanza to the room

If stanza is a Jabber::Message, stanza.type will be automatically set to :groupchat if directed to room or :chat if directed to participant.

stanza:[XMLStanza] to send
to:[String] Stanza destination recipient, or room if nil

[Source]

     # File lib/xmpp4r/muc/helper/mucclient.rb, line 240
240:       def send(stanza, to=nil)
241:         if stanza.kind_of? Message
242:           stanza.type = to ? :chat : :groupchat
243:         end
244:         stanza.from = @my_jid
245:         stanza.to = JID::new(jid.node, jid.domain, to)
246:         @stream.send(stanza)
247:       end

[Validate]