ScriptFu: extract PDB proc script-fu-server from plugin script-fu

Create new plugin file script-fu-server-plugin.c
with code extracted from script-fu.c, which is an omnibus plugin
implementing PDB proc extension-script-fu and other PDB procs.

Why:

1. extension-script-fu is smaller and doesn't doesn't link to socket libraries.
   (GIMP always starts extension-script-fu and it stays running.)

2. packagers/admins can omit script-fu-server executable from an installation,
   if they think letting users serve net ports is not secure.

3. crashing script-fu-server does not crash extension-script-fu,
   which requires restart of GIMP

The changes are mostly a simple refactor, extracting code.
No functional change apparent to users.
Low risk of introduced bugs.
Extremely few users use script-fu-server anyway.
Added some logging.
While at it, use G_DECLARE_FINAL_TYPE
This commit is contained in:
lloyd konneker 2022-06-13 16:13:36 -04:00 committed by Lloyd Konneker
parent 4e3edb5121
commit 07ceb5a086
16 changed files with 434 additions and 129 deletions

View File

@ -3154,6 +3154,7 @@ plug-ins/script-fu/Makefile
plug-ins/script-fu/libscriptfu/Makefile
plug-ins/script-fu/libscriptfu/ftx/Makefile
plug-ins/script-fu/libscriptfu/tinyscheme/Makefile
plug-ins/script-fu/server/Makefile
plug-ins/script-fu/scripts/Makefile
plug-ins/script-fu/scripts/images/Makefile
plug-ins/selection-to-path/Makefile

View File

@ -36,10 +36,7 @@ AM_CPPFLAGS = \
$(GEGL_CFLAGS) \
-I$(includedir) \
-I$(srcdir)/libscriptfu \
-DG_LOG_DOMAIN=\"scriptfu\" \
-DSTANDALONE=0 \
-DUSE_INTERFACE=1 \
-DUSE_STRLWR=0
-DG_LOG_DOMAIN=\"scriptfu\"
AM_CFLAGS = \
$(xobjective_c)
@ -52,11 +49,12 @@ AM_LDFLAGS = \
$(framework_cocoa) \
$(xnone)
SUBDIRS = libscriptfu scripts
SUBDIRS = libscriptfu scripts server
libexecdir = $(gimpplugindir)/plug-ins/script-fu
# Each plugin must be installed in a dir of the same name as the executable
script_fudir = $(gimpplugindir)/plug-ins/script-fu
libexec_PROGRAMS = script-fu
script_fu_PROGRAMS = script-fu
script_fu_SOURCES = \
script-fu.c \
@ -66,12 +64,10 @@ script_fu_SOURCES = \
script-fu-eval.c \
script-fu-eval.h \
script-fu-text-console.h \
script-fu-text-console.c \
script-fu-server.c \
script-fu-server.h
script-fu-text-console.c
# link with libgimp-scriptfu and the usual gimp suspects
# LibTool will add rpath to private shared libgimp-scriptfu in gimppluginsdir/lib
script_fu_LDADD = \
$(libgimp_scriptfu) \
$(libgimpui) \
@ -82,8 +78,6 @@ script_fu_LDADD = \
$(libgimpcolor) \
$(libgimpbase) \
$(GTK_LIBS) \
$(SOCKET_LIBS) \
$(WINSOCK_LIBS) \
$(RT_LIBS) \
$(INTLLIBS) \
$(script_fu_RC)

View File

