view libpurple/purple-url-handler @ 25453:a946cffda321

Use g_direct_hash/equal instead of g_int_hash/equal for the hash table that holds the saved statuses. The effect is that this will take into account the different size of time_t across 32-bit and 64-bit systems. There should not be any side effects because it is only used at runtime for the hash key, and all the important data is stored in the value. This should stop any mysterious infinite loop problems on big-endian systems which were trying to use the MSB of the time as a hash key. Fixes #5887.
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Sun, 15 Feb 2009 07:19:59 +0000
parents 0009541d4ec2
children 971b89243a20
line wrap: on
line source

#!/usr/bin/env python

import dbus
import re
import sys
import time
import urllib

bus = dbus.SessionBus()
obj = None
try:
    obj = bus.get_object("im.pidgin.purple.PurpleService",
                         "/im/pidgin/purple/PurpleObject")
except dbus.DBusException, e:
    if e._dbus_error_name == "org.freedesktop.DBus.Error.ServiceUnknown":
        print "Error: no libpurple-powered client is running. Try starting Pidgin or Finch."
        sys.exit(1)
purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")

class CheckedObject:
    def __init__(self, obj):
        self.obj = obj

    def __getattr__(self, attr):
        return CheckedAttribute(self, attr)

class CheckedAttribute:
    def __init__(self, cobj, attr):
        self.cobj = cobj
        self.attr = attr

    def __call__(self, *args):
        # Redirect stderr to suppress the printing of an " Introspect error"
        # message if nothing is listening on the bus.  We print a friendly
        # error message ourselves.
        real_stderr = sys.stderr
        sys.stderr = None
        result = self.cobj.obj.__getattr__(self.attr)(*args)
        sys.stderr = real_stderr

# This can be useful for debugging.
#        if (result == 0):
#            print "Error: " + self.attr + " " + str(args) + " returned " + str(result)

        return result

cpurple = CheckedObject(purple)

def extendlist(list, length, fill):
    if len(list) < length:
        return list + [fill] * (length - len(list))
    else:
        return list

def convert(value):
    try:
        return int(value)
    except:
        return value

def account_not_found():
    print "No matching account found."
    sys.exit(1)

def bring_account_online(account):
    if not cpurple.PurpleAccountIsConnected(account):
        # The last argument is meant to be a GList * but the D-Bus binding
        # generator thing just wants a UInt32, which is pretty failing.
        # Happily, passing a 0 to mean an empty list turns out to work anyway.
        purple.PurpleAccountSetStatusList(account, "online", 1, 0)
        purple.PurpleAccountConnect(account)

def findaccount(protocolname, accountname="", matcher=None):
    if matcher:
        for account in cpurple.PurpleAccountsGetAll():
            if accountname != "" and accountname != cpurple.PurpleAccountGetUsername(a):
                continue
            if matcher(account):
                bring_account_online(account)
                return account
        account_not_found()

    # prefer connected accounts
    account = cpurple.PurpleAccountsFindConnected(accountname, protocolname)
    if (account != 0):
        return account

    # try to get any account and connect it
    account = cpurple.PurpleAccountsFindAny(accountname, protocolname)
    if (account == 0):
        account_not_found()

    bring_account_online(account)
    return account

def goim(account, screenname, message=None):
    # XXX: 1 == PURPLE_CONV_TYPE_IM
    conversation = cpurple.PurpleConversationNew(1, account, screenname)
    if message:
        purple.PurpleConvSendConfirm(conversation, message)

def gochat(account, params, message=None):
    connection = cpurple.PurpleAccountGetConnection(account)
    purple.ServJoinChat(connection, params)

    if message != None:
    	for i in range(20):
            # XXX: 2 == PURPLE_CONV_TYPE_CHAT
            conversation = purple.PurpleFindConversationWithAccount(2, params.get("channel", params.get("room")), account)
            if conversation:
                purple.PurpleConvSendConfirm(conversation, message)
                break
            else:
                time.sleep(0.5)

def addbuddy(account, screenname, group="", alias=""):
    cpurple.PurpleBlistRequestAddBuddy(account, screenname, group, alias)


