Merged pidgin/main into default
[pidgin-git.git] / libpurple / purple-remote
blob1f392af129a5c644ecd31fa8ac986411a78d22ca
1 #!/usr/bin/env python
3 from __future__ import absolute_import, division, print_function
5 import codecs
6 import re
7 import sys
8 try:
9 from urllib.parse import unquote
10 except ImportError:
11 from urllib import unquote
12 import xml.dom.minidom
14 import dbus
17 sys.stdin = codecs.getwriter('utf-8')(sys.stdin)
18 sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
20 xml.dom.minidom.Element.all = xml.dom.minidom.Element.getElementsByTagName
22 obj = None
23 try:
24 obj = dbus.SessionBus().get_object("im.pidgin.purple.PurpleService",
25 "/im/pidgin/purple/PurpleObject")
26 except:
27 pass
29 purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")
32 class CheckedObject(object):
33 def __init__(self, obj):
34 self.obj = obj
36 def __getattr__(self, attr):
37 return CheckedAttribute(self, attr)
40 class CheckedAttribute(object):
41 def __init__(self, cobj, attr):
42 self.cobj = cobj
43 self.attr = attr
45 def __call__(self, *args):
46 result = self.cobj.obj.__getattr__(self.attr)(*args)
47 if result == 0:
48 raise Exception("Error: %s %s returned %s" %
49 (self.attr, args, result))
50 return result
53 def show_help(requested=False):
54 print("""This program uses D-Bus to communicate with purple.
56 Usage:
58 %s "command1" "command2" ...
60 Each command is of one of the three types:
62 [protocol:]commandname?param1=value1&param2=value2&...
63 FunctionName?param1=value1&param2=value2&...
64 FunctionName(value1,value2,...)
66 The second and third form are provided for completeness but their use
67 is not recommended; use purple-send or purple-send-async instead. The
68 second form uses introspection to find out the parameter names and
69 their types, therefore it is rather slow.
71 Examples of commands:
73 jabber:goim?screenname=testone@localhost&message=hi
74 jabber:gochat?room=TestRoom&server=conference.localhost
75 jabber:getinfo?screenname=testone@localhost
76 jabber:addbuddy?screenname=my friend
78 setstatus?status=away&message=don't disturb
79 getstatus
80 getstatusmessage
81 quit
83 PurpleAccountsFindConnected?name=&protocol=jabber
84 PurpleAccountsFindConnected(,jabber)
85 """ % (sys.argv[0], ))
86 if (requested):
87 sys.exit(0)
88 else:
89 sys.exit(1)
92 cpurple = CheckedObject(purple)
94 urlregexp = r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?"
97 def extendlist(list, length, fill):
98 if len(list) < length:
99 return list + [fill] * (length - len(list))
100 else:
101 return list
104 def convert(value):
105 try:
106 return int(value)
107 except:
108 return value
111 def findaccount(accountname, protocolname):
112 try:
113 # prefer connected accounts
114 account = cpurple.PurpleAccountsFindConnected(accountname,
115 protocolname)
116 return account
117 except:
118 # try to get any account and connect it
119 account = cpurple.PurpleAccountsFindAny(accountname, protocolname)
120 purple.PurpleAccountSetStatusVargs(account, "online", 1)
121 purple.PurpleAccountConnect(account)
122 return account
125 def execute(uri):
126 match = re.match(urlregexp, uri)
127 protocol = match.group(2)
128 if protocol == "xmpp":
129 protocol = "jabber"
130 if protocol is not None:
131 protocol = "prpl-" + protocol
132 command = match.group(5)
133 paramstring = match.group(7)
134 params = {}
135 if paramstring is not None:
136 for param in paramstring.split("&"):
137 key, value = extendlist(param.split("=", 1), 2, "")
138 params[key] = unquote(value)
140 accountname = params.get("account", "")
142 if command == "goim":
143 account = findaccount(accountname, protocol)
144 conversation = cpurple.PurpleConversationNew(1, account,
145 params["screenname"])
146 if "message" in params:
147 im = cpurple.PurpleConversationGetImData(conversation)
148 purple.PurpleConvImSend(im, params["message"])
149 return None
151 elif command == "gochat":
152 account = findaccount(accountname, protocol)
153 connection = cpurple.PurpleAccountGetConnection(account)
154 return purple.PurpleServJoinChat(connection, params)
156 elif command == "addbuddy":
157 account = findaccount(accountname, protocol)
158 return cpurple.PurpleBlistRequestAddBuddy(account,
159 params["screenname"],
160 params.get("group", ""),
163 elif command == "setstatus":
164 current = purple.PurpleSavedstatusGetCurrent()
166 if "status" in params:
167 status_id = params["status"]
168 status_type = purple.PurplePrimitiveGetTypeFromId(status_id)
169 else:
170 status_type = purple.PurpleSavedstatusGetType(current)
171 status_id = purple.PurplePrimitiveGetIdFromType(status_type)
173 if "message" in params:
174 message = params["message"]
175 else:
176 message = purple.PurpleSavedstatusGetMessage(current)
178 if "account" in params:
179 accounts = [cpurple.PurpleAccountsFindAny(accountname, protocol)]
181 for account in accounts:
182 status = purple.PurpleAccountGetStatus(account, status_id)
183 type = purple.PurpleStatusGetType(status)
184 purple.PurpleSavedstatusSetSubstatus(current, account, type,
185 message)
186 purple.PurpleSavedstatusActivateForAccount(current, account)
187 else:
188 saved = purple.PurpleSavedstatusNew("", status_type)
189 purple.PurpleSavedstatusSetMessage(saved, message)
190 purple.PurpleSavedstatusActivate(saved)
192 return None
194 elif command == "getstatus":
195 current = purple.PurpleSavedstatusGetCurrent()
196 status_type = purple.PurpleSavedstatusGetType(current)
197 status_id = purple.PurplePrimitiveGetIdFromType(status_type)
198 return status_id
200 elif command == "getstatusmessage":
201 current = purple.PurpleSavedstatusGetCurrent()
202 return purple.PurpleSavedstatusGetMessage(current)
204 elif command == "getinfo":
205 account = findaccount(accountname, protocol)
206 connection = cpurple.PurpleAccountGetConnection(account)
207 return purple.ServGetInfo(connection, params["screenname"])
209 elif command == "quit":
210 return purple.PurpleCoreQuit()
212 elif command == "uri":
213 return None
215 else:
216 match = re.match(r"(\w+)\s*\(([^)]*)\)", command)
217 if match is not None:
218 name = match.group(1)
219 argstr = match.group(2)
220 if argstr == "":
221 args = []
222 else:
223 args = argstr.split(",")
224 fargs = []
225 for arg in args:
226 fargs.append(convert(arg.strip()))
227 return purple.__getattr__(name)(*fargs)
228 else:
229 # Introspect the object to get parameter names and types. This is
230 # slow because the entire introspection info must be downloaded.
231 interface = dbus.Interface(obj,
232 "org.freedesktop.DBus.Introspectable")
233 data = interface.Introspect()
234 introspect = xml.dom.minidom.parseString(data).documentElement
235 for method in introspect.all("method"):
236 if command == method.getAttribute("name"):
237 methodparams = []
238 for arg in method.all("arg"):
239 if arg.getAttribute("direction") == "in":
240 value = params[arg.getAttribute("name")]
241 type = arg.getAttribute("type")
242 if type == "s":
243 methodparams.append(value)
244 elif type == "i":
245 methodparams.append(int(value))
246 else:
247 raise Exception(
248 "Don't know how to handle type \"%s\"" % (
249 type, ))
250 return purple.__getattr__(command)(*methodparams)
251 show_help()
254 if len(sys.argv) == 1:
255 show_help()
256 elif sys.argv[1] == "--help" or sys.argv[1] == "-h":
257 show_help(True)
258 elif obj is None:
259 print("No existing libpurple instance detected.")
260 sys.exit(1)
262 for arg in sys.argv[1:]:
263 output = execute(arg)
265 if output is not None:
266 print(output)