@ -171,6 +171,8 @@ tinyscheme_init (GList *path,
{
GList *list;
g_debug ("Loading init and compat scripts.");
for (list = path; list; list = g_list_next (list))
{
gchar *dir = g_file_get_path (list->data);
@ -198,6 +200,8 @@ tinyscheme_init (GList *path,
if (list == NULL)
g_warning ("Unable to read initialization file script-fu.init\n");
}
else
g_warning ("Not loading initialization or compatibility scripts.");
}
/* Create an SF-RUN-MODE constant for use in scripts.

View File

@ -139,3 +139,37 @@ script_fu_register_post_command_callback (void (*func) (void))
{
ts_register_post_command_callback (func);
}
/*
* Return list of paths to directories containing .scm and .init scripts.
* Usually at least GIMP's directory named like "/scripts."
* List can also contain dirs custom or private to a user.
" The GIMP dir often contain: plugins, init scripts, and utility scripts.
*
* Caller must free the returned list.
*/
GList *
script_fu_search_path (void)
{
gchar *path_str;
GList *path = NULL;
path_str = gimp_gimprc_query ("script-fu-path");
if (path_str)
{
GError *error = NULL;
path = gimp_config_path_expand_to_files (path_str, &error);
g_free (path_str);
if (! path)
{
g_warning ("Can't convert script-fu-path to filesystem encoding: %s",
error->message);
g_clear_error (&error);
}
}
return path;
}

View File

@ -20,6 +20,7 @@
gboolean script_fu_extension_is_busy (void);
GList * script_fu_search_path (void);
void script_fu_find_and_register_scripts (GimpPlugIn *plugin,
GList *paths);

View File

@ -12,3 +12,4 @@ EXPORTS
script_fu_run_read_eval_print_loop
script_fu_register_quit_callback
script_fu_register_post_command_callback
script_fu_search_path

View File

@ -1,22 +1,26 @@
# Build the one executable that defines five PDB procs.
# The executable is not versioned since installed private in /plug-ins
# Build executable plugins that define several PDB procs.
# An executable is not versioned since installed private in /plug-ins
# Not define include_directories; no higher gimp source references scriptfu
# Not using c_args: -DSTANDALONE=0','-DUSE_INTERFACE=1','-DUSE_STRLWR=0',
# since those are compile time switches for tinyscheme, not present in this dir
subdir('libscriptfu')
subdir('scripts')
subdir('server')
executable_name = 'script-fu'
# script-fu.c registers registers many PDB procs in the PDB.
# Four source files implement the PDB procedures of type PLUGIN, of similar names.
# Several source files implement the PDB procedures of type PLUGIN, of similar names.
# script-fu.c also implements PDB procedure of type EXTENSION "extension-script-fu"
plugin_sources = [
'script-fu-console.c',
'script-fu-eval.c',
'script-fu-server.c',
'script-fu-text-console.c',
'script-fu.c',
@ -24,7 +28,7 @@ plugin_sources = [
if platform_windows
plugin_sources += windows.compile_resources(
gimp_plugins_rc,
plugin_rc,
args: [
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(executable_name+'.exe'),
'--define', 'INTERNALNAME_STR="@0@"' .format(executable_name),
@ -37,7 +41,6 @@ if platform_windows
endif
# Several components use Gtk
# script-fu-server uses sockets
# libscriptfu is installed to standard place; no rpath necessary
@ -46,13 +49,9 @@ executable(executable_name,
dependencies: [
libgimpui_dep,
math,
winsock,
],
c_args: [
'-DG_LOG_DOMAIN="scriptfu"',
'-DSTANDALONE=0',
'-DUSE_INTERFACE=1',
'-DUSE_STRLWR=0',
],
include_directories: [
libscriptfuInclude,

View File

@ -23,32 +23,20 @@
#include "script-fu-console.h"
#include "script-fu-eval.h"
#include "script-fu-server.h"
#include "script-fu-text-console.h"
#include "libscriptfu/script-fu-lib.h"
#include "libscriptfu/script-fu-intl.h"
typedef struct _ScriptFu ScriptFu;
typedef struct _ScriptFuClass ScriptFuClass;
#define SCRIPT_FU_TYPE (script_fu_get_type ())
G_DECLARE_FINAL_TYPE (ScriptFu, script_fu, SCRIPT, FU, GimpPlugIn)
struct _ScriptFu
{
GimpPlugIn parent_instance;
};
struct _ScriptFuClass
{
GimpPlugInClass parent_class;
};
#define SCRIPT_FU_TYPE (script_fu_get_type ())
#define SCRIPT_FU (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SCRIPT_FU_TYPE, ScriptFu))
GType script_fu_get_type (void) G_GNUC_CONST;
static GList * script_fu_query_procedures (GimpPlugIn *plug_in);
static GimpProcedure * script_fu_create_procedure (GimpPlugIn *plug_in,
const gchar *name);
@ -63,7 +51,6 @@ static GimpValueArray * script_fu_batch_run (GimpProcedure *proced
gpointer run_data);
static void script_fu_run_init (GimpProcedure *procedure,
GimpRunMode run_mode);
static GList * script_fu_search_path (void);
static void script_fu_extension_init (GimpPlugIn *plug_in);
static GimpValueArray * script_fu_refresh_proc (GimpProcedure *procedure,
const GimpValueArray *args,
@ -99,7 +86,6 @@ script_fu_query_procedures (GimpPlugIn *plug_in)
list = g_list_append (list, g_strdup ("extension-script-fu"));
list = g_list_append (list, g_strdup ("plug-in-script-fu-console"));
list = g_list_append (list, g_strdup ("plug-in-script-fu-text-console"));
list = g_list_append (list, g_strdup ("plug-in-script-fu-server"));
list = g_list_append (list, g_strdup ("plug-in-script-fu-eval"));
return list;
@ -179,59 +165,6 @@ script_fu_create_procedure (GimpPlugIn *plug_in,
GIMP_RUN_INTERACTIVE,
G_PARAM_READWRITE);
}
else if (! strcmp (name, "plug-in-script-fu-server"))
{
procedure = gimp_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
script_fu_run, NULL, NULL);
gimp_procedure_set_menu_label (procedure, N_("_Start Server..."));
gimp_procedure_add_menu_path (procedure,
"<Image>/Filters/Development/Script-Fu");
gimp_procedure_set_documentation (procedure,
N_("Server for remote Script-Fu "
"operation"),
"Provides a server for remote "
"script-fu operation. NOTE that for "
"security reasons this procedure's "
"API was changed in an incompatible "
"way since GIMP 2.8.12. You now have "
"to pass the IP to listen on as "
"first parameter. Calling this "
"procedure with the old API will "
"fail on purpose.",
name);
gimp_procedure_set_attribution (procedure,
"Spencer Kimball & Peter Mattis",
"Spencer Kimball & Peter Mattis",
"1997");
GIMP_PROC_ARG_ENUM (procedure, "run-mode",
"Run mode",
"The run mode",
GIMP_TYPE_RUN_MODE,
GIMP_RUN_INTERACTIVE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_STRING (procedure, "ip",
"IP",
"The IP on which to listen for requests",
NULL,
G_PARAM_READWRITE);
GIMP_PROC_ARG_INT (procedure, "port",
"Port",
"The port on which to listen for requests",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
GIMP_PROC_ARG_STRING (procedure, "logfile",
"Log File",
"The file to log activity to",
NULL,
G_PARAM_READWRITE);
}
else if (! strcmp (name, "plug-in-script-fu-eval"))
{
procedure = gimp_batch_procedure_new (plug_in, name, "Script-fu (scheme)",
@ -295,14 +228,6 @@ script_fu_run (GimpProcedure *procedure,
return_vals = script_fu_console_run (procedure, args);
}
else if (strcmp (name, "plug-in-script-fu-server") == 0)
{
/*
* The script-fu server for remote operation
*/
return_vals = script_fu_server_run (procedure, args);
}
if (! return_vals)
return_vals = gimp_procedure_new_return_values (procedure,
@ -377,32 +302,6 @@ script_fu_run_init (GimpProcedure *procedure,
g_list_free_full (path, (GDestroyNotify) g_object_unref);
}
static GList *
script_fu_search_path (void)
{
gchar *path_str;
GList *path = NULL;
path_str = gimp_gimprc_query ("script-fu-path");
if (path_str)
{
GError *error = NULL;
path = gimp_config_path_expand_to_files (path_str, &error);
g_free (path_str);
if (! path)
{
g_warning ("Can't convert script-fu-path to filesystem encoding: %s",
error->message);
g_clear_error (&error);
}
}
return path;
}
static void
script_fu_extension_init (GimpPlugIn *plug_in)
{

6
plug-ins/script-fu/server/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/Makefile.in
/Makefile
/.deps
/_libs
/.libs
/script-fu-server.exe

View File

@ -0,0 +1,79 @@
## Process this file with automake to produce Makefile.in
if PLATFORM_OSX
xobjective_c = "-xobjective-c"
xobjective_cxx = "-xobjective-c++"
xnone = "-xnone"
framework_cocoa = -framework Cocoa
endif
if OS_WIN32
mwindows = -mwindows
WINSOCK_LIBS = -lws2_32
else
libm = -lm
endif
libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la $(libm)
# link to libscriptfu
libgimp_scriptfu = $(top_builddir)/plug-ins/script-fu/libscriptfu/libgimp-scriptfu-$(GIMP_API_VERSION).la
if HAVE_WINDRES
include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
script_fu_server_RC = script-fu-server.rc.o
endif
# include srcdir parent to find libscriptfu include files
AM_CPPFLAGS = \
-I$(top_srcdir) \
$(GTK_CFLAGS) \
$(GEGL_CFLAGS) \
-I$(includedir) \
-I$(srcdir)/.. \
-DG_LOG_DOMAIN=\"scriptfu\"
AM_CFLAGS = \
$(xobjective_c)
AM_CXXFLAGS = \
$(xobjective_cxx)
AM_LDFLAGS = \
$(mwindows) \
$(framework_cocoa) \
$(xnone)
# Each plugin must be installed in a dir of the same name as the executable
script_fu_serverdir = $(gimpplugindir)/plug-ins/script-fu-server
script_fu_server_PROGRAMS = script-fu-server
script_fu_server_SOURCES = \
script-fu-server.c \
script-fu-server.h \
script-fu-server-plugin.c
# link with libgimp-scriptfu and the usual gimp suspects
# Also link w socket libs
script_fu_server_LDADD = \
$(libgimp_scriptfu) \
$(libgimpui) \
$(libgimpwidgets) \
$(libgimpconfig) \
$(libgimpmath) \
$(libgimp) \
$(libgimpcolor) \
$(libgimpbase) \
$(GTK_LIBS) \
$(SOCKET_LIBS) \
$(WINSOCK_LIBS) \
$(RT_LIBS) \
$(INTLLIBS) \
$(script_fu_server_RC)

View File

@ -0,0 +1,47 @@
scriptfuInclude = include_directories('..')
executable_name = 'script-fu-server'
plugin_sources = [
'script-fu-server.c',
'script-fu-server-plugin.c',
]
if platform_windows
plugin_sources += windows.compile_resources(
plugin_rc,
args: [
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(executable_name+'.exe'),
'--define', 'INTERNALNAME_STR="@0@"' .format(executable_name),
'--define', 'TOP_SRCDIR="@0@"' .format(meson.source_root()),
],
include_directories: [
rootInclude, appInclude,
],
)
endif
# The differences from the script-fu executable:
# name and sources
# also links with winsock
# Note the server rolls its own log, no need for a different G_LOG_DOMAIN
executable(executable_name,
plugin_sources,
dependencies: [
libgimpui_dep,
math,
winsock,
],
c_args: [
'-DG_LOG_DOMAIN="scriptfu"',
],
include_directories: [
scriptfuInclude,
],
link_with : libscriptfu,
install: true,
install_dir: gimpplugindir / 'plug-ins' / executable_name,
)

View File

@ -0,0 +1,240 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <libgimp/gimp.h>
#include "script-fu-server.h"
#include "libscriptfu/script-fu-lib.h"
#include "libscriptfu/script-fu-intl.h"
#define SCRIPT_FU_SERVER_TYPE (script_fu_server_get_type ())
G_DECLARE_FINAL_TYPE (ScriptFuServer, script_fu_server, SCRIPT, FU_SERVER, GimpPlugIn)
struct _ScriptFuServer
{
GimpPlugIn parent_instance;
};
static GList * script_fu_server_query_procedures (GimpPlugIn *plug_in);
static GimpProcedure * script_fu_server_create_procedure (GimpPlugIn *plug_in,
const gchar *name);
static GimpValueArray * script_fu_server_outer_run (GimpProcedure *procedure,
const GimpValueArray *args,
gpointer run_data);
static void script_fu_server_run_init (GimpProcedure *procedure,
GimpRunMode run_mode);
G_DEFINE_TYPE (ScriptFuServer, script_fu_server, GIMP_TYPE_PLUG_IN)
GIMP_MAIN (SCRIPT_FU_SERVER_TYPE)
DEFINE_STD_SET_I18N
static void
script_fu_server_class_init (ScriptFuServerClass *klass)
{
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
plug_in_class->query_procedures = script_fu_server_query_procedures;
plug_in_class->create_procedure = script_fu_server_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
static void
script_fu_server_init (ScriptFuServer *script_fu_server)
{
}
static GList *
script_fu_server_query_procedures (GimpPlugIn *plug_in)
{
GList *list = NULL;
list = g_list_append (list, g_strdup ("plug-in-script-fu-server"));
return list;
}
static GimpProcedure *
script_fu_server_create_procedure (GimpPlugIn *plug_in,
const gchar *name)
{
GimpProcedure *procedure = NULL;
/* The run func script_fu_server_outer_run is defined in this source file. */
procedure = gimp_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
script_fu_server_outer_run, NULL, NULL);
gimp_procedure_set_menu_label (procedure, N_("_Start Server..."));
gimp_procedure_add_menu_path (procedure,
"<Image>/Filters/Development/Script-Fu");
gimp_procedure_set_documentation (procedure,
N_("Server for remote Script-Fu "
"operation"),
"Provides a server for remote "
"script-fu operation. NOTE that for "
"security reasons this procedure's "
"API was changed in an incompatible "
"way since GIMP 2.8.12. You now have "
"to pass the IP to listen on as "
"first parameter. Calling this "
"procedure with the old API will "
"fail on purpose.",
name);
gimp_procedure_set_attribution (procedure,
"Spencer Kimball & Peter Mattis",
"Spencer Kimball & Peter Mattis",
"1997");
GIMP_PROC_ARG_ENUM (procedure, "run-mode",
"Run mode",
"The run mode",
GIMP_TYPE_RUN_MODE,
GIMP_RUN_INTERACTIVE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_STRING (procedure, "ip",
"IP",
"The IP on which to listen for requests",
NULL,
G_PARAM_READWRITE);
GIMP_PROC_ARG_INT (procedure, "port",
"Port",
"The port on which to listen for requests",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
/* FUTURE: GIMP_PROC_ARG_FILE, but little benefit, need change script-fu-server.c */
GIMP_PROC_ARG_STRING (procedure, "logfile",
"Log File",
"The file to log activity to",
NULL,
G_PARAM_READWRITE);
return procedure;
}
/*
* Test cases:
*
* Normal starting is from GIMP GUI: "Filters>Development>Script-Fu>Start server...""
* Expect a dialog to enter IP, etc.
* Expect a console msg: "ScriptFu server: initialized and listening...""
*
* Does not have settings. After the above,
* Expect "Filters>Repeat Last" and "Reshow Last" to be disabled (greyed out)
*
* Execute the server from headless GIMP:
* gimp -i --batch-interpreter='plug-in-script-fu-eval'
" -c '(plug-in-script-fu-server 1 "127.0.0.1" 10008 "/tmp/gimp-log")'
*
* Execute the binary from command line fails with:
* "script-fu-server is a GIMP plug-in and must be run by GIMP to be used"
*
* The PDB procedure plug-in-script-fu-server CAN be called from another procedure
* (but shouldn't be.)
* Expect plug-in-script-fu-server to never return
*/
/*
* ScriptFu Server listens and responds to clients.
* The server responds with a success indication,
* and a string representation of the result
* (a representation in Lisp, human-readable but also interpretable.)
* A client may also expect side-effects, e.g. on images and image files.
*
* The server has its own logging.
* Its logging defaults to stdout, but optionally to a file.
* The server logs errors in interpretation of the stream from the client.
*
* A client may quit the server by eval "(gimp-quit)"
* Otherwise, the server blocks on IO from the client.
*
* A server that dies leaves the client with a broken connection,
* but does not affect extension-script-fu.
*
* A server is a child process of a GIMP process.
* Quitting or killing the parent process also kills the server.
*/
static GimpValueArray *
script_fu_server_outer_run (GimpProcedure *procedure,
const GimpValueArray *args,
gpointer run_data)
{
GimpValueArray *return_vals = NULL;
if (gimp_value_array_length (args) > 0)
script_fu_server_run_init (procedure, GIMP_VALUES_GET_ENUM (args, 0));
else
script_fu_server_run_init (procedure, GIMP_RUN_NONINTERACTIVE);
/* Remind any users watching the console. */
g_debug ("Starting. Further logging by server might be to a log file.");
/*
* Call the inner run func, defined in script-fu-server.c
* !!! This does not return unless a client evals "(gimp-quit)"
*/
return_vals = script_fu_server_run (procedure, args);
/*
* The server returns SUCCESS but no other values (to the caller)
* if it was quit properly.
* The server also returns ERROR if it can't start properly.
*/
g_assert (return_vals != NULL);
return return_vals;
}
/*
* The server is just the interpreter.
* It does not register any scripts as TEMPORARY procs.
* extension-script-fu should also be running, to register its TEMPORARY procs
* (those defined by .scm files in /scripts)
* in the PDB, and to execute the TEMPORARY PDB procs.
*
* We do load initialization and compatibility scripts.
*/
static void
script_fu_server_run_init (GimpProcedure *procedure,
GimpRunMode run_mode)
{
GList *path;
/*
* Non-null path so we load init and compat scripts
* which are jumbled in same dir as TEMPORARY procedure scripts.
*/
path = script_fu_search_path ();
/* Init the interpreter, not allow register scripts */
script_fu_init_embedded_interpreter (path, FALSE, run_mode);
g_list_free_full (path, (GDestroyNotify) g_object_unref);
}

View File

@ -96,8 +96,8 @@ typedef short sa_family_t; /* Not defined by winsock */
#include "libgimp/gimp.h"
#include "libgimp/gimpui.h"
#include "script-fu-intl.h"
#include "script-fu-lib.h"
#include "libscriptfu/script-fu-lib.h"
#include "libscriptfu/script-fu-intl.h"
#include "script-fu-server.h"

View File

@ -6,7 +6,7 @@
plug-ins/script-fu/script-fu.c
plug-ins/script-fu/script-fu-console.c
plug-ins/script-fu/script-fu-eval.c
plug-ins/script-fu/script-fu-server.c
plug-ins/script-fu/server/script-fu-server.c
plug-ins/script-fu/libscriptfu/script-fu-interface.c
plug-ins/script-fu/libscriptfu/script-fu-scripts.c
plug-ins/script-fu/script-fu-text-console.c