Change the "length of bstream" data type to be a gsize, since it represents
[pidgin-git.git] / libpurple / purple-url-handler
blob4407d8fb07203c81b12fd3ced56822dd43a1089a
1 #!/usr/bin/env python
3 import dbus
4 import re
5 import sys
6 import time
7 import urllib
9 bus = dbus.SessionBus()
10 obj = None
11 try:
12 obj = bus.get_object("im.pidgin.purple.PurpleService",
13 "/im/pidgin/purple/PurpleObject")
14 except dbus.DBusException, e:
15 if e._dbus_error_name == "org.freedesktop.DBus.Error.ServiceUnknown":
16 print "Error: no libpurple-powered client is running. Try starting Pidgin or Finch."
17 sys.exit(1)
18 purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")
20 class CheckedObject:
21 def __init__(self, obj):
22 self.obj = obj
24 def __getattr__(self, attr):
25 return CheckedAttribute(self, attr)
27 class CheckedAttribute:
28 def __init__(self, cobj, attr):
29 self.cobj = cobj
30 self.attr = attr
32 def __call__(self, *args):
33 # Redirect stderr to suppress the printing of an " Introspect error"
34 # message if nothing is listening on the bus. We print a friendly
35 # error message ourselves.
36 real_stderr = sys.stderr
37 sys.stderr = None
38 result = self.cobj.obj.__getattr__(self.attr)(*args)
39 sys.stderr = real_stderr
41 # This can be useful for debugging.
42 # if (result == 0):
43 # print "Error: " + self.attr + " " + str(args) + " returned " + str(result)
45 return result
47 cpurple = CheckedObject(purple)
49 def extendlist(list, length, fill):
50 if len(list) < length:
51 return list + [fill] * (length - len(list))
52 else:
53 return list
55 def convert(value):
56 try:
57 return int(value)
58 except:
59 return value
61 def account_not_found():
62 print "No matching account found."
63 sys.exit(1)
65 def bring_account_online(account):
66 if not cpurple.PurpleAccountIsConnected(account):
67 # The last argument is meant to be a GList * but the D-Bus binding
68 # generator thing just wants a UInt32, which is pretty failing.
69 # Happily, passing a 0 to mean an empty list turns out to work anyway.
70 purple.PurpleAccountSetStatusList(account, "online", 1, 0)
71 purple.PurpleAccountConnect(account)
73 def findaccount(protocolname, accountname="", matcher=None):
74 if matcher:
75 for account in cpurple.PurpleAccountsGetAll():
76 if (protocolname != cpurple.PurpleAccountGetProtocolID(account)) or \
77 (accountname != "" and accountname != cpurple.PurpleAccountGetUsername(account)):
78 continue
79 if matcher(account):
80 bring_account_online(account)
81 return account
82 account_not_found()
84 # prefer connected accounts
85 account = cpurple.PurpleAccountsFindConnected(accountname, protocolname)
86 if (account != 0):
87 return account
89 # try to get any account and connect it
90 account = cpurple.PurpleAccountsFindAny(accountname, protocolname)
91 if (account == 0):
92 account_not_found()
94 bring_account_online(account)
95 return account
97 def goim(account, screenname, message=None):
98 # XXX: 1 == PURPLE_CONV_TYPE_IM
99 conversation = cpurple.PurpleConversationNew(1, account, screenname)
100 if message:
101 purple.PurpleConvSendConfirm(conversation, message)
103 def gochat(account, params, message=None):
104 connection = cpurple.PurpleAccountGetConnection(account)
105 purple.ServJoinChat(connection, params)
107 if message != None:
108 for i in range(20):
109 # XXX: 2 == PURPLE_CONV_TYPE_CHAT
110 conversation = purple.PurpleFindConversationWithAccount(2, params.get("channel", params.get("room")), account)
111 if conversation:
112 purple.PurpleConvSendConfirm(conversation, message)
113 break
114 else:
115 time.sleep(0.5)
117 def addbuddy(account, screenname, group="", alias=""):
118 cpurple.PurpleBlistRequestAddBuddy(account, screenname, group, alias)
121 def aim(uri):
122 protocol = "prpl-aim"
123 match = re.match(r"^aim:([^?]*)(\?(.*))", uri)
124 if not match:
125 print "Invalid aim URI: %s" % uri
126 return
128 command = urllib.unquote_plus(match.group(1))
129 paramstring = match.group(3)
130 params = {}
131 if paramstring:
132 for param in paramstring.split("&"):
133 key, value = extendlist(param.split("=", 1), 2, "")
134 params[key] = urllib.unquote_plus(value)
135 accountname = params.get("account", "")
136 screenname = params.get("screenname", "")
138 account = findaccount(protocol, accountname)
140 if command.lower() == "goim":
141 goim(account, screenname, params.get("message"))
142 elif command.lower() == "gochat":
143 gochat(account, params)
144 elif command.lower() == "addbuddy":
145 addbuddy(account, screenname, params.get("group", ""))
147 def gg(uri):
148 protocol = "prpl-gg"
149 match = re.match(r"^gg:(.*)", uri)
150 if not match:
151 print "Invalid gg URI: %s" % uri
152 return
154 screenname = urllib.unquote_plus(match.group(1))
155 account = findaccount(protocol)
156 goim(account, screenname)
158 def icq(uri):
159 protocol = "prpl-icq"
160 match = re.match(r"^icq:([^?]*)(\?(.*))", uri)
161 if not match:
162 print "Invalid icq URI: %s" % uri
163 return
165 command = urllib.unquote_plus(match.group(1))
166 paramstring = match.group(3)
167 params = {}
168 if paramstring:
169 for param in paramstring.split("&"):
170 key, value = extendlist(param.split("=", 1), 2, "")
171 params[key] = urllib.unquote_plus(value)
172 accountname = params.get("account", "")
173 screenname = params.get("screenname", "")
175 account = findaccount(protocol, accountname)
177 if command.lower() == "goim":
178 goim(account, screenname, params.get("message"))
179 elif command.lower() == "gochat":
180 gochat(account, params)
181 elif command.lower() == "addbuddy":
182 addbuddy(account, screenname, params.get("group", ""))
184 def irc(uri):
185 protocol = "prpl-irc"
186 match = re.match(r"^irc:(//([^/]*))?/?([^?]*)(\?(.*))?", uri)
187 if not match:
188 print "Invalid irc URI: %s" % uri
189 return
191 server = urllib.unquote_plus(match.group(2)) or ""
192 target = match.group(3) or ""
193 query = match.group(5) or ""
195 modifiers = {}
196 if target:
197 for modifier in target.split(",")[1:]:
198 modifiers[modifier] = True
200 isnick = modifiers.has_key("isnick")
202 paramstring = match.group(5)
203 params = {}
204 if paramstring:
205 for param in paramstring.split("&"):
206 key, value = extendlist(param.split("=", 1), 2, "")
207 params[key] = urllib.unquote_plus(value)
209 def correct_server(account):
210 username = cpurple.PurpleAccountGetUsername(account)
211 return ((server == "") or ("@" in username) and (server == (username.split("@"))[1]))
213 account = findaccount(protocol, matcher=correct_server)
215 if (target != ""):
216 if (isnick):
217 goim(account, urllib.unquote_plus(target.split(",")[0]), params.get("msg"))
218 else:
219 channel = urllib.unquote_plus(target.split(",")[0])
220 if channel[0] != "#":
221 channel = "#" + channel
222 gochat(account, {"server": server, "channel": channel, "password": params.get("key", "")}, params.get("msg"))
224 def msnim(uri):
225 protocol = "prpl-msn"
226 match = re.match(r"^msnim:([^?]*)(\?(.*))", uri)
227 if not match:
228 print "Invalid msnim URI: %s" % uri
229 return
231 command = urllib.unquote_plus(match.group(1))
232 paramstring = match.group(3)
233 params = {}
234 if paramstring:
235 for param in paramstring.split("&"):
236 key, value = extendlist(param.split("=", 1), 2, "")
237 params[key] = urllib.unquote_plus(value)
238 screenname = params.get("contact", "")
240 account = findaccount(protocol)
242 if command.lower() == "chat":
243 goim(account, screenname)
244 elif command.lower() == "add":
245 addbuddy(account, screenname)
247 def myim(uri):
248 protocol = "prpl-myspace"
249 print "TODO: send uri: ", uri
250 assert False, "Not implemented"
252 def sip(uri):
253 protocol = "prpl-simple"
254 match = re.match(r"^sip:(.*)", uri)
255 if not match:
256 print "Invalid sip URI: %s" % uri
257 return
259 screenname = urllib.unquote_plus(match.group(1))
260 account = findaccount(protocol)
261 goim(account, screenname)
263 def xmpp(uri):
264 protocol = "prpl-jabber"
265 match = re.match(r"^xmpp:(//([^/?#]*)/?)?([^?#]*)(\?([^;#]*)(;([^#]*))?)?(#(.*))?", uri)
266 if not match:
267 print "Invalid xmpp URI: %s" % uri
268 return
270 tmp = match.group(2)
271 if (tmp):
272 accountname = urllib.unquote_plus(tmp)
273 else:
274 accountname = ""
276 screenname = urllib.unquote_plus(match.group(3))
278 tmp = match.group(5)
279 if (tmp):
280 command = urllib.unquote_plus(tmp)
281 else:
282 command = ""
284 paramstring = match.group(7)
285 params = {}
286 if paramstring:
287 for param in paramstring.split(";"):
288 key, value = extendlist(param.split("=", 1), 2, "")
289 params[key] = urllib.unquote_plus(value)
291 account = findaccount(protocol, accountname)
293 if command.lower() == "message":
294 goim(account, screenname, params.get("body"))
295 elif command.lower() == "join":
296 room, server = screenname.split("@")
297 gochat(account, {"room": room, "server": server})
298 elif command.lower() == "roster":
299 addbuddy(account, screenname, params.get("group", ""), params.get("name", ""))
300 else:
301 goim(account, screenname)
303 def gtalk(uri):
304 protocol = "prpl-jabber"
305 match = re.match(r"^gtalk:([^?]*)(\?(.*))", uri)
306 if not match:
307 print "Invalid gtalk URI: %s" % uri
308 return
310 command = urllib.unquote_plus(match.group(1))
311 paramstring = match.group(3)
312 params = {}
313 if paramstring:
314 for param in paramstring.split("&"):
315 key, value = extendlist(param.split("=", 1), 2, "")
316 params[key] = urllib.unquote_plus(value)
317 accountname = params.get("from_jid", "")
318 jid = params.get("jid", "")
320 account = findaccount(protocol, accountname)
322 if command.lower() == "chat":
323 goim(account, jid)
324 elif command.lower() == "call":
325 # XXX V&V prompt to establish call
326 goim(account, jid)
328 def ymsgr(uri):
329 protocol = "prpl-yahoo"
330 match = re.match(r"^ymsgr:([^?]*)(\?([^&]*)(&(.*))?)", uri)
331 if not match:
332 print "Invalid ymsgr URI: %s" % uri
333 return
335 command = urllib.unquote_plus(match.group(1))
336 screenname = urllib.unquote_plus(match.group(3))
337 paramstring = match.group(5)
338 params = {}
339 if paramstring:
340 for param in paramstring.split("&"):
341 key, value = extendlist(param.split("=", 1), 2, "")
342 params[key] = urllib.unquote_plus(value)
344 account = findaccount(protocol)
346 if command.lower() == "sendim":
347 goim(account, screenname, params.get("m"))
348 elif command.lower() == "chat":
349 gochat(account, {"room": screenname})
350 elif command.lower() == "addfriend":
351 addbuddy(account, screenname)
354 def main(argv=sys.argv):
355 if len(argv) != 2 or argv[1] == "--help" or argv[1] == "-h":
356 print "Usage: %s URI" % argv[0]
357 print "Example: %s \"xmpp:romeo@montague.net?message\"" % argv[0]
359 if len(argv) != 2:
360 sys.exit(1)
361 else:
362 return 0
364 uri = argv[1]
365 type = uri.split(":")[0]
367 try:
368 if type == "aim":
369 aim(uri)
370 elif type == "gg":
371 gg(uri)
372 elif type == "icq":
373 icq(uri)
374 elif type == "irc":
375 irc(uri)
376 elif type == "msnim":
377 msnim(uri)
378 elif type == "myim":
379 myim(uri)
380 elif type == "sip":
381 sip(uri)
382 elif type == "xmpp":
383 xmpp(uri)
384 elif type == "gtalk":
385 gtalk(uri)
386 elif type == "ymsgr":
387 ymsgr(uri)
388 else:
389 print "Unknown protocol: %s" % type
390 except dbus.DBusException, e:
391 print "Error: %s" % (e.message)
392 sys.exit(1)
394 if __name__ == "__main__":
395 main()