/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * 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 . */ #include "config.h" #include #include #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, PikaPlugIn) struct _ScriptFuServer { PikaPlugIn parent_instance; }; static GList * script_fu_server_query_procedures (PikaPlugIn *plug_in); static PikaProcedure * script_fu_server_create_procedure (PikaPlugIn *plug_in, const gchar *name); static PikaValueArray * script_fu_server_outer_run (PikaProcedure *procedure, const PikaValueArray *args, gpointer run_data); static void script_fu_server_run_init (PikaProcedure *procedure, PikaRunMode run_mode); G_DEFINE_TYPE (ScriptFuServer, script_fu_server, PIKA_TYPE_PLUG_IN) PIKA_MAIN (SCRIPT_FU_SERVER_TYPE) DEFINE_STD_SET_I18N static void script_fu_server_class_init (ScriptFuServerClass *klass) { PikaPlugInClass *plug_in_class = PIKA_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 (PikaPlugIn *plug_in) { GList *list = NULL; list = g_list_append (list, g_strdup ("plug-in-script-fu-server")); return list; } static PikaProcedure * script_fu_server_create_procedure (PikaPlugIn *plug_in, const gchar *name) { PikaProcedure *procedure = NULL; /* The run func script_fu_server_outer_run is defined in this source file. */ procedure = pika_procedure_new (plug_in, name, PIKA_PDB_PROC_TYPE_PLUGIN, script_fu_server_outer_run, NULL, NULL); pika_procedure_set_menu_label (procedure, _("_Start Server...")); pika_procedure_add_menu_path (procedure, "/Filters/Development/Script-Fu"); pika_procedure_set_documentation (procedure, _("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 PIKA 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); pika_procedure_set_attribution (procedure, "Spencer Kimball & Peter Mattis", "Spencer Kimball & Peter Mattis", "1997"); PIKA_PROC_ARG_ENUM (procedure, "run-mode", "Run mode", "The run mode", PIKA_TYPE_RUN_MODE, PIKA_RUN_INTERACTIVE, G_PARAM_READWRITE); PIKA_PROC_ARG_STRING (procedure, "ip", "IP", "The IP on which to listen for requests", NULL, G_PARAM_READWRITE); PIKA_PROC_ARG_INT (procedure, "port", "Port", "The port on which to listen for requests", 0, G_MAXINT, 0, G_PARAM_READWRITE); /* FUTURE: PIKA_PROC_ARG_FILE, but little benefit, need change script-fu-server.c */ PIKA_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 PIKA 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 PIKA: * pika -i --batch-interpreter='plug-in-script-fu-eval' " -c '(plug-in-script-fu-server 1 "127.0.0.1" 10008 "/tmp/pika-log")' * * Execute the binary from command line fails with: * "script-fu-server is a PIKA plug-in and must be run by PIKA 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 "(pika-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 PIKA process. * Quitting or killing the parent process also kills the server. */ static PikaValueArray * script_fu_server_outer_run (PikaProcedure *procedure, const PikaValueArray *args, gpointer run_data) { PikaValueArray *return_vals = NULL; if (pika_value_array_length (args) > 0) script_fu_server_run_init (procedure, PIKA_VALUES_GET_ENUM (args, 0)); else script_fu_server_run_init (procedure, PIKA_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 "(pika-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 (PikaProcedure *procedure, PikaRunMode 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); }