Automatic Pidgin status with DBUS and NetworkManager

It’s official.  I have a new mistress and her name is DBUS.  After seeing how easy it was to take an action when a particular storage device was attached, I was hooked.  Since I know NetworkManager has a robust DBUS interface , I decided to try something a little more interesting.

Something I’ve always wanted is for Pidgin to be aware of my network connectivity and adjust my status accordingly.  I work from home most of the time, so I set my status to indicate this fact and expose my home office phone number for colleagues.  I go into the office so occasionally that I never remember to change my Pidgin status accordingly, thus confusing people who were expecting me to be in that day.

I set out to write something to effectively bridge NetworkManager’s DBUS interface with that of Pidgin.  There would need to be some logic in the middle to determine the proper status message given the current state of the network.  First, I wrote a python module to query NetworkManager for details about activated devices.  Next, I wrote a (probably overly complicated) location module that reads a config file and provides an interface to return properties of the current location, based on the information about the current active device, as determined by the previous module.  The config file looks something like this:

[Home]
devices = eth0
subnet = 192.168.1
caption = At Home
foobar = baz

[Home-Wireless]
devices = ath0
subnet = 192.168.1
caption = At Home (wireless)

[Work]
devices = eth0
subnet = 10.0.12
caption = At the office

This lets me match settings based on not only a bit of the IP address, but also on the device name.  With those two data points, I can have separate status messages for Home and Home-Wireless.

Next, all I needed was something to watch for NetworkManager’s DBUS signal that the active device has changed, determine the new location, and tell Pidgin about it.  After seeing some examples , I found that it is surprisingly simple :

import dbus
import gobject
import dbus.mainloop.glib

import locations
import sys

def change_status(id, caption):
global pidgin

status = pidgin.PurpleSavedstatusNew(“”, 2)
pidgin.PurpleSavedstatusSetMessage(status, caption)
pidgin.PurpleSavedstatusActivate(status)

def dev_changed(*args, **kwargs):
if not kwargs[“member”] == “DeviceNowActive”:
return

loc = locations.LocationService(sys.argv[1]).current_location()
change_status(loc.name, loc.caption)

def monitor_nm():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

bus = dbus.SystemBus()
bus.add_signal_receiver(dev_changed,
interface_keyword=”dbus_interface”,
member_keyword=”member”Smilie: ;)

loop = gobject.MainLoop()
loop.run()

def connect_to_pidgin():
global pidgin

bus = dbus.SessionBus()
obj = bus.get_object(“im.pidgin.purple.PurpleService”,
“/im/pidgin/purple/PurpleObject”Smilie: ;)
pidgin = dbus.Interface(obj, “im.pidgin.purple.PurpleInterface”Smilie: ;)

if len(sys.argv) < 2:
print “Usage: %s <location_config>” % sys.argv[0]
sys.exit(1)

connect_to_pidgin()
monitor_nm()

The dev_changed() function gets called for each signal (I think there must be a better way to select specific signals you’re interested, but this is quick and it works).  If the signal matches the correct name, then we determine the current location and call change_status() to tell Pidgin about it.  How awesome is that?

I’ve thought about generalizing this into a “Location Awareness Service” that would emit signals on DBUS to notify other applications.  It would be really awesome to write something that would tell Asterisk to forward my extension to another line, depending on where I am:

  • If I’m at “Home”, ring my desk line
  • If I’m at “Home-Wireless”, ring the house phones
  • If I’m at “Work”, forward to my work line
  • If I’m anywhere else, forward to my cell phone

On the other hand, maybe I’ll hold off on that last item… Smilie: :)

Category(s): Codemonkeying, Linux

One Response to Automatic Pidgin status with DBUS and NetworkManager