# class GxG::Networking::XmppAgent

XMPP Client

### Public Class Methods

new(options={}) click to toggle source

Initialization

    # File lib/gxg/net_clients.rb, line 3564
    def initialize(options={})
      @client = nil
      @pubsub = nil
      @roster = nil
      @browser = nil
      @transfer_manager = nil
      @xfr_callbacks = nil
      @conversations = []
      @conversation_thread_safety = ::Mutex.new
      @invitations = []
      @invitation_thread_safety = ::Mutex.new
      @download_directory = ::File.expand_path(".")
      @file_transfers = []
      @file_transfers_thread_safety = ::Mutex.new
      @notification_object = options[:notify]
      self
    end

online_availability_values() click to toggle source

    # File lib/gxg/net_clients.rb, line 3146
    def self.online_availability_values()
      {:online => :chat, :busy => :dnd, :away => :away, :extended_away => :xa, :offline => :unavailable, :error => :error}
    end

register_with_server(the_url=nil, fields={}) click to toggle source

    # File lib/gxg/net_clients.rb, line 3233
    def self.register_with_server(the_url=nil, fields={})
        # Review : convert this code to Blather compatible
        # Note : see https://www.rubydoc.info/gems/blather/Blather/Stanza/Iq for researching ideas.
        # Note : see https://www.rubydoc.info/gems/xmpp4r/Jabber/Client#register-instance_method for researching ideas.
        result = false
        begin
            if the_url.is_a?(::URI::Generic)
            if the_url.password() == nil
                raise ArgumentError, "You MUST provide a vailid password."
            else
                fields['password'] = the_url.password.to_s
            end
            the_jid = ""
            if the_url.user()
                the_jid << the_url.user.to_s
                fields['username'] = the_url.user.to_s
            else
                raise ArgumentError, "You MUST provide a vailid user name."
            end
            if the_url.hostname()
                the_jid << ("@" + the_url.hostname.to_s)
            else
                raise ArgumentError, "You MUST provide a vailid host or IP Address."
            end
            if the_url.path()
                the_jid << ("/" + File.basename(the_url.path.to_s))
            end
            # xxx
            # client = ::Jabber::Client.new(the_jid)
            # client.connect(the_url.hostname.to_s, (the_url.port || 5222))
            # valid_fields = ::GxG::Networking::XmppClient::registration_fields().keys
            # the_fields = {}
            # fields.each_pair do |key, entry|
            #     if valid_fields.include?(key.to_sym)
            #     the_fields[(key.to_s)] = entry
            #     end
            # end
            # if the_fields.keys.size > 0
            #     client.register(the_url.password.to_s, the_fields)
            # else
            #     client.register(the_url.password.to_s)
            # end
            # if client.status == 2
            #     client.close
            # end
            result = true
            else
            raise ArgumentError, "You MUST provide a vailid URL."
            end
        rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:url => the_url, :fields => fields}})
        end
        result
    end

registration_fields() click to toggle source

    # File lib/gxg/net_clients.rb, line 3150
    def self.registration_fields()
      # XEP-0077 Support
      {:username => 'Account name associated with the user', :nick => 'Familiar name of the user', :password => 'Password or secret for the user', :name => 'Full name of the user', :first => 'First name or given name of the user', :last => 'Last name, surname, or family name of the user', :email => 'Email address of the user', :address => 'Street portion of a physical or mailing address', :city => 'Locality portion of a physical or mailing address', :state => 'Region portion of a physical or mailing address', :zip => 'Postal code portion of a physical or mailing address', :phone => 'Telephone number of the user', :url => 'URL to web page describing the user', :date => 'Some date (e.g., birth date, hire date, sign-up date)'}.clone
    end

