How can i receive events from Skype via D-Bus using python? - python

(i know this resembles Python and d-bus: How to set up main loop? , but without complete code in the "Answer", i'm unable to figure out where i'm going wrong. it might just be a change in a Skype)
Here is my program:
import gobject
import dbus
import dbus.mainloop.glib
dbus_gmainloop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
sessbus = dbus.SessionBus()
skype = sessbus.get_object('com.Skype.API', '/com/Skype')
skypec = sessbus.get_object('com.Skype.API', '/com/Skype/Client')
skype_iface = dbus.Interface(skype, dbus_interface='com.Skype.API')
skype_iface.Invoke("NAME py1")
# ... waits for user click in Skype ...
#==> dbus.String(u'OK')
skype_iface.Invoke("PROTOCOL 7")
#==> dbus.String(u'PROTOCOL 7')
def got_signal(sender, destination, member, interface, path):
print "got_signal(sender=%s, dest=%s, member=%s, iface=%s, path=%s)" \
% (sender, destination, member, interface, path)
skypec.connect_to_signal('Notify', got_signal, sender_keyword='sender', \
destination_keyword='destination', member_keyword='member', \
interface_keyword='interface', path_keyword='path')
mainloop = gobject.MainLoop()
mainloop.run()
When run (e.g. python skype-call.py), it pauses after sending the NAME py1 command to Skype and waits for an interactive confirmation in the Skype UI, then continues. As such, the skype_iface object is clearly working at least to a certain degree.
However, python then emits the following error:
ERROR:dbus.proxies:Introspect error on :1.152:/com/Skype/Client: dbus.exceptions.DBusException: org.freedesktop.DBus.Error.UnknownObject: No such object path '/com/Skype/Client'
I also tried the following (instead of connect_to_signal, just before starting the gobject mainloop at the end):
def receiver(x, **kwargs):
print "receiver(%s)" % (x,)
sessbus.add_signal_receiver(receiver, signal_name='Notify', \
dbus_interface='com.Skype.API', bus_name='com.Skype.API', path='/com/Skype/Client')
And while that didn't complain, it never gets called. I tried sending the Skype user a message. What sorts of events should trigger it?
The docs at https://dev.skype.com/desktop-api-reference#DBUSUsage aren't terribly helpful.
This is Skype for Linux 4.2.0.11 on Debian 7.0 multiarch (amd64/i386).

looking back at http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html#exporting-methods-with-dbus-service-method , i tried taking their example:
import gobject
import dbus
from dbus.decorators import method
import dbus.mainloop.glib
import dbus.service
dbus_gmainloop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
sessbus = dbus.SessionBus()
class Example(dbus.service.Object):
def __init__(self, bus):
dbus.service.Object.__init__(self, bus, '/com/Skype/Client')
#method(dbus_interface='com.Skype.API.Client', in_signature='s', \
sender_keyword='sender', destination_keyword='dest', \
rel_path_keyword='rel_path', path_keyword='path', \
message_keyword='message', connection_keyword='conn')
def Notify(self, s, sender=None, dest=None, rel_path=None, path=None, \
message=None, conn=None):
print "Notify(%s, sender=%s, dest=%s, rel_path=%s, path=%s, message=%s, conn=%s)" \
% (s, sender, path, dest, message, rel_path, conn,)
# make one:
ex = Example(sessbus)
skype = sessbus.get_object('com.Skype.API', '/com/Skype')
skype_iface = dbus.Interface(skype, dbus_interface='com.Skype.API')
skype_iface.Invoke("NAME py1")
##=> dbus.String(u'OK')
skype_iface.Invoke("PROTOCOL 7")
##=> dbus.String(u'PROTOCOL 7')
mainloop = gobject.MainLoop()
mainloop.run()
and lo and behold i get Notify calls:
Notify(CONNSTATUS ONLINE, sender=:1.152, path=/com/Skype/Client, dest=:1.275, message=<dbus.lowlevel.MethodCallMessage path: /com/Skype/Client, iface: com.Skype.API.Client, member: Notify dest: :1.275>, rel_path=/, conn=<dbus._dbus.SessionBus (session) at 0x2118e90>)
Notify(CURRENTUSERHANDLE ******, sender=:1.152, path=/com/Skype/Client, dest=:1.275, message=<dbus.lowlevel.MethodCallMessage path: /com/Skype/Client, iface: com.Skype.API.Client, member: Notify dest: :1.275>, rel_path=/, conn=<dbus._dbus.SessionBus (session) at 0x2118e90>)
Notify(USERSTATUS ONLINE, sender=:1.152, path=/com/Skype/Client, dest=:1.275, message=<dbus.lowlevel.MethodCallMessage path: /com/Skype/Client, iface: com.Skype.API.Client, member: Notify dest: :1.275>, rel_path=/, conn=<dbus._dbus.SessionBus (session) at 0x2118e90>)
Obviously, this isn't a great example of a well-structured program, but the d-bus bits do appear to connect.

