<commit_before>#
# Copyright (c) 2006-2009 National ICT Australia (NICTA), Australia
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#
# = omfXMPPServices.rb
#
# == Description
#
# This file implements 
#
# a Publish/Subscribe Service Helper.
# This PubSub Service Helper is based on XMPP.
# This current implementation uses the library XMPP4R.
#

require 'rubygems'
require 'xmpp4r'
require 'xmpp4r/pubsub'
require 'xmpp4r/pubsub/helper/servicehelper'
require 'xmpp4r/pubsub/helper/nodebrowser'
require 'omf-common/mobject'
#Jabber::debug = true

GATEWAY_TIMEOUT = 10 # in sec
RECONNECT_INTERVAL = 5 # in sec
PING_INTERVAL = 60 # in sec
PING_THRESHOLD = 10 # in number of pings

#
# This class subclasses 'Jabber::PubSub::ServiceHelper' because its 
# 'unsubscribe_from' method is broken. 
# Indeed, as stated in the XMPP4R v0.4 API, it does NOT support the 'subid' 
# field. However, the OpenFire v3.6 server (which we currently use as XMPP 
# Server) requires the use of that field to process unsubsribe requests, 
# otherwise it replies with a 'Bad request' error.
# This class also implements a 'ping' back to the XMPP server, as defined
# in http://xmpp.org/extensions/xep-0199.html#c2s
#
class OmfServiceHelper < Jabber::PubSub::ServiceHelper

  #
  # Perform a 'unsubscribe_from' from scratch
  #
  def unsubscribe_from_fixed (node,subid)
    iq = basic_pubsub_query(:set)
    sub = REXML::Element.new('unsubscribe')
    sub.attributes['node'] = node
    sub.attributes['jid'] = @stream.jid.strip.to_s
    sub.attributes['subid']=subid
    iq.pubsub.add(sub)
    ret = false
    @stream.send_with_id(iq) do |reply|
      ret = reply.kind_of?(Jabber::Iq) and reply.type == :result
    end # @stream.send_with_id(iq)
    ret  
  end
  
  #
  # Send a ping to the PubSub server
  # implemented according to
  # http://xmpp.org/extensions/xep-0199.html#c2s
  #
  def ping
    iq = Jabber::Iq.new(:get, @stream.jid.domain)
    iq.from = @stream.jid
    ping = iq.add(REXML::Element.new('ping'))
    ping.add_namespace 'urn:xmpp:ping'
    @stream.send_with_id(iq) do |reply|
      ret = reply.kind_of?(Jabber::Iq) and reply.type == :result
    end # @stream.send_with_id(iq)
  end
  
  #
  # Another bug in XMPP4r
  # owner field is missing when purging items
  # see http://www.ejabberd.im/node/3413
  #
  def purge_items_from(node)
    iq = basic_pubsub_query(:set,true)
    purge = REXML::Element.new('purge')
    purge.attributes['node'] = node
    iq.pubsub.add(purge)
    @stream.send_with_id(iq)
  end

  def stream
    @stream
  end
end # END of OmfServiceHelper


