<commit_before># dbus.rb - Module containing the low-level D-Bus implementation
#
# This file is part of the ruby-dbus project
# Copyright (C) 2007 <NAME> and <NAME>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License, version 2.1 as published by the Free Software Foundation.
# See the file "COPYING" for the exact licensing terms.

require 'socket'
require 'thread'
require 'singleton'
require 'fcntl'

# = D-Bus main module
#
# Module containing all the D-Bus modules and classes.
module DBus
  # This represents a remote service. It should not be instantiated directly
  # Use Bus::service()
  class Service
    # The service name.
    attr_reader :name
    # The bus the service is running on.
    attr_reader :bus
    # The service root (FIXME).
    attr_reader :root

    # Create a new service with a given _name_ on a given _bus_.
    def initialize(name, bus)
      @name, @bus = name, bus
      @root = Node.new("/")
    end

    # Determine whether the service name already exists.
    def exists?
      bus.proxy.ListNames[0].member?(@name)
    end

    # Perform an introspection on all the objects on the service
    # (starting recursively from the root).
    def introspect
      if block_given?
        raise NotImplementedError
      else
        rec_introspect(@root, "/")
      end
      self
    end

    # Retrieves an object at the given _path_.
    # @return [ProxyObject]
    def object(path)
      node = get_node(path, true)
      if node.object.nil?
        node.object = ProxyObject.new(@bus, @name, path)
      end
      node.object
    end

    # Export an object _obj_ (an DBus::Object subclass instance).
    def export(obj)
      obj.service = self
      get_node(obj.path, true).object = obj
    end

    # Undo exporting an object _obj_.
    # Raises ArgumentError if it is not a DBus::Object.
    # Returns the object, or false if _obj_ was not exported.
    def unexport(obj)
      raise ArgumentError.new("DBus::Service#unexport() expects a DBus::Object argument") unless obj.kind_of?(DBus::Object)
      return false unless obj.path
      pathSep = obj.path.rindex("/") #last path seperator
      parent_path = obj.path[1..pathSep-1]
      node_name = obj.path[pathSep+1..-1]

      parent_node = get_node(parent_path, false)
      return false unless parent_node
      obj.service = nil
      parent_node.delete(node_name)
    end
	
    # Get the object node corresponding to the given _path_. if _create_ is
    # true, the the nodes in the path are created if they do not already exist.
    def get_node(path, create = false)
      n = @root
      path.sub(/^\//, "").split("/").each do |elem|
        if not n[elem]
          if not create
            return nil
          else
            n[elem] = Node.new(elem)
          end
        end
        n = n[elem]
      end
      if n.nil?
        puts "Warning, unknown object #{path}" if $DEBUG
      end
      n
    end

    #########
    private
    #########

    # Perform a recursive retrospection on the given current _node_
    # on the given _path_.
    def rec_introspect(node, path)
      xml = bus.introspect_data(@name, path)
      intfs, subnodes = IntrospectXMLParser.new(xml).parse
      subnodes.each do |nodename|
        subnode = node[nodename] = Node.new(nodename)
        if path == "/"
          subpath = "/" + nodename
        else
          subpath = path + "/" + nodename
        end
        rec_introspect(subnode, subpath)
      end
      if intfs.size > 0
        node.object = ProxyObjectFactory.new(xml, @bus, @name, path).build
      end
    end
  end

  # = Object path node class
  #
  # Class representing a node on an object path.
  class Node < Hash
    # The D-Bus object contained by the node.
    attr_accessor :object
    # The name of the node.
    attr_reader :name

    # Create a new node with a given _name_.
    def initialize(name)
      @name = name
      @object = nil
    end

    # Return an XML string representation of the node.
    # It is shallow, not recursing into subnodes
    def to_xml
      xml = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
'
      self.each_pair do |k, v|
        xml += "<node name=\"#{k}\" />"
      end
      if @object
        @object.intfs.each_pair do |k, v|
          xml += %{<interface name="#{v.name}">\n}
          v.methods.each_value { |m| xml += m.to_xml }
          v.signals.each_value { |m| xml += m.to_xml }
          xml +="</interface>\n"
        end
      end
      xml += '</node>'
      xml
    end

    # Return inspect information of the node.
    def inspect
      # Need something here
      "<DBus::Node #{sub_inspect}>"
    end

    # Return instance inspect information, used by Node#inspect.
    def sub_inspect
      s = ""
      if not @object.nil?
        s += "%x " % @object.object_id
      end
      s + "{" + keys.collect { |k| "#{k} => #{self[k].sub_inspect}" }.join(",") + "}"
    end
  end # class Inspect

  # FIXME: rename Connection to Bus?

  # D-Bus main connection class
  #
  # Main class that maintains a connection to a bus and can handle incoming
  # and outgoing messages.
  class Connection
    # The unique name (by specification) of the message.
    attr_reader :unique_name
    # The socket that is used to connect with the bus.
    attr_reader :socket

    # Create a new connection to the bus for a given connect _path_. _path_
    # format is described in the D-Bus specification:
    # http://dbus.freedesktop.org/doc/dbus-specification.html#addresses
    # and is something like:
    # "transport1:key1=value1,key2=value2;transport2:key1=value1,key2=value2"
    # e.g. "unix:path=/tmp/dbus-test" or "tcp:host=localhost,port=2687"
    def initialize(path)
      @path = path
      @unique_name = nil
      @buffer = ""
      @method_call_replies = Hash.new
      @method_call_msgs = Hash.new
      @signal_matchrules = Hash.new
      @proxy = nil
      @object_root = Node.new("/")
      @is_tcp = false
    end

    # Connect to the bus and initialize the connection.
    def connect
      addresses = @path.split ";"
      # connect to first one that succeeds
      worked = addresses.find do |a|
        transport, keyvaluestring = a.split ":"
        kv_list = keyvaluestring.split ","
        kv_hash = Hash.new
        kv_list.each do |kv|
          key, escaped_value = kv.split "="
          value = escaped_value.gsub(/%(..)/) {|m| [$1].pack "H2" }
          kv_hash[key] = value
        end
        case transport
          when "unix"
          connect_to_unix kv_hash
          when "tcp"
          connect_to_tcp kv_hash
          when "launchd"
          connect_to_launchd kv_hash
          else
          # ignore, report?
        end
      end
      worked
      # returns the address that worked or nil.
      # how to report failure?
    end

    # Connect to a bus over tcp and initialize the connection.
    def connect_to_tcp(params)
      #check if the path is sufficient
      if params.key?("host") and params.key?("port")
        begin
          #initialize the tcp socket
          @socket = TCPSocket.new(params["host"],params["port"].to_i)
          @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
          init_connection
          @is_tcp = true
        rescue
          puts "Error: Could not establish connection to: #{@path}, will now exit."
          exit(0) #a little harsh
        end
      else
        #Danger, <NAME>: the specified "path" is not usable
        puts "Error: supplied path: #{@path}, unusable! sorry."
      end
    end

    # Connect to an abstract unix bus and initialize the connection.
    def connect_to_unix(params)
      @socket = Socket.new(Socket::Constants::PF_UNIX,Socket::Constants::SOCK_STREAM, 0)
      @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
      if ! params['abstract'].nil?
        if HOST_END == LIL_END
          sockaddr = "\1\0\0#{params['abstract']}"
        else
          sockaddr = "\0\1\0#{params['abstract']}"
        end
      elsif ! params['path'].nil?
        sockaddr = Socket.pack_sockaddr_un(params['path'])
      end
      @socket.connect(sockaddr)
      init_connection
    end
<commit_msg>Don't mask a TCP connection failure for a success.<commit_after># dbus.rb - Module containing the low-level D-Bus implementation
#
# This file is part of the ruby-dbus project
# Copyright (C) 2007 <NAME> and <NAME>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License, version 2.1 as published by the Free Software Foundation.
# See the file "COPYING" for the exact licensing terms.

require 'socket'
require 'thread'
require 'singleton'
require 'fcntl'

# = D-Bus main module
#
# Module containing all the D-Bus modules and classes.
module DBus
  # This represents a remote service. It should not be instantiated directly
  # Use Bus::service()
  class Service
    # The service name.
    attr_reader :name
    # The bus the service is running on.
    attr_reader :bus
    # The service root (FIXME).
    attr_reader :root

    # Create a new service with a given _name_ on a given _bus_.
    def initialize(name, bus)
      @name, @bus = name, bus
      @root = Node.new("/")
    end

    # Determine whether the service name already exists.
    def exists?
      bus.proxy.ListNames[0].member?(@name)
    end

    # Perform an introspection on all the objects on the service
    # (starting recursively from the root).
    def introspect
      if block_given?
        raise NotImplementedError
      else
        rec_introspect(@root, "/")
      end
      self
    end

    # Retrieves an object at the given _path_.
    # @return [ProxyObject]
    def object(path)
      node = get_node(path, true)
      if node.object.nil?
        node.object = ProxyObject.new(@bus, @name, path)
      end
      node.object
    end

    # Export an object _obj_ (an DBus::Object subclass instance).
    def export(obj)
      obj.service = self
      get_node(obj.path, true).object = obj
    end

    # Undo exporting an object _obj_.
    # Raises ArgumentError if it is not a DBus::Object.
    # Returns the object, or false if _obj_ was not exported.
    def unexport(obj)
      raise ArgumentError.new("DBus::Service#unexport() expects a DBus::Object argument") unless obj.kind_of?(DBus::Object)
      return false unless obj.path
      pathSep = obj.path.rindex("/") #last path seperator
      parent_path = obj.path[1..pathSep-1]
      node_name = obj.path[pathSep+1..-1]

      parent_node = get_node(parent_path, false)
      return false unless parent_node
      obj.service = nil
      parent_node.delete(node_name)
    end
	
    # Get the object node corresponding to the given _path_. if _create_ is
    # true, the the nodes in the path are created if they do not already exist.
    def get_node(path, create = false)
      n = @root
      path.sub(/^\//, "").split("/").each do |elem|
        if not n[elem]
          if not create
            return nil
          else
            n[elem] = Node.new(elem)
          end
        end
        n = n[elem]
      end
      if n.nil?
        puts "Warning, unknown object #{path}" if $DEBUG
      end
      n
    end

    #########
    private
    #########

    # Perform a recursive retrospection on the given current _node_
    # on the given _path_.
    def rec_introspect(node, path)
      xml = bus.introspect_data(@name, path)
      intfs, subnodes = IntrospectXMLParser.new(xml).parse
      subnodes.each do |nodename|
        subnode = node[nodename] = Node.new(nodename)
        if path == "/"
          subpath = "/" + nodename
        else
          subpath = path + "/" + nodename
        end
        rec_introspect(subnode, subpath)
      end
      if intfs.size > 0
        node.object = ProxyObjectFactory.new(xml, @bus, @name, path).build
      end
    end
  end

  # = Object path node class
  #
  # Class representing a node on an object path.
  class Node < Hash
    # The D-Bus object contained by the node.
    attr_accessor :object
    # The name of the node.
    attr_reader :name

    # Create a new node with a given _name_.
    def initialize(name)
      @name = name
      @object = nil
    end

    # Return an XML string representation of the node.
    # It is shallow, not recursing into subnodes
    def to_xml
      xml = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
'
      self.each_pair do |k, v|
        xml += "<node name=\"#{k}\" />"
      end
      if @object
        @object.intfs.each_pair do |k, v|
          xml += %{<interface name="#{v.name}">\n}
          v.methods.each_value { |m| xml += m.to_xml }
          v.signals.each_value { |m| xml += m.to_xml }
          xml +="</interface>\n"
        end
      end
      xml += '</node>'
      xml
    end

    # Return inspect information of the node.
    def inspect
      # Need something here
      "<DBus::Node #{sub_inspect}>"
    end

    # Return instance inspect information, used by Node#inspect.
    def sub_inspect
      s = ""
      if not @object.nil?
        s += "%x " % @object.object_id
      end
      s + "{" + keys.collect { |k| "#{k} => #{self[k].sub_inspect}" }.join(",") + "}"
    end
  end # class Inspect

  # FIXME: rename Connection to Bus?

  # D-Bus main connection class
  #
  # Main class that maintains a connection to a bus and can handle incoming
  # and outgoing messages.
  class Connection
    # The unique name (by specification) of the message.
    attr_reader :unique_name
    # The socket that is used to connect with the bus.
    attr_reader :socket

    # Create a new connection to the bus for a given connect _path_. _path_
    # format is described in the D-Bus specification:
    # http://dbus.freedesktop.org/doc/dbus-specification.html#addresses
    # and is something like:
    # "transport1:key1=value1,key2=value2;transport2:key1=value1,key2=value2"
    # e.g. "unix:path=/tmp/dbus-test" or "tcp:host=localhost,port=2687"
    def initialize(path)
      @path = path
      @unique_name = nil
      @buffer = ""
      @method_call_replies = Hash.new
      @method_call_msgs = Hash.new
      @signal_matchrules = Hash.new
      @proxy = nil
      @object_root = Node.new("/")
      @is_tcp = false
    end

    # Connect to the bus and initialize the connection.
    def connect
      addresses = @path.split ";"
      # connect to first one that succeeds
      worked = addresses.find do |a|
        transport, keyvaluestring = a.split ":"
        kv_list = keyvaluestring.split ","
        kv_hash = Hash.new
        kv_list.each do |kv|
          key, escaped_value = kv.split "="
          value = escaped_value.gsub(/%(..)/) {|m| [$1].pack "H2" }
          kv_hash[key] = value
        end
        case transport
          when "unix"
          connect_to_unix kv_hash
          when "tcp"
          connect_to_tcp kv_hash
          when "launchd"
          connect_to_launchd kv_hash
          else
          # ignore, report?
        end
      end
      worked
      # returns the address that worked or nil.
      # how to report failure?
    end

    # Connect to a bus over tcp and initialize the connection.
    def connect_to_tcp(params)
      #check if the path is sufficient
      if params.key?("host") and params.key?("port")
        begin
          #initialize the tcp socket
          @socket = TCPSocket.new(params["host"],params["port"].to_i)
          @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
          init_connection
          @is_tcp = true
        rescue
          puts "Error: Could not establish connection to: #{@path}, will now exit."
          exit(1) #a little harsh
        end
      else
        #Danger, <NAME>: the specified "path" is not usable
        puts "Error: supplied path: #{@path}, unusable! sorry."
      end
    end

    # Connect to an abstract unix bus and initialize the connection.
    def connect_to_unix(params)
      @socket = Socket.new(Socket::Constants::PF_UNIX,Socket::Constants::SOCK_STREAM, 0)
      @socket.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
      if ! params['abstract'].nil?
        if HOST_END == LIL_END
          sockaddr = "\1\0\0#{params['abstract']}"
        else
          sockaddr = "\0\1\0#{params['abstract']}"
        end
      elsif ! params['path'].nil?
        sockaddr = Socket.pack_sockaddr_un(params['path'])
      end
      @socket.connect(sockaddr)
      init_connection
    end

{'fraction_non_alphanumeric': 0.10302848575712144, 'fraction_numerical': 0.0047976011994002995, 'mean_word_length': 2.2532188841201717, 'pattern_counts': {'":': 2, '<': 25, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 28}, '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': '1596701', 'n_tokens_mistral': 5217, 'n_tokens_neox': 5107, 'n_words': 1642}