I'm trying to debug the same thing, maybe we can sort something out together (I'm using wheezy amd64 too, btw)...
From what I understood, it looks like com.Skype.API is not exposing an object named /com/Skype/Client (and d-feet confirms that).
I used dbus-monitor to monitor the bus while sending a message to my skype account. Amongst the other output, I got this:
method call sender=:1.43 -> dest=:1.132 serial=324 path=/com/Skype/Client; interface=com.Skype.API.Client; member=Notify
string "CHAT #rshk-testuser1/$myusername;<hex-code-here> ACTIVITY_TIMESTAMP 1370647479"
error sender=:1.132 -> dest=:1.43 error_name=org.freedesktop.DBus.Error.UnknownMethod reply_serial=324
string "Method "Notify" with signature "s" on interface "com.Skype.API.Client" doesn't exist
"
method call sender=:1.43 -> dest=:1.132 serial=325 path=/com/Skype/Client; interface=com.Skype.API.Client; member=Notify
string "CHATMESSAGE 1538281 STATUS RECEIVED"
error sender=:1.132 -> dest=:1.43 error_name=org.freedesktop.DBus.Error.UnknownMethod reply_serial=325
string "Method "Notify" with signature "s" on interface "com.Skype.API.Client" doesn't exist
"
So, it looks like there's another interface named com.Skype.API.Client that's exposing the /com/Skype/Client object, but for some reason that interface is unreachable..
I had a look at /etc/dbus-1/system.d/skype.conf that's only listing com.Skype.API.
I'm not very experienced with dbus, but I'm trying to dig further and understand what's wrongs..

Related

PubNub Exception in subscribe loop

I am trying to make a basic connection to PubNub and get some basic output with python. When I run the files in bash on windows I am getting a 504 error. I checked Pubnub and it says I am getting some usage which is strange. I am using pubnub 4.1.6
Any help with this would be much appreciated
Thank you so much for your help in advance
Please see the image to see the code I run and the error I am getting.
:
import time
from pubnub.pubnub import PubNub
from pubnub.pnconfiguration import PNConfiguration
from pubnub.callbacks import SubscribeCallback
pnconfig = PNConfiguration()
#pnconfig.ssl = True
pnconfig.subscribe_key = subscribe_key = 'XXX'
pnconfig.publish_key = publish_key ='XXX'
pubnub = PubNub(pnconfig)
'''Test Channel global variable'''
TEST_CHANNEL = 'TEST_CHANNEL'
pubnub.subscribe().channels([TEST_CHANNEL]).execute()
'''
Listen class extends SubscribeCallback and herits its behaviour
Must be put into a class as it's equipped to handle the different events that occur in this channel
'''
class Listener(SubscribeCallback):
def message(self, pubnub, message_object):
print(f'\n-- Incoming message object: {message_object}')
'''Instansiate an instance of message class within a call to add listener'''
pubnub.add_listener(Listener())
def main():
'''Sleep to ensure subsribe runs runs'''
time.sleep(1)
pubnub.publish().channel(TEST_CHANNEL).message({'foo': 'bar'}).sync()
if __name__=='main':
main()

Sublime Text 3: Simple plug-in that changes color theme depending on remote host

