; -*-Emacs-Lisp-*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; File: mud-telnet-Sleeper.el ; RCS: $Header: $ ; Description: Combo of all mud.el's that I found ; Author: Sleeper@LambdaMOO ; Created: Fri Aug 26 11:35:01 1994 ; Modified: Sat Oct 22 14:14:26 1997 (Sleeper) Sleeper@LambdaMOO ; Language: Emacs-Lisp ; Package: N/A ; Status: Experimental (Do Not Distribute) ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Major Mode for talking to MUDs ;;; by James Aspnes (asp@cs.cmu.edu), Stewart Clamen (clamen@cs.cmu.edu) ;;; and Pavel Curtis (pavel@parc.xerox.com) ;;; 1989, 1990, 1991, 1992 ;;; ;;; MODIFICATION HISTORY ;;; ;;; May/June 1990 - Generalized to handle SMUG and LPMUD ;;; ;;; January 1991 - Added Pavel Curtis' MOO support and assorted bug fixes, ;;; also changed process-status call to run under 18.56. ;;; ;;; February 1991 - Added input-history browsing support (M-p/M-n); ;;; commands for sending the latest item on the kill ;;; ring (C-c C-y), optionally with each line bracketed by a ;;; given prefix and suffix (C-u C-c C-y); and a command to ;;; clear the current input line (C-c C-u). ;;; Added support for adding/overriding server definitions ;;; and the default server in one's .mud file. ;;; Fixed some bugs. ;;; Added support for people who prefer that the type-in ;;; point for a MUD buffer stay glued to the bottom of the ;;; window (see the 'mud-use-entire-window' option). ;;; ;;; October 1992 - Added support for server-initiated creation of local ;;; editing windows, manipulating text to be stored back on ;;; the server. At present, this is done as part of the ;;; MOO-specific support; at some point I'll pull it out to ;;; make it generic across MUD types. ;;; ;;; May 1994 - Merge all these (mud.el's) I can find, added moo-code.el ;;; support, well... the (require... line. ;;; Sleeper Merged in highlight code from afo. ;;; February 1994 - Added support for emacs V19 and hilit19 ;;; (Aaron Oppenheimer afo@wal.hp.com) ;;; To use hilit19 support, put this in your .emacs *after* ;;; you load hilit19.el: ;;; (hilit-translate mud-player-name 'cyan) ;;; (hilit-translate mud-page 'yellow) ;;; (hilit-set-mode-patterns ;;; 'mud-interactive-mode ;;; '((".*page.*" nil mud-page)) ;;; nil ;;; t) ;;; ;;; Sleeper May 1995 - Merged in Pavel's latest changes from ftp.parc. ;;; ;;; Sleeper June 1995 - Fix for hilighting bug encountered when ^U M-x mud ;;; was used without having a character. ;;; ;;; Sleeper January-March 1996 - ;;; Merged in Dave Van Buren's AstroVR hook for Mosaic. ;;; Added a separate ZENMOO type (rings the bell) ;;; Don't capitalize initial letters of every word ;;; in mud-send-kill-prefix added to page regexps ;;; using the variable `baud-rate' instead of the ;;; obsolete function added code to popup the ;;; window in mud-check-page ;;; ;;; Sleeper Sept 1996 - Add word boundary to name if its short, to ;;; reduce mid-word highighting. (If name was `A', ;;; *a*ll *a*'s *a*re highlighted....) ;;; ;;; Sleeper Oct 1996 - Remove extra blank linke from mud-send-kill-prefix. ;;; ;;; Sleeper Feb 1998 - Added Cold type. ;;; (if window-system (require 'hilit19) ) ;; This is the default set of 'server' lines in MUD entry files (e.g., ~/.mud) (defconst mud-default-servers '( ;;; ;;; SERVER NAME MUD SITE PORT ;;; ;; On Brigadoon days ("TinyMUD Classic" TinyMUD "fuzine.mt.cs.cmu.edu" 2323) ("fuzine" TinyMUD "fuzine.mt.cs.cmu.edu" 4201) ("TinyHELL" TinyMUD "uokmax.ecn.uoknor.edu" 6250) ("AmosMUD" TinyMUD "amos.ucsd.edu" 4201) ("Atlantis" TinyMUD "nyquist.bellcore.com" 4201) ("Auroris" TinyMUD "quiche.cs.mcgill.ca" 4200) ("CITMUD" TinyMUD "chrome.caltech.edu" 4201) ("ClubMUD" TinyMUD "milton.u.washington.edu" 1984) ("dragonMUD" TinyMUD "satan.ucsd.edu" 4201) ("Eden" TinyMUD "unicorn.cc.wwu.edu" 4201) ("EVILMud" TinyMUD "convx1.ccit.arizona.edu" 4201) ("FantaMUD" TinyMUD "sage.cc.purdue.edu" 5950) ("FurryMUCK" TinyMUD "hobbes.catt.ncsu.edu" 4242) ("GenericMUD" TinyMUD "apex.yorku.ca" 4201) ("Islandia" TinyMUD "planck.physics.purdue.edu" 2323) ("MoonMUD" TinyMUD "granite.cs.rochester.edu" 4201) ("MumbleMUD" TinyMUD "berlin.rtp.dg.com" 4201) ("PoohMUD" TinyMUD "eeyore.caltech.edu" 4201) ("QuartzPARADISE" TinyMUD "quartz.rutgers.edu" 9999) ("StoMUD" TinyMUD "dagon.acc.stolaf.edu" 8888) ("SunMUD" TinyMUD "einstein.mpccl.ksu.edu" 4201) ("TinyCWRU" TinyMUD "solarium.scl.cwru.edu.edu" 4201) ("TinyHOLLAND" TinyMUD "fysae.fys.ruu.nl" 4201) ("TinyHORNS" TinyMUD "bashful.cc.utexas.edu" 4201) ("TinyMUD" TinyMUD "planck.physics.purdue.edu" 2323) ("TinyMush" TinyMUD "sigh.berkeley.edu" 4201) ("TinySWAT" TinyMUD "masada.cs.swarthmore.edu" 4201) ("TinyTIM" TinyMUD "grape.ecs.clarkson.edu" 6250) ("TinyUSC" TinyMUD "coyote.usc.edu" 4201) ("Tinywonk" TinyMUD "ux.acs.umn.edu" 4200) ("TinyWORLD" TinyMUD "rillonia.ssc.gov" 6250) ; ("SMUG" SMUG "lancelot" 4201) ("Anarchy!" TinyMUCK "galjoen.cs.vu.nl" 4201) ("Brigadoon" TinyMUCK "dante.cs.uiuc.edu" 4201) ("Chaos!" TinyMUCK "uokmax.ecn.uoknor.edu" 6250) ; ("MbongoMUCK" TinyMUCK "mbongo.ucsd.edu" 4201) ("MbongoMUCK" TinyMUCK "watpc13.ucr.edu" 4201) ("Pegasus" TinyMUCK "l_cae05.icaen.uiowa.edu" 2001) ("TigerMUCK" TinyMUCK "Sun1.forestry.auburn.edu" 6250) ("TroyMUCK" TinyMUCK "pawl24.pawl.rpi.edu" 4201) ("TinyMUSH" TinyMUSH "manray.CSUFresno.edu" 4201) ("ToonMUSH" TinyMUSH "uokmax.ecn.uoknor.edu" 4835) ("Pern" TinyMUSH "199.166.230.69" 4201) ("MaineMud" LPMUD "chevette.umcs.maine.edu" 2000) ("Darker Realms" LPMUD "worf.tamu.edu" 2000) ("Sanctuary" LPMUD "j.ms.uky.edu" 2000) ("Warhammer" LPMUD "issunbane.engrg.uwo.ca" 2112) ("The PIT" LPMUD "obie.cis.pitt.edu" 2000) ("Theive's World" LPMUD "uokmax.ecn.uoknor.edu" 2000) ("Avalon" LPMUD "el.ecn.purdue.edu" 2000) ("Boiling MUD" LPMUD "frey.nu.oz.au" 2000) ("Phoenix" LPMUD "galjas.cs.vu.nl" 2000) ("PMC" MOO "hero.village.virginia.edu" 7777) ("DiversityMOO" MOO "erau.db.erau.edu" 8888) ("AlphaMOO" MOO "belch.berkeley.edu" 7777) ("LambdaMOO" MOO "lambda.moo.mud.org" 8888) ("MOO2000" MOO "sunlab.npac.syr.edu" 2000) ("ChibaSprawl" MOO "sequoia.picosof.com" 7777) ("WorldMOO" MOO "world.sensemedia.net" 1234) ("ChaosMOO" MOO "cub.math.oxy.edu" 8888) ("cybermoo" MOO "umbio.med.miami.edu" 7777) ("MediaMOO" MOO "purple-crayon.media.mit.edu" 8888) ("JaysHouseMOO" MOO "theory.cs.mankato.msus.edu" 1709) ("PARC" Jupiter "osprey.parc.xerox.com" 7777) ;JHM at jhm.ccs.neu.edu 1709 ;LambdaMOO at lambda.xerox.com 8888 ;Foothills at 128.197.10.75 2010 ;Harper's_Tale at netman.widener.edu 8888 ;BayMOO at moo.crl.com 8888 ;Rivendel at 128.8.11.201 5000 ;WorldMOO at chiba.picosof.com 1234 ;Sprawl at chiba.picosof.com 7777 ;SyrinxMOO at cimsun.aidt.edu 2112 ;Eon at mcmuse.mc.maricopa.edu 8888 ;Entropy at monsoon.weather.brockport.edu 7777 ;Dhalgren at actinic.princeton.edu 7777 ;DreamMOO at Feenix.metronet.com 8888 ;Dfire-Dragonsfire at moo.eskimo.com 7777 ;DivursityU at erau.db.erau.edu 8888 ;MarlDOOM at seabass.st.usm.edu 7777 ;MOOsaico at moo.di.uminho.pt 7777 ;MuMoo at chestnut.enmu.edu 7777 ;TNGMOO at tng-moo.dungeon.com 1701 ;trekmoo at trekmoo.microserve.com 2499 ;PtMOOt at 128.83.194.17 8888 ;PMC at hero.village.virginia.edu 7777 )) (defvar mud-default-default-server "LambdaMOO" "Default 'default-server' name.") (defvar muds nil "List of all defined MUD types") (defmacro defmud (mud prompt connect-filter connect-command filters command-filters sentinels startup-hook page-regexp) (list 'progn (list 'defvar mud nil) (list 'setplist (list 'quote mud) nil) (list 'put (list 'quote mud) ''prompt prompt) (list 'put (list 'quote mud) ''connect-filter connect-filter) (list 'put (list 'quote mud) ''connect-command connect-command) (list 'put (list 'quote mud) ''filters filters) (list 'put (list 'quote mud) ''command-filters command-filters) (list 'put (list 'quote mud) ''sentinels sentinels) (list 'put (list 'quote mud) ''startup-hook startup-hook) (list 'put (list 'quote mud) ''page-regexp page-regexp) (list 'if (list 'not (list 'memq (list 'quote mud) 'muds)) (list 'setq 'muds (list 'cons (list 'quote mud) 'muds))) (list 'quote mud))) (defun mud-prompt () (get mud 'prompt)) (defun mud-connect-filter () (get mud 'connect-filter)) (defun mud-connect-command () (get mud 'connect-command)) (defun mud-filters () (get mud 'filters)) (defun mud-sentinels () (get mud 'sentinels)) (defun mud-command-filters () (get mud 'command-filters)) (defun mud-startup-hook () (get mud 'startup-hook)) (defun mud-page-regexp () (get mud 'page-regexp)) ;;; Equivalent mud types (defmacro eqmud (mud2 mud1) (list 'progn (list 'setplist (list 'quote mud2) (list 'symbol-plist (list 'quote mud1))) (list 'if (list 'not (list 'memq (list 'quote mud2) 'muds)) (list 'setq 'muds (list 'cons (list 'quote mud2) 'muds))))) (defmud TinyMUD ?> ; prompt char 'tinymud-connect-filter "connect" 'tinymud-filter-hook 'nil 'nil 'tinymud-mode-hook "\\(You sense that [^ ]* is looking for you in \\|\\w+ pages: \\)" ) (eqmud TinyMUCK TinyMUD) (eqmud TinyMUSH TinyMUD) (eqmud TeenyMUD TinyMUD) (defmud SMUG ?= 'nil "" 'smug-filter-hook 'smug-macro-command-filter-hook 'nil 'smug-mode-hook "You sense that [^ ]* is looking for you in " ) (defmud LPMUD ?\ ; prompt char nil "" nil nil nil 'tinymud-mode-hook "You sense that [^ ]* is looking for you in " ) (defmud MOO ?> 'tinymud-connect-filter "connect" 'moo-filter-hook 'nil 'nil 'moo-mode-hook ".* pages?\\(, \"\\|: \\)\\|-> .*\\|.* responds?, \".*\\|(from .*).*\\|\\[from .*\\].*\\|<hiding under \\(the\\|your\\) bed>.*\\|<in the hot tub>.*\\|From the shadows, .*\\|You have new mail .*\\|Help>>>" ) (defmud Cold ?> 'tinymud-connect-filter "connect" 'cold-filter-hook 'nil 'nil 'cold-mode-hook ".* pages?\\(, \"\\|: \\)\\|-> .*\\|.* responds?, \".*\\|(from .*).*\\|\\[from .*\\].*\\|<hiding under \\(the\\|your\\) bed>.*\\|<in the hot tub>.*\\|From the shadows, .*\\|You have new mail .*\\|Help>>>" ) (defmud ZENMOO ?> 'tinymud-connect-filter "connect" 'zenmoo-filter-hook 'nil 'nil 'moo-mode-hook "[^ ]+ pages?[,:] \"" ) (defmud Jupiter ?> 'tinymud-connect-filter "connect" 'jupiter-filter-hook 'nil 'jupiter-sentinel-hook 'moo-mode-hook "\\(You sense that [^ ]* is looking for you in \\)" ) (eqmud JupiterX Jupiter) (defvar mud-jupiter-client-prog "/project/jupiter/bin/jswitch" "*File name of the special client program for Jupiter servers.") (defvar mud-show-page nil "*If non-nil, pop up MUD buffer whenever a page arrives.") (defvar mud-reconnect-regexp "#### Please reconnect to \\([^@]*\\)@\\([^ @]*\\) *\\(\\|([^ @]*)\\) port \\([0-9]+\\) ####.*$" "Regular expression for detecting reconnect signals.") (defconst mud-new-connectionp nil "Flag to identify hail for new connection") (defvar mud-accept-reconnects nil "*If nil, reject reconnect signals. If non-nil, accept reconnect signals by breaking existing connection and establishing new connection. If an integer, spawn <n> connections before breaking any.") (defun mud-check-reconnect () "Look for reconnect signal and open new connection if non to that site already exists." (goto-char (point-min)) (while (not (eobp)) (if (and mud-accept-reconnects (looking-at mud-reconnect-regexp)) (let ((mud-name (buffer-substring (match-beginning 1) (match-end 1))) (mud-server-addr (buffer-substring (match-beginning 2) (match-end 2))) (mud-server (and (not (eq (match-beginning 3) (match-end 3))) (buffer-substring (1+ (match-beginning 3)) (1- (match-end 3))))) (mud-port (string-to-int (buffer-substring (match-beginning 4) (match-end 4))))) (delete-region (match-beginning 0) (match-end 0)) (let* ((mud-sys (assoc mud-name (mud-servers))) (mud-buffer-name (concat "*" mud-name "*")) (mud-buffer-process (mud-find-existing-process mud-name))) (cond (mud-buffer-process ; Existing connection to that site... (message "Connection to that site had already been established.") (pop-to-buffer (process-buffer mud-buffer-process))) ((not mud-server) (message "GNU Emacs cannot handle nonsymbolic names. Sorry.")) ((zerop mud-port) (message "Illformed portal signal. Inform Builder.")) (t (save-excursion (setq mud-new-connectionp mud-buffer-name) (open-mud mud-sys t))))))) (beginning-of-line 2))) (defun mud-find-existing-process (name) "Find process of established Mud connection, if it exists" (let ((processes (process-list)) (result nil)) (while (and processes (not result)) (if (string-equal (upcase (process-name (car processes))) (upcase name)) (setq result (car processes)) (setq processes (cdr processes)))) result)) (defun mud-check-page () "Look for page message, and pop-up buffer if specified." (goto-char (point-min)) (while (not (eobp)) (if (and mud-show-page (looking-at (mud-page-regexp))) (progn ;(make-frame-visible) ; <- deiconify, but don't raise (raise-frame (selected-frame)) ; <- deiconify and/or raise (display-buffer (current-buffer)) (message "You are being paged in %s" (buffer-name (current-buffer))))) (beginning-of-line 2))) (defvar mud-break-lines t "*Non-nil if lines of output from the MUD should be broken as necessary at word boundaries. (buffer-local)") (make-variable-buffer-local 'mud-break-lines) (defun mud-fill-lines () "Fill buffer line by line." (if mud-break-lines (save-restriction (goto-char (point-max)) (beginning-of-line) (narrow-to-region (point-min) (point)) (goto-char (point-min)) (while (not (eobp)) (let ((break (move-to-column (1+ fill-column)))) (if (<= break fill-column) (beginning-of-line 2) ;; else fill (skip-chars-backward "^ \n") (if (bolp) ;; can't fill, we lose (beginning-of-line 2) (delete-horizontal-space) (insert ?\n)))))))) (defun mud-filter (proc string) "Filter for input from MUD process. Calls MUD-specific filters as well. Also, if recently established new connection automatically, check to see if number of active connections exceeded connection limit and delete current process if so." (let ((mud-select-buffer nil)) (save-excursion ;; Occasionally-useful debugging code. '(progn (set-buffer (get-buffer-create "*MUD Packets*")) (goto-char (point-max)) (insert "\n\n<<") (insert string) (insert ">>")) (set-buffer (process-buffer proc)) (goto-char (marker-position (process-mark proc))) (let ((start (point))) (insert-before-markers string) (let ((end (point))) (if (featurep 'hilit19) (hilit-highlight-region start end 'nil t)) (goto-char start) (beginning-of-line nil) (save-restriction (narrow-to-region (point) end) (while (search-forward "\^m" nil t) (replace-match "")) (goto-char (point-min)) (run-hooks (mud-filters)))))) (if (and (= scroll-step 1) (eq (current-buffer) (process-buffer proc)) (= (point) (point-max))) (recenter -1)) (if (and mud-select-buffer (eq (current-buffer) (process-buffer proc))) (pop-to-buffer mud-select-buffer))) (cond (mud-new-connectionp (if (or ; Do we close current connection? (not (numberp mud-accept-reconnects)) (let ((c mud-accept-reconnects) (l (process-list))) (while l (if (and (eq (process-filter (car l)) 'mud-filter) (memq (process-status (car l)) '(open run))) (setq c (1- c))) (setq l (cdr l))) (< c 0))) (progn (delete-process (get-buffer-process (current-buffer))) (kill-buffer (current-buffer)))) (pop-to-buffer mud-new-connectionp) (if (> baud-rate search-slow-speed) (recenter)) (setq mud-new-connectionp nil)))) (defun mud-sentinel (proc change) "Called on state changes so hooks can get run." (run-hooks (mud-sentinels))) (defun mud-send () "Send current line of input to a MUD." (interactive) (let ((proc (get-buffer-process (current-buffer)))) (cond ((or (null proc) (not (memq (process-status proc) '(open run)))) (message "Not connected--- nothing sent.") (insert ?\n)) (t ;; process exists, send line (let ((start (mud-find-input))) (send-region proc start (point)) (send-string proc "\n") (mud-remember-input (buffer-substring start (point))) (goto-char (point-max)) (insert ?\n) (move-marker (process-mark proc) (point)) (insert (mud-prompt)) (if (= scroll-step 1) (recenter -1)) ))))) (defun mud-realign-and-send () (interactive) (recenter 0) (mud-send)) (defun mud-cancel-input () (interactive) (let ((start (mud-find-input))) (delete-region start (point)))) (defun mud-send-kill (arg) (interactive "P") (if arg (call-interactively 'mud-send-kill-prefix) (let ((proc (get-buffer-process (current-buffer)))) (mud-send-string (car kill-ring) proc)))) (defun mud-send-kill-prefix (prefix suffix) (interactive "sPrefix: \nsSuffix: ") (let ((buf (current-buffer)) (temp (generate-new-buffer " *MUD temp*"))) (save-excursion (set-buffer temp) (yank) (let ((proc (get-buffer-process buf)) (case-replace nil)) (goto-char (point-min)) (untabify (point-min) (point-max)) ;; remove last char if it is a newline (if (string-equal (buffer-substring (- (point-max) 1) (point-max)) "\n") (progn (goto-char (1- (point-max))) (delete-char 1) (goto-char (point-min)))) (while (re-search-forward "^\\(.*\\)$" nil t) (replace-match (concat prefix "\\1" suffix) t)) (send-region proc (point-min) (point-max)) (send-string proc "\n") ;; Flush remaining input (kill-buffer temp))))) (defun mud-quit () "Quit MUD process." (interactive) (if (yes-or-no-p "Are you sure you want to quit this MUD session?") (delete-process (get-buffer-process (current-buffer))))) (defconst mud nil "Variable representing type of MUD active in current buffer") (make-variable-buffer-local 'mud) (defvar mud-use-entire-window nil "*Try to keep the type-in point for a MUD buffer at the bottom of the window.") (defvar mud-mode-syntax-table nil "Syntax table used while in MUD mode.") (defvar mud-interactive-mode-map (let ((map (make-sparse-keymap))) (define-key map "\n" 'mud-realign-and-send) (define-key map "\r" 'mud-send) (define-key map "\^c\^c" 'mud-quit) (define-key map "\^c " 'mud-make-empty-buffer) (define-key map "\^c\^m" 'mud-macro-command) (define-key map "\^c\^u" 'mud-cancel-input) (define-key map "\^c\^y" 'mud-send-kill) (define-key map "\ep" 'mud-previous-command) (define-key map "\en" 'mud-next-command) map) "Keymap for MUD interactive mode.") (defvar mud-interactive-mode-abbrev-table nil "Abbreviation table used in mud-interactive buffers.") (define-abbrev-table 'mud-interactive-mode-abbrev-table ()) (defun mud-interactive-mode (mud-type) "Major Mode for talking to inferior MUD processes. Commands: \\{mud-interactive-mode-map} Global Variables: [default in brackets] mud-show-page [nil] If non-nil, pop up MUD buffer whenever a page arrives. mud-accept-reconnects [nil] If nil, reject reconnect signals. If non-nil, accept reconnect signals by breaking existing connection and establishing new connection. If an integer, spawn that many connections before breaking any. mud-entry-file [\"~/.mud\"] Pathname to location of MUD address/character/password file. mud-use-entire-window [nil] Try to keep the type-in point for the MUD buffer at the bottom of the window, so as not to have a half-window of blank space. defmud parameters: prompt Character to identify MUD command input. connect-filters Initial filter hooks (before login) filters List of hooks to call before displaying output from MUD process to MUD buffer. [Default hooks support line-filling, page checking, and reconnect detection.] startup-hook Hook to run at startup. Users wishing to use macros may want to bind it to the following in their .emacs file: (setq tinymud-mode-hook '(lambda () (mud-load-macro-commands tinymud-macro-commands-file))) " (interactive) (kill-all-local-variables) (setq major-mode 'mud-interactive-mode) (setq mode-name (symbol-name mud-type)) (setq local-abbrev-table mud-interactive-mode-abbrev-table) (setq mud mud-type) (setq fill-column (1- (window-width))) (setq indent-tabs-mode nil) (if (null mud-mode-syntax-table) (progn (setq mud-mode-syntax-table (make-syntax-table)) (set-syntax-table mud-mode-syntax-table) (modify-syntax-entry ?_ "w") (modify-syntax-entry ?\[ "(]") (modify-syntax-entry ?\] ")[")) (set-syntax-table mud-mode-syntax-table)) (use-local-map (copy-keymap mud-interactive-mode-map)) (make-local-variable 'mode-line-process) (let* ((s (and (concat "@" mud-server))) (ss (cond ((not mud-accept-reconnects) "") (t (if (> (length s) 20) (substring s 0 20) s))))) (setq mode-line-process (list (concat ss ":%s")))) (run-hooks (mud-startup-hook))) (defun mud (&optional server autoconnect) "Connect to MUD, asking for site to connect to. With optional argument, look in mud-entry-file for name to connect with and attempt connect." (interactive (list (let* ((completion-ignore-case t) (default (mud-default-server)) (name (completing-read (format "Server (default %s): " default) (mud-servers) nil t))) (if (equal name "") default name)) current-prefix-arg)) (let* ((choice (assoc server (mud-servers))) (mud-name (car choice)) (mud-sys (car (cdr choice))) (mud-server (car (cdr (cdr choice)))) (mud-port (car (cdr (cdr (cdr choice)))))) (open-mud mud-sys autoconnect))) (defvar mud-use-telnet t "*t if telnetting, nil otherwise.") (defun open-mud (mud-sys autoconnect) (let ((index 0) (buf-name-root (concat "*" mud-name "*")) (buf-name nil)) (while (and (get-buffer (setq buf-name (if (= index 0) buf-name-root (format "%s<%d>" buf-name-root index)))) (get-buffer-process buf-name) (process-status (get-buffer-process buf-name))) (setq index (+ index 1))) (let* ((buf (get-buffer-create buf-name)) ;;; name buffer host service/port (proc (if (string= mud-sys "Jupiter") (let ((process-connection-type nil)) (start-process "MUD" buf mud-jupiter-client-prog "-n" "-t" (symbol-name mud-sys) mud-server (int-to-string mud-port))) (if mud-use-telnet (start-process "MUD" buf "telnet" mud-server (int-to-string mud-port)) (open-network-stream "MUD" buf mud-server mud-port))))) (condition-case nil ;; Despite how it looks, the following line ensures that Emacs *not* ;; kill our network connection on exit without asking us first. Some ;; earlier versions of Emacs do not allow the second argument, so this ;; call is wrapped in a CONDITION-CASE; in such versions, we'll just do ;; nothing. (process-kill-without-query proc t) (error nil)) (if autoconnect (let ((entry (mud-login-for-server mud-name)) (filter (or (mud-connect-filter) 'mud-filter))) (set-process-filter proc filter) (mud-send-string (mapconcat '(lambda (x) x) (cons (let ((mud mud-sys)) (mud-connect-command)) entry) " ") proc) (if (and entry (featurep 'hilit19)) (let* ((name (car entry)) ;; hack to keep short player names from ;; being highlighted in mid-word. (list (if (> (length name) 3) (cons name '(nil mud-player-name)) (cons (concat "\\b" name "\\b") '(nil mud-player-name)))) (args (cons list nil)) (current (assoc 'mud-interactive-mode hilit-patterns-alist))) (if current (let* ((now (cdr (cdr current))) (new (cons list now))) (hilit-set-mode-patterns 'mud-interactive-mode new nil t)) (hilit-set-mode-patterns 'mud-interactive-mode args) ))) )) (set-process-filter proc 'mud-filter) (set-process-sentinel proc 'mud-sentinel) (switch-to-buffer buf) (newline) (goto-char (point-max)) (set-marker (process-mark proc) (point)) (mud-interactive-mode mud-sys) (insert (mud-prompt)) (cond (mud-use-entire-window (make-local-variable 'scroll-step) (setq scroll-step 1)) (t (recenter '(4)))) (mud-initialize-input-history)))) ;;; Input History Maintenance (defun mud-make-history (size) ;; (head tail . vector) ;; head is the index of the most recent item in the history. ;; tail is the index one past the oldest item ;; if head == tail, the history is empty ;; all index arithmetic is mod the size of the vector (cons 0 (cons 0 (make-vector (+ size 1) nil)))) (defun mud-decr-mod (n m) (if (= n 0) (1- m) (1- n))) (defun mud-history-insert (history element) (let* ((head (car history)) (tail (car (cdr history))) (vec (cdr (cdr history))) (size (length vec)) (new-head (mud-decr-mod head size))) (aset vec new-head element) (setcar history new-head) (if (= new-head tail) ; history is full, so forget oldest element (setcar (cdr history) (mud-decr-mod tail size))))) (defun mud-history-empty-p (history) (= (car history) (car (cdr history)))) (defun mud-history-ref (history index) (let* ((head (car history)) (tail (car (cdr history))) (vec (cdr (cdr history))) (size (if (<= head tail) (- tail head) (+ tail (- (length vec) head))))) (if (= size 0) (error "Ref of an empty history") (let ((i (% index size))) (if (< i 0) (setq i (+ i size))) (aref vec (% (+ head i) (length vec))))))) (defvar mud-input-history-size 20 "The number of past input commands remembered for possible reuse") (defvar mud-input-history nil) (defvar mud-input-index 0) (defun mud-initialize-input-history () (make-local-variable 'mud-input-history) (make-local-variable 'mud-input-index) (setq mud-input-history (mud-make-history mud-input-history-size)) (setq mud-input-index 0)) (defun mud-remember-input (string) (mud-history-insert mud-input-history string)) (defun mud-previous-command () (interactive) (mud-browse-input-history 1)) (defun mud-next-command () (interactive) (mud-browse-input-history -1)) (defun mud-browse-input-history (delta) (cond ((mud-history-empty-p mud-input-history) (error "You haven't typed any commands yet!")) ((eq last-command 'mud-browse-input-history) (setq mud-input-index (+ mud-input-index delta))) (t (setq mud-input-index 0))) (setq this-command 'mud-browse-input-history) (let ((start (mud-find-input))) (delete-region start (point)) (insert (mud-history-ref mud-input-history mud-input-index)))) (defun mud-find-input () (beginning-of-line 1) (let* ((proc (get-buffer-process (current-buffer))) (start (max (process-mark proc) (point)))) (if (equal (char-after start) (mud-prompt)) (setq start (1+ start))) (goto-char start) (end-of-line 1) start)) ;;; Macro Commands (defvar mud-current-process nil "Current MUD process") (defvar mud-current-macro-commands-alist nil "Current MUD macro command alist") (defvar mud-macro-commands-alist (list (cons nil "")) "*Alist of macros (keyed by strings)") (make-variable-buffer-local 'mud-macro-commands-alist) (defvar mud-macro-expansion-mode-map (let ((map (make-sparse-keymap))) (define-key map "\^c\^c" 'mud-macro-send-and-destroy) (define-key map "\^c\^s" 'mud-macro-send) (define-key map "\^cs" 'mud-macro-send) (define-key map "\^c\^]" 'mud-macro-abort) (define-key map "\^c\^t" 'mud-macro-define) map) "Keymap for mud-macro-expansion-mode.") (defun mud-macro-expansion-mode () "Major Mode for mucking with MUD macro expansion. Commands: \\{mud-macro-expansion-mode-map} " (interactive) (kill-all-local-variables) (setq mode-name "MUD-Macro-Expansion") (setq major-mode 'mud-macro-expansion-mode) (setq indent-tabs-mode nil) (set-syntax-table mud-mode-syntax-table) (use-local-map mud-macro-expansion-mode-map) (make-local-variable 'mud-expansion-macro-name) (message "Use ^C^S to send, ^C^C to send and destroy, ^C^] to abort...")) (defun mud-macro-define (name) "Define buffer as mud-macro." (interactive (list (completing-read "MUD Macro: " mud-current-macro-commands-alist nil nil mud-expansion-macro-name))) (let ((oldval (assoc name mud-current-macro-commands-alist))) (if oldval (setcdr oldval (buffer-string)) (setq mud-current-macro-commands-alist (cons (cons name (buffer-string)) mud-current-macro-commands-alist)))) (if (y-or-n-p "Save to file? ") (mud-store-macro-commands (expand-file-name (read-file-name (concat "File to save to (default " mud-macro-commands-file "): ") "~/" mud-macro-commands-file))))) ;;; Reading from entry file ;;; ;;; FORMAT: ;;; server <server-name> <mud-type> <host-name> <port> ;;; default-server <server-name> ;;; include <file-name> ;;; <server-name> <character-name> <password> ;;; default <character-name> <password> ;;; (defvar mud-entry-file "~/.mud" "*Pathname to location of MUD address/character/password file.") (defvar mud-servers nil) (defvar mud-default-server nil) (defvar mud-logins nil) (defvar mud-default-login nil) (defvar mud-entry-file-dates nil) (defun mud-match-field (i) (buffer-substring (match-beginning i) (match-end i))) (defun mud-report-syntax-error () (let ((start (point))) (end-of-line) (error (concat "Syntax error in MUD entry file " file ": " (buffer-substring start (point)))))) (defun mud-file-directory (name) (let ((i (1- (length name)))) (while (not (= (aref name i) ?/)) (setq i (1- i))) (substring name 0 (1+ i)))) (defun mud-file-write-date (file) (nth 5 (file-attributes file))) (defun mud-entry-pattern (keyword nargs) (let ((pattern "?$")) (while (> nargs 0) (setq pattern (concat "\\([^ \n]*\\) " pattern) nargs (1- nargs))) (if (null keyword) pattern (concat keyword " " pattern)))) (defun mud-parse-entry-file (name) (let ((file (expand-file-name name)) (old-buffer (current-buffer)) (buffer (generate-new-buffer " *MUD temp*"))) (if (not (file-exists-p file)) (error (concat "Can't find MUD entry file " file))) (setq mud-entry-file-dates (cons (cons file (mud-file-write-date file)) mud-entry-file-dates)) (unwind-protect (progn (set-buffer buffer) (buffer-flush-undo buffer) (insert-file-contents file) ;; Don't lose if no final newline. (goto-char (point-max)) (or (eq (preceding-char) ?\n) (newline)) (goto-char (point-min)) ;; handle "\\\n" continuation lines (while (not (eobp)) (end-of-line) (cond ((= (preceding-char) ?\\) (delete-char -1) (delete-char 1) (insert ?\ ))) (forward-char 1)) ;; simplify whitespace handling (goto-char (point-min)) (while (re-search-forward "^[ \t]+" nil t) (replace-match "")) (goto-char (point-min)) (while (re-search-forward "[ \t]+" nil t) (replace-match " ")) (goto-char (point-min)) (while (not (eobp)) (cond ((or (eolp) (looking-at "#"))) ((looking-at "server ") (let (port type) (if (or (not (looking-at (mud-entry-pattern "server" 4))) (= (setq port (string-to-int (mud-match-field 4))) 0) (not (memq (setq type (intern (mud-match-field 2))) muds))) (mud-report-syntax-error)) (setq mud-servers (cons (list (mud-match-field 1) type (mud-match-field 3) port) mud-servers)))) ((looking-at "default-server ") (if (not (looking-at (mud-entry-pattern "default-server" 1))) (mud-report-syntax-error)) (if (null mud-default-server) (setq mud-default-server (mud-match-field 1)))) ((looking-at "include ") (if (not (looking-at (mud-entry-pattern "include" 1))) (mud-report-syntax-error)) (mud-parse-entry-file (concat (mud-file-directory file) (mud-match-field 1)))) ((looking-at "default ") (if (not (looking-at (mud-entry-pattern "default" 2))) (mud-report-syntax-error)) (if (null mud-default-login) (setq mud-default-login (list (mud-match-field 1) (mud-match-field 2))))) ((looking-at (mud-entry-pattern nil 3)) (setq mud-logins (cons (list (mud-match-field 1) (mud-match-field 2) (mud-match-field 3)) mud-logins))) (t (mud-report-syntax-error))) (beginning-of-line 2))) (kill-buffer buffer) (set-buffer old-buffer)))) (defun mud-check-entry-file () (if (or (null mud-entry-file-dates) (let ((dates mud-entry-file-dates)) (while (and dates (equal (cdr (car dates)) (mud-file-write-date (car (car dates))))) (setq dates (cdr dates))) (not (null dates)))) (progn (setq mud-servers nil mud-default-server nil mud-logins nil mud-default-login nil mud-entry-file-dates nil) (if (file-exists-p mud-entry-file) (mud-parse-entry-file mud-entry-file)) (setq mud-servers (append (reverse mud-servers) mud-default-servers)) (if (null mud-default-server) (setq mud-default-server mud-default-default-server))))) (defun mud-servers () (mud-check-entry-file) mud-servers) (defun mud-default-server () (mud-check-entry-file) mud-default-server) (defun mud-login-for-server (server) (mud-check-entry-file) (or (cdr (assoc server mud-logins)) mud-default-login)) ;;; TinyMUD (defvar tinymud-filter-hook '(mud-check-reconnect mud-check-page mud-fill-lines) "*List of functions to call on each line of tinymud output. The function is called with no arguments and the buffer narrowed to just the line.") (defvar tinymud-connection-error-string "Either that player does not exist, or has a different password.") (defvar tinymud-macro-commands-file "~/.tinymud_macros" "*Pathname of tinymud macros.") (setq tinymud-output-filter nil) (defun tinymud-connect-filter (proc string) "Filter for connecting to a TinyMUD server. Replaced with tinymud-filter once successful." (if (not (string-equal string tinymud-connection-error-string)) (set-process-filter proc 'tinymud-filter))) ;;; SMUG (TinyMUD 2) (defvar smug-filter-hook '(mud-convert-tabs-to-newlines mud-fill-lines) "*List of functions to call on each line of Smug output. The function is called with no arguments and the buffer narrowed to just the line.") (setq smug-macro-command-filter-hook '(mud-convert-newlines-to-tabs-in-strings)) (defun mud-convert-tabs-to-newlines () "Replace all TABs to NEWLINEs in displaying of Smug output, since they represent new statements in the embedded programming language." (subst-char-in-region (point-min) (point-max) ?\t ?\n t)) (defun mud-convert-newlines-to-tabs-in-strings () "Replace all NEWLINEs present inside top-level strings with TABs, as they are likely code objects." (goto-char (point-min)) (if (re-search-forward "[\\[\"]" (point-max) t) (progn (forward-char -1) (subst-char-in-region (point) (save-excursion (forward-sexp 1) (point)) ?\n ?\t t)))) (defvar smug-macro-commands-file "~/.smug_macros" "*Pathname of SMUG macros.") ;;; MOO (defvar moo-mode-hook '(define-moo-mode-commands)) (defvar cold-mode-hook '(define-moo-mode-commands)) (defun define-moo-mode-commands () (define-key (current-local-map) "\^c\^d" 'moo-get-description) (define-key (current-local-map) "\^cd" 'moo-get-detail) (define-key (current-local-map) "\^ch" 'moo-get-help) (define-key (current-local-map) "\^c\^f" 'moo-get-field) (define-key (current-local-map) "\^c\^v" 'moo-get-verb-listing)) ;; AstroVR fetch requests: ;; #$# fetch host: <name> directory: <dir> filename: <name> type: <type> (defun moo-check-fetch () "Look for page message, and pop-up buffer if specified." (goto-char (point-min)) (while (not (eobp)) (if (looking-at (concat "#\\$# fetch " "host: \\(.*\\) " "directory: \\(.*\\) " "file: \\(.*\\) " "type: \\(.*\\) " "destination: \\(.*\\)$")) (let ((host (mud-match-field 1)) (dir (mud-match-field 2)) (file (mud-match-field 3)) (type (mud-match-field 4)) (dest (mud-match-field 5))) (delete-region (point) (save-excursion (beginning-of-line 2) (point))) (call-process "fetch-file" nil 0 nil host dir file type dest))) (beginning-of-line 2))) (defvar *moo-gopher-buffer* nil) (defun moo-check-gopher () "look for a gopher request"; (goto-char (point-min)) (while (not (eobp)) (if (looking-at (concat "#\\$# gopher" "\t\\(.*\\)" "\t\\(.*\\)" "\t\\(.*\\)" "\t\\(.*\\)$")) (let ((here (current-buffer)) (changed nil) (host (mud-match-field 1)) (port (mud-match-field 2)) (descr (mud-match-field 3)) (path (mud-match-field 4))) (delete-region (point) (save-excursion (beginning-of-line 2) (point))) (if (not (fboundp 'gopher-set-object-host)) (load-library "gopher")) (setq port (car (read-from-string port))) (save-excursion (gopher-dispatch-object (vector (aref descr 0) (substring descr 1) path host port) *moo-gopher-buffer*) (cond( (not (equal here (current-buffer))) (setq *moo-gopher-buffer* (current-buffer)) (setq changed t) )) ) (cond (changed (display-buffer *moo-gopher-buffer* t))) ) (beginning-of-line 2) ))) (defun moo-explode-message () "Convert a list of strings into more readable/editable text." (interactive) (goto-char (point-min)) (while (search-forward "{\"" nil t) (replace-match "{\n")) (goto-char (point-min)) (while (search-forward "\", \"" nil t) (replace-match "\n")) (goto-char (point-min)) (while (search-forward "\"}" nil t) (replace-match "\n}")) (goto-char (1- (point-max))) (if (looking-at "\n") (delete-char 1))) (defun moo-implode-message () "Convert readable/editable text into a list of strings." (interactive) (goto-char (point-min)) (while (search-forward "{\n" nil t) (replace-match "{\"")) (goto-char (point-min)) (while (search-forward "\n}" nil t) (replace-match "\"}")) (goto-char (point-min)) (while (search-forward "\n" nil t) (replace-match "\", \""))) (defun moo-get-help () "Fetch a given help text and explode it." (interactive) (moo-do-fetch "Edit which help text: " "%s" "@gethelp %s" 'moo-null-fixer)) (defun moo-null-fixer () ;; Nothing required. ) (defun moo-get-field () "Fetch the value of some field." (interactive) (moo-do-fetch "Edit what field: " "%s" "@show %s" 'moo-fix-field)) (defun moo-get-detail () "Fetch the value of some detail of the current room." (interactive) (moo-do-fetch "Edit what detail: " "%s" "dump_detail %s" 'moo-null-fixer)) (defun moo-get-description () "Fetch the description of some object." (interactive) (moo-do-fetch "Edit description of what object: " "%s" "@show %s.description" 'moo-fix-field)) (defun moo-fix-field () (define-key (current-local-map) "\^c\^e" 'moo-explode-message) (define-key (current-local-map) "\^c\^i" 'moo-implode-message) (insert "; !(") (search-forward ".") (insert "(\"") (end-of-line) (insert "\") = ") (let ((start (point))) (re-search-forward "Value: *") (delete-region start (point))) (save-excursion (end-of-line) (insert ")"))) (defun moo-get-verb-listing () "Fetch the MOO code for a particular verb." (interactive) (moo-do-fetch "Program what verb: " "%s" "@list %s without numbers" 'moo-fix-listing)) (defun moo-fix-listing () (moo-code-mode) (cond ((looking-at "That object") (let ((message (substring (buffer-string) 0 -1))) (erase-buffer) (error message))) ((looking-at "That verb") (let ((start (point))) (end-of-line) (delete-region start (point))))) (insert (concat "@program " moo-object "\n")) (if (looking-at "#") ; Kill the header line. (let ((start (point))) (beginning-of-line 2) (delete-region start (point)))) (goto-char (point-max)) (insert ".\n") (goto-char (point-min)) (beginning-of-line 2)) (defun moo-do-fetch (prompt object-fmt command-fmt fixer) (setq moo-object (format object-fmt (read-string prompt)) moo-state 'waiting moo-fixer fixer mud-current-process (get-buffer-process (current-buffer)) moo-buffer (get-buffer-create moo-object)) (moo-set-delimiter moo-suffix) (pop-to-buffer moo-buffer) (erase-buffer) (mud-send-string (concat "PREFIX " moo-prefix "\nSUFFIX " moo-suffix "\n" (format command-fmt moo-object) "\nPREFIX\nSUFFIX\n") mud-current-process)) (defun moo-set-delimiter (str) (setq moo-delim-string str) (setq moo-delim-regexp (concat (regexp-quote str) "$"))) (defvar moo-prefix "===MOO-Prefix===") (defvar moo-suffix "===MOO-Suffix===") (defvar moo-upload-command nil) ;(defvar moo-edit-regexp (concat "#\\$# edit " ; "name: \\(.*\\) " ; "upload: \\(.*\\)$")) ; Hmm. From the dec-94 file. (defvar moo-edit-regexp (concat "#\\$# edit " "name: \\(.*\\) " "upload: \\(.*\\)\n")) (defvar moo-buffer nil) (defvar moo-delim-string nil) (defvar moo-delim-regexp nil) (defvar moo-state 'idle) (defvar moo-object nil) (defvar moo-fixer nil) (defvar moo-filter-hook '(moo-filter moo-check-fetch moo-check-gopher mud-check-page mud-check-reconnect astrovr-mosaic-hook Sleeper-netscape-browser-hook mud-fill-lines)) (defvar cold-filter-hook '(cold-filter moo-check-fetch moo-check-gopher mud-check-page mud-check-reconnect astrovr-mosaic-hook Sleeper-netscape-browser-hook cold-tkMOOTAG-hook mud-fill-lines)) (defvar zenmoo-filter-hook '(moo-filter zen-alert mud-check-page mud-check-reconnect mud-fill-lines)) (defun moo-quote-dots () "Double any initial dot on every line of the current (narrowed) buffer." (save-excursion (goto-char (point-min)) (while (re-search-forward "^\\." nil t) (replace-match "..")))) (defun moo-unquote-dots () "Un-double any initial dots on every line of the current (narrowed) buffer." (save-excursion (goto-char (point-min)) (while (re-search-forward "^\\.\\." nil t) (replace-match ".")))) (make-variable-buffer-local 'moo-upload-command) (defun moo-filter () (goto-char (point-min)) (while (not (eobp)) (let ((start (point))) (cond ((and (eq moo-state 'waiting) (looking-at (concat moo-prefix "\n"))) (beginning-of-line 2) (delete-region start (point)) (setq moo-state 'copying moo-upload-command nil)) ((and (eq moo-state 'idle) '(let ((string (buffer-substring (point) (point-max)))) (save-excursion (set-buffer (get-buffer-create "*MUD Packets*")) (goto-char (point-max)) (insert "\n\n[[") (insert string) (insert "]]") t)) (looking-at moo-edit-regexp)) (let ((name (mud-match-field 1)) (upload (mud-match-field 2))) (beginning-of-line 2) (delete-region start (point)) (setq moo-state 'copying moo-buffer (get-buffer-create (concat name "-" (buffer-name))) mud-current-process (get-buffer-process (current-buffer)) moo-fixer 'moo-unquote-dots) (moo-set-delimiter ".") (let ((buff (current-buffer))) (set-buffer moo-buffer) (erase-buffer) (setq moo-upload-command upload) (set-buffer buff)))) ((eq moo-state 'copying) (cond ((looking-at moo-delim-regexp) (setq moo-state 'idle) (beginning-of-line 2) (delete-region start (point)) (let ((buff (current-buffer))) (set-buffer moo-buffer) (goto-char (point-min)) (let ((upload moo-upload-command)) (if (string-match ":" (buffer-name)) ;; Assume verb edit, since there is a ":" ;; (Can't be bad, if .prop has a ":" ;; who cares if we have some extra verbing keys?) (moo-code-mode) (mud-macro-expansion-mode)) (if upload (setq moo-upload-command upload))) (and moo-fixer (funcall moo-fixer)) (setq mud-select-buffer moo-buffer) (set-buffer buff))) (t (beginning-of-line 2) (let* ((buff (current-buffer)) (str (buffer-substring start (point))) (len (length str))) (if (or (> len (length moo-delim-string)) (not (equal (substring moo-delim-string 0 len) str))) (progn (delete-region start (point)) (set-buffer moo-buffer) (goto-char (point-max)) (insert str) (set-buffer buff))))))) (t (beginning-of-line 2)))))) (defun cold-filter () (goto-char (point-min)) (while (not (eobp)) (let ((start (point))) (cond ((and (eq moo-state 'waiting) (looking-at (concat moo-prefix "\n"))) (beginning-of-line 2) (delete-region start (point)) (setq moo-state 'copying moo-upload-command nil)) ((and (eq moo-state 'idle) '(let ((string (buffer-substring (point) (point-max)))) (save-excursion (set-buffer (get-buffer-create "*MUD Packets*")) (goto-char (point-max)) (insert "\n\n[[") (insert string) (insert "]]") t)) (looking-at moo-edit-regexp)) (let ((name (mud-match-field 1)) (upload (mud-match-field 2))) (beginning-of-line 2) (delete-region start (point)) (setq moo-state 'copying moo-buffer (get-buffer-create (concat name "-" (buffer-name))) mud-current-process (get-buffer-process (current-buffer)) moo-fixer 'moo-unquote-dots) (moo-set-delimiter ".") (let ((buff (current-buffer))) (set-buffer moo-buffer) (erase-buffer) (setq moo-upload-command upload) (set-buffer buff)))) ((eq moo-state 'copying) (cond ((looking-at moo-delim-regexp) (setq moo-state 'idle) (beginning-of-line 2) (delete-region start (point)) (let ((buff (current-buffer))) (set-buffer moo-buffer) (goto-char (point-min)) (let ((upload moo-upload-command)) (if (string-match "." (buffer-name)) ;; Assume method edit, since there is a "." ;; (Hmm. Can Cold varibales have periods in them?) ;; (who cares if we have some extra verbing keys?) (progn (coldc-mode) (and (setq tmap (current-local-map)) (define-key tmap "\^c\^c" 'mud-macro-send-and-destroy) (define-key tmap "\^c\^s" 'mud-macro-send) (define-key tmap "\^cs" 'mud-macro-send) (define-key tmap "\^c\^]" 'mud-macro-abort) (define-key tmap "\^c\^k" 'comment-region))) (mud-macro-expansion-mode)) (if upload (setq moo-upload-command upload))) (and moo-fixer (funcall moo-fixer)) (setq mud-select-buffer moo-buffer) (set-buffer buff))) (t (beginning-of-line 2) (let* ((buff (current-buffer)) (str (buffer-substring start (point))) (len (length str))) (if (or (> len (length moo-delim-string)) (not (equal (substring moo-delim-string 0 len) str))) (progn (delete-region start (point)) (set-buffer moo-buffer) (goto-char (point-max)) (insert str) (set-buffer buff))))))) (t (beginning-of-line 2)))))) (defun cold-tkMOOTAG-hook () ) (defun zen-alert () (ding t) (message "ZenMOO beckons.") ) ;;; Jupiter (defvar jupiter-filter-hook '(jupiter-filter moo-filter mud-check-page mud-check-reconnect mud-fill-lines)) (defvar jupiter-sentinel-hook '(jupiter-sentinel)) (defvar jupiter-process nil "Process variable for mooaudio program.") (make-variable-buffer-local 'jupiter-process) (defconst jupiter-mooaudio "/project/jupiter/etc/mooaudio") (defun jupiter-filter () "Filter room change strings." (goto-char (point-min)) (if (re-search-forward "^@@#\\([0-9]*\\)\n" (point-max) t) (let ((room (buffer-substring (match-beginning 1) (match-end 1)))) (jupiter-set-room room) (delete-region (match-beginning 0) (match-end 0)))) (goto-char (point-min)) (if (re-search-forward "^#\\$# This server supports fancy clients.\n" (point-max) t) (progn (send-string (get-buffer-process (current-buffer)) "@client emacs\n") (delete-region (match-beginning 0) (match-end 0)))) (goto-char (point-min)) (if (re-search-forward "^#\\$#channel \\([\.0-9]*\\)\n" (point-max) t) (let ((channel (buffer-substring (match-beginning 1) (match-end 1)))) (jupiter-set-channel channel) (delete-region (match-beginning 0) (match-end 0))))) (defun jupiter-set-room (room) (jupiter-set-channel (concat "224.4." room))) (defun jupiter-set-channel (channel) (if (or (null jupiter-process) (not (eq (process-status jupiter-process) 'run))) (setq jupiter-process (start-process "jupiter-audio" nil jupiter-mooaudio channel)) (send-string jupiter-process (concat "g " channel "\n")))) (defun jupiter-sentinel () (if (and (not (eq (process-status proc) 'run)) (not (null jupiter-process))) (process-send-eof jupiter-process))) ;;; Generic stuff. (defun mud-macro-abort () "Abort macro expansion buffer." (interactive) (kill-buffer (current-buffer)) ;(delete-window) ; this annoyingly destroys previously existing windows. -Sleeper ) (defun mud-macro-send () "Send contents of macro expansion buffer." (interactive) (let ((str (buffer-string))) (mud-macro-send-2 str))) (defun mud-macro-send-and-destroy () "Send contents of macro expansion buffer and then kill the buffer." (interactive) (let ((str (buffer-string))) (mud-macro-send-2 str) (mud-macro-abort))) (defun mud-macro-send-2 (str) (save-excursion (let ((proc mud-current-process) (upload moo-upload-command)) (set-buffer (process-buffer proc)) (setq mud-macro-commands-alist mud-current-macro-commands-alist) (mud-send-string (let ((start (point))) (insert str) (save-restriction (narrow-to-region start (point)) (if upload (progn (moo-quote-dots) (goto-char (point-min)) (insert (concat upload "\n")) (goto-char (point-max)) (if (not (bolp)) (insert "\n")) (insert ".\n")) (run-hooks (mud-command-filters))) (prog1 (buffer-string) (delete-region (point-min) (point-max))))) proc)))) (defun mud-send-string (string proc) "Send STRING as input to PROC" (if (not (= (aref string (- (length string) 1)) ?\n)) (setq string (concat string "\n"))) (send-string proc string)) (defun mud-load-macro-commands (filename) "Load file of mud-macros" (setq mud-macro-commands-alist (if (file-exists-p filename) (progn (setq mud-macro-commands-file filename) (let ((tempbuf (get-buffer-create " *MUD Macros*")) (buf (current-buffer))) (set-buffer tempbuf) (erase-buffer) (insert-file filename) (prog1 (car (read-from-string (buffer-string))) (set-buffer buf)))) '(nil . nil)))) (defun mud-store-macro-commands (filename) "Store MUD macros in filename" (interactive "FFile to save to: ") (setq mud-macro-commands-file filename) (save-excursion (let ((tmp (get-buffer-create " *Macros to write*"))) (set-buffer tmp) (erase-buffer) (insert (prin1-to-string mud-current-macro-commands-alist)) (write-file filename)))) (defun mud-macro-command (arg) "Insert into stream one of the commands in mud-macro-commands-alist. Without command argument, opens buffer for editting. With argument sends alist entry directly to process." (interactive "P") (let ((macro (assoc (or (if (stringp arg) arg) (completing-read "MUD Macro: " mud-macro-commands-alist nil t nil)) mud-macro-commands-alist))) (let ((match (car macro)) (stuff (cdr macro))) (if (stringp stuff) (let ((buff (get-buffer-create "*Expansion*")) (proc (get-buffer-process (current-buffer))) (alist mud-macro-commands-alist)) (if (not arg) (progn (pop-to-buffer buff) (erase-buffer) (insert stuff) (goto-char (point-min)) (mud-macro-expansion-mode) (setq mud-expansion-macro-name match) (setq mud-current-process proc) (setq mud-current-macro-commands-alist alist) ) (mud-send-string stuff proc))))))) (defun mud-make-empty-buffer () "Create a new empty buffer in MUD Macro Expansion mode, for local composition of a set of input lines to be sent to the MUD process." (interactive) (let ((buff (generate-new-buffer "*MUD Input*")) (proc (get-buffer-process (current-buffer)))) (pop-to-buffer buff) (mud-macro-expansion-mode) (setq mud-current-process proc))) ;;; Utilities (defun mud-cleanup-extra-processes () (interactive) (mapcar '(lambda (p) (if (not (buffer-name (process-buffer (get-process p)))) (delete-process p))) (process-list))) ;;; astrovr connection for Mosaic. ;;;;>read #73619 (on Lambda) ;;;;There appears to be some writing on the note ... ;;;; ;;; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ;;; ;;; NCSA Mosaic hooks for mud.el from AstroVR. ;;; ========================================== ;;; ;;; - D. Van Buren, dave@ipac.caltech.edu ;;; ;;; These mods to mud.el allow the connected server to run NCSA Mosaic ;;; on your cpu and display. You need to have mosaic in your path and have ;;; write permissions on /tmp. This code was written to run on a Sparc 1 ;;; running SunOS 4.1.2, and will probably run on many UNIX boxes with at ;;; most minor changes. ;;; ;;; ;;; 1. Add this line to your *-filter-hook routine in mud.el, for ;;; example in your moo-filter-hook or a filter package called ;;; by that routine: ;;; ;;; (astrovr-mosaic-hook) ;;; ;;; This should come *before* the symbol mud-fill-lines appears. ;;; ;;; ;;; 2. Substitute the local name of your NCSA Mosaic program in the line ;;; ;;; (start-process "mosaic" "*mosaic*" "xmosaic" "-home" ;;; ~~~~~~~ ;;; where it currently has the string `xmosaic'. ;;; ;;; ;;; ;;; 3. Run the `kill -l' program on your unix system and ;;; note the place of the SIGUSR1 entry, for example on ;;; my machine it is the 30th entry. In the line ;;; ;;; (start-process "kill" "*kill*" "kill" "-30" (format "%d" ;;; ~~ ;;; change the `30' to the place number you found. ;;; ;;; - OR - ;;; ;;; Check that your system supports kill -USR1 and change the "-30" ;;; to "-USR1". To do this check, see if typing `kill -USR1' gives ;;; an error from the Unix prompt. ;;; ;;; ;;; 4. Include this code in your mud.el. ;;; ;;; ;;; ;;; 5. When your client sees a line that looks like this from the server ;;; ;;; #$#display-url [*] command: <goto|newwin> url: <url> upload: [*] ;;; ;;; it will instruct mosaic to display the document. Here [*] just ;;; means any string including the empty string. The first one is a ;;; placeholder for an authentication key which is used to control ;;; access to your mosaic process (not implemented) and the other is ;;; a placeholder for a string to be sent back to the server upon ;;; completion of the local display task (also not implemented). ;;; Note that the blank spaces are required, if you omit the [*] ;;; entries, you still need the blanks, for example: ;;; ;;; #$#display-url command: goto url: http://foo/ upload: ;;; ^^ ^ ;;; 2 blanks 1 blank ;;; ;;; ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (defun astrovr-del-request-line () "Deletes a line from the current buffer, typically the mud process buffer (from mud.el)." (delete-region (point) (save-excursion (beginning-of-line 2) (point))) ) (defun astrovr-mosaic-hook () "service a mosaic request." (goto-char (point-min)) (while (not (eobp)) (if (looking-at (concat "#\\$#display-url \\(.*\\) " "command: \\(.*\\) " "url: \\(.*\\) " "upload: \\(.*\\)$" )) (let ((astrovr-mosaic-url (mud-match-field 3)) (astrovr-mosaic-command (mud-match-field 2)) (astrovr-mosaic-upload (mud-match-field 4))) (astrovr-del-request-line) (if (not(process-status "mosaic")) (start-process "mosaic" "*mosaic*" "Mosaic" "-home" astrovr-mosaic-url) (save-excursion (set-buffer (generate-new-buffer "*mosaic-cmd*")) (insert astrovr-mosaic-command) (insert "\n") (insert astrovr-mosaic-url) (setq mosaic-cmd-file (format "/tmp/Mosaic.%d" (process-id (get-process "mosaic")))) (write-region (point-min) (point-max) mosaic-cmd-file nil 'foo) (start-process "kill" "*kill*" "kill" "-USR1" (format "%d" (process-id (get-process "mosaic")))) (kill-buffer (current-buffer)) )))) (beginning-of-line 2))) (defun Sleeper-netscape-browser-hook () "service a mosaic request." (goto-char (point-min)) (while (not (eobp)) (if (looking-at (concat "#\\$#display-url \\(.*\\) ?" "url: \\(.*\\)")) (let ((astrovr-mosaic-url (mud-match-field 2))) (astrovr-del-request-line) (if (not(process-status "webviewer")) (start-process "webviewer" "*webview*" "netscape" astrovr-mosaic-url) (start-process "webupdate" "*webupdate*" "netscape" "-remote" (concat "openURL(" astrovr-mosaic-url ")")) ))) (beginning-of-line 2))) (require 'moo-code) (require 'coldc-mode)