registration_info(the_url=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 3155
    def self.registration_info(the_url=nil)
      result = nil
      begin
        if the_url.is_a?(::URI::Generic)
            the_jid = "anonymous"
            if the_url.hostname()
                the_jid << ("@" + the_url.hostname.to_s)
            else
                raise ArgumentError, "You MUST provide a vailid host or IP Address in a valid URI."
            end
            # Review : convert this code to Blather compatible
            # Note : see https://www.rubydoc.info/gems/blather/Blather/Stanza/Iq for researching ideas.
            # Note : see https://www.rubydoc.info/gems/xmpp4r/Jabber/Client#register-instance_method for researching ideas.
            result = []
            #   client = ::Jabber::Client.new(the_jid)
            #   client.connect(the_url.hostname.to_s, (the_url.port || 5222))
            #   info = client.register_info()
            #   if client.status == 2
            #     client.close
            #   end
            #   if info.is_a?(::Array)
            #     fields = ::GxG::Networking::XmppClient::registration_fields()
            #     result = {:instructions => info[0], :registration_fields => {}}
            #     info[1].each do |the_raw_key|
            #       result[:registration_fields][(the_raw_key.to_sym)] = fields[(the_raw_key.to_sym)]
            #     end
            #   end
        else
          raise ArgumentError, "You MUST provide a vailid URL."
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {:url => the_url}})
      end
      result
    end

remove_registration(the_url=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 3191
    def self.remove_registration(the_url=nil)
        # Review : convert this code to Blather compatible
        # Note : see https://www.rubydoc.info/gems/blather/Blather/Stanza/Iq for researching ideas.
        # Note : see https://www.rubydoc.info/gems/xmpp4r/Jabber/Client#register-instance_method for researching ideas.
        result = false
        begin
            if the_url.is_a?(::URI::Generic)
            if the_url.password() == nil
                raise ArgumentError, "You MUST provide a vailid password."
            end
            the_jid = ""
            if the_url.user()
                the_jid << the_url.user.to_s
            else
                raise ArgumentError, "You MUST provide a vailid user name."
            end
            if the_url.hostname()
                the_jid << ("@" + the_url.hostname.to_s)
            else
                raise ArgumentError, "You MUST provide a vailid host or IP Address."
            end
            if the_url.path()
                the_jid << ("/" + File.basename(the_url.path.to_s))
            end
            # Here ???
            # Connect
            client = ::Blather::Client::setup(the_jid, the_url.password.to_s, the_url.hostname.to_s, (the_url.port || 5222))
            client.run
            # xxx
            # client.remove_registration
            # xxx
            client.close
            result = true
            else
            raise ArgumentError, "You MUST provide a vailid URL."
            end
        rescue Exception => the_error
            log_error({:error => the_error, :parameters => {:url => the_url, :fields => fields}})
        end
        result
    end

### Public Instance Methods

<<(stanza) click to toggle source

    # File lib/gxg/net_clients.rb, line 3296
    def <<(stanza)
        if @client
            @client.write stanza
        end
        self
    end

add_buddy(the_jid=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 3798
    def add_buddy(the_jid=nil)
      result = false
      begin
        if @client
          if the_jid.is_a?(::String)
            unless the_jid.valid_jid?
              raise ArgumentError, "You MUST provide a valid JID string."
            end
            @client.write(Blather::Stanza::Presence::Subscription.new(::Blather::JID.new(the_jid), "subscribe"))
            result = true
          end
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {:the_jid => the_jid}})
      end
      result
    end

after(handler = nil, *guards, &block) click to toggle source

### Setup an after filter

@param [Symbol] handler (optional) the stanza handler the filter should run after @param [guards] guards (optional) a set of guards to check the stanza against @yield [Blather::Stanza] stanza

    # File lib/gxg/net_clients.rb, line 3325
    def after(handler = nil, *guards, &block)
        if @client
            @client.register_filter :after, handler, *guards, &block
        end
    end

before(handler = nil, *guards, &block) click to toggle source

### Setup a before filter

@param [Symbol] handler (optional) the stanza handler the filter should run before @param [guards] guards (optional) a set of guards to check the stanza against @yield [Blather::Stanza] stanza

    # File lib/gxg/net_clients.rb, line 3313
    def before(handler = nil, *guards, &block)
        if @client
            @client.register_filter :before, handler, *guards, &block
        end
    end

buddies() click to toggle source

    # File lib/gxg/net_clients.rb, line 3777
    def buddies()
        result = []
        begin
            if @client
                @client.roster.items.each_pair do |key_object, data|
                    new_record = {:jid => "", :title => "Untitled", :groups => [], :status => :offline}
                    new_record[:jid] = key_object.to_s
                    new_record[:title] = data.name.to_s
                    new_record[:groups] = data.groups
                    if data.status()
                        new_record[:status] = data.status().state()
                    end
                    result << new_record
                end
            end
        rescue Exception => the_error
            log_error({:error => the_error, :parameters => {}})
        end
        result
    end

client() click to toggle source

