summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2011-10-29 05:21:27 +0200
committerFlorent Le Coz <louiz@louiz.org>2011-10-29 05:21:27 +0200
commitafcc3870021ddfda19fdee5069349ed8e929a077 (patch)
treee766bfb168fde098ed6a7eaf322bad511ec6695a
parent5050d775d9e1f117766e721168c2f35f981d7146 (diff)
parentf8fcf6696d0044817d596e7d09dcbdcc8a52aac6 (diff)
downloadpoezio-afcc3870021ddfda19fdee5069349ed8e929a077.tar.gz
poezio-afcc3870021ddfda19fdee5069349ed8e929a077.tar.bz2
poezio-afcc3870021ddfda19fdee5069349ed8e929a077.tar.xz
poezio-afcc3870021ddfda19fdee5069349ed8e929a077.zip
Merge branch 'remote_exec' into plugins
-rw-r--r--src/core.py34
-rwxr-xr-xsrc/daemon.py63
-rw-r--r--src/fifo.py70
3 files changed, 163 insertions, 4 deletions
diff --git a/src/core.py b/src/core.py
index 41a54b23..712eed62 100644
--- a/src/core.py
+++ b/src/core.py
@@ -49,6 +49,7 @@ from contact import Contact, Resource
from text_buffer import TextBuffer
from keyboard import read_char
from theming import get_theme
+from fifo import Fifo
# http://xmpp.org/extensions/xep-0045.html#errorstatus
ERROR_AND_STATUS_CODES = {
@@ -94,6 +95,7 @@ class Core(object):
sys.excepthook = self.on_exception
self.running = True
self.xmpp = singleton.Singleton(connection.Connection)
+ self.remote_fifo = None
# a unique buffer used to store global informations
# that are displayed in almost all tabs, in an
# information window.
@@ -157,7 +159,6 @@ class Core(object):
'M-z': self.go_to_previous_tab,
'^L': self.full_screen_redraw,
'M-j': self.go_to_room_number,
-# 'M-c': self.coucou,
}
# Add handlers
@@ -191,9 +192,6 @@ class Core(object):
for plugin in plugins.split():
self.plugin_manager.load(plugin)
- def coucou(self):
- self.command_pubsub('pubsub.louiz.org')
-
def start(self):
"""
Init curses, create the first tab, etc
@@ -1707,3 +1705,31 @@ class Core(object):
return False
self.current_tab().command_say(msg)
return True
+
+ def exec_command(self, command):
+ """
+ Execute an external command on the local or a remote
+ machine, depending on the conf. For example, to open a link in a
+ browser, do exec_command("firefox http://poezio.eu"),
+ and this will call the command on the correct computer.
+ The remote execution is done by writing the command on a fifo.
+ That fifo has to be on the machine where poezio is running, and
+ accessible (through sshfs for example) from the local machine (where
+ poezio is not running). A very simple daemon reads on that fifo,
+ and executes any command that is read in it.
+ """
+ if config.get('exec_remote', 'false') == 'true':
+ # We just write the command in the fifo
+ if not self.remote_fifo:
+ try:
+ self.remote_fifo = Fifo(os.path.join(config.get('remote_fifo_path', './'), 'poezio.fifo'), 'w')
+ except (OSError, IOError) as e:
+ self.information('Could not open fifo file for writing: %s' % (e,), 'Error')
+ return
+ try:
+ self.remote_fifo.write(command)
+ except (IOError) as e:
+ self.information('Could not execute [%s]: %s' % (command, e,), 'Error')
+ self.remote_fifo = None
+ else:
+ pass
diff --git a/src/daemon.py b/src/daemon.py
new file mode 100755
index 00000000..a9d888f1
--- /dev/null
+++ b/src/daemon.py
@@ -0,0 +1,63 @@
+# Copyright 2011 Florent Le Coz <louiz@louiz.org>
+#
+# This file is part of Poezio.
+#
+# Poezio is free software: you can redistribute it and/or modify
+# it under the terms of the zlib license. See the COPYING file.
+
+"""
+This file is a standalone program that creates a fifo file (if it doesn’t exist
+yet), opens it for reading, reads commands from it and executes them (each line
+should be a command).
+
+Usage: ./daemon.py <path_tofifo>
+
+That fifo should be in a directory, shared through sshfs, with the remote
+machine running poezio. Poezio then writes command in it, and this daemon
+executes them on the local machine.
+Note that you should not start this daemon if you do not trust the remote
+machine that is running poezio, since this could make it run any (dangerous)
+command on your local machine.
+"""
+
+import sys
+import threading
+import subprocess
+
+from fifo import Fifo
+
+class Executor(threading.Thread):
+ """
+ Just a class to execute commands in a thread.
+ This way, the execution can totally fail, we don’t care,
+ and we can start commands without having to wait for them
+ to return
+ """
+ def __init__(self, command):
+ threading.Thread.__init__(self)
+ self.command = command
+
+ def run(self):
+ print('executing %s' % (self.command,))
+ subprocess.call(self.command.split())
+
+def main(path):
+ while True:
+ fifo = Fifo(path, 'r')
+ while True:
+ line = fifo.readline()
+ if line == '':
+ del fifo
+ break
+ e = Executor(line)
+ e.start()
+
+def usage():
+ print('Usage: %s <fifo_name>' % (sys.argv[0],))
+
+if __name__ == '__main__':
+ argc = len(sys.argv)
+ if argc != 2:
+ usage()
+ else:
+ main(sys.argv[1])
diff --git a/src/fifo.py b/src/fifo.py
new file mode 100644
index 00000000..8306e24b
--- /dev/null
+++ b/src/fifo.py
@@ -0,0 +1,70 @@
+# Copyright 2011 Florent Le Coz <louiz@louiz.org>
+#
+# This file is part of Poezio.
+#
+# Poezio is free software: you can redistribute it and/or modify
+# it under the terms of the zlib license. See the COPYING file.
+
+"""
+Defines the Fifo class
+"""
+
+import logging
+log = logging.getLogger(__name__)
+
+import os
+import threading
+
+class OpenTrick(threading.Thread):
+ """
+ A threaded trick to make the open for writing succeed.
+ A fifo cannot be opened for writing if it has not been
+ yet opened by the other hand for reading.
+ So, we just open the fifo for reading and close it
+ immediately afterwards.
+ Once that is done, we can freely keep the fifo open for
+ writing and write things in it. The writing can fail if
+ there’s still nothing reading that fifo, but we just yell
+ an error in that case.
+ """
+ def __init__(self, path):
+ threading.Thread.__init__(self)
+ self.path = path
+
+ def run(self):
+ open(self.path, 'r').close()
+
+
+class Fifo(object):
+ """
+ Just a simple file handler, writing and reading in a fifo.
+ Mode is either 'r' or 'w', just like the mode for the open()
+ function.
+ """
+ def __init__(self, path, mode):
+ self.trick = None
+ if not os.path.exists(path):
+ os.mkfifo(path)
+ if mode == 'w':
+ self.trick = OpenTrick(path)
+ # that thread will wait until we open it for writing
+ self.trick.start()
+ self.fd = open(path, mode)
+
+ def write(self, data):
+ """
+ Try to write on the fifo. If that fails, this means
+ that nothing has that fifo opened, so the writing is useless,
+ so we just return (and display an error telling that, somewhere).
+ """
+ self.fd.write(data)
+ self.fd.flush()
+
+ def readline(self):
+ return self.fd.readline()
+
+ def __del__(self):
+ try:
+ self.fd.close()
+ except:
+ pass