# 
# This class defines a XMPP Service Helper for OMF entities.
# Following the PubSub communication paradigm, this class will be the
# 'XMPP Client' which will talk to an 'XMPP Server'. So far, we have tested
# this class with OpenFire (v3.6) and EJabberd XMPP servers.
# This Service Helper will handle all messages to and from the XMPP Server.
# Following the XMPP4R scheme, this class holds a single connection to a
# main (or 'home') XMPP server, and potentially several 'service helpers'
# which are used to access other XMPP servers via 'home' server and the 
# XMPP Server2Server capability.
#
class OmfXMPPServices < MObject

  @clientHelper = nil
  @nodeBrowser = nil

  attr_reader :clientHelper

  #
  # Create a new instance of XMPP Services 
  # This instance will maintain a single connection to a 'home' XMPP server
  # and will serve as an entry-point into the XMPP world to interact with 
  # potentially multiple XMPP servers via Server2Server communication.
  # A 'service helper' will be required for each XMPP server we want to
  # interact with (see the 'add_service' method)
  # 
  # - user = [String] username to connect to the home XMPP server  
  # - password = [String], password to connect to the home XMPP server
  # - host = [String] hostname of the home XMPP server   
  # - port = [Fixnum] optional port number of the home XMPP server
  # - useDnsSrv = [Bool] optional flag to enable DNS SRV record resolution
  #
  def initialize(user, password, host, port = nil, useDnsSrv = nil, max_retries = nil)

    # Set internal attributes
    @userJID = "#{user}@#{host}"
    @password = password
    @homeServer = host
    @port = port || 5222
    @useDnsSrv = useDnsSrv || false
    @max_retries = max_retries || 0
    @serviceHelpers = Hash.new # Holds the list of service helpers
    @connecting = false
    @keepAliveThread = nil
    @cSemaphore = Mutex.new

    # Open a connection to the home XMPP Server
    # Any exception raised here shall be caught by the caller
    @clientHelper = Jabber::Client.new(@userJID)
    connect
    @clientHelper.on_exception { connect }
  end

  def connect
    # Only allow one connection attempt at a time! 
    @cSemaphore.synchronize {
      return if @connecting 
      @connecting = true
    }
<<<<<<< HEAD
    @connection_attempts = 1
    debug "Try to connect to Pubsub Gateway '#{@homeServer}:#{@port}'..."
=======
    debug "Try to connect to Pubsub Gateway '#{@homeServer}'..."
    # In case "connect" was called even though we are already connected
    # try close the connection first.
    # Ignore any exception in doing so (e.g. if there is no previous connection)
    begin 
      @clientHelper.close if !@clientHelper.nil?
    rescue Exception => ex
      debug "Cannot close a previous (if any) connection to PubSub Gateway '#{@homeServer}'"
    end
    # We are passing the hostname here to prevent xmpp4r from trying to resolve
    # the DNS SRV record
