From 7b90c29f1fd7f685d883ef6c0be75c46ec495a34 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 16 Aug 2020 23:15:32 +0200
Subject: Extended the File menu to run external Python scripts on demand.

---
 configure.ac                         |   1 +
 plugins/python/Makefile.am           |   3 +-
 plugins/python/scripting/Makefile.am |   8 +++
 plugins/python/scripting/__init__.py |   2 +
 plugins/python/scripting/core.py     | 101 +++++++++++++++++++++++++++++++++++
 5 files changed, 114 insertions(+), 1 deletion(-)
 create mode 100644 plugins/python/scripting/Makefile.am
 create mode 100644 plugins/python/scripting/__init__.py
 create mode 100644 plugins/python/scripting/core.py

diff --git a/configure.ac b/configure.ac
index 04cb1ef..f467f66 100644
--- a/configure.ac
+++ b/configure.ac
@@ -467,6 +467,7 @@ AC_CONFIG_FILES([Makefile
                  plugins/python/apkfiles/Makefile
                  plugins/python/checksec/Makefile
                  plugins/python/liveconv/Makefile
+                 plugins/python/scripting/Makefile
                  plugins/readdex/Makefile
                  plugins/readelf/Makefile
                  plugins/readmc/Makefile
diff --git a/plugins/python/Makefile.am b/plugins/python/Makefile.am
index d094ccc..c96b6c5 100644
--- a/plugins/python/Makefile.am
+++ b/plugins/python/Makefile.am
@@ -3,4 +3,5 @@ SUBDIRS = \
 	abackup \
 	apkfiles \
 	checksec \
-	liveconv
+	liveconv \
+	scripting
diff --git a/plugins/python/scripting/Makefile.am b/plugins/python/scripting/Makefile.am
new file mode 100644
index 0000000..5d38d6e
--- /dev/null
+++ b/plugins/python/scripting/Makefile.am
@@ -0,0 +1,8 @@
+
+scriptingdir = $(pluginsdatadir)/python/scripting
+
+scripting_DATA = 							\
+	__init__.py								\
+	core.py
+
+EXTRA_DIST = $(scripting_DATA)
diff --git a/plugins/python/scripting/__init__.py b/plugins/python/scripting/__init__.py
new file mode 100644
index 0000000..82accc0
--- /dev/null
+++ b/plugins/python/scripting/__init__.py
@@ -0,0 +1,2 @@
+
+from scripting.core import ScriptingEngine as AutoLoad
diff --git a/plugins/python/scripting/core.py b/plugins/python/scripting/core.py
new file mode 100644
index 0000000..7aff551
--- /dev/null
+++ b/plugins/python/scripting/core.py
@@ -0,0 +1,101 @@
+
+from gi.repository import Gtk
+
+from pychrysalide import PluginModule
+from pychrysalide import core
+from pychrysalide.gui import core as gcore
+from pychrysalide.gtkext import EasyGtk
+
+
+class ScriptingEngine(PluginModule):
+    """Extend the GUI to run external Python scripts."""
+
+    _name = 'ScriptingEngine'
+    _desc = 'Run external Python scripts on demand'
+    _version = '0.1'
+    _url = 'https://www.chrysalide.re/'
+
+    _actions = ( )
+
+
+    def __init__(self):
+        """Initialize the plugin for Chrysalide."""
+
+        super(ScriptingEngine, self).__init__()
+
+        # Insert the new menu item into 'File' submenu
+
+        bar = gcore.find_editor_item_by_key('menubar')
+
+        builder = gcore.get_editor_builder()
+
+        file_menu = builder.get_object('file').get_submenu()
+        sep_item = builder.get_object('file_sep_1')
+        save_item = builder.get_object('file_save_project')
+
+        index = EasyGtk.find_contained_child_index(file_menu, save_item)
+
+        if index == -1:
+            raise RuntimeError('file menu not found')
+
+        prev = EasyGtk.get_nth_contained_child(file_menu, index - 1)
+
+        if sep_item == prev:
+
+            sep = Gtk.SeparatorMenuItem()
+            sep.show()
+
+            file_menu.insert(sep, index)
+
+        item = Gtk.MenuItem(label='Run Python script...')
+        item.connect("activate", self._on_file_run_script_activate)
+        item.show()
+
+        file_menu.insert(item, index)
+
+
+    def _on_file_run_script_activate(self, widget):
+        """Look for a new script to run."""
+
+        dialog = Gtk.FileChooserDialog(title='Please choose a Python script to execute',
+                                       transient_for=gcore.get_editor_window(),
+                                       action=Gtk.FileChooserAction.OPEN)
+
+        dialog.add_buttons(Gtk.STOCK_CANCEL,
+                           Gtk.ResponseType.CANCEL,
+                           Gtk.STOCK_OPEN,
+                           Gtk.ResponseType.OK)
+
+        ffilter = Gtk.FileFilter()
+        ffilter.set_name('Python files')
+        ffilter.add_mime_type('text/x-python')
+        dialog.add_filter(ffilter)
+
+        response = dialog.run()
+
+        if response == Gtk.ResponseType.OK:
+            filename = dialog.get_filename()
+        else:
+            filename = None
+
+        dialog.destroy()
+
+        if filename:
+            self._run_script_file(filename)
+
+
+    def _run_script_file(self, filename):
+        """Run a given script file."""
+
+        core.log_message(core.LogMessageType.INFO, 'Execute the script file \'%s\'' % filename)
+
+        try:
+            with open(filename, 'r') as fd:
+                content = fd.read()
+
+            code = compile(content, '<string>', 'exec')
+
+            eval(code)
+
+        except Exception as e:
+            core.log_message(core.LogMessageType.EXT_ERROR, 'Error while running the script: %s' % str(e))
-- 
cgit v0.11.2-87-g4458