2008-07-23

Send IM messages from the command line with iChat, Adium or Pidgin



In my office there was a tradition of using the zwrite command line tool for writing IM to eachother. This is useful to send snippets such as
grep FATAL logfile | zwrite coworker
It's quick, avoids tedious copy and paste and allows sending messages from batch run scripts. However, zwrite started to show its age long ago, being difficult to setup on various systems and having poor desktop integration and power.

Using XMPP (mostly over the Google Talk servers) works nicely, having good native clients, a web client (gmail) and a great java library for programmatic access. Missing was a zwrite-like command line way of sending snippets. I wrote a small shell script working with a running instance of either Pidgin under *nix (using D-Bus python bindings) and iChat or Adium (using applescript) on OS X:
#!/bin/sh

test $# -eq 0 && echo "Usage: echo hi | $0 user [otherusers] " && exit 1

export MESSAGE="`cat`"

while test "$1"; do

BUDDY=$1

# aliases
test $BUDDY = friend1 && BUDDY=friend1.account
test $BUDDY = friend2 && BUDDY=friend2.account
# ..

# default to @gmail.com
test `echo $BUDDY | grep @` || BUDDY=$BUDDY@gmail.com

export BUDDY

OS=`uname`
if [ "$OS" = "Darwin" ]; then
# use applescript to call either ichat or adium
/usr/bin/osascript <<EOL
set stdinText to do shell script "echo \"\$MESSAGE\"" without altering line endings

tell application "System Events" to set iChatRunning to (name of processes) contains "iChat"
if iChatRunning then
tell application "iChat"
send stdinText to buddy "$BUDDY"
activate
end tell
else
tell application "System Events" to set adiumRunning to (name of processes) contains "Adium"
if adiumRunning then
tell application "Adium"
tell the first account of the service "GTalk" to ¬
set newChat to ¬
make new chat with contacts {contact "$BUDDY"} ¬
with new chat window
send newChat message stdinText
activate
end tell
else
display dialog "ERROR: You must run either iChat or Adium" buttons "OK" default button "OK"
end if
end if
EOL
else
# calling pidgin over dbus
python -t - <<EOL
import os, sys
try:
import dbus
except ImportError: sys.exit('ERROR: You need dbus with python bindings installed')

try:
bus = dbus.SessionBus()
service = bus.get_object("im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject")
purple = dbus.Interface(service, "im.pidgin.purple.PurpleInterface")
except: sys.exit('ERROR: Could not connect - is pidgin up and running?')

xmppAccount = None
for account in purple.PurpleAccountsGetAllActive():
if 'XMPP' == purple.PurpleAccountGetProtocolName(account): xmppAccount = account
if xmppAccount == None: sys.exit('ERROR: Cannot find any xmpp account')

recipient = os.environ['BUDDY']
matches = purple.PurpleFindBuddies(xmppAccount, recipient)
if len(matches) == 0: sys.exit('ERROR: Buddy "%s" not found!' % recipient)

conversationType = 1 # http://developer.pidgin.im/doxygen/dev/html/conversation_8h-source.html#l00051
conversation = purple.PurpleConversationNew(conversationType, xmppAccount, recipient)
im = purple.PurpleConvIm(conversation)
message = os.environ['MESSAGE']
purple.PurpleConvImSend(im, message)
EOL
test $? -ne 0 && exit 1
fi

shift
done

3 comments:

Tur said...

how do i use it?
I'm using Ubuntu.
thank you.

J.J. said...

I had a problem with cutting and pasting the script on my OS X system:

482:487: syntax error: A unknown token can’t go after this “to”. (-2740)

There is a one character of junk after the AppleScript Continuation Character "¬" (Option-l). I opened it in TextEdit, converted to text and saved and the problem was fixed.

Anonymous said...

can you also paste the actual file? I am getting indentation errors and do not know anything about the python to fix it