Setup: I use Sublime Text 3 (ST), and I often have 2-3 different sessions with Sublime + iTerm2 open in different remote workspaces using RemoteSubl.
Using a simple batch script, I have set my iTerm2 to change colours (by activating a different iTerm user) when I ssh into a different host.
I was wondering if the same could be done for RemoteSubl? Such that when I open something from a specific host/ip/port, then Sublime opens in a different colour scheme, depending on the host/ip/port.
Solution attempt: So far, this is my attempt at building a small plugin that changes colour scheme when host is remote_host.
import sublime
import sublime_plugin
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, view):
try:
host = view.settings().get('remote_subl.host')
print(host)
if host == 'remote_host':
view.settings().set(
'color_scheme',
'Packages/Color Scheme - Default/Mariana.tmTheme')
print(view.settings().get('color_scheme'))
except:
print("Not on remote_host")
pass
Problem: When using using view.settings().get('remote_subl.host') in the console it works fine, and returns remote_host. However, when running the script view.run_command('example') I get the "Not on remote_host" print, indicating that the try loop fails for some reason.
After Keiths suggestions:
import sublime
import sublime_plugin
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, view):
view = self.view
host = view.settings().get('remote_subl.host', None)
print(host)
if host:
view.settings().set(
'color_scheme',
'Packages/Color Scheme - Default/Mariana.tmTheme')
print(view.settings().get('color_scheme'))
if host is None:
view.settings().set(
'color_scheme',
'Packages/Color Scheme - Default/Monokai.tmTheme')
print(view.settings().get('color_scheme'))
view isn't an argument that is passed to the TextCommand's run method. Instead, it is a property on self. Changing it to the following should work:
import sublime
import sublime_plugin
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, edit):
view = self.view
try:
host = view.settings().get('remote_subl.host')
print(host)
if host == 'dsintmain':
view.settings().set(
'color_scheme',
'Packages/Color Scheme - Default/Mariana.tmTheme')
print(view.settings().get('color_scheme'))
except:
print("Not on remote_host")
pass
I would also recommend printing the exception that occurs to help debug things like this in future. Even better, rather than expecting an exception in normal usage, provide a default value to the get method on the settings (i.e. None) and remove the exception handling altogether.
host = view.settings().get('remote_subl.host', None)
That way, if something does really go wrong, you'll see the traceback in the ST console.

mitmproxy load script using API (Python)

Good day,
I am trying to implement the mitmproxy into a bigger application.
For that, I need to be able to load those so called inline scripts in my code and not via command line. I could not find any helpful information about that in the documentation.
I am using mitmproxy version 0.17 and Python 2.7.
I know there is a newer version available, but that one didnt worked using the code examples.
This is the base code I have:
from mitmproxy import controller, proxy
from mitmproxy.proxy.server import ProxyServer
class ProxyMaster(controller.Master):
def __init__(self, server):
controller.Master.__init__(self, server)
def run(self):
try:
return controller.Master.run(self)
except KeyboardInterrupt:
self.shutdown()
def handle_request(self, flow):
flow.reply()
def handle_response(self, flow):
flow.reply()
config = proxy.ProxyConfig(port=8080)
server = ProxyServer(config)
m = ProxyMaster(server)
m.run()
How could I run this proxy using inline scripts?
Thanks in advance
I figured myself out a really ugly workaround.
Instead of using controller.Master I had to use flow.FlowMaster as the controller.Master lib does not seem to be able to handle inline scripts.
For some reason just loading the files did not work, they get triggered immediately, but not by running their matching hooks.
Instead of using the hooks which are not working, I am loading the matching functions as you can see in handle_response (try/except is missing and threading could be useful)
from mitmproxy import flow, proxy
from mitmproxy.proxy.server import ProxyServer
import imp
class ProxyMaster(flow.FlowMaster):
def run(self):
try:
return flow.FlowMaster.run(self)
except KeyboardInterrupt:
self.shutdown()
def handle_request(self, flow):
flow.reply()
def handle_response(self, flow):
for inline_script in self.scripts:
script_file = imp.load_source("response", inline_script.filename)
script_file.response(self, flow)
flow.reply()
proxy_config = proxy.ProxyConfig(port=8080)
server = ProxyServer(proxy_config)
state = flow.State()
m = ProxyMaster(server, state)
m.load_script("upsidedowninternet.py")
m.load_script("add_header.py")
m.run()
Any ideas about doing it the right way are appreciated.

Callbacks and events in python

