mcevent.py
author Mikael Berthe <mikael@lilotux.net>
Sat, 21 Jun 2008 20:31:38 +0200
changeset 9 91f9fe1adf0c
parent 8 14dd3f4fd4dc
child 10 cf31fa2e0bbc
permissions -rwxr-xr-x
Add a small input check

#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
#
#  Copyright (C) 2007 Adam Wolk "Mulander" <netprobe@gmail.com>
#  Copyright (C) 2007, 2008 Mikael Berthe "McKael" <mikael@lilotux.net>
#
# This script is provided under the terms of the GNU General Public License,
# see the file COPYING in the root mcabber source directory.
#

import sys, getopt
import os
import pynotify

CONFFILE = "mcevent.cfg"

# Default option values
opt = {
        'use_notify': 0,
        'use_voice':  0,
        'use_sound':  1,
        'short_nick': 1,
        'unread_file': '',
        'snd_cmd_msg_in': '/usr/bin/play -V0 -v3 sound.wav',
}

NOTIFY_TIMEOUT=4000

contact_map = { }
# Nickname used for the notification

contact_custom_msg = { }
# Message used for the notification

online_alerts = { }
# 0: disabled  1: normal notification  2: permanent notify box

voicemap = { }
# Specify the name pronounced by espeak

blacklist = { }
# No notification for these JIDs

CMD_ESPEAK="/usr/bin/espeak"

def init_notify():
    import locale
    global encoding
    global NOTIFY_LOADED
    pynotify.init('mcnotify')
    encoding = (locale.getdefaultlocale())[1]
    NOTIFY_LOADED = True

def read_conf_from_file():
    import ConfigParser

    config = ConfigParser.ConfigParser()
    config.read(CONFFILE)

    contact_map.clear()
    contact_custom_msg.clear()
    online_alerts.clear()
    voicemap.clear()
    blacklist.clear()

    if config.has_option("Notifications", "notify"):
        opt['use_notify'] = int(config.get("Notifications", "notify"))
    if config.has_option("Notifications", "voice"):
        opt['use_voice']  = int(config.get("Notifications", "voice"))
    if config.has_option("Notifications", "sound"):
        opt['use_sound']  = int(config.get("Notifications", "sound"))
    if config.has_option("Notifications", "short_nick"):
        opt['short_nick'] = int(config.get("Notifications", "short_nick"))
    if config.has_option("Notifications", "unread_file"):
        opt['unread_file'] = config.get("Notifications", "unread_file")
    if config.has_option("Notifications", "snd_cmd_msg_in"):
        opt['snd_cmd_msg_in'] = config.get("Notifications", "snd_cmd_msg_in")

    if config.has_section("Contacts"):
        for id in config.options("Contacts"):
            contact_map[id] = config.get("Contacts", id)

    if config.has_section("Contact_Customized_Messages"):
        for id in config.options("Contact_Customized_Messages"):
            contact_custom_msg[id] = config.get("Contact_Customized_Messages", id)

    if config.has_section("Alerts"):
        for id in config.options("Alerts"):
            online_alerts[id] = int(config.get("Alerts", id))

    if config.has_section("Voicemap"):
        for id in config.options("Voicemap"):
            voicemap[id] = config.get("Voicemap", id)

    if config.has_section("Blacklist"):
        for id in config.options("Blacklist"):
            blacklist[id] = int(config.get("Blacklist", id))

    if opt['use_notify'] and not NOTIFY_LOADED:
        init_notify()

def say(buddy, text):
    import subprocess
    p = subprocess.Popen(CMD_ESPEAK, stdin=subprocess.PIPE, close_fds=True)
    child_stdin = p.stdin
    child_stdin.write(buddy + " " + text)
    child_stdin.close()

def notify(buddy, msg, timeout):
    msgbox = pynotify.Notification(unicode(buddy, encoding),
                                   unicode(msg, encoding))
    msgbox.set_timeout(timeout)
    msgbox.set_urgency(pynotify.URGENCY_LOW)
    msgbox.show()

