3 from __future__
import absolute_import
, division
, print_function
10 from urllib
.parse
import unquote_plus
12 from urllib
import unquote_plus
15 bus
= dbus
.SessionBus()
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.")
25 purple
= dbus
.Interface(obj
, "im.pidgin.purple.PurpleInterface")
28 class CheckedObject(object):
29 def __init__(self
, obj
):
32 def __getattr__(self
, attr
):
33 return CheckedAttribute(self
, attr
)
36 class CheckedAttribute(object):
37 def __init__(self
, cobj
, 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
47 result
= self
.cobj
.obj
.__getattr
__(self
.attr
)(*args
)
48 sys
.stderr
= real_stderr
50 # This can be useful for debugging.
52 # print("Error:", self.attr, str(args), "returned", str(result))
57 cpurple
= CheckedObject(purple
)
60 def extendlist(list, length
, fill
):
61 if len(list) < length
:
62 return list + [fill
] * (length
- len(list))
74 def account_not_found():
75 print("No matching account found.")
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):
90 for account
in cpurple
.PurpleAccountsGetAll():
91 if protocolname
!= cpurple
.PurpleAccountGetProtocolId(account
):
93 if (accountname
!= "" and
94 accountname
!= cpurple
.PurpleAccountGetUsername(account
)):
97 bring_account_online(account
)
101 # prefer connected accounts
102 account
= cpurple
.PurpleAccountsFindConnected(accountname
, protocolname
)
106 # try to get any account and connect it
107 account
= cpurple
.PurpleAccountsFindAny(accountname
, protocolname
)
111 bring_account_online(account
)
115 def goim(account
, screenname
, message
=None):
116 # XXX: 1 == PURPLE_CONV_TYPE_IM
117 conversation
= cpurple
.PurpleConversationNew(1, account
, screenname
)
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:
128 # XXX: 2 == PURPLE_CONV_TYPE_CHAT
129 conversation
= purple
.PurpleFindConversationWithAccount(
131 params
.get("channel", params
.get("room")),
134 purple
.PurpleConvSendConfirm(conversation
, message
)
140 def addbuddy(account
, screenname
, group
="", alias
=""):
141 cpurple
.PurpleBlistRequestAddBuddy(account
, screenname
, group
, alias
)
145 protocol
= "prpl-aim"
146 match
= re
.match(r
"^aim:([^?]*)(\?(.*))", uri
)
148 print("Invalid aim URI: %s" % (uri
, ))
151 command
= unquote_plus(match
.group(1))
152 paramstring
= match
.group(3)
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", ""))
173 match
= re
.match(r
"^gg:(.*)", uri
)
175 print("Invalid gg URI: %s" % (uri
, ))
178 screenname
= unquote_plus(match
.group(1))
179 account
= findaccount(protocol
)
180 goim(account
, screenname
)
184 protocol
= "prpl-icq"
185 match
= re
.match(r
"^icq:([^?]*)(\?(.*))", uri
)
187 print("Invalid icq URI: %s" % (uri
, ))
190 command
= unquote_plus(match
.group(1))
191 paramstring
= match
.group(3)
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", ""))
211 protocol
= "prpl-irc"
212 match
= re
.match(r
"^irc:(//([^/]*))?/?([^?]*)(\?(.*))?", uri
)
214 print("Invalid irc URI: %s" % (uri
, ))
217 server
= unquote_plus(match
.group(2) or "")
218 target
= match
.group(3) or ""
219 query
= match
.group(5) or ""
223 for modifier
in target
.split(",")[1:]:
224 modifiers
[modifier
] = True
226 paramstring
= match
.group(5)
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
)
241 if "isnick" in modifiers
:
242 goim(account
, unquote_plus(target
.split(",")[0]),
245 channel
= unquote_plus(target
.split(",")[0])
246 if channel
[0] != "#":
247 channel
= "#" + channel
251 "password": params
.get("key", "")},
256 protocol
= "prpl-msn"
257 match
= re
.match(r
"^msnim:([^?]*)(\?(.*))", uri
)
259 print("Invalid msnim URI: %s" % (uri
, ))
262 command
= unquote_plus(match
.group(1))
263 paramstring
= match
.group(3)
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
)
280 protocol
= "prpl-simple"
281 match
= re
.match(r
"^sip:(.*)", uri
)
283 print("Invalid sip URI: %s" % (uri
, ))
286 screenname
= unquote_plus(match
.group(1))
287 account
= findaccount(protocol
)
288 goim(account
, screenname
)
292 protocol
= "prpl-jabber"
294 r
"^xmpp:(//([^/?#]*)/?)?([^?#]*)(\?([^;#]*)(;([^#]*))?)?(#(.*))?",
297 print("Invalid xmpp URI: %s" % (uri
, ))
302 accountname
= unquote_plus(tmp
)
306 screenname
= unquote_plus(match
.group(3))
310 command
= unquote_plus(tmp
)
314 paramstring
= match
.group(7)
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", ""))
332 goim(account
, screenname
)
336 protocol
= "prpl-jabber"
337 match
= re
.match(r
"^gtalk:([^?]*)(\?(.*))", uri
)
339 print("Invalid gtalk URI: %s" % (uri
, ))
342 command
= unquote_plus(match
.group(1))
343 paramstring
= match
.group(3)
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":
356 elif command
.lower() == "call":
357 # XXX V&V prompt to establish call
362 protocol
= "prpl-yahoo"
363 match
= re
.match(r
"^ymsgr:([^?]*)(\?([^&]*)(&(.*))?)", uri
)
365 print("Invalid ymsgr URI: %s" % (uri
, ))
368 command
= unquote_plus(match
.group(1))
369 screenname
= unquote_plus(match
.group(3))
370 paramstring
= match
.group(5)
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], ))
398 type = uri
.split(":")[0]
409 elif type == "msnim":
415 elif type == "gtalk":
417 elif type == "ymsgr":
420 print("Unknown protocol: %s" % (type, ))
421 except dbus
.DBusException
as e
:
422 print("Error: %s" % (str(e
), ))
426 if __name__
== "__main__":