>>>>>>> 9a59ab6... Fixed bug #556, ignore any exception when we try to close a session with the XMPP server from previous instance runs
    begin
      success = call_with_timeout("Timing out while connecting to "+<commit_msg>Revert commit 9f2df89f (wrong commit while conflicts were still present)<commit_after>#
# Copyright (c) 2006-2009 National ICT Australia (NICTA), Australia
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#
# = omfXMPPServices.rb
#
# == Description
#
# This file implements 
#
# a Publish/Subscribe Service Helper.
# This PubSub Service Helper is based on XMPP.
# This current implementation uses the library XMPP4R.
#

require 'rubygems'
require 'xmpp4r'
require 'xmpp4r/pubsub'
require 'xmpp4r/pubsub/helper/servicehelper'
require 'xmpp4r/pubsub/helper/nodebrowser'
require 'omf-common/mobject'
#Jabber::debug = true

GATEWAY_TIMEOUT = 10 # in sec
RECONNECT_INTERVAL = 5 # in sec
PING_INTERVAL = 60 # in sec
PING_THRESHOLD = 10 # in number of pings

#
# This class subclasses 'Jabber::PubSub::ServiceHelper' because its 
# 'unsubscribe_from' method is broken. 
# Indeed, as stated in the XMPP4R v0.4 API, it does NOT support the 'subid' 
# field. However, the OpenFire v3.6 server (which we currently use as XMPP 
# Server) requires the use of that field to process unsubsribe requests, 
# otherwise it replies with a 'Bad request' error.
# This class also implements a 'ping' back to the XMPP server, as defined
# in http://xmpp.org/extensions/xep-0199.html#c2s
#
class OmfServiceHelper < Jabber::PubSub::ServiceHelper

  #
  # Perform a 'unsubscribe_from' from scratch
  #
  def unsubscribe_from_fixed (node,subid)
    iq = basic_pubsub_query(:set)
    sub = REXML::Element.new('unsubscribe')
    sub.attributes['node'] = node
    sub.attributes['jid'] = @stream.jid.strip.to_s
    sub.attributes['subid']=subid
    iq.pubsub.add(sub)
    ret = false
    @stream.send_with_id(iq) do |reply|
      ret = reply.kind_of?(Jabber::Iq) and reply.type == :result
    end # @stream.send_with_id(iq)
    ret  
  end
  
  #
  # Send a ping to the PubSub server
  # implemented according to
  # http://xmpp.org/extensions/xep-0199.html#c2s
  #
  def ping
    iq = Jabber::Iq.new(:get, @stream.jid.domain)
    iq.from = @stream.jid
    ping = iq.add(REXML::Element.new('ping'))
    ping.add_namespace 'urn:xmpp:ping'
    @stream.send_with_id(iq) do |reply|
      ret = reply.kind_of?(Jabber::Iq) and reply.type == :result
    end # @stream.send_with_id(iq)
  end
  
  #
  # Another bug in XMPP4r
  # owner field is missing when purging items
  # see http://www.ejabberd.im/node/3413
  #
  def purge_items_from(node)
    iq = basic_pubsub_query(:set,true)
    purge = REXML::Element.new('purge')
    purge.attributes['node'] = node
    iq.pubsub.add(purge)
    @stream.send_with_id(iq)
  end

  def stream
    @stream
  end
end # END of OmfServiceHelper


# 
# This class defines a XMPP Service Helper for OMF entities.
# Following the PubSub communication paradigm, this class will be the
# 'XMPP Client' which will talk to an 'XMPP Server'. So far, we have tested
# this class with OpenFire (v3.6) and EJabberd XMPP servers.
# This Service Helper will handle all messages to and from the XMPP Server.
# Following the XMPP4R scheme, this class holds a single connection to a
# main (or 'home') XMPP server, and potentially several 'service helpers'
# which are used to access other XMPP servers via 'home' server and the 
# XMPP Server2Server capability.
#
class OmfXMPPServices < MObject

  @clientHelper = nil
  @nodeBrowser = nil

  attr_reader :clientHelper

  #
  # Create a new instance of XMPP Services 
  # This instance will maintain a single connection to a 'home' XMPP server
  # and will serve as an entry-point into the XMPP world to interact with 
  # potentially multiple XMPP servers via Server2Server communication.
  # A 'service helper' will be required for each XMPP server we want to
  # interact with (see the 'add_service' method)
  # 
  # - user = [String] username to connect to the home XMPP server  
  # - password = [String], password to connect to the home XMPP server
  # - host = [String] hostname of the home XMPP server   
  # - port = [Fixnum] optional port number of the home XMPP server
  # - useDnsSrv = [Bool] optional flag to enable DNS SRV record resolution
  #
  def initialize(user, password, host, port = nil, useDnsSrv = nil, max_retries = nil)

    # Set internal attributes
    @userJID = "#{user}@#{host}"
    @password = password
    @homeServer = host
    @port = port || 5222
    @useDnsSrv = useDnsSrv || false
    @max_retries = max_retries || 0
    @serviceHelpers = Hash.new # Holds the list of service helpers
    @connecting = false
    @keepAliveThread = nil
    @cSemaphore = Mutex.new

    # Open a connection to the home XMPP Server
    # Any exception raised here shall be caught by the caller
    @clientHelper = Jabber::Client.new(@userJID)
    connect
    @clientHelper.on_exception { connect }
  end

  def connect
    # Only allow one connection attempt at a time! 
    @cSemaphore.synchronize {
      return if @connecting 
      @connecting = true
    }
    @connection_attempts = 1
    debug "Try to connect to Pubsub Gateway '#{@homeServer}:#{@port}'..."
    begin
      success = call_with_timeout("Timing out while connecting to "+
{'fraction_non_alphanumeric': 0.08702076366747026, 'fraction_numerical': 0.008865386110895093, 'mean_word_length': 3.703730797366496, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2131285', 'n_tokens_mistral': 4156, 'n_tokens_neox': 4011, 'n_words': 1517}