Review : debug only method

    # File lib/gxg/net_clients.rb, line 3582
    def client()
        @client
    end

conversations(select_jid=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 3902
    def conversations(select_jid=nil)
      result = []
      begin
        if @client
          @conversation_thread_safety.synchronize {
            @conversations.each do |entry|
                if select_jid
                    if select_jid.to_s == entry.jid.to_s
                        unless entry.closed?
                            result << entry
                            break
                        end
                    end
                else
                    unless entry.closed?
                        result << entry
                    end
                end
            end
          }
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {}})
      end
      result
    end

create_conversation(the_jid=nil, password=nil, configuration={}) click to toggle source

    # File lib/gxg/net_clients.rb, line 3929
    def create_conversation(the_jid=nil, password=nil, configuration={})
      result = false
      begin
        if @client
          unless the_jid.is_a?(::String)
            raise ArgumentError, "You MUST provide a valid JID String."
          end
          unless the_jid.valid_jid?()
            raise ArgumentError, "You MUST provide a valid JID String. The one you provided is malformed."
          end
          if (self.buddies.collect {|entry| entry[:jid]}).include?(the_jid)
            # private channel
            the_channel = self.conversations(the_jid)[0]
            unless the_channel
                the_channel = ::GxG::Networking::XmppAgentConversation.new(self, {:sender => the_jid, :type => :chat})
                @conversation_thread_safety.synchronize { @conversations << the_channel }
            end
          else
            # groupchat channel
            the_channel = self.conversations(the_jid)[0]
            unless the_channel
                the_channel = ::GxG::Networking::XmppAgentConversation.new(self, {:sender => the_jid, :type => :groupchat})
                @conversation_thread_safety.synchronize { @conversations << the_channel }
            end
            if the_channel
                the_channel.join(the_jid)
                if configuration.is_any?(::Hash, ::GxG::Database::PersistedHash)
                  if configuration.keys.size > 0
                    the_channel.change_configuration(configuration)
                  end
                end
            end
          end
          result = true
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {:jid => the_jid}})
      end
      result
    end

disconnected(&block) click to toggle source

### Wrapper for “handle :disconnected”

This is run after the connection has been shut down.

@example Reconnect after a disconnection

    disconnected { client.run }

    # File lib/gxg/net_clients.rb, line 3353
    def disconnected(&block)
        self.handle :disconnected, &block
    end

discover(what, who, where, &callback) click to toggle source

### Request items or info from an entity

    discover (items|info), [jid], [node] do |response|
    end

    # File lib/gxg/net_clients.rb, line 3479
    def discover(what, who, where, &callback)
        if @client
            stanza = Blather::Stanza.class_from_registration(:query, "http://jabber.org/protocol/disco##{what}").new
            stanza.to = who
            stanza.node = where

            @client.register_tmp_handler stanza.id, &callback
            @client.write stanza
        end
    end

download_directory() click to toggle source

    # File lib/gxg/net_clients.rb, line 3994
    def download_directory()
      @file_transfers_thread_safety.synchronize { @download_directory }
    end

download_directory=(the_path=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 3998
    def download_directory=(the_path=nil)
      unless the_path.is_a?(::String)
        raise ArgumentError, "You MUST supply a String as valid file path."
      end
      the_path = ::File.expand_path(the_path)
      unless the_path.valid_path?()
        raise ArgumentError, "You MUST supply a valid file path."
      end
      unless ::File.exist?(the_path)
        raise ArgumentError, "You MUST supply a valid file path - File does not exist."
      end
      @file_transfers_thread_safety.synchronize { @download_directory = the_path }
    end

file_transfers() click to toggle source

    # File lib/gxg/net_clients.rb, line 4057
    def file_transfers()
      result = []
      if @client
        begin
          @file_transfers.each do |entry|
            if (entry.pending? || entry.in_progress? || entry.percent_completed < 100)
              result << entry
            end
          end
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {}})
        end
      end
      result
    end

find_file_transfer(reference=nil, use_session = false) click to toggle source

    # File lib/gxg/net_clients.rb, line 4104
    def find_file_transfer(reference=nil, use_session = false)
      result = nil
      begin
        if @client
          manifest = []
          @file_transfers_thread_safety.synchronize {
            @file_transfers.each do |entry|
              manifest << entry
            end
          }
          manifest.each do |entry|
            if use_session == true
              if (reference == entry.session_id())
                result = entry
                break
              end
            else
              if (reference == entry.reference())
                result = entry
                break
              end
            end
          end
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {}})
      end
      result
    end