I'm making a bot to link IRC and DC (direct connect) together. There is an existing implementation in C++ I've been following, but it doesn't have all the feature's we're after.
I'm using an IRC library for python which is really well coded. I can register some callback handlers for various IRC events (specifically receiving a public message). This callback function is able to reference objects created in the main python execution from the thread within the IRC library.
Here are my callbacks:
def on_connect(connection, event):
connection.join(ircSettings['channel'])
def on_disconnect(connection, event):
sys.exit()
def on_pubmsg(connection, event):
hubClient.sendMessage(event.source.split('!')[0] + ': ' + event.arguments[0])
And here's how I set them up:
# Create the IRC client
ircClient = irc.client.IRC()
try:
ircConnection = ircClient.server().connect(ircSettings['server'], ircSettin$
except irc.client.ServerConnectionError, x:
print x
sys.exit()
# Set the IRC event handlers
ircConnection.add_global_handler("welcome", on_connect)
ircConnection.add_global_handler("pubmsg", on_pubmsg)
ircConnection.add_global_handler("disconnect", on_disconnect)
I really like this solution, as it makes for very tidy code (particularly in this example). However, I have no idea how to modify my DC library to generate these events.
The main point of interest is the callback's ability to reference the hubClient, which is created in the main python program like so:
# Create the DC client
hubClient = DC.DirectConnect(dcSettings)
hubClient.connect(dcSettings['hub'])
Initially, I passed a function pointer to my DC library to run whenever a message is received:
def messageHandler(nick, msg):
if nick is not ircSettings['nick']:
ircConnection.privmsg(ircSettings['channel'], nick + ': ' + msg)
dcSettings = {
'nick': 'dans_bot',
'sharesize': 10*1024**3, # 10GB
'ip': '0.0.0.0', # XXX: This might not matter, but needed for library
'hub': ('192.168.1.129', 411),
'handler': messageHandler
}
But I get the error:
NameError: global name 'ircConnection' is not defined
How can I set up my DC client to create a callback in a way that I can still reference these local (to the main execution) objects?
Edit: I added a declaration for 'ircConnection'.
I suppose ircConnection is a third party module. And a simple import of that module may solve this error of global nameircConnectionis not defined. Try import ircConnection in your main module
The only problem in your code is that the reference to ircConnection is first seen inside the try-except block and if it fails then the var will be None. Just write ircConnection = None before try.
# Create the IRC client
ircClient = irc.client.IRC()
ircConnection = None
try:
ircConnection = ircClient.server().connect(ircSettings['server'], ircSettin$
except irc.client.ServerConnectionError, x:
print x
sys.exit()
# Set the IRC event handlers
ircConnection.add_global_handler("welcome", on_connect)
ircConnection.add_global_handler("pubmsg", on_pubmsg)
ircConnection.add_global_handler("disconnect", on_disconnect)

twisted: How to send and receive the same object with Perspective Broker?

I have a simple 'echo' PB client and server where the client sends an object to the server which echo the same object back to the client:
The client:
from twisted.spread import pb
from twisted.internet import reactor
from twisted.python import util
from amodule import aClass
factory = pb.PBClientFactory()
reactor.connectTCP("localhost", 8282, factory)
d = factory.getRootObject()
d.addCallback(lambda object: object.callRemote("echo", aClass()))
d.addCallback(lambda response: 'server echoed: '+response)
d.addErrback(lambda reason: 'error: '+str(reason.value))
d.addCallback(util.println)
d.addCallback(lambda _: reactor.stop())
reactor.run()
The server:
from twisted.application import internet, service
from twisted.internet import protocol
from twisted.spread import pb
from amodule import aClass
class RemoteClass(pb.RemoteCopy, aClass):
pass
pb.setUnjellyableForClass(aClass, RemoteClass)
class PBServer(pb.Root):
def remote_echo(self, a):
return a
application = service.Application("Test app")
# Prepare managers
clientManager = internet.TCPServer(8282, pb.PBServerFactory(PBServer()));
clientManager.setServiceParent(application)
if __name__ == '__main__':
print "Run with twistd"
import sys
sys.exit(1)
The aClass is a simple class implementing Copyable:
from twisted.spread import pb
class aClass(pb.Copyable):
pass
When i run the above code, i get this error:
twisted.spread.jelly.InsecureJelly: Module builtin not allowed (in type builtin.RemoteClass).
In fact, the object is sent to the server without any problem since it was secured with pb.setUnjellyableForClass(aClass, RemoteClass) on the server side, but once it gets returned to the client, that error is raised.
Am looking for a way to get an easy way to send/receive my objects between two peers.
Perspective broker identifies classes by name when talking about them over the network. A class gets its name in part from the module in which it is defined. A tricky problem with defining classes in a file that you run from the command line (ie, your "main script") is that they may end up with a surprising name. When you do this:
python foo.py
The module name Python gives to the code in foo.py is not "foo" as one might expect. Instead it is something like "__main__" (which is why the if __name__ == "__main__": trick works).
However, if some other part of your application later tries to import something from foo.py, then Python re-evaluates its contents to create a new module named "foo".
Additionally, the classes defined in the "__main__" module of one process may have nothing to do with the classes defined in the "__main__" module of another process. This is the case in your example, where __main__.RemoteClass is defined in your server process but there is no RemoteClass in the __main__ module of your client process.
So, PB gets mixed up and can't complete the object transfer.
The solution is to keep the amount of code in your main script to a minimum, and in particular to never define things with names there (no classes, no function definitions).
However, another problem is the expectation that a RemoteCopy can be sent over PB without additional preparation. A Copyable can be sent, creating a RemoteCopy on the peer, but this is not a symmetric relationship. Your client also needs to allow this by making a similar (or different) pb.setUnjellyableForClass call.

Categories