Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2007-05-01 03:44:39 (GMT)
committer Dan Williams <dcbw@redhat.com>2007-05-01 03:44:39 (GMT)
commit570c7e6052d419ec86587a8c1ebda66c0db8c2e1 (patch)
treefd5c40a5e1c407d914293a8ca4e50e4b8e6e6a11
parent0ebba0d454a2243e7a683d0f0c279c559d0f9c4c (diff)
Add buddy ip4-address property (temporary)
-rw-r--r--services/presence/buddy.py230
-rw-r--r--services/presence/server_plugin.py7
-rw-r--r--sugar/presence/buddy.py8
3 files changed, 229 insertions, 16 deletions
diff --git a/services/presence/buddy.py b/services/presence/buddy.py
index ca3aff2..fcc655b 100644
--- a/services/presence/buddy.py
+++ b/services/presence/buddy.py
@@ -47,6 +47,9 @@ _PROP_COLOR = "color"
_PROP_OWNER = "owner"
_PROP_VALID = "valid"
+# Will go away soon
+_PROP_IP4_ADDRESS = "ip4-address"
+
class Buddy(DBusGObject):
"""Person on the network (tracks properties and shared activites)
@@ -86,7 +89,8 @@ class Buddy(DBusGObject):
_PROP_COLOR : (str, None, None, None, gobject.PARAM_READWRITE),
_PROP_CURACT : (str, None, None, None, gobject.PARAM_READWRITE),
_PROP_VALID : (bool, None, None, False, gobject.PARAM_READABLE),
- _PROP_OWNER : (bool, None, None, False, gobject.PARAM_READABLE)
+ _PROP_OWNER : (bool, None, None, False, gobject.PARAM_READABLE),
+ _PROP_IP4_ADDRESS : (str, None, None, None, gobject.PARAM_READWRITE)
}
def __init__(self, bus_name, object_id, **kwargs):
@@ -120,11 +124,12 @@ class Buddy(DBusGObject):
self._current_activity = None
self._nick = None
self._color = None
+ self._ip4_address = None
if not kwargs.get(_PROP_KEY):
raise ValueError("key required")
- _ALLOWED_INIT_PROPS = [_PROP_NICK, _PROP_KEY, _PROP_ICON, _PROP_CURACT, _PROP_COLOR]
+ _ALLOWED_INIT_PROPS = [_PROP_NICK, _PROP_KEY, _PROP_ICON, _PROP_CURACT, _PROP_COLOR, _PROP_IP4_ADDRESS]
for (key, value) in kwargs.items():
if key not in _ALLOWED_INIT_PROPS:
logging.debug("Invalid init property '%s'; ignoring..." % key)
@@ -155,6 +160,8 @@ class Buddy(DBusGObject):
return self._valid
elif pspec.name == _PROP_OWNER:
return self._owner
+ elif pspec.name == _PROP_IP4_ADDRESS:
+ return self._ip4_address
def do_set_property(self, pspec, value):
"""Set given property
@@ -177,7 +184,11 @@ class Buddy(DBusGObject):
elif pspec.name == _PROP_CURACT:
self._current_activity = value
elif pspec.name == _PROP_KEY:
+ if self._key:
+ raise RuntimeError("Key already set.")
self._key = value
+ elif pspec.name == _PROP_IP4_ADDRESS:
+ self._ip4_address = value
self._update_validity()
@@ -259,6 +270,12 @@ class Buddy(DBusGObject):
props[_PROP_OWNER] = self.props.owner
props[_PROP_KEY] = self.props.key
props[_PROP_COLOR] = self.props.color
+
+ if self.props.ip4_address:
+ props[_PROP_IP4_ADDRESS] = self.props.ip4_address
+ else:
+ props[_PROP_IP4_ADDRESS] = ""
+
if self.props.current_activity:
props[_PROP_CURACT] = self.props.current_activity
else:
@@ -346,6 +363,12 @@ class Buddy(DBusGObject):
self._current_activity = curact
changed_props[_PROP_CURACT] = curact
changed = True
+ if _PROP_IP4_ADDRESS in properties.keys():
+ ip4addr = properties[_PROP_IP4_ADDRESS]
+ if ip4addr != self._ip4_address:
+ self._ip4_address = ip4addr
+ changed_props[_PROP_IP4_ADDRESS] = ip4addr
+ changed = True
if not changed or not len(changed_props.keys()):
return
@@ -378,6 +401,176 @@ class Buddy(DBusGObject):
except AttributeError:
self._valid = False
+
+NM_SERVICE = 'org.freedesktop.NetworkManager'
+NM_IFACE = 'org.freedesktop.NetworkManager'
+NM_IFACE_DEVICES = 'org.freedesktop.NetworkManager.Devices'
+NM_PATH = '/org/freedesktop/NetworkManager'
+
+class IP4AddressMonitor(gobject.GObject):
+ """This class, and direct buddy IPv4 address access, will go away quite soon"""
+
+ __gsignals__ = {
+ 'address-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ __gproperties__ = {
+ 'address' : (str, None, None, None, gobject.PARAM_READABLE)
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self._nm_present = False
+ self._matches = []
+ self._addr = None
+ self._nm_obj = None
+
+ sys_bus = dbus.SystemBus()
+ bus_object = sys_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
+ try:
+ if bus_object.GetNameOwner(NM_SERVICE, dbus_interface='org.freedesktop.DBus'):
+ self._nm_present = True
+ except dbus.DBusException:
+ pass
+
+ if self._nm_present:
+ self._connect_to_nm()
+ else:
+ addr = self._get_address_fallback()
+ self._update_address(addr)
+
+ def do_get_property(self, pspec):
+ if pspec.name == "address":
+ return self._addr
+
+ def _update_address(self, new_addr):
+ if new_addr == "0.0.0.0":
+ new_addr = None
+ if new_addr == self._addr:
+ return
+
+ self._addr = new_addr
+ logging.debug("IP4 address now '%s'" % new_addr)
+ self.emit('address-changed', new_addr)
+
+ def _connect_to_nm(self):
+ """Connect to NM device state signals to tell when the IPv4 address changes"""
+ try:
+ sys_bus = dbus.SystemBus()
+ proxy = sys_bus.get_object(NM_SERVICE, NM_PATH)
+ self._nm_obj = dbus.Interface(proxy, NM_IFACE)
+ except dbus.DBusException, err:
+ logging.debug("Error finding NetworkManager: %s" % err)
+ self._nm_present = False
+ return
+
+ sys_bus = dbus.SystemBus()
+ match = sys_bus.add_signal_receiver(self._nm_device_active_cb,
+ signal_name="DeviceNowActive",
+ dbus_interface=NM_IFACE)
+ self._matches.append(match)
+
+ match = sys_bus.add_signal_receiver(self._nm_device_no_longer_active_cb,
+ signal_name="DeviceNoLongerActive",
+ dbus_interface=NM_IFACE,
+ named_service=NM_SERVICE)
+ self._matches.append(match)
+
+ match = sys_bus.add_signal_receiver(self._nm_state_change_cb,
+ signal_name="StateChange",
+ dbus_interface=NM_IFACE,
+ named_service=NM_SERVICE)
+ self._matches.append(match)
+
+ state = self._nm_obj.state()
+ if state == 3: # NM_STATE_CONNECTED
+ self._query_devices()
+
+ def _device_properties_cb(self, *props):
+ active = props[4]
+ if not active:
+ return
+ act_stage = props[5]
+ # HACK: OLPC NM has an extra stage, so activated == 8 on OLPC
+ # but 7 everywhere else
+ if act_stage != 8 and act_stage != 7:
+ # not activated
+ return
+ self._update_address(props[6])
+
+ def _device_properties_error_cb(self, err):
+ logging.debug("Error querying device properties: %s" % err)
+
+ def _query_device_properties(self, device):
+ sys_bus = dbus.SystemBus()
+ proxy = sys_bus.get_object(NM_SERVICE, device)
+ dev = dbus.Interface(proxy, NM_IFACE_DEVICES)
+ dev.getProperties(reply_handler=self._device_properties_cb,
+ error_handler=self._device_properties_error_cb)
+
+ def _get_devices_cb(self, ops):
+ """Query each device's properties"""
+ for op in ops:
+ self._query_device_properties(op)
+
+ def _get_devices_error_cb(self, err):
+ logging.debug("Error getting NetworkManager devices: %s" % err)
+
+ def _query_devices(self):
+ """Query NM for a list of network devices"""
+ self._nm_obj.getDevices(reply_handler=self._get_devices_cb,
+ error_handler=self._get_devices_error_cb)
+
+ def _nm_device_active_cb(self, device, ssid=None):
+ self._query_device_properties(device)
+
+ def _nm_device_no_longer_active_cb(self, device):
+ self._update_address(None)
+
+ def _nm_state_change_cb(self, new_state):
+ if new_state == 4: # NM_STATE_DISCONNECTED
+ self._update_address(None)
+
+ def handle_name_owner_changed(self, name, old, new):
+ """Clear state when NM goes away"""
+ if name != NM_SERVICE:
+ return
+ if (old and len(old)) and (not new and not len(new)):
+ # NM went away
+ self._nm_present = False
+ for match in self._matches:
+ match.remove()
+ self._matches = []
+ self._update_address(None)
+ elif (not old and not len(old)) and (new and len(new)):
+ # NM started up
+ self._nm_present = True
+ self._connect_to_nm()
+
+ def _get_iface_address(self, iface):
+ import socket
+ import fcntl
+ import struct
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ fd = s.fileno()
+ SIOCGIFADDR = 0x8915
+ addr = fcntl.ioctl(fd, SIOCGIFADDR, struct.pack('256s', iface[:15]))[20:24]
+ s.close()
+ return socket.inet_ntoa(addr)
+
+ def _get_address_fallback(self):
+ import commands
+ (s, o) = commands.getstatusoutput("/sbin/route -n")
+ if s != 0:
+ return
+ for line in o.split('\n'):
+ fields = line.split(" ")
+ if fields[0] == "0.0.0.0":
+ iface = fields[len(fields) - 1]
+ return self._get_iface_address(iface)
+ return None
+
class GenericOwner(Buddy):
"""Common functionality for Local User-like objects
@@ -421,6 +614,23 @@ class GenericOwner(Buddy):
Buddy.__init__(self, bus_name, object_id, **kwargs)
self._owner = True
+ self._bus = dbus.SessionBus()
+ self._bus.add_signal_receiver(self._name_owner_changed_cb,
+ signal_name="NameOwnerChanged",
+ dbus_interface="org.freedesktop.DBus")
+
+ self._ip4_addr_monitor = IP4AddressMonitor()
+ self._ip4_addr_monitor.connect("address-changed", self._ip4_address_changed_cb)
+
+ def _ip4_address_changed_cb(self, monitor, address):
+ """Handle IPv4 address change, set property to generate event"""
+ props = {_PROP_IP4_ADDRESS: address}
+ self.set_properties(props)
+
+ def _name_owner_changed_cb(self, name, old, new):
+ """Handle D-Bus services we care about appearing and disappearing."""
+ self._ip4_addr_monitor.handle_name_owner_changed(name, old, new)
+
def get_registered(self):
"""Retrieve whether owner has registered with presence server"""
return self._registered
@@ -479,11 +689,6 @@ class ShellOwner(GenericOwner):
color=color, icon=icon, server=server, key_hash=key_hash,
registered=registered)
- self._bus = dbus.SessionBus()
- self._bus.add_signal_receiver(self._name_owner_changed_handler,
- signal_name="NameOwnerChanged",
- dbus_interface="org.freedesktop.DBus")
-
# Connect to the shell to get notifications on Owner object
# property changes
try:
@@ -496,13 +701,10 @@ class ShellOwner(GenericOwner):
if value:
profile.set_server_registered()
- def _name_owner_changed_handler(self, name, old, new):
- """Handle DBUS notification of a new / renamed service
-
- Watches for the _SHELL_SERVICE, i.e. the Sugar Shell,
- and registers with it if we have not yet registered
- with it (using _connect_to_shell).
- """
+ def _name_owner_changed_cb(self, name, old, new):
+ # chain up to superclass
+ GenericOwner._name_owner_changed_cb(self, name, old, new)
+
if name != self._SHELL_SERVICE:
return
if (old and len(old)) and (not new and not len(new)):
diff --git a/services/presence/server_plugin.py b/services/presence/server_plugin.py
index ddbee41..cfdaf47 100644
--- a/services/presence/server_plugin.py
+++ b/services/presence/server_plugin.py
@@ -164,7 +164,7 @@ class ServerPlugin(gobject.GObject):
if properties.has_key("nick"):
self._set_self_alias()
- if properties.has_key("color"):
+ if properties.has_key("color") or properties.has_key("ip4-address"):
self._set_self_olpc_properties()
def _owner_icon_changed_cb(self, owner, icon):
@@ -447,6 +447,11 @@ class ServerPlugin(gobject.GObject):
props = {}
props['color'] = self._owner.props.color
props['key'] = dbus.ByteArray(self._owner.props.key)
+ addr = self._owner.props.ip4_address
+ if not addr:
+ props['ip4-address'] = ""
+ else:
+ props['ip4-address'] = addr
self._conn[CONN_INTERFACE_BUDDY_INFO].SetProperties(props,
reply_handler=self._ignore_success_cb,
error_handler=lambda *args: self._log_error_cb("setting properties", *args))
diff --git a/sugar/presence/buddy.py b/sugar/presence/buddy.py
index f21c883..ead9482 100644
--- a/sugar/presence/buddy.py
+++ b/sugar/presence/buddy.py
@@ -65,7 +65,8 @@ class Buddy(gobject.GObject):
'nick' : (str, None, None, None, gobject.PARAM_READABLE),
'color' : (str, None, None, None, gobject.PARAM_READABLE),
'current-activity' : (object, None, None, gobject.PARAM_READABLE),
- 'owner' : (bool, None, None, False, gobject.PARAM_READABLE)
+ 'owner' : (bool, None, None, False, gobject.PARAM_READABLE),
+ 'ip4-address' : (str, None, None, None, gobject.PARAM_READABLE)
}
_PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
@@ -134,6 +135,11 @@ class Buddy(gobject.GObject):
if not self._icon:
self._icon = _bytes_to_string(self._buddy.GetIcon())
return self._icon
+ elif pspec.name == "ip4-address":
+ # IPv4 address will go away quite soon
+ if not self._properties.has_key("ip4-address"):
+ return None
+ return self._properties["ip4-address"]
def object_path(self):
"""Retrieve our dbus object path"""