get_status() click to toggle source

    # File lib/gxg/net_clients.rb, line 3367
    def get_status()
        if @client
            @client.status
        else
            :unavailable
        end
    end

gxg_message_to_xmpp(the_message=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 3535
    def gxg_message_to_xmpp(the_message=nil)
      # need: :to, :body, :state, :subject, :context, :type
      # ::Celluloid::UUID::random_generate().to_s
      unless the_message.is_a?(::GxG::Events::Message)
        raise ArgumentError, "You MUST provide a valid message object: GxG::Events::Message or new_message Hash."
      end
      xmpp_message = Blather::Stanza::Message.new(the_message[:to], the_message[:body])
      # chat states: active composing gone inactive paused
      # xmpp_message.set_chat_state(the_message[:state].to_s.to_sym)
      xmpp_message.id = (the_message[:id].to_s)
      xmpp_message.from = (the_message[:sender].to_s)
      xmpp_message.to = (the_message[:to].to_s)
      if the_message[:context].to_s.size > 0
        xmpp_message.thread = (the_message[:context].to_s)
      end
      xmpp_message.subject = (the_message[:subject].to_s)
      #
      # The following <type> Symbols are allowed:
      # * :chat
      # * :error
      # * :groupchat
      # * :headline
      # * :normal
      xmpp_message.type = (the_message[:type] || :chat)
      xmpp_message.body = the_message[:body]
      xmpp_message
    end

halt() click to toggle source

### Halt the handler chain

Use this to stop the propogation of the stanza though the handler chain.

@example Ignore all IQ stanzas

    before(:iq) { halt }

    # File lib/gxg/net_clients.rb, line 3456
    def halt
        # Review : how to actually use this? I see no way to call 'throw' yet. (research)
        # throw :halt
    end

handle(handler, *guards, &block) click to toggle source

### Set handler for a stanza type

@param [Symbol] handler the stanza type it should handle @param [guards] guards (optional) a set of guards to check the stanza against @yield [Blather::Stanza] stanza

    # File lib/gxg/net_clients.rb, line 3336
    def handle(handler, *guards, &block)
        if @client
            @client.register_handler handler, *guards, &block
        end
    end

invitations() click to toggle source

    # File lib/gxg/net_clients.rb, line 3834
    def invitations()
      result = []
      begin
        if @client
          @invitation_thread_safety.synchronize {
            @invitations.each do |entry|
              if entry.pending?
                result << entry
              end
            end
          }
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {}})
      end
      result
    end

jid() click to toggle source

### The JID according to the server

@return [Blather::JID]

    # File lib/gxg/net_clients.rb, line 3417
    def jid
        if @client
            @client.jid
        else
            nil
        end
    end

jid_domain() click to toggle source

    # File lib/gxg/net_clients.rb, line 3433
    def jid_domain()
        jid = self.jid
        if jid
            jid.domain()
        else
            nil
        end
    end

jid_node() click to toggle source

other supporting JID methods

    # File lib/gxg/net_clients.rb, line 3425
    def jid_node()
        jid = self.jid
        if jid
            jid.node()
        else
            nil
        end
    end

jid_resource() click to toggle source

    # File lib/gxg/net_clients.rb, line 3441
    def jid_resource()
        jid = self.jid
        if jid
            jid.resource()
        else
            nil
        end
    end

join(room, service, nickname = nil) click to toggle source

### Helper method to join a MUC room

