At work we use a Jabber instant messenger (IM) server for internal company communications, so that regardless of whether someone is in the office, working from home, or on the road, they can be reached via IM.
I’m running Ubuntu both at work and at home and I use the Pidgin IM client to talk to the Jabber server. I work from home on Thursdays, and I’m always forgetting to turn Pidgin off when I leave work on Wednesday. I usually end up ssh-ing into my work box from home and killing the Pidgin client off remotely, but sometimes I forget and when I come back to work on Friday there are a half-dozen “Are you there?” -type messages on my Pidgin work-client.
So I figured I’d automate the process, automatically setting Pidgin status to “Away” and “Available” using cron, turning the work-client off entirely on Thursdays and weekends, and automatically turning the home-client on Thursday mornings and off Thursday night.
I did a little digging and found a command-line program called purple-remote that allows me to automatically update the Pidgin status and message lines. The purple-remote program is included in the libpurple-bin package, which I installed with System > Administration > Synaptic Package Manager.
Once purple-remote was installed, I fired up a terminal and did a little experimenting on the command line. I found I could set Pidigin’s status to “Away” and the status message to “At lunch” by typing:
/usr/bin/purple-remote "setstatus?status=away&message=At lunch"
I could set the status to “Available” and blank the status message by typing:
/usr/bin/purple-remote "setstatus?status=available&message="
So far so good. I can also cause Pidgin to exit with:
/usr/bin/purple-remote "quit"
Starting Pidgin is just a matter of running:
/usr/bin/pidgin
Time to set up the cron jobs. I fired up crontab -e and entered:
# IM Status SHELL=/bin/bash 00 08 * * Mon,Fri /usr/bin/pidgin & 01 08 * * Mon,Tue,Wed,Fri /usr/bin/purple-remote "setstatus?status=away&message=" 00 09 * * Mon,Tue,Wed,Fri /usr/bin/purple-remote "setstatus?status=available&message=" 30 13 * * Mon,Tue,Wed,Fri /usr/bin/purple-remote "setstatus?status=away&message=At lunch" 30 14 * * Mon,Tue,Wed,Fri /usr/bin/purple-remote "setstatus?status=available&message=" 30 17 * * Mon,Tue,Wed,Fri /usr/bin/purple-remote "setstatus?status=away&message=" 00 19 * * Wed,Fri /usr/bin/purple-remote "quit"
This would start Pidgin at 8:00am, set my status to “Away” at 8:01am, “Available” at 9:00am, “Away – At lunch” at 1:30pm, “Available” again at 2:30pm, “Away” at 5:30pm. On Wednesday and Friday nights at 7:00pm the client shuts down entirely, on Monday and Friday mornings Pidgin gets restarted. That will leave the client off all day on Thursdays and on weekends when I’m not at the office. If my schedule changes for any reason I can still update my status in Pidgin manually.
Looks good, but this doesn’t work. Although the commands listed above work just fine on the command line, they’d fail when they were executed from cron. Checking my mail I found error messages like this:
Traceback (most recent call last): File "/usr/bin/purple-remote", line 16, in obj = dbus.SessionBus().get_object("im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject") File "/var/lib/python-support/python2.5/dbus/_dbus.py", line 218, in __new__ mainloop=mainloop) File "/var/lib/python-support/python2.5/dbus/_dbus.py", line 107, in __new__ bus = BusConnection.__new__(subclass, bus_type, mainloop=mainloop) File "/var/lib/python-support/python2.5/dbus/bus.py", line 121, in __new__ bus = cls._new_for_bus(address_or_type, mainloop=mainloop) dbus.exceptions.DBusException: org.freedesktop.DBus.Error.Spawn.ExecFailed: dbus-launch failed to autolaunch D-Bus session: Autolaunch error: X11 initialization failed.
The key part of that message is “dbus-launch failed to autolaunch D-Bus session: Autolaunch error: X11 initialization failed.” dbus is a messaging system, and X11 is the implementation of X-Windows Ubuntu uses, which is what the Gnome desktop runs on. Pidgin is an application running on the Gnome desktop / X-Windows. The error message is saying that the program failed to send a message to X11 (X-Windows) and on to Pidgin.
There are three problems here:
- The first is that in order for purple-remote to send messages to Pidigin via DBUS it has to work it needs to know the value of the DBUS_SESSION_BUS_ADDRESS environment variable. (Kudos to explicitly ambiguous and his article at http://ubuntuforums.org/showthread.php?t=632580 for pointing me towards this solution.)
- In order to start Pidgin at 8:00am Pidgin needs to know the value of the of the XAUTHORITY environment variable otherwise it won’t be authorized to start up on a screen that I’m logged into.
- In order to start Pidgin at 8:00am Pidgin needs to know the value of the DISPLAY environment variable so it knows what screen to start up on.
When you start up Ubuntu the dbus daemon starts up and creates a unique session address. Your applications have to know this session address in order to send messages using the daemon. The address is stored in the DBUS_SESSION_BUS_ADDRESS environment variable when you log in, so if you try to run an application from the command line it gets the session address from the DBUS_SESSION_BUS_ADDRESS environment variable. Since cron runs in it’s own environment it doesn’t know the value of DBUS_SESSION_BUS_ADDRESS, so programs that depend on dbus fail when you try to run them from a cron job.
You can see the value by typing:
> env | grep DBUS_SESSION_BUS_ADDRESS DBUS_SESSION_BUS_ADDRESS=unix:abstract= /tmp/dbus-AmUs20000,guid=6cce82d52ca190000000000000000000
Likewise, the value of XAUTHORITY changes every time you restart your computer. You can see the current value by typing:
> env | grep XAUTHORITY
DISPLAY remains the same between reboots. To get the value for your system, type:
> env | grep DISPLAY DISPLAY=:0.0
Add the “DISPLAY=:0.0” line at the beginning of your crontab file and it’ll be set for Pidgin.
In order to make the environment variables available to cron jobs I created the program ~/bin/export_x_info which looks like this:
#!/bin/bash # Export the dbus session address on startup so it can be used by cron touch $HOME/.Xdbus chmod 600 $HOME/.Xdbus env | grep DBUS_SESSION_BUS_ADDRESS > $HOME/.Xdbus echo 'export DBUS_SESSION_BUS_ADDRESS' >> $HOME/.Xdbus # Export XAUTHORITY value on startup so it can be used by cron env | grep XAUTHORITY >> $HOME/.Xdbus echo 'export XAUTHORITY' >> $HOME/.Xdbus
Create this script, type chmod 700 ~/bin/export_x_info so you can execute it, then execute it, then add it to System > Preferences > Sessions > Startup Programs so it will execute every time you start your computer and record the latest session address and XAUTHORITY value.
This script creates a 4-line file ~/.Xdbus with the current session address and XAUTHORITY value. By sourcing this file in the crontab file your scripts can now use dbus to send messages to X-Windows applications. My final crontab file looks like this:
SHELL=/bin/bash DISPLAY=:0.0 # IM Status 00 08 * * Mon,Fri source ~/.Xdbus; /usr/bin/pidgin & 01 08 * * Mon,Tue,Wed,Fri source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=away&message=" 00 09 * * Mon,Tue,Wed,Fri source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=available&message=" 30 13 * * Mon,Tue,Wed,Fri source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=away&message=At lunch" 30 14 * * Mon,Tue,Wed,Fri source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=available&message=" 30 17 * * Mon,Tue,Wed,Fri source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=away&message=" 00 19 * * Wed,Fri source ~/.Xdbus; /usr/bin/purple-remote "quit"
The call to source ~/.Xdbus on each line loads the DBUS_SESSION_BUS_ADDRESS and XAUTHORITY environment variables before executing the purple-remote command or starting Pidgin.
Now the cron works and my Pidgin status is constantly updated. The cron on my home computer is much simpler:
SHELL=/bin/bash DISPLAY=:0.0 # IM Status 00 08 * * Thu source ~/.Xdbus; /usr/bin/pidgin & 01 08 * * Thu source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=away&message=" 00 09 * * Thu source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=available&message=" 30 13 * * Thu source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=away&message=At lunch" 30 14 * * Thu source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=available&message=" 30 17 * * Thu source ~/.Xdbus; /usr/bin/purple-remote "setstatus?status=away&message=" 00 19 * * Thu source ~/.Xdbus; /usr/bin/purple-remote "quit"
The same technique works for other X-Windows programs as well. For instance, I added this line to my cron:
30 17 * * Mon,Tue,Wed,Fri source ~/.Xdbus; /usr/bin/notify-send "Go Home" "Time to Go"
So every day at 5:30pm a “notify” message pops up reminding me that it’s time to go home.
Hope you find this useful.
This was very helpful… I’m using to set my away message every hour while i do walkthroughs of my facility along with an alarm using “mocp” to remind me to leave my workstation.
SHELL=/bin/bash
DISPLAY=:0.0
# m h dom mon dow command
00 0-8 * * 1,3 mocp -l MiscStuff/alarm.mp3 >/dev/null 2>&1
00 0-12 * * 2,4 mocp -l MiscStuff/alarm.mp3 >/dev/null 2>&1
00 0-8 * * 1-4 source ~/.Xdbus; purple-remote “setstatus?status=away&message=Out on the colo floor” >/dev/null 2>&1
10 0-8 * * 1-4 source ~/.Xdbus; purple-remote “setstatus?status=available&message=” >/dev/null 2>&1
Hi – this is a great tip! I wonder if you might submit a link to any other tips you write to ubuntukungfu.org? This aims to be the biggest repository of Ubuntu tips. Cheers!
Glad you found this useful. I just installed Skype at home and at work and found that this technique also works for starting up Skype, so if someone calls my Skype phone the computer where I’m located is the one that currently has Skype running.
Thank you so very very much! I have been trying to do this all day, this really helped me, it took a pretty long while for me to find this post.
Thanks again. :)
You don’t need to dump the environment to a file. You can use something like:
ps -e e | grep pidgin | grep -v grep
If you’re creative, you could even take that output and suck it into a script that finds just the correct variable so you can assign it to something. Like via invoking it with “
How do I set it to one of my saved statuses, so there aren’t 50 copies of the same status in my drop-down box?
Exit Pidgin.
Edit the ~/.purple/status.xml file and get rid of the 50 copies of the same status message.
Restart Pidgin.
Set your current status to the one you want to update / remember.
Get the internal Pidgin status ID with:
/usr/bin/purple-remote “PurpleSavedstatusGetCurrent()”
To set that status with a message, without creating a duplicate entry, enter:
STATUS=[the id number]
/usr/bin/purple-remote “PurpleSavedstatusSetMessage($STATUS, At lunch)”
You can find more info here:
http://developer.pidgin.im/wiki/DbusHowto
like johnkzin suggest, you don’t need to dump the environment to a file.
But there is an even better method :-)
simply read the DBUS_SESSION_BUS_ADDRESS variable from the file in ~/.dbus/session-bus/
for example simply include the following in your bash script
#!/bin/bash
…
for file in ~/.dbus/session-bus/*;do
source “$file”
done
…
Good solution, that’s much simpler. However, DBUS can leave old files in place in that directory (after a system crash, for example), so you want to make sure you’re sourcing the latest file. You could do something like:
… the last file sourced is always the latest file.
Right on, but is there a way to call “source” from within a program?
“source” is a shell script command. We’re using bash in these examples.
You’re my hero, I’ve been trying to make something like this work all day. I love the fact that you set a reminder to go home :) I totally need that.
Hello,
It’s excellent thanks a lot.
For a multi-user system, i have include this script in /etc/gdm/PreSessions for create the file each users. it works.
But i’m surpised: i have a system routine with fcron (fcrontab -e -u systab), also the “shutdown -P now” works for all users, the notification message doesn’t work.. have you any idea please?
Thanks,
Regards from France,
Philippe.
Are you using each user’s DBUS_SESSION_BUS_ADDRESS to notify them individually?
Does anyone know how to escape characters in message text ?
Otherwise the message is truncated to the first non-alphanumeric/punctuation character.
Use single quotes around the text, rather than double-quotes. e.g., if you type:
purple-remote ‘setstatus?status=available&message=test$@%^*()test’
This will change the message to test$@%^*()test
You can’t use &, ? and # in the message. & and ? are used as separators by the command, # is treated as “start of a comment” and is ignored.
Pingback: Change Your Skype Mood Text In Linux With Python | Projects Blog
Pingback: Can't get DBUS data for automatic statuschange of pidgin | Q&A System
Pingback: Can’t get DBUS data for automatic statuschange of pidgin | PHP Developer Resource
Nice solution.. I’m using this now for notify-send to remind me check posture and move around a bit :)
re obtaining DBUS_SESSION_BUS_ADDRESS — I’m kind of uncomfortable sourcing a normally non-executable file into a running script, so I do this:
DBUS_SESSION_BUS_ADDRESS=”`grep –only-matching ‘unix:abstract=/tmp/dbus-[A-Za-z0-9]\+,guid=[0-9a-f]\+$’ “/home/pidgin/.dbus/session-bus/$l”`”
($l comes from a loop similar to the one Earl Ruby used).