MUME REMOTE EDITING FOR JMC Built for JMC version 3.26 with VBScript enabled. (c) Rashnak 2004-02-11 1. INSTALLATION Modify the VBScript code in part 3 to your needs, then copy the code to settings\commonlib.scr in your JMC directory. If you have other scripts that implement Jmc_Incoming function, you have to be careful to combine them. Contact me if you have trouble doing that. 2. DOCUMENTATION This module implements MUME's remote editing protocol for JMC. It differs somewhat from the implementations in powwow or other clients, especially in the user interface, mainly because without messing with JMC source code, it's not easy to create this functionality any other way. USE AT YOUR OWN RISK! Here is the alias you need to set up: #alias edit #script EditEdit "%0" This alias accepts various parameters, which are now discussed in detail. >edit identify Sends MUME a client identification, telling that we CAN do remote editing. To actually CHOOSE remote editing over the standard line editor, you have to use this MUME command: >change editor mume Now you are set up for remote editing. Let's start with an example of changing your whois. When you enter "change whois" command, MUME will send a specially marked text to you, containing your current whois and other data. This script will recognise the pattern, decode the data, and save your current whois in a temporary file (in c:\mume by default). The script will then display this filename on the screen, where you can copy it and load the file MANUALLY in your favourite text editor. Important feature of the remote editing protocol is that you can continue playing in client window, while the text is being edited in another program. After you have made the changes in the whois, save the file and close it. One of the forementioned limitations of this imlementation is that the new whois will not be automatically sent to MUME. You can use the "edit" command to view currently open edit sessions: >edit 1 E c:\mume\tmp_edit_8028872.txt Whois 2 E c:\mume\tmp_edit_8028728.txt Description In this case, you have 2 open editing sessions. To send your new whois to MUME, do this: >edit 1 send This will send the whois to MUME and delete the local file. >edit 2 E c:\mume\tmp_edit_8028728.txt Description To cancel the remaining editing sessions: >edit 2 cancel >edit There are no open editing sessions! This may look complicated, but I did not find an easy way to interface external editor from active scripting, so this is better than nothing. Maybe in future someone will build a better implementation into JMC source code. 3. VBSCRIPT CODE '******************************************************* ' REMOTE EDITING: VBSCRIPT CODE STARTS HERE ' Configure as needed, and copy this to settings\commonlib.scr ' in your JMC directory. '******************************************************* ' SETTINGS, MODIFY THESE IF YOU WANT: ' Comment this setting if it is already defined in another module ' Const mumeDirectory = "c:\mume" ' INTERNAL VARIABLES: ' INTERNAL VARIABLES: ' File open modes ' Comment these if they are already defined elsewhere in your scripts: Const ForReading = 1, ForWriting = 2, ForAppending = 8 dim remoteEditingMCI remoteEditingMCI = "~$#EI" & vbCr dim remoteEditingMPI remoteEditingMPI = "~$#E" dim remoteEditingMPI_asRegEx remoteEditingMPI_asRegEx = "~\$#E" dim remoteEditing_RecOn remoteEditing_RecOn = false ' remoteEditingReceiver is used to receive data for editing/viewing Set remoteEditingReceiver = CreateObject("Scripting.Dictionary") ' remoteEditingSessionList contains a list of currently active ' editing/viewing sessions (keys: number.id, number.mode, number.title, number.data) Set remoteEditingSessionList = CreateObject("Scripting.Dictionary") '******************************************************* ' REMOTE EDITING: Jmc_Incoming ' This is the event handler for all lines coming from MUME. I try to ' separate my modules by category, so if a line from mud is identified ' as a narrate, for example, there is no need to look for a match in ' other categories. This may, in the long run, make up for the processing ' required by complex searches. Comment out those parts which you have ' not installed. '****************************************************** Sub Jmc_Incoming (line) dim match match = false ' EditIncoming has to be checked first here, otherwise ' you may get weird behaviour in certain cases. if (not match) then match = EditIncoming(line) if (match) then jmc.Event = "." jmc.DropEvent end if end if if (not match) then match = ComIncoming(line) end if End sub '******************************************************* ' REMOTE EDITING LIBRARY: EditIncoming (line) ' Checks the incoming line data related to MUME remote ' editing '****************************************************** Function EditIncoming (line) Dim regEx, Match, Matches, retVal retVal = false line = jmc.Event if (remoteEditing_RecOn) then retVal = true if (remoteEditingReceiver.item("line") = 0) then ' This is the first line if (remoteEditingReceiver.item("mode") = "E") then ' M50230552 --> get session ID remoteEditingReceiver.item("id") = right(line, len(line) - 1) end if if (remoteEditingReceiver.item("mode") = "V") then remoteEditingReceiver.item("id") = EditGenerateViewID remoteEditingReceiver.add "title", line end if remoteEditingReceiver.add "header", line & vbCr else if (remoteEditingReceiver.item("line") = 1 and remoteEditingReceiver.item("mode") = "E") then ' Enter new whois remoteEditingReceiver.add "title", line tempHeader = remoteEditingReceiver.item("header") & line & vbCr remoteEditingReceiver.remove("header") remoteEditingReceiver.add "header", tempHeader else ' Get real data tempData = remoteEditingReceiver.item("data") & line & vbCr remoteEditingReceiver.remove("data") remoteEditingReceiver.add "data", tempData end if end if if (len(remoteEditingReceiver.item("data")) + len(remoteEditingReceiver.item("header")) >= CInt(remoteEditingReceiver.item("size"))) then ' End of data remoteEditing_RecOn = false tempData = replace(remoteEditingReceiver.item("data"), vbCr, vbNewLine) remoteEditingReceiver.remove("data") remoteEditingReceiver.add "data", tempData EditStart end if tempLine = remoteEditingReceiver.item("line") + 1 remoteEditingReceiver.remove("line") remoteEditingReceiver.add "line", tempLine else Set regEx = New RegExp regEx.Pattern = "^" & remoteEditingMPI_asRegEx & "(\D)(\d+)$" if (regEx.Test(line)) then ' Editing protocol start Set matches = regEx.Execute(line) Set match = matches(0) remoteEditing_RecOn = true remoteEditingReceiver.removeAll remoteEditingReceiver.add "mode", match.SubMatches(0) remoteEditingReceiver.add "size", CInt(match.SubMatches(1)) remoteEditingReceiver.add "line", 0 retVal = true end if end if EditIncoming = retVal End Function '******************************************************* ' REMOTE EDITING LIBRARY: EditStart ' Start to edit or view the received data '****************************************************** Sub EditStart Dim editMode, fn, sessionNumber editMode = "edit" if (remoteEditingReceiver.item("mode") <> "E") then editMode = "view" end if fn = mumeDirectory & "\tmp_" & editMode & "_" & remoteEditingReceiver.item("id") & ".txt" Set fso = CreateObject("Scripting.FileSystemObject") Set stream = fso.OpenTextFile(fn, ForWriting, True) stream.Write remoteEditingReceiver.item("data") stream.Close() ' Give this session a number sessionNumber = EditGetFreeSessionNumber ' Create new active session remoteEditingSessionList.add sessionNumber & ".id", remoteEditingReceiver.item("id") remoteEditingSessionList.add sessionNumber & ".title", remoteEditingReceiver.item("title") remoteEditingSessionList.add sessionNumber & ".mode", remoteEditingReceiver.item("mode") remoteEditingSessionList.add sessionNumber & ".data", remoteEditingReceiver.item("data") ' Display filename jmc.ShowMe "Remote editing session " & sessionNumber & ": " & fn ' Clear receiver structure remoteEditingReceiver.removeAll End Sub '******************************************************* ' REMOTE EDITING LIBRARY: EditSend (number) ' End editing, send data to MUME if it was modifed and ' close editing session. '****************************************************** Sub EditSend(number) Dim fn, tempChanged, buf if ((not remoteEditingSessionList.exists(number & ".id")) or _ remoteEditingSessionList.item(number & ".id") = "") then jmc.ShowMe "Invalid session number" exit sub end if if (remoteEditingSessionList.item(number & ".mode") <> "E") then jmc.ShowMe "This session is for viewing only." exit sub end if fn = mumeDirectory & "\tmp_edit_" & remoteEditingSessionList.item(number & ".id") & ".txt" Set fso = CreateObject("Scripting.FileSystemObject") Set stream = fso.OpenTextFile(fn, ForReading, True) tempData = "" if stream.AtEndOfStream <> True then tempData = stream.ReadAll end if stream.Close() fso.DeleteFile(fn) tempChanged = false if (tempData <> remoteEditingSessionList.item(number & ".data")) then tempChanged = true end if remoteEditingSessionList.remove(number & ".data") remoteEditingSessionList.add number & ".data", tempData if (tempChanged and remoteEditingSessionList.item(number & ".mode") = "E") then ' Send data to MUME jmc.showme "Data changed." tempData = replace(tempData, vbNewLine, vbCr) buf = "_" & remoteEditingSessionList.item(number & ".id") & "_" buf = remoteEditingMPI & "E" & (len(buf) + len(tempData)) & vbCr & _ remoteEditingSessionList.item(number & ".mode") & _ remoteEditingSessionList.item(number & ".id") jmc.send(buf) ' Send edited file one line at a time lines = Split(tempData, vbCr, -1) For Each line in lines jmc.send line & vbCr Next EditCancel number else jmc.showme "No changes!" EditCancel number end if End Sub '******************************************************* ' REMOTE EDITING LIBRARY: EditCancel (number) ' Cancel editing, don't send data back to MUME. '****************************************************** Sub EditCancel(number) dim keystr, buf, editMode keystr = "C" & remoteEditingSessionList.item(number & ".id") & vbCr buf = remoteEditingMPI & "E" & Len(keystr) & vbCr & keystr jmc.output "MUME Edit: Cancel" jmc.send(buf) editMode = "edit" if (remoteEditingSessionList.item(i & ".mode") <> "E") then editMode = "view" end if fn = mumeDirectory & "\tmp_" & editMode & "_" & remoteEditingSessionList.item(number & ".id") & ".txt" Set fso = CreateObject("Scripting.FileSystemObject") if (fso.FileExists(fn)) then fso.DeleteFile(fn) end if remoteEditingSessionList.remove(number & ".id") remoteEditingSessionList.remove(number & ".mode") remoteEditingSessionList.remove(number & ".title") remoteEditingSessionList.remove(number & ".data") End Sub '******************************************************* ' REMOTE EDITING LIBRARY: EditGetFreeSessionNumber ' Returns next available session number '****************************************************** Function EditGetFreeSessionNumber dim tempNumber tempNumber = 100 while (tempNumber > 0 And Not remoteEditingSessionList.exists(tempNumber & ".id")) tempNumber = tempNumber - 1 wend tempNumber = tempNumber + 1 EditGetFreeSessionNumber = tempNumber End Function '******************************************************* ' REMOTE EDITING LIBRARY: EditGenerateViewID ' Generates a number for viewing session id '****************************************************** Function EditGenerateViewID dim tempNumber tempNumber = 10000000 fn = mumeDirectory & "\tmp_view_" & tempNumber & ".txt" Set fso = CreateObject("Scripting.FileSystemObject") while (tempNumber < 99999998 and fso.FileExists(fn)) tempNumber = tempNumber + 1 fn = mumeDirectory & "\tmp_view_" & tempNumber & ".txt" wend EditGenerateViewID = tempNumber End Function '******************************************************* ' REMOTE EDITING LIBRARY: EditIdentify ' Tells MUME that we can handle remote editing '****************************************************** Sub EditIdentify jmc.send(remoteEditingMCI) End Sub '******************************************************* ' REMOTE EDITING LIBRARY: EditList ' Display list of active edit sessions '****************************************************** Sub EditList Dim sessions, editMode, fn sessions = EditGetFreeSessionNumber - 1 For i = 1 to sessions If (remoteEditingSessionList.exists(i & ".id") and _ remoteEditingSessionList.item(i & ".id") <> "") Then editMode = "edit" if (remoteEditingSessionList.item(i & ".mode") <> "E") then editMode = "view" end if fn = mumeDirectory & "\tmp_" & editMode & "_" & _ remoteEditingSessionList.item(i & ".id") & ".txt" sessionStr = i & " " & remoteEditingSessionList.item(i & ".mode") & _ " " & fn & " " & remoteEditingSessionList.item(i & ".title") jmc.ShowMe(sessionStr) End If Next End Sub '******************************************************* ' REMOTE EDITING LIBRARY: EditEdit (line) ' Main user interface ' >edit [number] [s(end|ave)|c(ancel)] '****************************************************** Sub EditEdit(line) dim number, cmd if (line = "" or line = "list") then ' No parameters, display list of active edit sessions EditList exit sub end if if (line = "identify") then EditIdentify exit sub end if ' Parse session number and command number = 1 cmd = "send" Dim regEx Set regEx = New RegExp regEx.Pattern = "\s" If (regEx.Test(line)) Then Dim lineArr lineArr = Split(line, " ", 2) number = lineArr(0) cmd = lineArr(1) End if cmd = left(cmd, 1) if (not remoteEditingSessionList.exists(number & ".id")) then jmc.showme "Edit session " & number & " does not exist!" exit sub end if if (cmd = "s") then EditSend number end if if (cmd = "c") then EditCancel number end if End Sub