Mercurial > pidgin
view libpurple/purple-url-handler @ 27161:7054f810b0f9
Check in code that connects to oscar using clientLogin. This is the
authentication scheme they've publically documented. We still use
the old MD5-style login as the default, but you can optionally try
this out by checking a check box on the advanced tab of your oscar
account.
Functionally everything is supposed to be the same. However, for
some reason users with Mobile IM forwarding turned on don't show
up online and can't be messaged. Not sure why.
Using clientLogin DOES make it easier for AOL to track us. And yes,
it probably makes it easier for AOL to block us, too. But I don't
believe they want to do that. I believe they're trying to keep their
network open, and I think we should appreciate that and try to work
with them. We're not just some small open source project that slips
under the radar unnoticed anymore.
It's good to have options, right?
None of this code was taken from anywhere (outside of libpurple). I
wrote it all from scratch (and took a few bits from other places in
libpurple). I did use the documentation on http://dev.aol.com/aim ,
but I don't believe that affects us from a licensing standpoint in
any way. If you disagree we should talk about it on the devel
mailing list.
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 23 Jun 2009 18:20:12 +0000 |
parents | 971b89243a20 |
children | adef21420870 |
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) return ("@" in username) and (server == (username.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()