Fix some functions descriptions
[pidgin-git.git] / libpurple / purple-url-handler
blob6eb2efdc9a673cd540959eef46ddce8d0577529a
1 #!/usr/bin/env python
3 from __future__ import absolute_import, division, print_function
5 import dbus
6 import re
7 import sys
8 import time
9 try:
10 from urllib.parse import unquote_plus
11 except ImportError:
12 from urllib import unquote_plus
15 bus = dbus.SessionBus()
16 obj = None
17 try:
18 obj = bus.get_object("im.pidgin.purple.PurpleService",
19 "/im/pidgin/purple/PurpleObject")
20 except dbus.DBusException as e:
21 if e._dbus_error_name == "org.freedesktop.DBus.Error.ServiceUnknown":
22 print("Error: no libpurple-powered client is running. "
23 "Try starting Pidgin or Finch.")
24 sys.exit(1)
25 purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")
28 class CheckedObject(object):
29 def __init__(self, obj):
30 self.obj = obj
32 def __getattr__(self, attr):
33 return CheckedAttribute(self, attr)
36 class CheckedAttribute(object):
37 def __init__(self, cobj, attr):
38 self.cobj = cobj
39 self.attr = attr
41 def __call__(self, *args):
42 # Redirect stderr to suppress the printing of an " Introspect error"
43 # message if nothing is listening on the bus. We print a friendly
44 # error message ourselves.
45 real_stderr = sys.stderr
46 sys.stderr = None
47 result = self.cobj.obj.__getattr__(self.attr)(*args)
48 sys.stderr = real_stderr
50 # This can be useful for debugging.
51 # if result == 0:
52 # print("Error:", self.attr, str(args), "returned", str(result))
54 return result
57 cpurple = CheckedObject(purple)
60 def extendlist(list, length, fill):
61 if len(list) < length:
62 return list + [fill] * (length - len(list))
63 else:
64 return list
67 def convert(value):
68 try:
69 return int(value)
70 except:
71 return value
74 def account_not_found():
75 print("No matching account found.")
76 sys.exit(1)
79 def bring_account_online(account):
80 if not cpurple.PurpleAccountIsConnected(account):
81 # The last argument is meant to be a GList * but the D-Bus binding
82 # generator thing just wants a UInt32, which is pretty failing.
83 # Happily, passing a 0 to mean an empty list turns out to work anyway.
84 purple.PurpleAccountSetStatusList(account, "online", 1, 0)
85 purple.PurpleAccountConnect(account)
88 def findaccount(protocolname, accountname="", matcher=None):
89 if matcher:
90 for account in cpurple.PurpleAccountsGetAll():
91 if protocolname != cpurple.PurpleAccountGetProtocolId(account):
92 continue
93 if (accountname != "" and
94 accountname != cpurple.PurpleAccountGetUsername(account)):
95 continue
96 if matcher(account):
97 bring_account_online(account)
98 return account
99 account_not_found()
101 # prefer connected accounts
102 account = cpurple.PurpleAccountsFindConnected(accountname, protocolname)
103 if account != 0:
104 return account
106 # try to get any account and connect it
107 account = cpurple.PurpleAccountsFindAny(accountname, protocolname)
108 if account == 0:
109 account_not_found()
111 bring_account_online(account)
112 return account
115 def goim(account, screenname, message=None):
116 # XXX: 1 == PURPLE_CONV_TYPE_IM
117 conversation = cpurple.PurpleConversationNew(1, account, screenname)
118 if message:
119 purple.PurpleConvSendConfirm(conversation, message)
122 def gochat(account, params, message=None):
123 connection = cpurple.PurpleAccountGetConnection(account)
124 purple.PurpleServJoinChat(connection, params)
126 if message is not None:
127 for i in range(20):
128 # XXX: 2 == PURPLE_CONV_TYPE_CHAT
129 conversation = purple.PurpleFindConversationWithAccount(
131 params.get("channel", params.get("room")),
132 account)
133 if conversation:
134 purple.PurpleConvSendConfirm(conversation, message)
135 break
136 else:
137 time.sleep(0.5)
140 def addbuddy(account, screenname, group="", alias=""):
141 cpurple.PurpleBlistRequestAddBuddy(account, screenname, group, alias)
144 def aim(uri):
145 protocol = "prpl-aim"
146 match = re.match(r"^aim:([^?]*)(\?(.*))", uri)
147 if not match:
148 print("Invalid aim URI: %s" % (uri, ))
149 return
151 command = unquote_plus(match.group(1))
152 paramstring = match.group(3)
153 params = {}
154 if paramstring:
155 for param in paramstring.split("&"):
156 key, value = extendlist(param.split("=", 1), 2, "")
157 params[key] = unquote_plus(value)
158 accountname = params.get("account", "")
159 screenname = params.get("screenname", "")
161 account = findaccount(protocol, accountname)
163 if command.lower() == "goim":
164 goim(account, screenname, params.get("message"))
165 elif command.lower() == "gochat":
166 gochat(account, params)
167 elif command.lower() == "addbuddy":
168 addbuddy(account, screenname, params.get("group", ""))
171 def gg(uri):
172 protocol = "prpl-gg"
173 match = re.match(r"^gg:(.*)", uri)
174 if not match:
175 print("Invalid gg URI: %s" % (uri, ))
176 return
178 screenname = unquote_plus(match.group(1))
179 account = findaccount(protocol)
180 goim(account, screenname)
183 def icq(uri):
184 protocol = "prpl-icq"
185 match = re.match(r"^icq:([^?]*)(\?(.*))", uri)
186 if not match:
187 print("Invalid icq URI: %s" % (uri, ))
188 return
190 command = unquote_plus(match.group(1))
191 paramstring = match.group(3)
192 params = {}
193 if paramstring:
194 for param in paramstring.split("&"):
195 key, value = extendlist(param.split("=", 1), 2, "")
196 params[key] = unquote_plus(value)
197 accountname = params.get("account", "")
198 screenname = params.get("screenname", "")
200 account = findaccount(protocol, accountname)
202 if command.lower() == "goim":
203 goim(account, screenname, params.get("message"))
204 elif command.lower() == "gochat":
205 gochat(account, params)
206 elif command.lower() == "addbuddy":
207 addbuddy(account, screenname, params.get("group", ""))
210 def irc(uri):
211 protocol = "prpl-irc"
212 match = re.match(r"^irc:(//([^/]*))?/?([^?]*)(\?(.*))?", uri)
213 if not match:
214 print("Invalid irc URI: %s" % (uri, ))
215 return
217 server = unquote_plus(match.group(2) or "")
218 target = match.group(3) or ""
219 query = match.group(5) or ""
221 modifiers = {}
222 if target:
223 for modifier in target.split(",")[1:]:
224 modifiers[modifier] = True
226 paramstring = match.group(5)
227 params = {}
228 if paramstring:
229 for param in paramstring.split("&"):
230 key, value = extendlist(param.split("=", 1), 2, "")
231 params[key] = unquote_plus(value)
233 def correct_server(account):
234 username = cpurple.PurpleAccountGetUsername(account)
235 return (server == "" or
236 "@" in username and server == username.split("@")[1])
238 account = findaccount(protocol, matcher=correct_server)
240 if target != "":
241 if "isnick" in modifiers:
242 goim(account, unquote_plus(target.split(",")[0]),
243 params.get("msg"))
244 else:
245 channel = unquote_plus(target.split(",")[0])
246 if channel[0] != "#":
247 channel = "#" + channel
248 gochat(account,
249 {"server": server,
250 "channel": channel,
251 "password": params.get("key", "")},
252 params.get("msg"))
255 def msnim(uri):
256 protocol = "prpl-msn"
257 match = re.match(r"^msnim:([^?]*)(\?(.*))", uri)
258 if not match:
259 print("Invalid msnim URI: %s" % (uri, ))
260 return
262 command = unquote_plus(match.group(1))
263 paramstring = match.group(3)
264 params = {}
265 if paramstring:
266 for param in paramstring.split("&"):
267 key, value = extendlist(param.split("=", 1), 2, "")
268 params[key] = unquote_plus(value)
269 screenname = params.get("contact", "")
271 account = findaccount(protocol)
273 if command.lower() == "chat":
274 goim(account, screenname)
275 elif command.lower() == "add":
276 addbuddy(account, screenname)
279 def sip(uri):
280 protocol = "prpl-simple"
281 match = re.match(r"^sip:(.*)", uri)
282 if not match:
283 print("Invalid sip URI: %s" % (uri, ))
284 return
286 screenname = unquote_plus(match.group(1))
287 account = findaccount(protocol)
288 goim(account, screenname)
291 def xmpp(uri):
292 protocol = "prpl-jabber"
293 match = re.match(
294 r"^xmpp:(//([^/?#]*)/?)?([^?#]*)(\?([^;#]*)(;([^#]*))?)?(#(.*))?",
295 uri)
296 if not match:
297 print("Invalid xmpp URI: %s" % (uri, ))
298 return
300 tmp = match.group(2)
301 if tmp:
302 accountname = unquote_plus(tmp)
303 else:
304 accountname = ""
306 screenname = unquote_plus(match.group(3))
308 tmp = match.group(5)
309 if tmp:
310 command = unquote_plus(tmp)
311 else:
312 command = ""
314 paramstring = match.group(7)
315 params = {}
316 if paramstring:
317 for param in paramstring.split(";"):
318 key, value = extendlist(param.split("=", 1), 2, "")
319 params[key] = unquote_plus(value)
321 account = findaccount(protocol, accountname)
323 if command.lower() == "message":
324 goim(account, screenname, params.get("body"))
325 elif command.lower() == "join":
326 room, server = screenname.split("@")
327 gochat(account, {"room": room, "server": server})
328 elif command.lower() == "roster":
329 addbuddy(account, screenname, params.get("group", ""),
330 params.get("name", ""))
331 else:
332 goim(account, screenname)
335 def gtalk(uri):
336 protocol = "prpl-jabber"
337 match = re.match(r"^gtalk:([^?]*)(\?(.*))", uri)
338 if not match:
339 print("Invalid gtalk URI: %s" % (uri, ))
340 return
342 command = unquote_plus(match.group(1))
343 paramstring = match.group(3)
344 params = {}
345 if paramstring:
346 for param in paramstring.split("&"):
347 key, value = extendlist(param.split("=", 1), 2, "")
348 params[key] = unquote_plus(value)
349 accountname = params.get("from_jid", "")
350 jid = params.get("jid", "")
352 account = findaccount(protocol, accountname)
354 if command.lower() == "chat":
355 goim(account, jid)
356 elif command.lower() == "call":
357 # XXX V&V prompt to establish call
358 goim(account, jid)
361 def ymsgr(uri):
362 protocol = "prpl-yahoo"
363 match = re.match(r"^ymsgr:([^?]*)(\?([^&]*)(&(.*))?)", uri)
364 if not match:
365 print("Invalid ymsgr URI: %s" % (uri, ))
366 return
368 command = unquote_plus(match.group(1))
369 screenname = unquote_plus(match.group(3))
370 paramstring = match.group(5)
371 params = {}
372 if paramstring:
373 for param in paramstring.split("&"):
374 key, value = extendlist(param.split("=", 1), 2, "")
375 params[key] = unquote_plus(value)
377 account = findaccount(protocol)
379 if command.lower() == "sendim":
380 goim(account, screenname, params.get("m"))
381 elif command.lower() == "chat":
382 gochat(account, {"room": screenname})
383 elif command.lower() == "addfriend":
384 addbuddy(account, screenname)
387 def main(argv=sys.argv):
388 if len(argv) != 2 or argv[1] == "--help" or argv[1] == "-h":
389 print("Usage: %s URI" % (argv[0], ))
390 print("Example: %s \"xmpp:romeo@montague.net?message\"" % (argv[0], ))
392 if len(argv) != 2:
393 sys.exit(1)
394 else:
395 return 0
397 uri = argv[1]
398 type = uri.split(":")[0]
400 try:
401 if type == "aim":
402 aim(uri)
403 elif type == "gg":
404 gg(uri)
405 elif type == "icq":
406 icq(uri)
407 elif type == "irc":
408 irc(uri)
409 elif type == "msnim":
410 msnim(uri)
411 elif type == "sip":
412 sip(uri)
413 elif type == "xmpp":
414 xmpp(uri)
415 elif type == "gtalk":
416 gtalk(uri)
417 elif type == "ymsgr":
418 ymsgr(uri)
419 else:
420 print("Unknown protocol: %s" % (type, ))
421 except dbus.DBusException as e:
422 print("Error: %s" % (str(e), ))
423 sys.exit(1)
426 if __name__ == "__main__":
427 main()