@overload join(room_jid, nickname)

     @param [Blather::JID, #to_s] room the JID of the room to join
     @param [#to_s] nickname the nickname to join the room as
    @overload join(room_jid, nickname)
     @param [#to_s] room the name of the room to join
     @param [Blather::JID, #to_s] service the service domain the room is hosted at
     @param [#to_s] nickname the nickname to join the room as

    # File lib/gxg/net_clients.rb, line 3397
    def join(room, service, nickname = nil)
        join = Blather::Stanza::Presence::MUC.new
        if nickname
            join.to = "#{room}@#{service}/#{nickname}"
        else
            join.to = "#{room}/#{service}"
        end
        self.write join
    end

join_conversation(the_jid=nil, password=nil, options={}) click to toggle source

    # File lib/gxg/net_clients.rb, line 3970
    def join_conversation(the_jid=nil, password=nil, options={})
      result = false
      begin
        if @client
          unless the_jid.is_a?(::String)
            raise ArgumentError, "You MUST provide a valid JID String."
          end
          unless the_jid.valid_jid?()
            raise ArgumentError, "You MUST provide a valid JID String. The one you provided is malformed."
          end
          the_channel = self.conversations(the_jid)[0]
          unless the_channel
              the_channel = ::GxG::Networking::XmppAgentConversation.new(self, {:sender => the_jid, :type => :groupchat})
              @conversation_thread_safety.synchronize { @conversations << the_channel }
              the_channel.join(the_jid)
          end
          result = true
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {:jid => the_jid}})
      end
      result
    end

login(the_url=nil, options={}) click to toggle source

    # File lib/gxg/net_clients.rb, line 3596
    def login(the_url=nil, options={})
        result = false
        begin
            if the_url.is_a?(::URI::Generic)
                if the_url.password() == nil && the_url.user != "anonymous"
                raise ArgumentError, "You MUST provide a vailid password."
                end
                the_jid = ""
                if the_url.user()
                the_jid << the_url.user.to_s
                else
                raise ArgumentError, "You MUST provide a vailid user name."
                end
                if the_url.hostname()
                the_jid << ("@" + the_url.hostname.to_s)
                else
                raise ArgumentError, "You MUST provide a vailid host or IP Address."
                end
                if the_url.path()
                the_jid << ("/" + File.basename(the_url.path.to_s))
                end
                # Connect
                @client = ::Blather::Client::setup(the_jid, the_url.password.to_s, the_url.hostname.to_s, (the_url.port || 5222))
                # @client.run
                # Initialize Supports
                @pubsub = ::Blather::DSL::PubSub.new(@client, self.jid_domain)
                # Auto-reconnect if disconnected
                self.handle :disconnected do
                  @client.run
                end
                # ### Setup Message Reception: (skipping compose etc messages for now.)
                # Handlers Map : https://github.com/adhearsion/blather#handlers-hierarchy
                # Private Message (type :normal)
                self.handle :message, :normal?, :body do |message|
                  the_message = self.xmpp_message_to_gxg(message)
                  the_channel = self.conversations(the_message[:sender].to_s)[0]
                  unless the_channel
                      the_channel = ::GxG::Networking::XmppAgentConversation.new(self, {:sender => the_message[:sender], :type => :chat})
                      @conversation_thread_safety.synchronize { @conversations << the_channel }
                  end
                  the_channel.add_message(the_message)
                  self.notify({:event => :new_private_message, :conversation => the_channel.uuid, :message => the_message.id, :sender => the_message[:sender].to_s})
                  true
                end
                # Private Message (type :chat)
                self.handle :message, :chat?, :body do |message|
                    the_message = self.xmpp_message_to_gxg(message)
                    the_channel = self.conversations(the_message[:sender].to_s)[0]
                    unless the_channel
                        the_channel = ::GxG::Networking::XmppAgentConversation.new(self, {:sender => the_message[:sender], :type => :chat})
                        @conversation_thread_safety.synchronize { @conversations << the_channel }
                    end
                    the_channel.add_message(the_message)
                    self.notify({:event => :new_private_message, :conversation => the_channel.uuid, :message => the_message.id, :sender => the_message[:sender].to_s})
                    true
                end
                # Group Message
                self.handle :message, :groupchat?, :body do |message|
                    the_message = self.xmpp_message_to_gxg(message)
                    the_channel = self.conversations(the_message[:sender].to_s)[0]
                    unless the_channel
                        the_channel = ::GxG::Networking::XmppAgentConversation.new(self, {:sender => the_message[:sender], :type => :groupchat})
                        @conversation_thread_safety.synchronize { @conversations << the_channel }
                    end
                    the_channel.add_message(the_message)
                    self.notify({:event => :new_message, :conversation => the_channel.uuid, :message => the_message.id, :sender => the_message[:sender].to_s})
                    true
                end
                # Announcement Message
                self.handle :message, :headline?, :body do |message|
                  the_message = self.xmpp_message_to_gxg(message)
                  the_channel = self.conversations(the_message[:sender].to_s)[0]
                  unless the_channel
                      the_channel = ::GxG::Networking::XmppAgentConversation.new(self, {:sender => the_message[:sender], :type => :chat})
                      @conversation_thread_safety.synchronize { @conversations << the_channel }
                  end
                  the_channel.add_message(the_message)
                  self.notify({:event => :new_announcement, :conversation => the_channel.uuid, :message => the_message.id, :sender => the_message[:sender].to_s})
                  true
                end
                # Error Message
                self.handle :message, :error?, :body do |message|
                  the_message = self.xmpp_message_to_gxg(message)
                  the_channel = self.conversations(the_message[:sender].to_s)[0]
                  unless the_channel
                      the_channel = ::GxG::Networking::XmppAgentConversation.new(self, {:sender => the_message[:sender], :type => :chat})
                      @conversation_thread_safety.synchronize { @conversations << the_channel }
                  end
                  the_channel.add_message(the_message)
                  self.notify({:event => :new_error, :conversation => the_channel.uuid, :message => the_message.id, :sender => the_message[:sender].to_s})
                  true
                end
                # Presence
                self.handle :iq do |update|
                    if update.respond_to?(:type)
                        if update.is_a?(::Blather::Stanza::Iq::Ping)
                            # Auto-reply to Pings:
                            reply = update.reply
                            reply.type = :result
                            # Review : how to add a data payload to the reply?
                            self.write_to_stream(reply)
                        else
                            if update.is_a?(::Blather::Stanza::Iq)
                                # reply = update.reply
                                # reply.type = :result
                                # # Review : how to add a data payload to the reply?
                                # self.write_to_stream(reply)
                                # puts "Got: #{update.class.inspect}\n-----------------------------------------\n#{update.inspect}\n Sent: #{reply.inspect}\n-----------------------------------------\n"
                            end
                        end
                    end
                    # Note : returning 'false' signals that subsequent process of this stanza is desired.
                    false
                end
                # Invitation
                self.handle :subscription do |invitation|
                    gxg_invitation = ::GxG::Networking::XmppAgentInvitation.new(self, invitation)
                    @invitation_thread_safety.synchronize { @invitations << gxg_invitation }
                    self.notify({:event => :new_invitation, :invitation => gxg_invitation.uuid, :sender => gxg_invitation.from.to_s})
                    true
                end
                # Presence
                self.handle :presence do |presence_update|
                    the_sender = "#{presence_update.from.node.to_s}@#{presence_update.from.domain.to_s}"
                    self.my_roster.each do |roster_item|
                        if roster_item.jid.to_s == the_sender
                            roster_item.status = presence_update
                            break
                        end
                    end
                    false
                end
                # File Transfer
                self.handle :file_transfer do |invitation|
                    # gxg_invitation = ::GxG::Networking::XmppAgentInvitation.new(self, invitation)
                    # @invitation_thread_safety.synchronize { @invitations << gxg_invitation }
                    puts "Got (file transfer) : #{invitation.inspect}"
                    false
                end
                # Multi-User Chat (MUC) Invitation
                self.handle :muc_join do |invitation|
                    # gxg_invitation = ::GxG::Networking::XmppAgentInvitation.new(self, invitation)
                    # @invitation_thread_safety.synchronize { @invitations << gxg_invitation }
                    puts "Got (MUC join) : #{invitation.inspect}"
                    true
                end
                self.handle :muc_user do |invitation|
                    # try also: :muc_user, :invite?
                    # gxg_invitation = ::GxG::Networking::XmppAgentInvitation.new(self, invitation)
                    # @invitation_thread_safety.synchronize { @invitations << gxg_invitation }
                    puts "Got (MUC user) : #{invitation.inspect}"
                    true
                end
                # Connect
                @client.run
                result = true
                timeout = Time.now.to_f + 30.0
                until @client.connected? do
                    if Time.now.to_f >= timeout
                        result = false
                        break
                    end
                end
            end
        rescue Exception => the_error
            puts the_error.to_s
        end
        #
        result
    end

logout() click to toggle source

    # File lib/gxg/net_clients.rb, line 3767
    def logout
        if @client
            @client.clear_handlers :disconnected
            @client.close
            @client = nil
        end
        #
        true
    end

my_roster() click to toggle source

### Direct access to the roster

@return [Blather::Roster]

    # File lib/gxg/net_clients.rb, line 3377
    def my_roster
        if @client
            @client.roster
        end
    end

notify(notification_type=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 3586
    def notify(notification_type=nil)
      if notification_type
        if @notification_object
          if @notification_object.respond_to?(:notify)
            @notification_object.notify(notification_type)
          end
        end
      end
    end

pass() click to toggle source

### Pass responsibility to the next handler

Use this to jump out of the current handler and let the next registered handler take care of the stanza

@example Pass a message to the next handler

This is contrive and should be handled with guards, but pass a message to the next handler based on the content

    message { |s| puts "message caught" }
    message { |s| pass if s.body =~ /pass along/ }

    # File lib/gxg/net_clients.rb, line 3472
    def pass
        # Review : how to actually use this? I see no way to call 'throw' yet. (research)
        # throw :pass
    end

publish_and_subscribe() click to toggle source

    # File lib/gxg/net_clients.rb, line 3303
    def publish_and_subscribe
        @pubsub
    end

refresh_conversations() click to toggle source

    # File lib/gxg/net_clients.rb, line 3877
    def refresh_conversations()
      result = false
      begin
        if @client
          deadlist = []
          @conversation_thread_safety.synchronize {
            @conversations.each_index do |index|
              if @conversations[(index)].closed?
                deadlist << index
              end
            end
            if deadlist.size > 0
              deadlist.reverse.each do |the_index|
                @conversations.delete_at(the_index)
              end
            end
            result = true
          }
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {}})
      end
      result
    end

refresh_file_transfers() click to toggle source

    # File lib/gxg/net_clients.rb, line 4073
    def refresh_file_transfers()
      result = false
      begin
        if @client
          manifest = []
          deadlist = []
          @file_transfers_thread_safety.synchronize {
            @file_transfers.each do |entry|
              manifest << entry
            end
          }
          manifest.each_with_index do |entry, index|
            unless (entry.pending?() || entry.in_progress?())
              deadlist << index
            end
          end
          @file_transfers_thread_safety.synchronize {
            if deadlist.size > 0
              deadlist.reverse.each do |the_index|
                @file_transfers.delete_at(the_index)
              end
            end
          }
          result = true
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {}})
      end
      result
    end