def aim(uri):
    protocol = "prpl-aim"
    match = re.match(r"^aim:([^?]*)(\?(.*))", uri)
    if not match:
        print "Invalid aim URI: %s" % uri
        return

    command = urllib.unquote_plus(match.group(1))
    paramstring = match.group(3)
    params = {}
    if paramstring:
        for param in paramstring.split("&"):
            key, value = extendlist(param.split("=", 1), 2, "")
            params[key] = urllib.unquote_plus(value)
    accountname = params.get("account", "")
    screenname = params.get("screenname", "")

    account = findaccount(protocol, accountname)

    if command.lower() == "goim":
        goim(account, screenname, params.get("message"))
    elif command.lower() == "gochat":
        gochat(account, params)
    elif command.lower() == "addbuddy":
        addbuddy(account, screenname, params.get("group", ""))

def gg(uri):
    protocol = "prpl-gg"
    match = re.match(r"^gg:(.*)", uri)
    if not match:
        print "Invalid gg URI: %s" % uri
        return

    screenname = urllib.unquote_plus(match.group(1))
    account = findaccount(protocol)
    goim(account, screenname)

def icq(uri):
    protocol = "prpl-icq"
    match = re.match(r"^icq:([^?]*)(\?(.*))", uri)
    if not match:
        print "Invalid icq URI: %s" % uri
        return

    command = urllib.unquote_plus(match.group(1))
    paramstring = match.group(3)
    params = {}
    if paramstring:
        for param in paramstring.split("&"):
            key, value = extendlist(param.split("=", 1), 2, "")
            params[key] = urllib.unquote_plus(value)
    accountname = params.get("account", "")
    screenname = params.get("screenname", "")

    account = findaccount(protocol, accountname)

    if command.lower() == "goim":
        goim(account, screenname, params.get("message"))
    elif command.lower() == "gochat":
        gochat(account, params)
    elif command.lower() == "addbuddy":
        addbuddy(account, screenname, params.get("group", ""))

def irc(uri):
    protocol = "prpl-irc"
    match = re.match(r"^irc:(//([^/]*)/)?([^?]*)(\?(.*))?", uri)
    if not match:
        print "Invalid irc URI: %s" % uri
        return

    server = urllib.unquote_plus(match.group(2)) or ""
    target = match.group(3) or ""
    query = match.group(5) or ""

    modifiers = {}
    if target:
        for modifier in target.split(",")[1:]:
            modifiers[modifier] = True

    isnick = modifiers.has_key("isnick")

    paramstring = match.group(5)
    params = {}
    if paramstring:
        for param in paramstring.split("&"):
            key, value = extendlist(param.split("=", 1), 2, "")
            params[key] = urllib.unquote_plus(value)

    def correct_server(account):
        username = cpurple.PurpleAccountGetUsername(account)
        user_split = (username.split("@"))
        # Not all accounts have a split, so append an empty string so the
        # [1] doesn't throw an IndexError.
        user_split.append("")
        return (server == user_split[1])

    account = findaccount(protocol, matcher=correct_server)

    if (target != ""):
        if (isnick):
            goim(account, urllib.unquote_plus(target.split(",")[0]), params.get("msg"))
        else:
            channel = urllib.unquote_plus(target.split(",")[0])
            if channel[0] != "#":
                channel = "#" + channel
            gochat(account, {"server": server, "channel": channel, "password": params.get("key", "")}, params.get("msg"))

def msnim(uri):
    protocol = "prpl-msn"
    match = re.match(r"^msnim:([^?]*)(\?(.*))", uri)
    if not match:
        print "Invalid msnim URI: %s" % uri
        return

    command = urllib.unquote_plus(match.group(1))
    paramstring = match.group(3)
    params = {}
    if paramstring:
        for param in paramstring.split("&"):
            key, value = extendlist(param.split("=", 1), 2, "")
            params[key] = urllib.unquote_plus(value)
    screenname = params.get("contact", "")

    account = findaccount(protocol)

    if command.lower() == "chat":
        goim(account, screenname)
    elif command.lower() == "add":
        addbuddy(account, screenname)

def myim(uri):
        protocol = "prpl-myspace"
        print "TODO: send uri: ", uri
        assert False, "Not implemented"

