mirror of
https://github.com/mistergibson/gxg-framework.git
synced 2026-08-15 03:46:00 -07:00
2866 lines
No EOL
122 KiB
Ruby
2866 lines
No EOL
122 KiB
Ruby
|
|
# require 'xmpp4r/client'
|
|
# require 'xmpp4r/reliable'
|
|
# require 'xmpp4r/roster'
|
|
# require 'xmpp4r/muc'
|
|
# require 'xmpp4r/bytestreams'
|
|
|
|
# new xmpp client:
|
|
# require "blather/client/dsl"
|
|
# require "blather/client/dsl/pubsub"
|
|
Thread.new { ::EM.run }
|
|
# ### MUC extentions for Blather:
|
|
# See: https://github.com/maccman/blather and https://github.com/adhearsion/blather/issues/81
|
|
# module Blather
|
|
# class Roster
|
|
# def push(elem, send = true, groups = ["Buddies"])
|
|
# jid = elem.respond_to?(:jid) && elem.jid ? elem.jid : JID.new(elem)
|
|
# @items[key(jid)] = node = RosterItem.new(elem)
|
|
# @items[key(jid)].subscription = :both
|
|
# @items[key(jid)].groups = groups
|
|
# @stream.write(node.to_stanza(:set)) if send
|
|
# end
|
|
# alias_method :add, :push
|
|
# end
|
|
# class Client
|
|
# def unbind
|
|
# # Fix bug where closing connection stops EM for ALL Client Instances.
|
|
# # call_handler_for(:disconnected, nil) || (EM.reactor_running? && EM.stop)
|
|
# call_handler_for(:disconnected, nil)
|
|
# true
|
|
# end
|
|
# end
|
|
# #
|
|
# module DSL
|
|
# class MultiUserChat
|
|
# def initialize(client, jid, nickname = nil, password = nil)
|
|
# @client = client
|
|
# @room = ::Blather::JID.new(jid)
|
|
# @nickname = nickname || @room.resource
|
|
# @password = password
|
|
# @room.strip!
|
|
# end
|
|
|
|
# def join(reason = nil)
|
|
# join = ::Blather::Stanza::Presence::MUCJoin.new
|
|
# join.to = "#{@room}/#{@nickname}"
|
|
# join.password = @password
|
|
# write join
|
|
# end
|
|
|
|
# # <presence
|
|
# # from='wiccarocks@shakespeare.lit/laptop'
|
|
# # to='darkcave@chat.shakespeare.lit/oldhag'>
|
|
# # <show>available</show>
|
|
# # </presence>
|
|
# def status=(state)
|
|
# status = ::Blather::Stanza::Presence::Status.new
|
|
# status.state = state
|
|
# status.to = @room
|
|
# write status
|
|
# end
|
|
|
|
# # <message to='room@service'>
|
|
# # <x xmlns='http://jabber.org/protocol/muc#user'>
|
|
# # <invite to='jid'>
|
|
# # <reason>comment</reason>
|
|
# # </invite>
|
|
# # </x>
|
|
# # </message>
|
|
# def invite(jid, reason = nil)
|
|
# message = ::Blather::Stanza::Message.new(@room, nil, nil)
|
|
# message << ::Blather::MUC::Invite.new(jid, reason, @password)
|
|
|
|
# write message
|
|
# end
|
|
|
|
# # <message to='room@service' type='groupchat'>
|
|
# # <body>foo</body>
|
|
# # </message>
|
|
# def say(msg, xhtml = nil)
|
|
# message = ::Blather::Stanza::Message.new(@room, msg, :groupchat)
|
|
# message.xhtml = xhtml if xhtml
|
|
# write message
|
|
# end
|
|
|
|
# # <message to='room@service' type='groupchat'>
|
|
# # <subject>foo</subject>
|
|
# # </message>
|
|
# def subject=(body)
|
|
# message = Blather::Stanza::Message.new(@room, nil, :groupchat)
|
|
# message.subject = body
|
|
# write message
|
|
# end
|
|
|
|
# def leave
|
|
# self.status = :unavailable
|
|
# end
|
|
|
|
# # <iq from='crone1@shakespeare.lit/desktop'
|
|
# # id='begone'
|
|
# # to='heath@chat.shakespeare.lit'
|
|
# # type='set'>
|
|
# # <query xmlns='http://jabber.org/protocol/muc#owner'>
|
|
# # <destroy jid='darkcave@chat.shakespeare.lit'>
|
|
# # <reason>Macbeth doth come.</reason>
|
|
# # </destroy>
|
|
# # </query>
|
|
# # </iq>
|
|
# def destroy(reason = nil)
|
|
# destroy = ::Blather::MUC::Owner::Destroy.new(@room)
|
|
|
|
# destroy.reason = reason
|
|
# write destroy
|
|
# end
|
|
|
|
# def get_configuration(&block)
|
|
# get_configure = ::Blather::MUC::Owner::Configure.new(:get, @room)
|
|
# write_with_handler(get_configure) do |stana|
|
|
# yield stana
|
|
# end
|
|
# end
|
|
# alias_method :configuration, :get_configuration
|
|
|
|
# def set_configuration(values, &block)
|
|
# set_configure = ::Blather::MUC::Owner::Configure.new(:set, @room)
|
|
# set_configure.data = values
|
|
# write_with_handler(set_configure, &block)
|
|
# end
|
|
# alias_method :configuration=, :set_configuration
|
|
|
|
# # <iq type='set' id='purple52b37aa2' to='test3@conference.macbook.local'>
|
|
# # <query xmlns='http://jabber.org/protocol/muc#owner'>
|
|
# # <x xmlns='jabber:x:data' type='submit'/></query>
|
|
# # </iq>
|
|
# def set_default_configuration(&block)
|
|
# set_configuration(:default) do
|
|
# yield if block_given?
|
|
# end
|
|
# end
|
|
# alias_method :unlock, :set_default_configuration
|
|
|
|
# # <iq from='crone1@shakespeare.lit/desktop'
|
|
# # id='member3'
|
|
# # to='darkcave@chat.shakespeare.lit'
|
|
# # type='get'>
|
|
# # <query xmlns='http://jabber.org/protocol/muc#admin'>
|
|
# # <item affiliation='member'/>
|
|
# # </query>
|
|
# # </iq>
|
|
# #
|
|
# # <iq from='darkcave@chat.shakespeare.lit'
|
|
# # id='member3'
|
|
# # to='crone1@shakespeare.lit/desktop'
|
|
# # type='result'>
|
|
# # <query xmlns='http://jabber.org/protocol/muc#admin'>
|
|
# # <item affiliation='member'
|
|
# # jid='hag66@shakespeare.lit'
|
|
# # nick='thirdwitch'
|
|
# # role='participant'/>
|
|
# # </query>
|
|
# # </iq>
|
|
# def members(&block)
|
|
# members = ::Blather::MUC::Admin::Members.new(@room)
|
|
|
|
# write_with_handler(members, &block)
|
|
# end
|
|
|
|
# def write(stanza)
|
|
# @client.write(stanza)
|
|
# end
|
|
|
|
# def write_with_handler(stanza, &block)
|
|
# @client.write_with_handler(stanza, &block)
|
|
# end
|
|
# end # end Class Blather::DSL::MultiUserChat
|
|
# end # end Module Blather::DSL
|
|
# # ### Support for MUC Presense
|
|
|
|
# module MUC
|
|
# #
|
|
# class Join < ::Blather::XMPPNode
|
|
# register :x, "http://jabber.org/protocol/muc"
|
|
|
|
# def self.new(password = nil)
|
|
# join = super :x
|
|
# join.password = password
|
|
# join
|
|
# end
|
|
|
|
# def password=(password)
|
|
# return if password.blank?
|
|
# create_password.content = password
|
|
# end
|
|
|
|
# protected
|
|
# def create_password
|
|
# unless create_password = find_first('ns:password', :ns => self.class.registered_ns)
|
|
# self << (create_password = XMPPNode.new('password', self.document))
|
|
# end
|
|
# create_password
|
|
# end
|
|
# end #Join
|
|
# # <x xmlns='http://jabber.org/protocol/muc#user'>
|
|
# # <invite to='jid'>
|
|
# # <reason>comment</reason>
|
|
# # </invite>
|
|
# # </x>
|
|
# class Invite < ::Blather::Stanza
|
|
# register :muc_invite, :x, "http://jabber.org/protocol/muc#user"
|
|
|
|
# def self.import(node)
|
|
# self.new(node.element_name).inherit(node)
|
|
# end
|
|
|
|
# def inherit(node)
|
|
# create_invite.remove
|
|
# self.from = node[:from]
|
|
# invite = node.find_first('ns:x/ns:invite', :ns => self.class.registered_ns)
|
|
# self << invite
|
|
# self
|
|
# end
|
|
|
|
# def self.new(jid = nil, reason = nil, password = nil)
|
|
# invite = super :x
|
|
# invite.invite_to = jid
|
|
# invite.reason = reason
|
|
# invite.password = password
|
|
# invite
|
|
# end
|
|
|
|
# def invite_to=(jid)
|
|
# create_invite[:to] = JID.new(jid)
|
|
# end
|
|
|
|
# def invite_to
|
|
# ::Blather::JID.new(create_invite[:to])
|
|
# end
|
|
|
|
# def invite_from
|
|
# create_invite[:from]
|
|
# end
|
|
|
|
# def reason=(reason)
|
|
# return if reason.blank?
|
|
# create_reason.content = reason
|
|
# end
|
|
|
|
# def reason
|
|
# create_reason.content
|
|
# end
|
|
|
|
# def password=(password)
|
|
# return if password.blank?
|
|
# create_password.content = password
|
|
# end
|
|
|
|
# def password
|
|
# create_password.content
|
|
# end
|
|
|
|
# protected
|
|
# def create_password
|
|
# unless create_password = find_first('ns:password', :ns => self.class.registered_ns)
|
|
# self << (create_password = XMPPNode.new('password', self.document))
|
|
# end
|
|
# create_password
|
|
# end
|
|
|
|
# def create_invite
|
|
# unless create_invite = find_first('ns:invite', :ns => self.class.registered_ns)
|
|
# self << (create_invite = XMPPNode.new('invite', self.document))
|
|
# end
|
|
# create_invite
|
|
# end
|
|
|
|
# def create_reason
|
|
# unless create_reason = create_invite.find_first('ns:reason', :ns => self.class.registered_ns)
|
|
# self.create_invite << (create_reason = XMPPNode.new('reason', self.document))
|
|
# end
|
|
# create_reason
|
|
# end
|
|
|
|
# def create_password
|
|
# unless create_password = find_first('ns:password', :ns => self.class.registered_ns)
|
|
# self << (create_password = XMPPNode.new('password', self.document))
|
|
# end
|
|
# create_password
|
|
# end
|
|
# end #Invite
|
|
# class Owner < Blather::Stanza::Iq::Query
|
|
# register :owner, :owner, 'http://jabber.org/protocol/muc#owner'
|
|
|
|
# def self.new(type = nil, to = nil)
|
|
# node = super(type)
|
|
# node.to = to
|
|
# node
|
|
# end
|
|
|
|
# class Configure < Owner
|
|
# DATA_NAMESPACE = 'jabber:x:data'
|
|
|
|
# def data=(data = :default)
|
|
# create_data[:type] = 'submit'
|
|
# unless data.blank? || data == :default
|
|
# raise "Invalid data format" unless data.is_a?(Hash)
|
|
# data.each {|key, value|
|
|
# create_field = XMPPNode.new('field', self.document)
|
|
# create_field[:var] = key
|
|
|
|
# create_field_value = XMPPNode.new('value', self.document)
|
|
# if [TrueClass, FalseClass].include?(value.class)
|
|
# value = value ? 1 : 0
|
|
# end
|
|
# create_field_value.content = value.to_s
|
|
|
|
# create_field << create_field_value
|
|
# create_data << create_field
|
|
# }
|
|
# end
|
|
# end
|
|
|
|
# def data
|
|
# items = create_data.find('//ns:field', :ns => self.class.registered_ns)
|
|
# items.inject({}) do |hash, item|
|
|
# key = item[:var]
|
|
# value = item.find_first('ns:value', :ns => self.class.registered_ns)
|
|
# value = value.content
|
|
# hash[key] = value
|
|
# hash
|
|
# end
|
|
# end
|
|
|
|
# protected
|
|
# def create_data
|
|
# unless create_data = query.find_first('ns:x', :ns => DATA_NAMESPACE)
|
|
# query << (create_data = XMPPNode.new('x', self.document))
|
|
# create_data.namespace = DATA_NAMESPACE
|
|
# end
|
|
# create_data
|
|
# end
|
|
# end
|
|
|
|
# # <iq from='crone1@shakespeare.lit/desktop'
|
|
# # id='begone'
|
|
# # to='heath@chat.shakespeare.lit'
|
|
# # type='set'>
|
|
# # <query xmlns='http://jabber.org/protocol/muc#owner'>
|
|
# # <destroy jid='darkcave@chat.shakespeare.lit'>
|
|
# # <reason>Macbeth doth come.</reason>
|
|
# # </destroy>
|
|
# # </query>
|
|
# # </iq>
|
|
# class Destroy < Owner
|
|
|
|
# def self.new(*args)
|
|
# query = super(:set, *args)
|
|
# query.create_destroy
|
|
# query
|
|
# end
|
|
|
|
# def reason=(reason)
|
|
# return if reason.blank?
|
|
# create_reason.content = reason
|
|
# end
|
|
|
|
# def create_reason # @private
|
|
# unless create_reason = create_destroy.find_first('ns:reason', :ns => self.class.registered_ns)
|
|
# create_destroy << (create_reason = XMPPNode.new('reason', self.document))
|
|
# end
|
|
# create_reason
|
|
# end
|
|
|
|
# def create_destroy # @private
|
|
# unless create_destroy = query.find_first('ns:destroy', :ns => self.class.registered_ns)
|
|
# query << (create_destroy = XMPPNode.new('destroy', self.document))
|
|
# end
|
|
# create_destroy
|
|
# end
|
|
# end
|
|
|
|
# end
|
|
# class Admin < Blather::Stanza::Iq::Query
|
|
# register :admin, :admin, 'http://jabber.org/protocol/muc#admin'
|
|
|
|
# def self.new(type = nil, to = nil)
|
|
# node = super(type)
|
|
# node.to = to
|
|
# node
|
|
# end
|
|
|
|
# # <iq from='crone1@shakespeare.lit/desktop'
|
|
# # id='member3'
|
|
# # to='darkcave@chat.shakespeare.lit'
|
|
# # type='get'>
|
|
# # <query xmlns='http://jabber.org/protocol/muc#admin'>
|
|
# # <item affiliation='member'/>
|
|
# # </query>
|
|
# # </iq>
|
|
# class Members < Admin
|
|
# def self.new(*args)
|
|
# query = super(:get, *args)
|
|
# query.create_item
|
|
# query
|
|
# end
|
|
|
|
# def create_item # @private
|
|
# unless create_item = query.find_first('ns:item', :ns => self.class.registered_ns)
|
|
# query << (create_item = XMPPNode.new('item', self.document))
|
|
# create_item[:affiliation] = 'member'
|
|
# end
|
|
# create_item
|
|
# end
|
|
# end
|
|
|
|
# end # Admin
|
|
# end # end module MUC
|
|
# #
|
|
# class Stanza
|
|
# class Presence
|
|
# class MUCJoin < ::Blather::Stanza::Presence
|
|
# MUC_NS = "http://jabber.org/protocol/muc"
|
|
|
|
# register :muc_join, :muc_join
|
|
|
|
# def password
|
|
# create_muc.content_from :password
|
|
# create_password.content
|
|
# end
|
|
|
|
# def password=(value)
|
|
# create_muc.set_content_for :password
|
|
# end
|
|
|
|
# private
|
|
# def create_muc
|
|
# unless create_muc = find_first('ns:x', :ns => MUC_NS)
|
|
# self << (create_muc = ::Blather::XMPPNode.new('x', self.document))
|
|
# create_muc.namespace = MUC_NS
|
|
# end
|
|
# create_muc
|
|
# end
|
|
# end #
|
|
# #
|
|
# class MUCUser < Presence
|
|
# class Status < ::Blather::XMPPNode
|
|
# def self.new(code)
|
|
# new_node = super :status
|
|
# new_node.code = code
|
|
# new_node
|
|
# end
|
|
|
|
# def code
|
|
# read_attr :code
|
|
# end
|
|
|
|
# def code=(var)
|
|
# write_attr :code, var
|
|
# end
|
|
# end
|
|
|
|
# MUC_NS = "http://jabber.org/protocol/muc#user"
|
|
|
|
# register :muc_user, :muc_user
|
|
|
|
# def affiliation
|
|
# create_ia[:affiliation]
|
|
# end
|
|
|
|
# def affiliation=(val)
|
|
# create_ia[:affiliation] = val
|
|
# end
|
|
|
|
# def role
|
|
# create_ia[:role]
|
|
# end
|
|
|
|
# def role=(val)
|
|
# create_ia[:role] = val
|
|
# end
|
|
|
|
# def jid
|
|
# create_ia[:jid]
|
|
# end
|
|
|
|
# def jid=(val)
|
|
# create_ia[:jid] = val
|
|
# end
|
|
|
|
# private
|
|
# def create_muc
|
|
# unless create_muc = find_first('ns:x', :ns => MUC_NS)
|
|
# self << (create_muc = ::Blather::XMPPNode.new('x', self.document))
|
|
# create_muc.namespace = MUC_NS
|
|
# end
|
|
# create_muc
|
|
# end
|
|
|
|
# def create_ia
|
|
# unless create_ia = create_muc.find_first('ns:item', :ns => self.class.registered_ns)
|
|
# create_muc << (create_ia = XMPPNode.new('item', self.document))
|
|
# end
|
|
# create_ia
|
|
# end
|
|
# end
|
|
# end
|
|
# end
|
|
# #
|
|
# end # end Module Blather
|
|
|
|
# XMPP Classes:
|
|
# Review : Blather switchover:
|
|
# require ::File.expand_path("./xmpp_client.rb",::File.dirname(__FILE__))
|
|
# # ### Invitations
|
|
# class XmppAgentInvitation
|
|
# def initialize(parent=nil, invitation=nil)
|
|
# @uuid = ::GxG::uuid_generate.to_sym
|
|
# @pending = true
|
|
# @parent = parent
|
|
# @invitation = invitation
|
|
# #
|
|
# if @invitation.is_a?(::Blather::Stanza::Presence)
|
|
# @details = {:sender => @invitation.from.to_s, :type => :association}
|
|
# else
|
|
# @details = {:sender => @invitation.from.to_s, :type => :unkown}
|
|
# end
|
|
# #
|
|
# self
|
|
# end
|
|
# # Review : debug only
|
|
# def invitation()
|
|
# @invitation
|
|
# end
|
|
# #
|
|
# def uuid()
|
|
# @uuid
|
|
# end
|
|
# #
|
|
# def inspect()
|
|
# @details.inspect
|
|
# end
|
|
# #
|
|
# def pending?()
|
|
# @pending
|
|
# end
|
|
# #
|
|
# def keys()
|
|
# @details.keys()
|
|
# end
|
|
# #
|
|
# def [](the_key)
|
|
# @details[(the_key)]
|
|
# end
|
|
# #
|
|
# def accept()
|
|
# if @invitation
|
|
# @parent.write(@invitation.approve!)
|
|
# @pending = false
|
|
# @parent.refresh_invitations()
|
|
# true
|
|
# else
|
|
# false
|
|
# end
|
|
# end
|
|
# #
|
|
# def decline()
|
|
# if @invitation
|
|
# @parent.write(@invitation.cancel!)
|
|
# @pending = false
|
|
# @parent.refresh_invitations()
|
|
# true
|
|
# else
|
|
# false
|
|
# end
|
|
# end
|
|
# end
|
|
# # ### File Transfer
|
|
# class XmppAgentFileTransfer
|
|
# # Review : totally rewrite this
|
|
# def initialize(manager, direction, details, parent)
|
|
# @reference = ::GxG::uuid_generate.to_sym
|
|
# @session_id = nil
|
|
# @pending = true
|
|
# @inprogress = false
|
|
# @percent_completed = 0
|
|
# @status_thread_safety = ::Mutex.new
|
|
# @manager = manager
|
|
# @direction = direction
|
|
# @info = {:reference => @reference}
|
|
# @bytestream = nil
|
|
# @file_details = nil
|
|
# @cancel = false
|
|
# the_value = ::GxG::SYSTEM.maximum_buffer_size.get_at_path("/:ipv4/:tcp/:write/:valid")
|
|
# if the_value.is_a?(::Range)
|
|
# @valid_write_buffer_sizes = the_value
|
|
# else
|
|
# @valid_write_buffer_sizes = (4096..65536)
|
|
# end
|
|
# @buffer_size = 4096
|
|
# @client = parent
|
|
# if @direction == :download
|
|
# @invitation = details[:iq]
|
|
# @sender = details[:iq].from
|
|
# @info[:sender] = @sender.to_s
|
|
# @info[:recipient] = @client.jid.to_s
|
|
# @file_details = {:filename => details[:file_info].fname, :path => (details[:download_directory] + "/" + details[:file_info].fname), :size => details[:file_info].size, :md5 => details[:file_info].hash, :description => details[:file_info].description}
|
|
# @download_directory = details[:download_directory]
|
|
# @info[:details] = @file_details
|
|
# @recipient = nil
|
|
# #
|
|
# #
|
|
# end
|
|
# if @direction == :upload
|
|
# @info[:sender] = @client.jid.to_s
|
|
# @info[:recipient] = details[:jid].to_s
|
|
# @recipient = ::Jabber::JID.new(details[:jid])
|
|
# @file_details = {:filename => ::File.basename(details[:path]), :path => details[:path], :size => ::File.size(details[:path]), :md5 => ::Digest::MD5.file(details[:path]), :description => details[:description]}
|
|
# @info[:details] = @file_details
|
|
# @invitation = nil
|
|
# @download_directory = nil
|
|
# end
|
|
# self
|
|
# end
|
|
# #
|
|
# def inspect()
|
|
# "<Transfer: #{@direction.inspect} - #{@reference}, with Session ID: #{@session_id} for File #{@file_details[:filename]}>"
|
|
# end
|
|
# #
|
|
# def info()
|
|
# @info.clone
|
|
# end
|
|
# #
|
|
# def reference()
|
|
# @reference.clone
|
|
# end
|
|
# #
|
|
# def session_id()
|
|
# @session_id.clone
|
|
# end
|
|
# #
|
|
# def pending?()
|
|
# @status_thread_safety.synchronize { @pending }
|
|
# end
|
|
# #
|
|
# def buffer_size()
|
|
# @status_thread_safety.synchronize { @buffer_size }
|
|
# end
|
|
# #
|
|
# def buffer_size=(the_size=4096)
|
|
# begin
|
|
# unless the_size.is_a?(::Integer)
|
|
# raise ArgumentError, "You MUST provide an Integer to set buffer size."
|
|
# end
|
|
# if @status_thread_safety.synchronize { @direction == :upload }
|
|
# unless @valid_write_buffer_sizes.include?(the_size)
|
|
# raise ArgumentError, "You MUST provide an Integer between #{@valid_read_buffer_sizes.first} and #{@valid_read_buffer_sizes.last}."
|
|
# @status_thread_safety.synchronize { @buffer_size = the_size }
|
|
# end
|
|
# else
|
|
# log_warn("Buffer size is only set on upload file transfers.")
|
|
# end
|
|
# the_size
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {}})
|
|
# nil
|
|
# end
|
|
# end
|
|
# #
|
|
# def cancelled?()
|
|
# @status_thread_safety.synchronize { @cancel }
|
|
# end
|
|
# #
|
|
# def cancel()
|
|
# if @client
|
|
# begin
|
|
# if @status_thread_safety.synchronize { @pending == true }
|
|
# @status_thread_safety.synchronize { @pending = false }
|
|
# end
|
|
# if @status_thread_safety.synchronize { @inprogress == true }
|
|
# @status_thread_safety.synchronize { @inprogress = false }
|
|
# end
|
|
# @status_thread_safety.synchronize { @cancel = true }
|
|
# @client.refresh_file_transfers
|
|
# true
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {}})
|
|
# end
|
|
# else
|
|
# false
|
|
# end
|
|
# end
|
|
# #
|
|
# def accept()
|
|
# if @client
|
|
# if @status_thread_safety.synchronize { @pending == true && @direction == :download }
|
|
# Thread.new {
|
|
# begin
|
|
# bytes_received = 0
|
|
# total_size = @file_details[:size]
|
|
# @bytestream = @manager.accept(@invitation)
|
|
# if @bytestream
|
|
# @bytestream.accept()
|
|
# @status_thread_safety.synchronize {
|
|
# @pending = false
|
|
# @inprogress = true
|
|
# @session_id = @bytestream.session_id.to_s
|
|
# }
|
|
# #
|
|
# cancel_callback = Proc.new do |the_iq|
|
|
# if the_iq.type == :error
|
|
# the_error = ::Jabber::ServerError.new(the_iq.error)
|
|
# if @invitation.id.to_s == the_iq.id.to_s
|
|
# the_transfer = @client.find_file_transfer(@reference)
|
|
# if the_transfer
|
|
# the_transfer.cancel
|
|
# end
|
|
# end
|
|
# log_error({:error => the_error, :parameters => {:iq => the_iq}})
|
|
# end
|
|
# end
|
|
# @client.set_xfr_callback(@session_id,&cancel_callback)
|
|
# #
|
|
# the_file = ::File.open(@file_details[:path], "w+b",0664)
|
|
# the_file.pos = 0
|
|
# buffer = @bytestream.read()
|
|
# while buffer && @status_thread_safety.synchronize { @cancel == false } do
|
|
# the_file.write(buffer.to_s)
|
|
# bytes_received += buffer.to_s.size
|
|
# @status_thread_safety.synchronize { @percent_completed = ((bytes_received.to_f / total_size.to_f) * 100.0).to_i }
|
|
# @client.notify({:event => :file_transfer_progress, :transfer => @reference, :progress => @status_thread_safety.synchronize { @percent_completed }})
|
|
# buffer = @bytestream.read()
|
|
# end
|
|
# the_file.close
|
|
# @bytestream.close
|
|
# @status_thread_safety.synchronize {
|
|
# @inprogress = false
|
|
# @pending = false
|
|
# }
|
|
# the_path = @file_details[:path]
|
|
# if @status_thread_safety.synchronize { @cancel == true }
|
|
# ::File.delete(the_path)
|
|
# @client.notify({:event => :file_transfer_cancelled, :transfer => @reference})
|
|
# else
|
|
# if @file_details[:md5]
|
|
# unless @file_details[:md5] == ::Digest::MD5.file(the_path)
|
|
# raise Exception, "MD5 Checksum Failure - file corruption on file: #{the_path}"
|
|
# end
|
|
# @client.notify({:event => :file_transfer_complete, :transfer => @reference})
|
|
# end
|
|
# end
|
|
# else
|
|
# @status_thread_safety.synchronize {
|
|
# @inprogress = false
|
|
# @pending = false
|
|
# }
|
|
# the_file = nil
|
|
# raise Exception, "Failed to negotiate a transfer method."
|
|
# end
|
|
# rescue Exception => the_error
|
|
# @status_thread_safety.synchronize {
|
|
# @inprogress = false
|
|
# @pending = false
|
|
# }
|
|
# if the_file
|
|
# the_file.close
|
|
# end
|
|
# if @bytestream
|
|
# @bytestream.close
|
|
# end
|
|
# log_error({:error => the_error, :parameters => {}})
|
|
# @client.notify({:event => :file_transfer_error, :transfer => @reference})
|
|
# end
|
|
# if @session_id
|
|
# @client.clear_xfr_callback(@session_id)
|
|
# end
|
|
# @client.refresh_file_transfers
|
|
# }
|
|
# end
|
|
# true
|
|
# else
|
|
# false
|
|
# end
|
|
# end
|
|
# #
|
|
# def decline()
|
|
# if @client
|
|
# if @status_thread_safety.synchronize { @pending == true && @direction == :download }
|
|
# begin
|
|
# @manager.decline(@invitation)
|
|
# @status_thread_safety.synchronize { @pending = false }
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {}})
|
|
# end
|
|
# end
|
|
# true
|
|
# else
|
|
# false
|
|
# end
|
|
# end
|
|
# #
|
|
# def in_progress?()
|
|
# @status_thread_safety.synchronize { @inprogress }
|
|
# end
|
|
# #
|
|
# def percent_completed()
|
|
# @status_thread_safety.synchronize { @percent_completed.clone }
|
|
# end
|
|
# #
|
|
# def file_details()
|
|
# @status_thread_safety.synchronize { @file_details.clone }
|
|
# end
|
|
# #
|
|
# def download_directory()
|
|
# @status_thread_safety.synchronize { @download_directory.clone }
|
|
# end
|
|
# #
|
|
# def download_directory=(the_path=nil)
|
|
# begin
|
|
# unless the_path.is_a?(::String)
|
|
# raise ArgumentError, "You MUST supply a String as valid directory path."
|
|
# end
|
|
# the_path = ::File.expand_path(the_path)
|
|
# unless the_path.valid_path?()
|
|
# raise ArgumentError, "You MUST supply a valid directory path."
|
|
# end
|
|
# unless ::File.exist?(the_path)
|
|
# raise ArgumentError, "You MUST supply a valid directory path - Directory does not exist."
|
|
# end
|
|
# @status_thread_safety.synchronize {
|
|
# unless @inprogress == true
|
|
# if @direction == :download
|
|
# @download_directory = ::File.expand_path(the_path)
|
|
# @file_details[:path] = (@download_directory + "/" + @file_details[:filename])
|
|
# end
|
|
# end
|
|
# }
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {}})
|
|
# end
|
|
# end
|
|
# #
|
|
# def upload_file(proxy=nil)
|
|
# if @client
|
|
# if @direction == :upload
|
|
# unless @status_thread_safety.synchronize { @inprogress == true }
|
|
# Thread.new {
|
|
# begin
|
|
# bytes_sent = 0
|
|
# buffer_size = @status_thread_safety.synchronize { @buffer_size }
|
|
# the_file_source = ::Jabber::FileTransfer::FileSource.new(@file_details[:path])
|
|
# the_file_source.length = buffer_size
|
|
# total_size = the_file_source.size
|
|
# @bytestream = nil
|
|
# response = @manager.offer(@recipient,the_file_source,@file_details[:description],nil,@reference.to_s)
|
|
# if response.is_a?(::Hash)
|
|
# @bytestream = response[:bytestream]
|
|
# the_iq_id = response[:iq_id]
|
|
# if @bytestream
|
|
# if @bytestream.is_a?(::Jabber::Bytestreams::SOCKS5BytestreamsInitiator)
|
|
# if proxy.is_any?(::String, ::Jabber::JID)
|
|
# @bytestream.add_streamhost(proxy)
|
|
# end
|
|
# end
|
|
# if @bytestream.is_a?(::Jabber::Bytestreams::IBBInitiator)
|
|
# @bytestream.block_size = buffer_size
|
|
# end
|
|
# #
|
|
# @status_thread_safety.synchronize {
|
|
# @pending = false
|
|
# @inprogress = true
|
|
# }
|
|
# open_response = @bytestream.open()
|
|
# if open_response
|
|
# puts "Got: (open_response) - #{open_response.inspect}"
|
|
# if open_response.type == :result
|
|
# #
|
|
# @session_id = @bytestream.session_id.to_s
|
|
# #
|
|
# cancel_callback = Proc.new do |the_iq|
|
|
# if the_iq.type == :error
|
|
# the_error = ::Jabber::ServerError.new(the_iq.error)
|
|
# if the_iq_id.to_s == the_iq.id.to_s
|
|
# the_transfer = @client.find_file_transfer(@reference)
|
|
# if the_transfer
|
|
# the_transfer.cancel
|
|
# end
|
|
# end
|
|
# log_error({:error => the_error, :parameters => {:iq => the_iq}})
|
|
# end
|
|
# end
|
|
# @client.set_xfr_callback(@session_id,&cancel_callback)
|
|
# #
|
|
# ::GxG.apportioned_ranges(total_size,buffer_size).each do |the_range|
|
|
# if @status_thread_safety.synchronize { @cancel == true }
|
|
# the_file_source.close
|
|
# break
|
|
# end
|
|
# the_file_source.seek(the_range.first)
|
|
# bytes_sent += @bytestream.write(the_file_source.read(the_range.size)).to_i
|
|
# @status_thread_safety.synchronize { @percent_completed = ((bytes_sent.to_f / total_size.to_f) * 100.0).to_i }
|
|
# #
|
|
# end
|
|
# @bytestream.flush
|
|
# @bytestream.close
|
|
# @status_thread_safety.synchronize { @inprogress = false }
|
|
# else
|
|
# # Error?
|
|
# @status_thread_safety.synchronize {
|
|
# @pending = false
|
|
# @inprogress = false
|
|
# }
|
|
# end
|
|
# else
|
|
# raise Exception, "Failed to open the stream."
|
|
# end
|
|
# end
|
|
# else
|
|
# @status_thread_safety.synchronize {
|
|
# @pending = false
|
|
# @inprogress = false
|
|
# }
|
|
# end
|
|
# rescue Exception => the_error
|
|
# the_file_source.close
|
|
# @bytestream.close
|
|
# @status_thread_safety.synchronize { @inprogress = false }
|
|
# log_error({:error => the_error, :parameters => {:proxy => proxy}})
|
|
# end
|
|
# @client.clear_xfr_callback(@reference.to_s)
|
|
# if @session_id
|
|
# @client.clear_xfr_callback(@session_id)
|
|
# end
|
|
# @client.refresh_file_transfers
|
|
# }
|
|
# end
|
|
# end
|
|
# end
|
|
# end
|
|
# #
|
|
# end
|
|
# #
|
|
# # ### Conversation Channel
|
|
# class XmppAgentConversation
|
|
# #
|
|
# def default_room_configuration(options={})
|
|
# unless options.is_a?(::Hash)
|
|
# options = {}
|
|
# end
|
|
# default_config = {
|
|
# 'FORM_TYPE' => 'http://jabber.org/protocol/muc#roomconfig',
|
|
# 'form' => 'config',
|
|
# 'muc#roomconfig_roomname' => nil,
|
|
# 'muc#roomconfig_roomdesc' => nil,
|
|
# 'leave' => 'has left',
|
|
# 'join' => 'has become available',
|
|
# 'rename' => 'is now known as',
|
|
# 'muc#roomconfig_changesubject' => 0,
|
|
# 'muc#roomconfig_maxusers' => 0,
|
|
# 'privacy' => 0,
|
|
# 'muc#roomconfig_publicroom' => 1,
|
|
# 'muc#roomconfig_persistentroom' => 1,
|
|
# 'legacy' => 0,
|
|
# 'muc#roomconfig_moderatedroom' => 0,
|
|
# 'defaulttype' => 0,
|
|
# 'privmsg' => 0,
|
|
# 'muc#roomconfig_membersonly' => 0,
|
|
# 'muc#roomconfig_allowinvites' => 1,
|
|
# 'muc#roomconfig_passwordprotectedroom' => 0,
|
|
# 'muc#roomconfig_roomsecret' => nil,
|
|
# 'muc#roomconfig_whois' => 'moderators',
|
|
# 'muc#roomconfig_enablelogging' => 0,
|
|
# 'logformat' => 'xml'
|
|
# }
|
|
# default_config.merge(options)
|
|
# end
|
|
# #
|
|
# def initialize(parent=nil, details={})
|
|
# if ::GxG::valid_uuid?(details[:context])
|
|
# @uuid = details[:context].to_s.to_sym
|
|
# else
|
|
# @uuid = ::GxG::uuid_generate.to_sym
|
|
# end
|
|
# @parent = parent
|
|
# # @details should have a JID for the sender-jid/room-jid
|
|
# # @details should indicate whether a private direct message or MUC ROOM message (:chat? or :groupchat?)
|
|
# @details = details
|
|
# #
|
|
# @received = []
|
|
# @received_thread_safety = ::Mutex.new
|
|
# # Add call backs
|
|
# # @parent.notify({:event => :new_message, :conversation => @uuid, :message => message.id})
|
|
# # @parent.notify({:event => :new_private_message, :conversation => @uuid, :message => message.id})
|
|
# self
|
|
# end
|
|
# #
|
|
# def uuid()
|
|
# @uuid
|
|
# end
|
|
# #
|
|
# def jid()
|
|
# @details[:sender].to_s
|
|
# end
|
|
# #
|
|
# def my_jid()
|
|
# result = nil
|
|
# if @parent
|
|
# result = @parent.jid().to_s
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def [](the_key=nil)
|
|
# result = nil
|
|
# if the_key.is_a?(::Symbol)
|
|
# result = @details[(the_key)]
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def title()
|
|
# result = nil
|
|
# # Review : TODO - return ROOM title
|
|
# result
|
|
# end
|
|
# #
|
|
# def inspect()
|
|
# {:jid => this().jid, :title => this().title}.inspect
|
|
# end
|
|
# #
|
|
# def closed?()
|
|
# # Review : integrate with new system
|
|
# false
|
|
# end
|
|
# #
|
|
# def process_received(&block)
|
|
# begin
|
|
# if block.respond_to?(:call)
|
|
# count = 0
|
|
# @received_thread_safety.synchronize {
|
|
# count = @received.size
|
|
# }
|
|
# record = nil
|
|
# count.times do
|
|
# @received_thread_safety.synchronize {
|
|
# record = @received.shift
|
|
# }
|
|
# if record
|
|
# block.call(record)
|
|
# end
|
|
# end
|
|
# true
|
|
# else
|
|
# false
|
|
# end
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {}})
|
|
# false
|
|
# end
|
|
# end
|
|
# #
|
|
# def add_message(the_message=nil)
|
|
# if the_message
|
|
# @received_thread_safety.synchronize { @received << the_message }
|
|
# true
|
|
# else
|
|
# false
|
|
# end
|
|
# end
|
|
# #
|
|
# def join(the_jid=nil, password=nil, options={})
|
|
# result = false
|
|
# begin
|
|
# # Review : TODO - MUC join
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {:the_jid => the_jid, :options => options}})
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def leave(exit_string=nil)
|
|
# result = false
|
|
# begin
|
|
# # Review : TODO - MUC leave
|
|
# # @parent.refresh_conversations
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {:exit_string => exit_string}})
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def chat_buddies()
|
|
# result = []
|
|
# begin
|
|
# # Review : TODO - like XmppAgent.buddies but for this ROOM only.
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {}})
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def say_something(the_message=nil, to_jid=nil)
|
|
# result = false
|
|
# begin
|
|
# if @details[:type] == :chat
|
|
# recipient = (to_jid || the_message[:to]).to_s
|
|
# @parent.say(::Blather::JID.new(recipient), @parent.gxg_message_to_xmpp(the_message))
|
|
# else
|
|
# # Review : TODO - send chat message to ROOM
|
|
# end
|
|
# result = true
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {:message => the_message, :to => to_jid}})
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def send_invitations(the_recipients=nil, reason=nil)
|
|
# result = false
|
|
# begin
|
|
# # Review : TODO - ROOM invitation list processing list.each { |i| send i }
|
|
# # "You MUST provide an Array of JID Strings."
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {:recipients => the_recipients, :message => reason}})
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def configuration()
|
|
# result = nil
|
|
# begin
|
|
# # Review : TODO - get ROOM configuration
|
|
# # if @handler
|
|
# # if @handler.owner?
|
|
# # current_configuration = {}
|
|
# # iq = ::Jabber::Iq.new(:get, @handler.jid.to_s)
|
|
# # iq.to = @handler.jid.to_s
|
|
# # iq.from = @handler.my_jid.to_s
|
|
# # iq.add(::Jabber::MUC::IqQueryMUCOwner.new)
|
|
# # field_keys = this().default_room_configuration.keys
|
|
# # response = @stream.send_with_id(iq)
|
|
# # if response
|
|
# # if (response.query && response.query.x(::Jabber::Dataforms::XData))
|
|
# # field_keys.each do |the_key|
|
|
# # field = response.query.x(::Jabber::Dataforms::XData).field(the_key.to_s)
|
|
# # if field.is_a?(::Jabber::Dataforms::XDataField)
|
|
# # current_configuration[(the_key.to_s)] = field.value
|
|
# # end
|
|
# # end
|
|
# # end
|
|
# # end
|
|
# # result = current_configuration
|
|
# # else
|
|
# # raise Exception, "You are not the owner of this conversation room."
|
|
# # end
|
|
# # end
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {}})
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def change_configuration(the_configuration=nil)
|
|
# result = false
|
|
# begin
|
|
# # Review : TODO - alter ROOM configuration if admin/owner
|
|
# # if @handler
|
|
# # if @handler.owner?
|
|
# # unless the_configuration.is_a?(::Hash)
|
|
# # raise ArgumentError, "You MUST provide a configuration Hash."
|
|
# # end
|
|
# # the_configuration = this().default_room_configuration(the_configuration)
|
|
# # @handler.submit_room_configuration(the_configuration)
|
|
# # result = true
|
|
# # else
|
|
# # raise Exception, "You are not the owner of this conversation room."
|
|
# # end
|
|
# # end
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error, :parameters => {:configuration => the_configuration}})
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# end
|
|
# # ### XMPP Client
|
|
# class XmppAgent
|
|
# # ###
|
|
# def self.online_availability_values()
|
|
# {:online => :chat, :busy => :dnd, :away => :away, :extended_away => :xa, :offline => :unavailable, :error => :error}
|
|
# end
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# # ### Support Methods
|
|
# def write(stanza)
|
|
# if @client
|
|
# @client.write stanza
|
|
# end
|
|
# true
|
|
# end
|
|
# #
|
|
# def <<(stanza)
|
|
# if @client
|
|
# @client.write stanza
|
|
# end
|
|
# self
|
|
# end
|
|
# #
|
|
# def publish_and_subscribe
|
|
# @pubsub
|
|
# end
|
|
# # ### 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
|
|
# def before(handler = nil, *guards, &block)
|
|
# if @client
|
|
# @client.register_filter :before, handler, *guards, &block
|
|
# end
|
|
# end
|
|
# # ### 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
|
|
# def after(handler = nil, *guards, &block)
|
|
# if @client
|
|
# @client.register_filter :after, handler, *guards, &block
|
|
# end
|
|
# end
|
|
# # ### 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
|
|
# def handle(handler, *guards, &block)
|
|
# if @client
|
|
# @client.register_handler handler, *guards, &block
|
|
# end
|
|
# end
|
|
# # ### Wrapper for "handle :ready" (just a bit of syntactic sugar)
|
|
# #
|
|
# # This is run after the connection has been completely setup
|
|
# def when_ready(&block)
|
|
# self.handle :ready, &block
|
|
# end
|
|
# # ### Wrapper for "handle :disconnected"
|
|
# #
|
|
# # This is run after the connection has been shut down.
|
|
# #
|
|
# # @example Reconnect after a disconnection
|
|
# # disconnected { client.run }
|
|
# def disconnected(&block)
|
|
# self.handle :disconnected, &block
|
|
# end
|
|
# # ### Set current status
|
|
# #
|
|
# # @param [Blather::Stanza::Presence::State::VALID_STATES] state the current
|
|
# # state
|
|
# # @param [#to_s] msg the status message to use
|
|
# def set_status(state = nil, msg = nil)
|
|
# if @client
|
|
# @client.status = state, msg
|
|
# end
|
|
# end
|
|
# #
|
|
# def get_status()
|
|
# if @client
|
|
# @client.status
|
|
# else
|
|
# :unavailable
|
|
# end
|
|
# end
|
|
# # ### Direct access to the roster
|
|
# #
|
|
# # @return [Blather::Roster]
|
|
# def my_roster
|
|
# if @client
|
|
# @client.roster
|
|
# end
|
|
# end
|
|
# # ### Write data to the stream
|
|
# #
|
|
# # @param [#to_xml, #to_s] stanza the data to send down the wire.
|
|
# def write_to_stream(stanza)
|
|
# self.write stanza
|
|
# end
|
|
# # ### 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
|
|
# 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
|
|
# # ### 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
|
|
# def say(to, msg, using = :chat)
|
|
# self.write Blather::Stanza::Message.new(to, msg, using)
|
|
# end
|
|
# # ### The JID according to the server
|
|
# #
|
|
# # @return [Blather::JID]
|
|
# def jid
|
|
# if @client
|
|
# @client.jid
|
|
# else
|
|
# nil
|
|
# end
|
|
# end
|
|
# # other supporting JID methods
|
|
# def jid_node()
|
|
# jid = self.jid
|
|
# if jid
|
|
# jid.node()
|
|
# else
|
|
# nil
|
|
# end
|
|
# end
|
|
# def jid_domain()
|
|
# jid = self.jid
|
|
# if jid
|
|
# jid.domain()
|
|
# else
|
|
# nil
|
|
# end
|
|
# end
|
|
# def jid_resource()
|
|
# jid = self.jid
|
|
# if jid
|
|
# jid.resource()
|
|
# else
|
|
# nil
|
|
# end
|
|
# end
|
|
# # ### 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 }
|
|
# def halt
|
|
# # Review : how to actually use this? I see no way to call 'throw' yet. (research)
|
|
# # throw :halt
|
|
# end
|
|
# # ### 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/ }
|
|
# def pass
|
|
# # Review : how to actually use this? I see no way to call 'throw' yet. (research)
|
|
# # throw :pass
|
|
# end
|
|
# # ### Request items or info from an entity
|
|
# # discover (items|info), [jid], [node] do |response|
|
|
# # end
|
|
# 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
|
|
# # ### 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
|
|
# def set_caps(node, identities, features)
|
|
# if @client
|
|
# @client.caps.node = node
|
|
# @client.caps.identities = identities
|
|
# @client.caps.features = features
|
|
# end
|
|
# end
|
|
# # Send capabilities to the server
|
|
# 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
|
|
# # ### Conversion Tools
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# # ### Initialization
|
|
# 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
|
|
# # Review : debug only method
|
|
# def client()
|
|
# @client
|
|
# end
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# def logout
|
|
# if @client
|
|
# @client.clear_handlers :disconnected
|
|
# @client.close
|
|
# @client = nil
|
|
# end
|
|
# #
|
|
# true
|
|
# end
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# def download_directory()
|
|
# @file_transfers_thread_safety.synchronize { @download_directory }
|
|
# end
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# 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
|
|
# #
|
|
# #
|
|
# end
|
|
|
|
# ### XMPP
|
|
# class BridgeAdapterXMPP < ::GxG::Communications::BridgeAdapter
|
|
# def self.protocol()
|
|
# :xmpp
|
|
# end
|
|
# #
|
|
# def self.abilities()
|
|
# [:message, :file_transfer, :request]
|
|
# end
|
|
# #
|
|
# def self.limits()
|
|
# {:message_size => 1048576, :file_transfer_size => nil, :request_size => 65536}
|
|
# end
|
|
# #
|
|
# def self.templates()
|
|
# {}
|
|
# end
|
|
# #
|
|
# private
|
|
# def decode_message(the_message=nil)
|
|
# result = message
|
|
# if message.is_a?(::GxG::Events::Message)
|
|
# fallback_key = nil
|
|
# key = nil
|
|
# message_sender = message[:sender].to_s
|
|
# @thread_safety.synchronize {
|
|
# if @keychain[(message_sender.to_s)]
|
|
# fallback_key = @keychain[(message_sender.to_s)][:original]
|
|
# key = @keychain[(message_sender.to_s)][:current]
|
|
# end
|
|
# }
|
|
# new_body = nil
|
|
# if key && fallback_key
|
|
# if message[:body].is_a?(::String)
|
|
# begin
|
|
# if message[:body].base64?
|
|
# new_body = message[:body].decode64.decrypt(key)
|
|
# else
|
|
# new_body = message[:body].decrypt(key)
|
|
# end
|
|
# new_body = ::Hash::gxg_import(::JSON::parse(new_body, {:symbolize_names => true}))
|
|
# rescue Exception => the_error
|
|
# begin
|
|
# if message[:body].base64?
|
|
# new_body = message[:body].decode64.decrypt(fallback_key)
|
|
# else
|
|
# new_body = message[:body].decrypt(fallback_key)
|
|
# end
|
|
# new_body = ::Hash::gxg_import(::JSON::parse(new_body, {:symbolize_names => true}))
|
|
# rescue Exception => the_error
|
|
# message[:bridge_unintelligible] = true
|
|
# log_error({:error => the_error})
|
|
# new_body = nil
|
|
# end
|
|
# end
|
|
# end
|
|
# else
|
|
# if message[:body].is_a?(::String)
|
|
# if message[:body].base64?
|
|
# new_body = message[:body].decode64
|
|
# else
|
|
# new_body = message[:body]
|
|
# end
|
|
# begin
|
|
# new_body = ::Hash::gxg_import(::JSON::parse(new_body, {:symbolize_names => true}))
|
|
# rescue Exception => the_error
|
|
# log_error({:error => the_error})
|
|
# new_body = nil
|
|
# end
|
|
# end
|
|
# end
|
|
# if new_body.is_a?(::Hash)
|
|
# message[:body] = new_body
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# public
|
|
# #
|
|
# def initialize(the_process=nil, the_url=nil, options={:sasl => :digest, :digest => true})
|
|
# super(the_process, the_url, options)
|
|
# unless @options[:sasl]
|
|
# @options = {:sasl => :digest, :digest => true}
|
|
# end
|
|
# #
|
|
# # Channels format: {<uuid> => {:channel => <XMPPConversation>, :entities => [<jid-string>, ...]}}
|
|
# @channels = {}
|
|
# # Keychain format: {:original => "", :current => ""}
|
|
# @keychain = {}
|
|
# # Messages format: {<uuid> => [<::GxG::Events::Message>, ...]}
|
|
# @messages = {}
|
|
# @messages_busy_semaphore = false
|
|
# @invitations = {}
|
|
# @file_transfers = {}
|
|
# #
|
|
# @connector = ::GxG::Networking::XmppClient.new({:notify => self})
|
|
# self.open
|
|
# #
|
|
# self
|
|
# end
|
|
# #
|
|
# def my_id()
|
|
# if @connector
|
|
# @connector.my_jid.to_s
|
|
# else
|
|
# nil
|
|
# end
|
|
# end
|
|
# # ### Information Refresh
|
|
# def notify(details=nil)
|
|
# if details.is_a?(::Hash)
|
|
# if @process
|
|
# if @process.respond_to?(:dispatcher) && @process.respond_to?(:respond_to_event?)
|
|
# case details[:event]
|
|
# when :new_invitation
|
|
# active_list = {}
|
|
# @connector.invitations.each do |the_invitation|
|
|
# active_list[(the_invitation.uuid)] = {:invitation => the_invitation, :title => the_invitation[:title].to_s, :sender => the_invitation[:sender].to_s, :type => the_invitation[:type].to_s}
|
|
# end
|
|
# @thread_safety.synchronize { @invitations = active_list }
|
|
# #
|
|
# if @process.respond_to_event?(:new_invitation)
|
|
# @process.dispatcher.post_event(:communications) do
|
|
# @process.call_event({:new_invitation => {:invitation => details[:invitation], :sender => details[:sender], :at => ::DateTime.now}})
|
|
# end
|
|
# end
|
|
# when :new_file_transfer
|
|
# # First, update Bridge Manifest
|
|
# active_list = {}
|
|
# @connector.file_transfers.each do |the_transfer|
|
|
# reference = the_transfer.reference
|
|
# file_name = the_transfer.file_details[:filename]
|
|
# file_size = the_transfer.file_details[:size]
|
|
# sender = the_transfer.info[:sender]
|
|
# # set download path
|
|
# unless ::File.exists?(GxG::SERVER_PATHS[:temporary] + "/" + reference.to_s)
|
|
# ::FileUtils.mkpath(GxG::SERVER_PATHS[:temporary] + "/" + reference.to_s)
|
|
# end
|
|
# the_transfer.download_directory = (GxG::SERVER_PATHS[:temporary] + "/" + reference.to_s)
|
|
# # store entry
|
|
# active_list[(reference)] = {:transfer => the_transfer, :sender => sender, :file => file_name, :size => file_size, :path => ("/System/Temporary/" + reference.to_s + "/" + file_name)}
|
|
# end
|
|
# @thread_safety.synchronize { @file_transfers = active_list }
|
|
# if @process.respond_to_event?(:new_file_transfer)
|
|
# @process.dispatcher.post_event(:communications) do
|
|
# @process.call_event({:new_file_transfer => {:transfer => details[:transfer], :sender => details[:sender], :at => ::DateTime.now}})
|
|
# end
|
|
# end
|
|
# when :file_transfer_complete, :file_transfer_cancelled, :file_transfer_error
|
|
# notification = {}
|
|
# notification[(details[:event])] = {:transfer => details[:transfer], :at => ::DateTime.now}
|
|
# #
|
|
# active_list = {}
|
|
# @connector.file_transfers.each do |the_transfer|
|
|
# reference = the_transfer.reference
|
|
# file_name = the_transfer.file_details[:filename]
|
|
# file_size = the_transfer.file_details[:size]
|
|
# sender = the_transfer.info[:sender]
|
|
# # store entry
|
|
# active_list[(reference)] = {:transfer => the_transfer, :sender => sender, :file => file_name, :size => file_size, :path => ("/System/Temporary/" + reference.to_s + "/" + file_name)}
|
|
# end
|
|
# @thread_safety.synchronize { @file_transfers = active_list }
|
|
# #
|
|
# if @process.respond_to_event?(details[:event])
|
|
# @process.call_event(notification)
|
|
# end
|
|
# when :file_transfer_progress
|
|
# if @process.respond_to_event?(:file_transfer_progress)
|
|
# @process.call_event({:file_transfer_progress => {:transfer => details[:transfer], :progress => details[:progress], :at => ::DateTime.now}})
|
|
# end
|
|
# when :new_message, :new_private_message, :new_announcement, :new_error
|
|
# # ### unless channel exists - add it
|
|
# the_channel = @thread_safety.synchronize { @channels[(details[:conversation].to_sym)] }
|
|
# unless the_channel
|
|
# found = nil
|
|
# @connector.conversations.each do |channel_object|
|
|
# if details[:conversation].to_sym == channel_object.uuid
|
|
# found = channel_object
|
|
# break
|
|
# end
|
|
# end
|
|
# if found
|
|
# @thread_safety.synchronize { @channels[(details[:conversation].to_sym)] = {:channel => found, :title => found.title()}}
|
|
# the_channel = found
|
|
# end
|
|
# end
|
|
# # ### get messages
|
|
# if the_channel
|
|
# unless @thread_safety.synchronize { @messages[(the_channel.uuid)].is_a?(::Array) }
|
|
# @thread_safety.synchronize { @messages[(the_channel.uuid)] = [] }
|
|
# end
|
|
# the_channel.process_received() do |the_message|
|
|
# # Note: this will pick up other messages from the adapter now, but it is ok - a notification will be generated on EACH message.
|
|
# the_message[:channel] = the_channel.uuid
|
|
# @thread_safety.synchronize { @messages[(the_channel.uuid)] << the_message }
|
|
# end
|
|
# end
|
|
# # Review : differentiate beteween private and open messages? How to do?
|
|
# if @process.respond_to_event?(:new_message)
|
|
# notification = {}
|
|
# notification[:new_message] = {:channel => details[:conversation], :message => details[:message], :sender => details[:sender].to_s, :at => ::DateTime.now}
|
|
# #
|
|
# @process.dispatcher.post_event(:communications) do
|
|
# @process.call_event(notification)
|
|
# end
|
|
# end
|
|
# #
|
|
# end
|
|
# end
|
|
# end
|
|
# end
|
|
# end
|
|
# # ### Keychain
|
|
# def set_key(recipient=nil, password=nil)
|
|
# result = false
|
|
# if recipient.to_s.valid_jid? && password.is_a?(::String)
|
|
# @thread_safety.synchronize {
|
|
# if @keychain[(recipient.to_s)]
|
|
# @keychain[(recipient.to_s)][:current] = password
|
|
# else
|
|
# @keychain[(recipient.to_s)] = {:original => password, :current => password}
|
|
# end
|
|
# result = true
|
|
# }
|
|
# end
|
|
# result
|
|
# end
|
|
# # ### Invitations
|
|
# def accept_invitation(the_invitation_uuid=nil)
|
|
# result = false
|
|
# if ::GxG::valid_uuid?(the_invitation_uuid)
|
|
# found = nil
|
|
# @thread_safety.synchronize {
|
|
# found = @invitations[(the_invitation_uuid.to_sym)]
|
|
# }
|
|
# if found
|
|
# found[:invitation].accept()
|
|
# result = true
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def decline_invitation(the_invitation_uuid=nil)
|
|
# result = false
|
|
# if ::GxG::valid_uuid?(the_invitation_uuid)
|
|
# found = nil
|
|
# @thread_safety.synchronize {
|
|
# found = @invitations[(the_invitation_uuid.to_sym)]
|
|
# }
|
|
# if found
|
|
# found[:invitation].decline()
|
|
# result = true
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# # ### File Transfers
|
|
# def file_transfers()
|
|
# result = {}
|
|
# @thread_safety.synchronize {
|
|
# @file_transfers.each_pair do |the_uuid, the_record|
|
|
# result[(the_uuid)] = {:sender => the_record[:sender], :file => the_record[:file], :size => the_record[:size], :path => the_record[:path]}
|
|
# end
|
|
# }
|
|
# result
|
|
# end
|
|
# #
|
|
# def accept_file_transfer(the_transfer_uuid=nil)
|
|
# result = false
|
|
# if ::GxG::valid_uuid?(the_transfer_uuid)
|
|
# found = nil
|
|
# @thread_safety.synchronize {
|
|
# found = @file_transfers[(the_transfer_uuid.to_sym)]
|
|
# }
|
|
# if found
|
|
# found[:transfer].accept()
|
|
# result = true
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def decline_file_transfer(the_transfer_uuid=nil)
|
|
# result = false
|
|
# if ::GxG::valid_uuid?(the_transfer_uuid)
|
|
# found = nil
|
|
# @thread_safety.synchronize {
|
|
# found = @file_transfers[(the_transfer_uuid.to_sym)]
|
|
# }
|
|
# if found
|
|
# found[:transfer].decline()
|
|
# if ::File.exists?(GxG::SERVER_PATHS[:temporary] + "/" + found[:transfer].reference.to_s)
|
|
# ::GxG::VFS.rmdir("/System/Temporary/" + found[:transfer].reference.to_s)
|
|
# end
|
|
# result = true
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def cancel_file_transfer(the_transfer_uuid=nil)
|
|
# result = false
|
|
# if ::GxG::valid_uuid?(the_transfer_uuid)
|
|
# found = nil
|
|
# @thread_safety.synchronize {
|
|
# found = @file_transfers[(the_transfer_uuid.to_sym)]
|
|
# }
|
|
# if found
|
|
# found[:transfer].cancel()
|
|
# if ::File.exists?(GxG::SERVER_PATHS[:temporary] + "/" + found[:transfer].reference.to_s)
|
|
# ::GxG::VFS.rmdir("/System/Temporary/" + found[:transfer].reference.to_s)
|
|
# end
|
|
# result = true
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# # ### Entities
|
|
# def entities()
|
|
# result = []
|
|
# @connector.buddies().each do |record|
|
|
# new_record = {:id => "", :title => "Untitled", :groups => [], :status => :offline}
|
|
# new_record[:id] = record[:jid]
|
|
# new_record[:title] = record[:title]
|
|
# new_record[:groups] = record[:groups]
|
|
# case record[:status]
|
|
# when :chat, :normal, :available
|
|
# new_record[:status] = :online
|
|
# when :dnd
|
|
# new_record[:status] = :busy
|
|
# when :away
|
|
# new_record[:status] = :away
|
|
# when :xa
|
|
# new_record[:status] = :extended_away
|
|
# when :unavailable, :offline
|
|
# new_record[:status] = :offline
|
|
# when :error
|
|
# new_record[:status] = :error
|
|
# end
|
|
# result << new_record
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def entity_status(the_address=nil)
|
|
# result = :invalid_address
|
|
# if the_address.valid_jid?()
|
|
# result = :unknown_address
|
|
# self.entities.each do |the_record|
|
|
# if the_record[:id] == the_address
|
|
# result = the_record[:status]
|
|
# break
|
|
# end
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def status()
|
|
# result = :offline
|
|
# case @adapter.get_status
|
|
# when :chat, :normal, :available
|
|
# result = :online
|
|
# when :dnd
|
|
# result = :busy
|
|
# when :away
|
|
# result = :away
|
|
# when :xa
|
|
# result = :extended_away
|
|
# when :unavailable, :offline
|
|
# result = :offline
|
|
# when :error
|
|
# result = :error
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def status=(the_status=nil, message=nil)
|
|
# result = :available
|
|
# case the_status
|
|
# when :online
|
|
# result = :available
|
|
# when :busy
|
|
# result = :dnd
|
|
# when :away
|
|
# result = :away
|
|
# when :extended_away
|
|
# result = :xa
|
|
# when :offline
|
|
# result = :unavailable
|
|
# when :error
|
|
# result = :error
|
|
# end
|
|
# @adapter.set_status(result, message)
|
|
# end
|
|
# # ### Basic Channel Support
|
|
# def channels()
|
|
# result = {}
|
|
# @thread_safety.synchronize {
|
|
# @channels.each_pair do |the_uuid, the_record|
|
|
# result[(the_uuid)] = the_record[:title]
|
|
# end
|
|
# }
|
|
# result
|
|
# end
|
|
# #
|
|
# def associate(recipient=nil)
|
|
# result = false
|
|
# if recipient.is_a?(::String)
|
|
# if recipient.valid_jid?
|
|
# @adapter.add_buddy(recipient)
|
|
# result = true
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def disassociate(recipient=nil)
|
|
# result = false
|
|
# if recipient.is_a?(::String)
|
|
# if recipient.valid_jid?
|
|
# @adapter.remove_buddy(recipient)
|
|
# result = true
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def open_channel(with_jid=nil, password=nil, configuration={})
|
|
# result = nil
|
|
# if with_jid.is_a?(::String)
|
|
# if with_jid.valid_jid? && configuration.is_any?(::Hash, ::GxG::Database::PersistedHash)
|
|
# # If channel already exists and they attempt a repeat opening action:
|
|
# @thread_safety.synchronize {
|
|
# @channels.each_pair do |the_uuid, the_record|
|
|
# if with_jid.to_s == the_record.jid.to_s
|
|
# result = the_record.uuid
|
|
# break
|
|
# end
|
|
# end
|
|
# }
|
|
# unless result
|
|
# # Channel needs to be constructed:
|
|
# if @connector.create_conversation(with_jid, password, configuration) == true
|
|
# existing_channels = self.channels()
|
|
# found = nil
|
|
# @thread_safety.synchronize {
|
|
# @connector.conversations.each do |channel_object|
|
|
# if existing_channels.keys.include?(channel_object.uuid)
|
|
# next
|
|
# else
|
|
# found = channel_object
|
|
# @channels[(channel_object.uuid)] = {:channel => found, :title => found.title()}
|
|
# break
|
|
# end
|
|
# end
|
|
# }
|
|
# if found
|
|
# result = channel_object.uuid
|
|
# if password
|
|
# if channel_object[:type] == :chat
|
|
# # on :groupchat password is only used for access, not encryption.
|
|
# self.set_key(with_jid, password)
|
|
# end
|
|
# end
|
|
# end
|
|
# #
|
|
# end
|
|
# end
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def join_channel(channel_jid=nil, password=nil, options={})
|
|
# result = nil
|
|
# if channel_jid.is_a?(::String)
|
|
# if channel_jid.valid_jid? && options.is_any?(::Hash, ::GxG::Database::PersistedHash)
|
|
# if @connector.join_conversation(channel_jid, password, options) == true
|
|
# existing_channels = self.channels()
|
|
# found = nil
|
|
# @thread_safety.synchronize {
|
|
# @connector.conversations.each do |channel_object|
|
|
# if existing_channels.keys.include?(channel_object.uuid)
|
|
# next
|
|
# else
|
|
# found = channel_object
|
|
# @channels[(channel_object.uuid)] = {:channel => found, :title => found.title()}
|
|
# break
|
|
# end
|
|
# end
|
|
# }
|
|
# if found
|
|
# result = channel_object.uuid
|
|
# end
|
|
# #
|
|
# end
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def close_channel(the_channel_uuid=nil)
|
|
# if ::GxG::valid_uuid?(the_channel_uuid)
|
|
# the_channel = nil
|
|
# @thread_safety.synchronize {
|
|
# if @channels[(the_channel_uuid.to_sym)].is_a?(::Hash)
|
|
# the_channel = @channels.delete(the_channel_uuid.to_sym)[:channel]
|
|
# end
|
|
# }
|
|
# if the_channel
|
|
# the_channel.leave("{ \"exit_channel\":\"#{the_channel.my_jid.to_s}\" }")
|
|
# true
|
|
# else
|
|
# false
|
|
# end
|
|
# else
|
|
# false
|
|
# end
|
|
# end
|
|
# # ### Messages
|
|
# def send_message(the_channel_uuid=nil, message=nil, recipient=nil, use_fallback_key=false)
|
|
# result = false
|
|
# #
|
|
# if ::GxG::valid_uuid?(the_channel_uuid)
|
|
# the_channel = nil
|
|
# @thread_safety.synchronize {
|
|
# if @channels[(the_channel_uuid.to_sym)].is_a?(::Hash)
|
|
# the_channel = @channels[(the_channel_uuid.to_sym)][:channel]
|
|
# end
|
|
# }
|
|
# if the_channel
|
|
# if message.is_any?(::String, ::Hash, ::GxG::Database::PersistedHash, ::GxG::Events::Message)
|
|
# if message.is_a?(::String)
|
|
# message = new_message({:sender => @connector.my_jid.to_s, :body => {:message => message}.gxg_export.to_json})
|
|
# end
|
|
# if message.is_a?(::Hash)
|
|
# message = new_message({:sender => @connector.my_jid.to_s, :body => message.gxg_export.to_json})
|
|
# end
|
|
# if message.is_a?(::GxG::Database::PersistedHash)
|
|
# message = new_message({:sender => @connector.my_jid.to_s, :body => message.sync_export.gxg_export.to_json})
|
|
# end
|
|
# if message.is_a?(::GxG::Events::Message)
|
|
# if message[:body].is_a?(::Hash)
|
|
# message[:body] = message[:body].gxg_export.to_json
|
|
# end
|
|
# if message[:body].is_a?(::GxG::Database::PersistedHash)
|
|
# message[:body] = message[:body].sync_export.gxg_export.to_json
|
|
# end
|
|
# end
|
|
# #
|
|
# if message.is_a?(::GxG::Events::Message)
|
|
# # Reset :sender if a ruby object is the current setting. (bridge addressing translation)
|
|
# unless message[:sender].is_a?(::String)
|
|
# message[:sender] = @connector.my_jid.to_s
|
|
# end
|
|
# # encrypt body?
|
|
# key = nil
|
|
# if recipient.is_a?(::String)
|
|
# intended_recipient = recipient
|
|
# else
|
|
# intended_recipient = the_channel.jid()
|
|
# end
|
|
# @thread_safety.synchronize {
|
|
# if @keychain[(intended_recipient.to_s)]
|
|
# if use_fallback_key == true
|
|
# key = @keychain[(intended_recipient.to_s)][:original]
|
|
# else
|
|
# key = @keychain[(intended_recipient.to_s)][:current]
|
|
# end
|
|
# end
|
|
# }
|
|
# if key.is_a?(::String)
|
|
# message[:body] = message[:body].encrypt(key).encode64
|
|
# else
|
|
# message[:body] = message[:body].encode64
|
|
# end
|
|
# # send message
|
|
# result = the_channel.say_something(message, recipient)
|
|
# # Review : use this next little bit of code in the request/reply code:
|
|
# # if result == true
|
|
# # message.succeed(message)
|
|
# # else
|
|
# # message.fail(message)
|
|
# # end
|
|
# end
|
|
# else
|
|
# raise ArgumentError, "You MUST provide the message as a String, Hash, GxG::Database::PersistedHash, or GxG::Events::Message; NOT #{message.class} ."
|
|
# end
|
|
# else
|
|
# raise ArgumentError, "Invalid Channel selector, the Channel was not found: #{the_channel.inspect} . Try opening the channel first."
|
|
# end
|
|
# else
|
|
# raise ArgumentError, "Invalid Channel selector: #{the_channel.inspect} . You MUST provide a valid UUID."
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def next_message(the_channel_uuid=nil)
|
|
# result = nil
|
|
# if ::GxG::valid_uuid?(the_channel_uuid)
|
|
# @thread_safety.synchronize {
|
|
# if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
|
# result = @messages[(the_channel_uuid.to_sym)].shift
|
|
# end
|
|
# }
|
|
# if result
|
|
# result = decode_message(result)
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def all_messages(the_channel_uuid=nil)
|
|
# result = []
|
|
# if ::GxG::valid_uuid?(the_channel_uuid)
|
|
# @thread_safety.synchronize {
|
|
# if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
|
# @messages[(the_channel_uuid.to_sym)].size.times do
|
|
# result << decode_message(@messages[(the_channel_uuid.to_sym)].shift)
|
|
# end
|
|
# end
|
|
# }
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def get_message(the_channel_uuid=nil, the_message_uuid=nil)
|
|
# result = nil
|
|
# if ::GxG::valid_uuid?(the_channel_uuid) && the_message_uuid
|
|
# @thread_safety.synchronize {
|
|
# if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
|
# @messages[(the_channel_uuid.to_sym)].each_with_index do |the_message, the_index|
|
|
# if the_message_uuid == the_message.id()
|
|
# result = @messages[(the_channel_uuid.to_sym)].delete_at(the_index)
|
|
# break
|
|
# end
|
|
# end
|
|
# end
|
|
# }
|
|
# if result
|
|
# result = decode_message(result)
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def get_messages_by_context(the_channel_uuid=nil, the_context_uuid=nil)
|
|
# result = []
|
|
# if ::GxG::valid_uuid?(the_channel_uuid) && the_context_uuid
|
|
# @thread_safety.synchronize {
|
|
# if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
|
# @messages[(the_channel_uuid.to_sym)].each_with_index do |the_message, the_index|
|
|
# if the_context_uuid.to_s.to_sym == the_message[:context].to_s.to_sym
|
|
# result << @messages[(the_channel_uuid.to_sym)].delete_at(the_index)
|
|
# end
|
|
# end
|
|
# end
|
|
# }
|
|
# if result
|
|
# result = decode_message(result)
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# def get_messages_by_sender(the_channel_uuid=nil, the_sender=nil)
|
|
# result = []
|
|
# if ::GxG::valid_uuid?(the_channel_uuid) && the_sender
|
|
# @thread_safety.synchronize {
|
|
# if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
|
# @messages[(the_channel_uuid.to_sym)].each_with_index do |the_message, the_index|
|
|
# if the_sender.to_s == the_message[:sender].to_s
|
|
# result << @messages[(the_channel_uuid.to_sym)].delete_at(the_index)
|
|
# end
|
|
# end
|
|
# end
|
|
# }
|
|
# if result
|
|
# result = decode_message(result)
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
# #
|
|
# end
|
|
# |