refresh_invitations() click to toggle source

    # File lib/gxg/net_clients.rb, line 3852
    def refresh_invitations()
      result = false
      begin
        if @client
          deadlist = []
          @invitation_thread_safety.synchronize {
            @invitations.each_index do |index|
              unless @invitations[(index)].pending?
                deadlist << index
              end
            end
            if deadlist.size > 0
              deadlist.reverse.each do |the_index|
                @invitations.delete_at(the_index)
              end
            end
            result = true
          }
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {}})
      end
      result
    end

remove_buddy(the_jid=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 3816
    def remove_buddy(the_jid=nil)
      result = false
      begin
        if @client
          if the_jid.is_a?(::String)
            unless the_jid.valid_jid?
              raise ArgumentError, "You MUST provide a valid JID string."
            end
            @client.write(Blather::Stanza::Presence::Subscription.new(::Blather::JID.new(the_jid), "unsubscribe"))
            result = true
          end
        end
      rescue Exception => the_error
        log_error({:error => the_error, :parameters => {:the_jid => the_jid}})
      end
      result
    end

say(to, msg, using = :chat) click to toggle source

### Helper method to make sending basic messages easier

@param [Blather::JID, to_s] to the JID of the message recipient @param [#to_s] msg the message to send @param [#to_sym] the stanza method to use

    # File lib/gxg/net_clients.rb, line 3411
    def say(to, msg, using = :chat)
        self.write Blather::Stanza::Message.new(to, msg, using)
    end

send_caps() click to toggle source

Send capabilities to the server

    # File lib/gxg/net_clients.rb, line 3502
    def send_caps
        if @client
            @client.register_handler :disco_info, :type => :get, :node => @client.caps.node do |s|
              r = @client.caps.dup
              r.to = s.from
              r.id = s.id
              @client.write r
            end
            @client.write client.caps.c
        end
    end

send_file(the_jid=nil,the_path=nil, description=nil, buffer_size=4096, proxy=nil) click to toggle source

    # File lib/gxg/net_clients.rb, line 4012
    def send_file(the_jid=nil,the_path=nil, description=nil, buffer_size=4096, proxy=nil)
      if @client
        begin
          unless the_jid.is_a?(::String)
            raise ArgumentError, "You MUST supply a valid JID String to specify the recipient of the file."
          end
          unless the_path.is_a?(::String)
            raise ArgumentError, "You MUST supply a String as valid file path."
          end
          the_path = ::File.expand_path(the_path)
          unless the_path.valid_path?()
            raise ArgumentError, "You MUST supply a valid file path."
          end
          unless ::File.exist?(the_path)
            raise ArgumentError, "You MUST supply a valid file path - File does not exist."
          end
          unless description.is_a?(::String)
            description = "File Transfer: #{::File.basename(the_path)}"
          end
          unless buffer_size.is_a?(::Integer)
            raise ArgumentError, "You MUST provide an Integer to set buffer size."
          end
          valid_buffer_size_range = ::GxG::SYSTEM.maximum_buffer_size.get_at_path("/:ipv4/:tcp/:write/:valid")
          unless valid_buffer_size_range.is_a?(::Range)
            valid_buffer_size_range = (4096..65536)
          end
          unless valid_buffer_size_range.include?(buffer_size)
            raise ArgumentError, "You MUST provide an Integer between #{valid_buffer_size_range.first} and #{valid_buffer_size_range.last}."
          end
          # Review : rebuild/rewrite this section and XmppAgentFileTransfer
            #   the_transfer = ::GxG::Networking::XmppAgentFileTransfer.new(@transfer_manager, :upload, {:jid => the_jid, :path => the_path, :description => description}, this())
            #   @file_transfers_thread_safety.synchronize {
            #     @file_transfers << the_transfer
            #   }
            #   the_transfer.buffer_size = buffer_size
            #   the_transfer.upload_file(proxy)
            #   the_transfer.reference
        rescue Exception => the_error
          log_error({:error => the_error, :parameters => {:jid => the_jid, :path => the_path, :description => description, :buffer_size => buffer_size}})
        end
      else
        nil
      end
    end

set_caps(node, identities, features) click to toggle source

### Set the capabilities of the client

@param [String] node the `URI` @param [Array<Hash>] identities an array of identities @param [Array<Hash>] features an array of features

    # File lib/gxg/net_clients.rb, line 3494
    def set_caps(node, identities, features)
        if @client
            @client.caps.node = node
            @client.caps.identities = identities
            @client.caps.features = features
        end
    end

set_status(state = nil, msg = nil) click to toggle source

### Set current status

@param [Blather::Stanza::Presence::State::VALID_STATES] state the current state @param [#to_s] msg the status message to use

    # File lib/gxg/net_clients.rb, line 3361
    def set_status(state = nil, msg = nil)
        if @client
            @client.status = state, msg
        end
    end

when_ready(&block) click to toggle source

### Wrapper for “handle :ready” (just a bit of syntactic sugar)

This is run after the connection has been completely setup

    # File lib/gxg/net_clients.rb, line 3344
    def when_ready(&block)
        self.handle :ready, &block
    end

write(stanza) click to toggle source

`Support` Methods

    # File lib/gxg/net_clients.rb, line 3289
    def write(stanza)
        if @client
            @client.write stanza
        end
        true
    end

write_to_stream(stanza) click to toggle source

### Write data to the stream

@param [#to_xml, to_s] stanza the data to send down the wire.

    # File lib/gxg/net_clients.rb, line 3385
    def write_to_stream(stanza)
        self.write stanza
    end

xmpp_message_to_gxg(the_message=nil) click to toggle source

Conversion Tools

    # File lib/gxg/net_clients.rb, line 3514
    def xmpp_message_to_gxg(the_message=nil)
        # need: :to, :body, :state, :subject, :context, :type
        # ::Celluloid::UUID::random_generate().to_s
        unless the_message.is_a?(Blather::Stanza::Message)
          raise ArgumentError, "You MUST provide a valid message object: Blather::Stanza::Message."
        end
        gxg_message = ::GxG::Events::Message.new({:sender => :unknown})
        gxg_message[:id] = (the_message.id || ::GxG::uuid_generate.to_sym)
        gxg_message[:sender] = the_message.from.to_s
        gxg_message[:to] = the_message.to.to_s
        gxg_message[:type] = the_message.type
        if the_message.thread.is_a?(::Hash)
            gxg_message[:context] = the_message.thread.values[0]
        else
            gxg_message[:context] = the_message.thread
        end
        gxg_message[:subject] = the_message.subject
        gxg_message[:body] = the_message.body
        gxg_message
    end