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