def get_nick(jid):
    if jid in contact_map:
        buddy = contact_map[jid]
    else:
        buddy = jid

    if opt['short_nick'] and '@' in buddy:
        buddy = buddy[0:buddy.index('@')]
    return buddy

def is_blacklisted(jid):
    if jid in blacklist and blacklist[jid]:
        return True
    return False

def process_line(args):
    argn = len(args)

    if argn < 2:
        print "Ignoring invalid event line."
        return
    elif argn == 2:
        event,arg1               = args[0:2]
        arg2                     = None
        filename                 = None
    elif argn == 3:
        event,arg1,arg2          = args[0:3]
        filename                 = None
    else:
        # For now we simply ignore the file name
        event,arg1,arg2          = args[0:3]
        filename                 = None

    if event == 'MSG' and arg1 == 'IN':
        import os

        jid = arg2
        if not jid:
            print "Ignoring invalid MSG event line."
            return

        buddy = get_nick(jid)
        if jid in contact_custom_msg:
            msg = contact_custom_msg[jid]
        elif 'default' in contact_custom_msg:
            msg = contact_custom_msg['default']
        else:
            msg = 'sent you a message.'

        if not is_blacklisted(jid):
            textmsg = None

            if filename and os.path.exists(filename):
                f   = file(filename)
                textmsg = f.read()

            if opt['use_notify']:
                if not textmsg:
                    textmsg = msg
                notify(buddy, textmsg, NOTIFY_TIMEOUT)

            if opt['use_sound']:
                os.system(opt['snd_cmd_msg_in'] + '> /dev/null 2>&1')

            if opt['use_voice'] and not is_blacklisted(jid):
                if jid in voicemap:
                    buddy = voicemap[jid]
                say(buddy, msg)

        if filename and os.path.exists(filename):
            os.remove(filename)

    elif event == 'STATUS':
        jid = arg2
        if arg1 == 'O' and jid in online_alerts:
            import os

            type = online_alerts[jid]
            if type > 0:
                if opt['use_sound']:
                    os.system(opt['snd_cmd_msg_in'] + '> /dev/null 2>&1')

                buddy = get_nick(jid)

                if opt['use_notify']:
                    if type == 1:
                        timeout = NOTIFY_TIMEOUT
                    else:
                        timeout = pynotify.EXPIRES_NEVER
                    notify(buddy, "is online", timeout)

                    if filename and os.path.exists(filename):
                        os.remove(filename)

                if opt['use_voice']:
                    if jid in voicemap:
                        buddy = voicemap[jid]
                    say(buddy, "is online now.")

    elif event == 'UNREAD':
        # arg1 is the number of unread buffers
        if opt['unread_file'] != '':
            fileHandle = open(opt['unread_file'], 'w')
            fileHandle.write(arg1)
            fileHandle.close()


##### MAIN #####

try:
    opts, args = getopt.getopt(sys.argv[1:], "c:", ["help", "output="])
except getopt.GetoptError, err:
    print str(err)
    sys.exit(2)

for o, a in opts:
    if o == "-c":
        CONFFILE = a

try:
    last_conf_read = os.stat(CONFFILE).st_ctime
except OSError:
    sys.stderr.write("Cannot read config file!\n")
    sys.exit(3)

NOTIFY_LOADED = False

read_conf_from_file()

# read stdin line by line
while 1:
    try:
        line = sys.stdin.readline()
    except KeyboardInterrupt:
        print "\nInterrupted!"
        exit(0)
    if not line:
        break

    last_conf_change = os.stat(CONFFILE).st_ctime
    if last_conf_change > last_conf_read:
        read_conf_from_file()
        last_conf_read = last_conf_change
    lineargs = line.split()
    process_line(lineargs)

if NOTIFY_LOADED:
    pynotify.uninit()

sys.exit(0)

# vim:set et sts=4 sw=4: