diff --git a/docker_medley/init/ONLINE-INIT b/docker_medley/init/ONLINE-INIT old mode 100755 new mode 100644 index f1de5c9..cdcae72 --- a/docker_medley/init/ONLINE-INIT +++ b/docker_medley/init/ONLINE-INIT @@ -1,10 +1,15 @@ (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) -(FILECREATED "18-Mar-2025 22:45:51" {DSK}medley>il>ONLINE-INIT.;1 10668 +(FILECREATED "29-Oct-2025 23:56:02" {DSK}frank>il>medley>greetfiles>ONLINE-INIT.;2 11034 - :EDIT-BY "guest" + :EDIT-BY "FGH" - :PREVIOUS-DATE "17-Mar-2025 17:06:18" {DSK}medley>il>ONLINE-INIT.;1) + :CHANGES-TO (ADVICE (SAVEVM :IN \IDLER)) + (FNS Online.SftpInitInfo Online.SftpUpdateInfo Online.SetUpNOTECARDSDIRECTORIES + Online.DoInit ONLINEP Online.FileButton) + (VARS ONLINE-INITCOMS) + + :PREVIOUS-DATE "18-Mar-2025 22:45:51" {DSK}frank>il>medley>greetfiles>ONLINE-INIT.;1) (PRETTYCOMPRINT ONLINE-INITCOMS) @@ -149,6 +154,8 @@ (Online.DoInit [LAMBDA NIL + (* ;; "Edited 29-Oct-2025 23:55 by FGH") + (* ;; "Edited 16-Mar-2025 23:26 by guest") (* ;; "Edited 25-Feb-2024 11:37 by fgh") @@ -217,14 +224,15 @@ (RPLACA (CAR CHAT.DISPLAYTYPES) NIL) - (* ;; - "Setup NOTECARDSDIRECTORIES. Should be done it APPS-INIT. But until thats done, we'll do it here.") + (* ;; "Create File Import/Export Button") - (Online.SetUpNOTECARDSDIRECTORIES) + (Online.FileButton) - (* ;; "Create File Import/Export Button") + (* ;; "If there is a start-script file, load it ") - (Online.FileButton]) + (LET [(START-SCRIPT (UNIX-GETENV 'START_SCRIPT] + (IF START-SCRIPT + THEN (LOAD START-SCRIPT]) (ONLINEP [LAMBDA NIL (* ; "Edited 24-Feb-2024 22:31 by fgh") @@ -239,7 +247,7 @@ (BKSYSBUF " ") ) (DECLARE%: DONTCOPY - (FILEMAP (NIL (1640 10532 (Online.SftpInitInfo 1650 . 2523) (Online.SftpUpdateInfo 2525 . 2780) ( -Online.SetUpNOTECARDSDIRECTORIES 2782 . 4490) (Online.FileButton 4492 . 7320) (Online.DoInit 7322 . -10393) (ONLINEP 10395 . 10530))))) + (FILEMAP (NIL (1924 10898 (Online.SftpInitInfo 1934 . 2807) (Online.SftpUpdateInfo 2809 . 3064) ( +Online.SetUpNOTECARDSDIRECTORIES 3066 . 4774) (Online.FileButton 4776 . 7604) (Online.DoInit 7606 . +10759) (ONLINEP 10761 . 10896))))) STOP diff --git a/docker_medley/init/ONLINE-INIT.LCOM b/docker_medley/init/ONLINE-INIT.LCOM old mode 100755 new mode 100644 index c4462eb..a9e38cd Binary files a/docker_medley/init/ONLINE-INIT.LCOM and b/docker_medley/init/ONLINE-INIT.LCOM differ diff --git a/docker_medley/scripts/run-online-medley b/docker_medley/scripts/run-online-medley index c2befda..b6850f7 100755 --- a/docker_medley/scripts/run-online-medley +++ b/docker_medley/scripts/run-online-medley @@ -67,6 +67,20 @@ if [ $# -gt 1 ] && [ "$2" = "custom" ]; then fi fi # +unset START_SCRIPT +if [ -n "${START_SCRIPT_URL}" ] +then + export START_SCRIPT="${MEDLEY_USERDIR}/initdir/START-SCRIPT" + mkdir -p "$(dirname "${START_SCRIPT}")" + wget "${START_SCRIPT_URL}" -O "${START_SCRIPT}" + if [ $? -ne 0 ] + then + rm -f "${START_SCRIPT}" + unset START_SCRIPT + fi +fi +unset START_SCRIPT_URL +# if [ $# -gt 2 ]; then width=$3 else diff --git a/start-scripts/START-INSPHEX b/start-scripts/START-INSPHEX new file mode 100644 index 0000000..e66faa5 --- /dev/null +++ b/start-scripts/START-INSPHEX @@ -0,0 +1,60 @@ +(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) + +(FILECREATED " 7-Nov-2025 10:43:14" {DSK}frank>il>online>test>start-scripts>START-INSPHEX.;10 2342 + + :EDIT-BY "FGH" + + :CHANGES-TO (FNS START-INSPHEX) + (VARS START-INSPHEXCOMS) + + :PREVIOUS-DATE " 6-Nov-2025 20:45:51" +{DSK}frank>il>online>test>start-scripts>START-INSPHEX.;2) + + +(PRETTYCOMPRINT START-INSPHEXCOMS) + +(RPAQQ START-INSPHEXCOMS ((P (DEFPACKAGE "INSPHEX" (:USE "LISP" "XCL"))) + (FUNCTIONS TmpShellWget) + (FNS START-INSPHEX) + (P (START-INSPHEX)))) + +(DEFPACKAGE "INSPHEX" (:USE "LISP" "XCL")) + +(CL:DEFUN TmpShellWget (URL OUTFILENAME) + (LET* ((WGET (ShellWhich "wget")) + (OUTNAME (OUTFILEP OUTFILENAME)) + (UNIXNAME (LET [(UN (UNIX-FILE-NAME OUTNAME 'OUTPUT] + (if (STREQUAL (SUBSTRING UN (NCHARS UN)) + ".") + then (SUBSTRING UN 1 -2) + else UN))) + (CMD (CONCAT WGET " " URL " -O " UNIXNAME))) + (if (NULL WGET) + then (ERROR "ShellWget - wget not available")) + (ShellCommand CMD) + OUTNAME)) +(DEFINEQ + +(START-INSPHEX + [LAMBDA NIL (* ; "Edited 7-Nov-2025 10:43 by FGH") + (LET ((INSPHEX.FILE (CONCAT LOGINDIR ">INSPHEX")) + INSPHEX.DFASL) + (TmpShellWget "https://raw.githubusercontent.com/pamoroso/insphex/refs/heads/main/INSPHEX" + INSPHEX.FILE) + (SETQ INSPHEX.DFASL (CL:COMPILE-FILE INSPHEX.FILE)) + (LOAD INSPHEX.DFASL) + [ADVISE '(TEDIT IN INSPHEX::CREATE-HEX-WINDOW) + 'BEFORE + '(SETQ WINDOW (CREATEW (CREATEREGION (FIX (TIMES 0.35 SCREENWIDTH)) + (FIX (TIMES 0.25 SCREENHEIGHT)) + (FIX (TIMES 0.5 SCREENWIDTH)) + (FIX (TIMES 0.5 SCREENHEIGHT] + (ADD.PROCESS (LIST (CL:INTERN "HEXDUMP" (CL:FIND-PACKAGE "INSPHEX")) + (KWOTE INSPHEX.DFASL) + T]) +) + +(START-INSPHEX) +(DECLARE%: DONTCOPY + (FILEMAP (NIL (706 1299 (TmpShellWget 706 . 1299)) (1300 2298 (START-INSPHEX 1310 . 2296))))) +STOP diff --git a/start-scripts/START-INSPHEX.DFASL b/start-scripts/START-INSPHEX.DFASL new file mode 100644 index 0000000..f5c0927 Binary files /dev/null and b/start-scripts/START-INSPHEX.DFASL differ diff --git a/start-scripts/START-INSPHEX.URL b/start-scripts/START-INSPHEX.URL new file mode 100644 index 0000000..638101c --- /dev/null +++ b/start-scripts/START-INSPHEX.URL @@ -0,0 +1,2 @@ +https://online.interlisp.org:8081/guest?start=https%3A%2F%2Fgithub.com%2FInterlisp%2Fonline%2Fraw%2Frefs%2Fheads%2Ffgh_museum-mode%2Fstart-scripts%2FSTART-INSPHEX.DFASL + diff --git a/start-scripts/START-KINETIC b/start-scripts/START-KINETIC new file mode 100644 index 0000000..299ebba --- /dev/null +++ b/start-scripts/START-KINETIC @@ -0,0 +1,33 @@ +(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) + +(FILECREATED " 1-Nov-2025 13:41:38" {DSK}frank>il>medley>START-KINETIC.;2 1112 + + :EDIT-BY "FGH" + + :CHANGES-TO (FNS START-KINETIC) + + :PREVIOUS-DATE " 1-Nov-2025 13:21:22" {DSK}frank>il>medley>START-KINETIC.;1) + + +(PRETTYCOMPRINT START-KINETICCOMS) + +(RPAQQ START-KINETICCOMS ((FILES KINETIC) + (FNS START-KINETIC) + (P (START-KINETIC)))) + +(FILESLOAD KINETIC) +(DEFINEQ + +(START-KINETIC + [LAMBDA NIL (* ; "Edited 1-Nov-2025 13:41 by FGH") + (* ; "Edited 1-Nov-2025 13:15 by FGH") + (ADD.PROCESS '(KINETIC (CREATEW (CREATEREGION (FIX (TIMES 0.25 SCREENWIDTH)) + (FIX (TIMES 0.25 SCREENHEIGHT)) + (FIX (TIMES 0.5 SCREENWIDTH)) + (FIX (TIMES 0.5 SCREENHEIGHT]) +) + +(START-KINETIC) +(DECLARE%: DONTCOPY + (FILEMAP (NIL (517 1068 (START-KINETIC 527 . 1066))))) +STOP diff --git a/start-scripts/START-KINETIC.URL b/start-scripts/START-KINETIC.URL new file mode 100644 index 0000000..74d5447 --- /dev/null +++ b/start-scripts/START-KINETIC.URL @@ -0,0 +1 @@ +https://online.interlisp.org:8081/guest?start=https%3A%2F%2Fgithub.com%2FInterlisp%2Fonline%2Fraw%2Frefs%2Fheads%2Ffgh_museum-mode%2Fstart-scripts%2FSTART-KINETIC diff --git a/web-portal/client/js/main.js b/web-portal/client/js/main.js index 7e35457..ed89400 100644 --- a/web-portal/client/js/main.js +++ b/web-portal/client/js/main.js @@ -159,36 +159,7 @@ function startSession (interlispOrXterm) { .then( data => { const isRunning = data.isRunning; const sessionType = data.target; - if(isRunning) { - new Promise((resolve, reject) => { - const dlg = document.getElementById("reconnect-dialog"); - const typeEl = document.getElementById("rd-type-span"); - typeEl.html = sessionType; - dlg.resolve = resolve; - dlg.reject = reject; - dlg.showModal(); - } - ) - .then(RorK => { - window.location.assign( - `/medley/${interlispOrXterm || "interlisp"}` - + `?screen_width=${screenWidth}` - + `&screen_height=${screenHeight}` - + `&if=${RorK}` - + `&resume=${resume || "false"}` - + `&custom=${custom || "false"}` - + `&custom_init=${customInit || "false"}` - + `¬ecards=${runNotecards || "false"}` - + `&rooms=${runRooms || "false"}` - + `&sftp=${startSftp || "false"}` - + `&exec=${medleyExec || "inter"}` - + ( isAutoLogin ? "&autologin" : "") - ); - } - ); - } - else { - window.location.assign( + const medley_url = `/medley/${interlispOrXterm || "interlisp"}` + `?screen_width=${screenWidth}` + `&screen_height=${screenHeight}` @@ -200,8 +171,22 @@ function startSession (interlispOrXterm) { + `&sftp=${startSftp || "false"}` + `&exec=${medleyExec || "inter"}` + ( isAutoLogin ? "&autologin" : "") - ); + + ( (alStart != "") ? `&start=${encodeURIComponent(alStart)}` : "" ) + ; + + if(isRunning) { + new Promise((resolve, reject) => { + const dlg = document.getElementById("reconnect-dialog"); + const typeEl = document.getElementById("rd-type-span"); + typeEl.html = sessionType; + dlg.resolve = resolve; + dlg.reject = reject; + dlg.showModal(); + } + ) + .then(RorK => { window.location.assign(medley_url + `&if=${RorK}`); } ); } + else window.location.assign(medley_url); }, reason => {} ); diff --git a/web-portal/client/views/again.pug b/web-portal/client/views/again.pug index 7bf68f8..4554555 100644 --- a/web-portal/client/views/again.pug +++ b/web-portal/client/views/again.pug @@ -28,5 +28,5 @@ block headeradds block content .row.text-center#again-button - button.main-button(type="button" onclick='window.location.assign(decodeURI(alURL));')!= "Run Medley Again" + button.main-button(type="button" onclick='window.location.assign(decodeURIComponent(alURL));')!= "Run Medley Again" diff --git a/web-portal/client/views/main.pug b/web-portal/client/views/main.pug index 2cb826e..145f78c 100644 --- a/web-portal/client/views/main.pug +++ b/web-portal/client/views/main.pug @@ -26,6 +26,7 @@ block headeradds const alNotecards = #{notecards}; const alRooms = #{rooms}; const alURL = "#{alURL}"; + const alStart = "#{start}"; link(rel="stylesheet", href="/stylesheets/main.css") diff --git a/web-portal/client/views/relogin.pug b/web-portal/client/views/relogin.pug new file mode 100644 index 0000000..48ff28a --- /dev/null +++ b/web-portal/client/views/relogin.pug @@ -0,0 +1,46 @@ +//- + /*************************************************************************** + * + * relogin.pug: relogin page for online.interlisp.org web portal. + * + * 2025-11-09 Frank Halasz + * + * + * Copyright: 2025 by Interlisp.org + * + * + **************************************************************************/ + +extends layout + +block variables + +block headeradds + + link(rel="stylesheet", href="/stylesheets/login.css") + + script. + + document.getElementById("username").innerHTML = "#{loggedUsername}"; + + function Yes() { window.location.assign("#{redirectYes}"); } + + function No() { window.location.assign("#{redirectNo}"); } + +block content + + div#page-title Change Login? + + div#logged-in-as-div + p Currently logged in as: + p + p + p Keep current login? + p + p + .row + .text-center#yes_no_button_div + button(type="button" id="yes_button" onclick="Yes()").main-button No, log in again + button(type="button" id="no_button" onclick="No()").main-button Yes, continue with current login + + diff --git a/web-portal/server/js/app.js b/web-portal/server/js/app.js index 469fc84..ff0e326 100644 --- a/web-portal/server/js/app.js +++ b/web-portal/server/js/app.js @@ -110,26 +110,62 @@ app.get('/main', isAutoLogin: isAutoLogin, notecards: (req.query.notecards != undefined), rooms: (req.query.rooms != undefined), - alURL: alURL || "dummy" + alURL: alURL || "dummy", + start: (req.query.start != undefined) && (req.query.start != "") ? req.query.start : "" } ); } ); -app.get('/guest', - (req, res) => { - - const cookieUrl = encodeURI(`${req.protocol}://${req.get('host')}${req.originalUrl}`); - res.cookie('autologinURL', cookieUrl); - - const newQuery = {}; - newQuery.autologin = ""; - newQuery.username = config.guestUsername; - newQuery.password = config.guestPassword; - if(req.query.notecards != undefined) newQuery.notecards=""; - if(req.query.rooms != undefined) newQuery.rooms=""; - res.redirect(url.format({pathname:"/user/autologin", query: newQuery})); - } + +function autologinGoToMain(req, res, next) { + const cookieUrl = encodeURIComponent(`${req.protocol}://${req.get('host')}${req.originalUrl}`); + res.cookie('autologinURL', cookieUrl); + res.redirect(url.format({pathname:"/main", query: req.query})); +} + +function autologinReturnTo(req) { + return req.originalUrl + (req.originalUrl.includes("?") ? "&" : "?") + "autologin=true"; +} + +app.get([ '/guest', '/demo', '/demo/guest' ], + (req, res, next) => { + if(req.query.autologin === undefined) { + if (req.isAuthenticated && req.isAuthenticated()) { + req.logout(); + } + req.session.returnTo = autologinReturnTo(req); + let newQuery = {}; + newQuery.username = config.guestUsername; + newQuery.password = config.guestPassword; + res.redirect(url.format({pathname:"/user/autologin", query: newQuery})); + } + else next(); + }, + autologinGoToMain + ); + +app.get([ '/demo/login' ], + (req, res, next) => { + if(req.query.autologin === undefined) { + req.session.returnTo = autologinReturnTo(req); + if (req.isAuthenticated && req.isAuthenticated()) { + if (req.user.username == config.guestUsername) + res.redirect(url.format({ pathname:"/user/autologin", query:{logout: "true"} })); + else res.render('relogin', + { + loggedUsername: req.user.username, + redirectNo: url.format({ pathname:"/user/autologin", query:{} }), + redirectYes: url.format({ pathname:"/user/autologin", query:{logout: "true"} }) + } + ); + } + else res.redirect(url.format({ pathname:"/user/autologin", query:{} })); + } + else next(); + }, + autologinGoToMain ); + app.use('/user', userRouter); app.use('/medley', ensureLoggedIn(), medleyRouter); app.use('/client', ensureLoggedIn(), clientRouter); diff --git a/web-portal/server/js/medley.js b/web-portal/server/js/medley.js index bd6d7be..9d4914a 100644 --- a/web-portal/server/js/medley.js +++ b/web-portal/server/js/medley.js @@ -70,6 +70,13 @@ function medleyEnvs(req) { const nc = (req.query.notecards && (req.query.notecards.toLowerCase() == "true")) ? "true" : "false"; const rooms = (req.query.rooms && (req.query.rooms.toLowerCase() == "true")) ? "true" : "false"; const exec = (req.query.exec && (req.query.exec.toLowerCase() == "common")) ? "common" : "inter"; + var start = false; + var frank = 0; + try { + if ((req.query.start != undefined) && (req.query.start != "")) + start = req.query.start; + } + catch(e) { start = false; frank = 2;} return ` --env MEDLEY_EMAIL='${u.username}'` + ` --env MEDLEY_UNAME='${u.uname || "medley" }'` + ` --env MEDLEY_FIRSTNAME='${u.firstname || "Medley"}'` @@ -79,6 +86,7 @@ function medleyEnvs(req) { + ` --env RUN_ROOMS=${rooms}` + ` --env MEDLEY_EXEC=${exec}` + ` --env MEDLEY_MEMORY=${config.medleyMemoryArg}` + + ( start ? ` --env START_SCRIPT_URL="${start}"` : "" ) ; } diff --git a/web-portal/server/js/user.js b/web-portal/server/js/user.js index e09e808..b590299 100644 --- a/web-portal/server/js/user.js +++ b/web-portal/server/js/user.js @@ -20,6 +20,7 @@ const {userModel, loginModel} = require('./mongodb'); const validateEmail = require('email-addresses').parseOneAddress; const crypto = require('crypto'); const gmailSend = require('./gmail-send')({user: config.gmailUsername, pass: config.gmailPassword, from: config.gmailFrom }); +const util = require('util'); // // The router @@ -101,7 +102,13 @@ function passportAuthenticate(req, res, next) { if (!user) { console.dir(info); - return res.redirect('/user/login?info=' + info); + let redirectTo = "/user/login"; + if ((info !== undefined) && (info != "")) { + redirectTo = redirectTo + "?info="; + if ( (typeof info) == "string") redirectTo = redirectTo + encodeURIComponent(info); + else redirectTo = redirectTo + encodeURIComponent(util.inspect(info, {depth:0})); + } + return res.redirect(redirectTo); } @@ -120,18 +127,8 @@ function passportAuthenticate(req, res, next) { } catch (err) { console.log("Error in logging login: " + err); } - if(user.uname) - if ((user.uname == "guest") && (req.query.autologin != undefined)) { - const newQuery={}; - newQuery.autologin=""; - if(req.query.notecards != undefined) newQuery.notecards=""; - if(req.query.rooms != undefined) newQuery.rooms=""; - return res.redirect(url.format({pathname:"/main", query: newQuery})); - } - else - return res.redirect('/main'); - else - return res.render('reregister', {isNCO: config.isNCO(req)}); + if(user.uname) return res.redirect(req.session.returnTo); + else return res.render('reregister', {isNCO: config.isNCO(req)}); } } ); @@ -140,7 +137,13 @@ function passportAuthenticate(req, res, next) { } userRouter.post('/login', passportAuthenticate); -userRouter.get('/autologin', passportAuthenticate); +userRouter.get('/autologin', + (req, res, next) => { + if(req.query.logout !== undefined) req.logout(); + next(); + }, + passportAuthenticate + ); userRouter.get('/login', (req, res) => {