def sip(uri):
    protocol = "prpl-simple"
    match = re.match(r"^sip:(.*)", uri)
    if not match:
        print "Invalid sip URI: %s" % uri
        return

    screenname = urllib.unquote_plus(match.group(1))
    account = findaccount(protocol)
    goim(account, screenname)

def xmpp(uri):
    protocol = "prpl-jabber"
    match = re.match(r"^xmpp:(//([^/?#]*)/?)?([^?#]*)(\?([^;#]*)(;([^#]*))?)?(#(.*))?", uri)
    if not match:
        print "Invalid xmpp URI: %s" % uri
        return

    tmp = match.group(2)
    if (tmp):
        accountname = urllib.unquote_plus(tmp)
    else:
        accountname = ""

    screenname = urllib.unquote_plus(match.group(3))

    tmp = match.group(5)
    if (tmp):
        command = urllib.unquote_plus(tmp)
    else:
        command = ""

    paramstring = match.group(7)
    params = {}
    if paramstring:
        for param in paramstring.split(";"):
            key, value = extendlist(param.split("=", 1), 2, "")
            params[key] = urllib.unquote_plus(value)

    account = findaccount(protocol, accountname)

    if command.lower() == "message":
        goim(account, screenname, params.get("body"))
    elif command.lower() == "join":
        room, server = screenname.split("@")
        gochat(account, {"room": room, "server": server})
    elif command.lower() == "roster":
        addbuddy(account, screenname, params.get("group", ""), params.get("name", ""))
    else:
        goim(account, screenname)

def gtalk(uri):
    protocol = "prpl-jabber"
    match = re.match(r"^gtalk:([^?]*)(\?(.*))", uri)
    if not match:
        print "Invalid gtalk URI: %s" % uri
        return

    command = urllib.unquote_plus(match.group(1))
    paramstring = match.group(3)
    params = {}
    if paramstring:
        for param in paramstring.split("&"):
            key, value = extendlist(param.split("=", 1), 2, "")
            params[key] = urllib.unquote_plus(value)
    accountname = params.get("from_jid", "")
    jid = params.get("jid", "")

    account = findaccount(protocol, accountname)

    if command.lower() == "chat":
        goim(account, jid)
    elif command.lower() == "call":
        # XXX V&V prompt to establish call
        goim(account, jid)

def ymsgr(uri):
    protocol = "prpl-yahoo"
    match = re.match(r"^ymsgr:([^?]*)(\?([^&]*)(&(.*))?)", uri)
    if not match:
        print "Invalid ymsgr URI: %s" % uri
        return

    command = urllib.unquote_plus(match.group(1))
    screenname = urllib.unquote_plus(match.group(3))
    paramstring = match.group(5)
    params = {}
    if paramstring:
        for param in paramstring.split("&"):
            key, value = extendlist(param.split("=", 1), 2, "")
            params[key] = urllib.unquote_plus(value)

    account = findaccount(protocol)

    if command.lower() == "sendim":
        goim(account, screenname, params.get("m"))
    elif command.lower() == "chat":
        gochat(account, {"room": screenname})
    elif command.lower() == "addfriend":
        addbuddy(account, screenname)


def main(argv=sys.argv):
    if len(argv) != 2 or argv[1] == "--help" or argv[1] == "-h":
        print "Usage: %s URI" % argv[0]
        print "Example: %s \"xmpp:romeo@montague.net?message\"" % argv[0]

        if len(argv) != 2:
            sys.exit(1)
        else:
            return 0

    uri = argv[1]
    type = uri.split(":")[0]

    try:
        if type == "aim":
            aim(uri)
        elif type == "gg":
            gg(uri)
        elif type == "icq":
            icq(uri)
        elif type == "irc":
            irc(uri)
        elif type == "msnim":
            msnim(uri)
        elif type == "myim":
            myim(uri)
        elif type == "sip":
            sip(uri)
        elif type == "xmpp":
            xmpp(uri)
        elif type == "gtalk":
            gtalk(uri)
        elif type == "ymsgr":
            ymsgr(uri)
        else:
            print "Unknown protocol: %s" % type
    except dbus.DBusException, e:
        print "Error: %s" % (e.message)
        sys.exit(1)

if __name__ == "__main__":
    main()