Path: utzoo!telly!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!PAWL.RPI.EDU!tale From: tale@PAWL.RPI.EDU (David C Lawrence) Newsgroups: gnu.emacs Subject: IRC-mode v 1.2 (part 2 of 3) Message-ID: <8908021317.AA15334@pawl.rpi.edu> Date: 2 Aug 89 13:17:06 GMT Sender: daemon@tut.cis.ohio-state.edu Distribution: gnu Organization: GNUs Not Usenet Lines: 852 By the way, this needs a nifty name. I'm wide open for suggestions. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'irc-2' <<'END_OF_FILE' X (interactive "p") X (if (> (point) irc-mark) X ;; only delete as far back as irc-mark at most X (if (> arg (- (point) irc-mark)) (delete-region (point) irc-mark) X (delete-backward-char arg)) X (if (and (< (point) irc-mark) irc-spacebar-pages) (scroll-down nil) X (ding)))) X X(defun irc-tab () X "If point is in the input region then tab-to-tab-stop. If it is in the Xoutput region, go to the previous line if irc-spacebar-pages; do nothing Xotherwise." X (interactive) X (if (>= (point) irc-mark) (tab-to-tab-stop) X (if irc-spacebar-pages (previous-line 1) X (ding)))) X X;; top-level -- entry, sentinel and mode X(defun irc (new-buffer) X "Enter the Internet Relay Chat conferencing system. XIf no connexion to an irc-server is open, then one is started. If no buffer X*IRC* exists then it is created otherwise the existing buffer is used. If Xa connexion is already active then the most recently started IRC session Xis switched to in the current window. This makes binding 'irc' to a key Xmuch more convenient. X XWith prefix argument NEW-BUFFER, another *IRC* buffer is created and a Xnew IRC session is started. This is provided so that multiple IRC Xsessions can co-exist in one Emacs, which is sometimes a useful thing." X (interactive "P") X (let ((buffer (if new-buffer (generate-new-buffer "*IRC*") X (get-buffer-create "*IRC*"))) X proc) X (if (and (not new-buffer) irc-processes) X ;; just head for the most recent session X (switch-to-buffer (process-buffer (car irc-processes))) X (switch-to-buffer buffer) X (goto-char (point-max)) X (insert "IRC-mode for GNU Emacs -- comments to tale@pawl.rpi.edu." X " C-c n for news.\n\n") X (irc-mode) X (condition-case NOT-IRCED X (progn X (setq proc (open-network-stream "irc" buffer irc-server irc-port)) X (set-process-filter proc 'irc-filter) X (set-process-sentinel proc 'irc-sentinel) X (irc-send (format "USER %s %s %s %s" (user-login-name) X (system-name) irc-server (user-full-name))) X (irc-send (concat "NICK " irc-nick)) X ;; a new process, so initialize the variables. they aren't set X ;; in irc-mode so that irc-mode can be called at any time. X (setq irc-away nil irc-channel 0 irc-history-index -1 X irc-operator nil irc-scratch "" irc-last-command "" X irc-last-explicit "*;" irc-last-private "*;" X irc-processes (cons proc irc-processes) X irc-last-time (irc-get-time) X irc-total-time (string-to-int (substring irc-last-time 3)) X ;; this next bit of messiness just ups irc-last-stamp X ;; in an effort to make nice numbers out of the time X ;; stamps -- ie, if the time is now 13:53 with an interval X ;; of 15 minutes, this makes it 13:45 X irc-last-stamp 0 X irc-last-stamp (progn X (while (< (+ irc-last-stamp irc-time-stamp) X irc-total-time) X (setq irc-last-stamp (+ irc-last-stamp X irc-time-stamp))) X irc-last-stamp))) X (error (irc-insert "Sorry ... couldn't connect to %s at %s.\n\n" X irc-port irc-server)))))) X X(defun irc-mode () X "To understand some documentation given with irc-mode variables and Xfunctions, \"output region\" is defined as everything before the irc-mark. Xirc-mark is a marker kept by irc-mode to know where to insert new text Xfrom IRC. Text in the output region cannot be modified by the most common Xmethods of typing a self-inserting character or pressing delete. X XThe input region is everything which follows irc-mark. It is what Xgets processed by irc-mode when you type LFD or RET. If irc-spacebar-pages Xis non-nil, the following keys are in effect when the cursor is in the Xoutput region: X XSPC scroll-forward DEL scroll-backward XLFD or RET next-line TAB previous-line X XLocal keys: X\\{irc-mode-map}" X (interactive) X (kill-all-local-variables) X (setq major-mode 'irc-mode mode-name "IRC") X (make-local-variable 'irc-away) ; for the mode-line X (make-local-variable 'irc-channel) ; for sendlists and broken PRIVMSGs X (make-local-variable 'irc-wholist) ; for sendlists X (make-local-variable 'irc-operator) ; for special priviledges X (make-local-variable 'irc-history-index) ; for the message history X (make-local-variable 'irc-scratch) ; for accumulating server messages X (make-local-variable 'irc-last-command) ; for the command history X (make-local-variable 'irc-last-explicit) ; for sendlist ; auto-expansion X (make-local-variable 'irc-last-private) ; for sendlist : auto-expansion X (make-local-variable 'irc-last-stamp) ; for time-sentinel X (make-local-variable 'irc-last-time) ; ditto X (make-local-variable 'irc-total-time) ; here too X ;; too many ways to get unbalanced parens (most notably ":-)") X (set (make-local-variable 'blink-matching-paren) nil) X ;; closest we can come to "natural" terminal scrolling X (set (make-local-variable 'scroll-step) 1) X (set (make-local-variable 'mode-line-format) X (list (purecopy "--- %14b") 'global-mode-string X (purecopy " %[(") 'mode-name 'irc-operator 'minor-mode-alist X (purecopy ")%]---") 'irc-nick 'irc-away (purecopy "-%-"))) X (set-marker (set (make-local-variable 'irc-mark) (make-marker)) (point-max)) X (buffer-enable-undo) X ;; "invisible subwindows" or whatever you would like to call them would be X ;; nice. That way I could make the output-region read-only. The two things X ;; most likely to screw up the buffer are backward-kill-word and kill-region X (use-local-map irc-mode-map) X (run-hooks 'irc-mode-hook)) X X(defun irc-sentinel (proc stat) X "The sentinel for the IRC connexion. XTakes the normal sentinel arguments PROCESS and STATUS." X ;; ignore anything but finished; i don't know what to do with the others X (cond ((string= stat "finished\n") X (save-excursion X (set-buffer (process-buffer proc)) X (goto-char (point-max)) X (irc-insert "\nIRC session finished.\n")) X ;; all that needs to be done is a little maintenance ... X (setq irc-processes (delq proc irc-processes))))) X X;; processing input X(defun irc-process-input () X "If in the input region, parse it for messages and commands. XIn the output region, next-line if irc-spacebar-pages, otherwise do nothing. X XLines are examined on a line-at-a-time basis moving from irc-mark to point-max. XNormally only one line will be there, but there can be many, as in the result Xfrom a cut-and-paste operation. Lines are limited to 250 characters; commands Xwhich are longer are ignored but messages are split into smaller segments Xto fit the limitation. If a message needs to be split this way, \" >>\" is Xappended to each line which is split to indicate that the line is continued Xin the next message." X (interactive) X ;; do the simple stuff for the output region X (if (< (point) irc-mark) (if irc-spacebar-pages (next-line 1) (ding)) X (irc-check-time) X ;; the input region is more work ... X ;; first, toast extraneous spaces, tabs and newlines at end of input region X (delete-region (goto-char (point-max)) X (if (re-search-backward "[^ \t\n]" irc-mark t) X (1+ (point)) (point))) X ;; nuke the white space at the beginning of input region, too X (delete-region (goto-char irc-mark) X (progn (re-search-forward "\\s *") (point))) X (setq irc-history-index -1) ; reset the history scroll location X (let ((to-do (buffer-substring irc-mark (point-max))) line ass) X ;; check to see if the input region is empty X (if (string= "" to-do) (message "(nothing sent to the irc-server)") X (while (string< "" to-do) ; plug away, line-at-a-time X (setq line (substring to-do 0 (string-match "\n\\|$" to-do)) X ;; to-do is now one line less X to-do (substring to-do (match-end 0))) X ;; go to the end of the line X (re-search-forward (regexp-quote line)) X ;; if there are more lines after this, just hop over the newline X ;; otherwise add a newline so messages show up in the right place X (if (looking-at "\n") (forward-char 1) (insert "\n")) X (set-marker irc-mark (point)) X (cond X ((string-match "^/" line) ; it's a command X (if (< (length line) 250) X (irc-execute-command (setq irc-last-command X (substring line 1))) X ;; can't use error because that kills the function X (ding) (message "IRC commands can't exceed 250 characters."))) X ((string< "" line) ; ignore null lines X ;; "a specified sendlist" -- was there one? X (setq ass (irc-find-to line 'explicit)) X (if (and ass (string-match "^[^:;]" line)) X ;; a real sendlist was specified -- update irc-last-explicit X (setq irc-last-explicit (irc-find-to line))) X (if (> (length line) 250) ; sigh. this is going to be fugly X (let ((send (substring line 0 251)) X (keep (substring line 251))) X (cond ; shape up space for sending X ((string-match "^[ \t]" keep) X ;; probably broke at the end of a word; take out the space X ;; for the next message. tab is wretched; servers convert X ;; them to a single space anyway so trying to preserve X ;; spacing with it is futile X (setq keep (substring keep 1))) X ((string-match "[ \t]+\\([^ \t]*\\)$" send) X ;; broken in a word or before one; glue last bit on to X ;; the front of keep X (setq keep (concat (substring send (match-beginning 1)) X keep) X send (substring send 0 (match-beginning 0))))) X (setq send (substring send 0 (string-match "[ \t]*$" send)) X line (concat send " >>") X ;; make next line of to-do ready to go to same place X to-do (concat (if ass ";" "") keep to-do)) X ;; this seems the easiest way to make sure point is where X ;; it should be for the following insertion X (re-search-backward (concat "^" (regexp-quote send))) X (re-search-forward (regexp-quote send)) X (insert " >>\n" (if ass ";" "")) X ;; get rid of the leading space we just pushed down X (delete-char 1) X (beginning-of-line))) ; make sure point is okay for messages X (irc-add-to-hist ; put it in the history list X (irc-execute-msg (concat (if (not ass) irc-default-to) line))))))) X ;; finally make sure irc-mark is at the start of a fresh input region X (set-marker irc-mark (goto-char (point-max)))))) X X(defun irc-execute-command (str) X "Execute the \"/\" command of STR. STR should not begin with a slash. XCommands are first looked up in the irc-alias-alist; if it is found there Xthen the alias gets passed recursively with any arguments the original Xhad. The irc-command-alist is checked next and finally the irc-operator-alist. XA command is considered \"found\" when it matches either exactly or Xunambiguously starting at the first character. That is, J would match JOIN, Xbut OIN would not." X (let* ((case-fold-search t) X (cmd (substring str 0 (string-match "\\(\\s +\\|$\\)" str))) X (text (substring str (match-end 0))) X (ambig (irc-check-list X (mapcar 'car (append irc-alias-alist irc-command-alist X (if irc-operator irc-operator-alist))) X cmd 'start-only)) X matches) X ;; if no matches are found the command might still be a valid command X ;; name hiding behind non-operator status. i don't like messages that X ;; lie and say "Unknown command '/REHASH'" so this should make it not lie. X (if (and (not irc-operator) (null ambig)) X (setq ambig (irc-check-list (mapcar 'car irc-operator-alist) cmd t))) X ;; first determine any ambiguities among the lists X (if (null ambig) X ;; no matches at all were found X (irc-insert "Unknown command '/%s'. Type /HELP for help." X (upcase cmd)) X ;; this is here for when a regular command gets aliased. it shows up as X ;; being ambiguous but it really isn't later on. X (if (member-general (car ambig) (cdr ambig) 'string=) X (setq ambig (cdr ambig))) X (if (> (length ambig) 1) X (irc-insert "Ambiguous command '/%s'. Could be %s." (upcase cmd) X (irc-subst-comma X (mapconcat (function (lambda (arg) X (concat "/" arg))) ambig ", ") X "or")) X ;; alias list has highest priority X (setq matches (irc-check-list (mapcar 'car irc-alias-alist) cmd t)) X (if matches X ;; call this function again with the text as argument X (irc-execute-command X (concat (cdr (assoc (car matches) irc-alias-alist)) X ;; the servers won't grok trailing whitespace for some X ;; messages so only use it to separate an argument X (if (string< "" text) " ") text)) X ;; next try the command alist X (setq matches (irc-check-list (mapcar 'car irc-command-alist) cmd t)) X (if matches X ;; call the appropriate irc-execute-* function X (funcall (intern-soft X (concat "irc-execute-" X (cdr (assoc (car matches) X irc-command-alist)))) text) X ;; no matches yet. last resort is the operator alist X (setq matches (irc-check-list (mapcar 'car irc-operator-alist) X cmd t)) X (if matches X (if irc-operator X (funcall (intern-soft X (concat "irc-execute-" X (cdr (assoc (car matches) X irc-operator-alist)))) text) X (irc-insert "Only IRC Operators can use the /%s command." X (upcase (car matches))))))))))) X X(defun irc-send (str) X "Send STR to process in the current buffer. XA CR-LFD pair is appended automatically as per the 'official' IRC protocol, Xbut it seems unnecessary. Returns its argument STR." X (send-string (get-buffer-process (current-buffer)) (concat str "\r\n")) X str) X X;; sending messages to people X(defun irc-execute-privmsg (str) X "Usage: /MSG recipient(s) message X XThis command is provided simply for compatability with the C client. It is Xpreferable instead to just type the name of the user followed by a semi-colon Xor colon and then the message. That is, \"tale;hi!\" will send the message X\"hi!\" to the user with the nickname which unambiguously matches \"tale\". XA semi-colon or colon at the beginning of the line means to send to the last Xrecipient explicity specified; typing a semi-colon at the beginning of a line Xexpands it to the last recipient(s) specified while typing a colon at the Xbeginning of the line automatically expands to the last person to have sent Xyou a private message. The recipients for a message can be a comma separated Xlist of users and/or channels." X (irc-add-to-hist X (irc-execute-msg (concat X (setq irc-last-explicit X (concat (substring X str 0 (string-match "\\s +\\|$" str)) ";")) X (substring str (match-end 0)))))) X X(defun irc-execute-msg (str) X "Send a message to a channel or another user. Returns its argument STR, Xmunged slightly to indicate where it was attempted to be sent." X ;; this really is an indirect fucntion of the UI (ie, not through a /COMMAND) X ;; so it isn't interactive X (let (tolist (orig str) icw confirm) X (if (string-match "^[;:]" str) X ;; a little bit of fill-in-the-blank X (setq str (concat irc-last-explicit (substring str 1))) X (if (not (irc-find-to str 'explicit)) X ;; prepend an implicit sendlist if need be X (if irc-default-to (setq str (concat irc-default-to str)) X (irc-insert "You have no default sendlist.")))) X (if (irc-find-to str 'explicit) X (setq icw (irc-find-to str) X tolist (irc-burst-comma (substring icw 0 (1- (length icw)))) X str (irc-find-message str))) X (setq X confirm X (delq ; whee. lisp indentation is fun. X nil X (mapcar (function X (lambda (to) X (if (not (zerop (string-to-int to))) X (if (= (string-to-int to) irc-channel) X (progn (irc-send (concat "MSG :" str)) to) X ;; new in 1.2 -- you _can_ send to a channel you X ;; are not on X (ir-send (concat "PRIVMSG " to " :" str)) X to) X (setq icw (irc-check-list irc-wholist to)) X (cond X ((string= to "*") X (if (zerop irc-channel) X (progn (irc-insert "You are not on any channel.") nil) X (irc-send (concat "MSG :" str)) X (int-to-string irc-channel))) X ((string= to "0") X (irc-insert "You can't send to channel 0.") nil) X ((= (length icw) 1) X (irc-send (concat "PRIVMSG " (car icw) " :" str)) X (car icw)) X ((not icw) X ;; wox. no one found, but we'll do a nonomatch. try X ;; sending it anyway and let the server bitch if necessary X (irc-maintain-list 'irc-wholist to 'add) X (irc-send (concat "PRIVMSG " to " :" str)) X to) X (t X (irc-insert "Ambiguous recipient \"%s\"; could be %s." X to (irc-subst-comma X (mapconcat 'eval icw ", ") "or")) nil))))) X tolist))) X (if (and confirm irc-confirm) X (irc-insert "(message sent to %s)" X (irc-subst-comma (mapconcat 'eval confirm ", ") "and")) X (if (not confirm) (irc-insert "(message not sent)"))) X orig)) X X(defun irc-execute-oops (newto) ; one of my favourites. X "Usage: /OOPS intended-recipient X XSend irc-oops to recipient(s) of last message and resend message to X'intended-recipient'. This command is handy when you've just sent a message Xto the wrong place and you want the person/people who saw it to know that they Xshould just disregard it. The message which was originally sent then gets Xforwarded to its proper destination." X (interactive) X ;; first do the oops message X (irc-execute-msg (concat (irc-find-to (car irc-history)) irc-oops)) X ;; then resend the original X (irc-execute-redirect newto)) X X(defun irc-execute-redirect (newto) X "Usage: /REDIRECT additional-recipient X XSend to 'additional-recipient' the last message which you sent. This Xcommand can be fairly easily duplicated using the history mechanism by hand Xbut it is provided to make it even easier." X (interactive (list X (read-string X (format "New recipient(s)? %s" X (if irc-default-to X (concat "[RET for " X (substring irc-default-to 0 X (1- (length irc-default-to))) X "] ") X ""))))) X (if (not (string-match "^[a-zA-Z0-9-_,|{*]*$" newto)) X ;; perhaps crapping out here is too harsh X (irc-insert "%s is not a valid sendlist. Message not redirected." newto) X (if (and (not (interactive-p)) (string= "" newto)) X (call-interactively 'irc-execute-redirect) X (setq newto (if (string= "" newto) irc-default-to (concat newto ";")) X irc-last-explicit newto) X (irc-add-to-hist X (irc-execute-msg (concat newto X (irc-find-message (car irc-history)))))))) X X;; /commands for the server X(defun irc-execute-quote (msg) X "Usage: /QUOTE string X XThis command is used to send 'string' directly to the IRC server without Xany local processing. Warning: this has the potential to screw up some Xthings in irc-mode, particularly if it is used to change your nickname or Xto switch channels." X (interactive "sString to send to server: ") X (if (string-match "^\\s *$" msg) X (irc-insert "(nothing was sent to the IRC server)") X (irc-send msg))) X X(defun irc-execute-who (channel) X "Usage: /WHO [ channel ] X XGet a list of the users on IRC. Optional argument 'channel' means to show Xjust the users on that channel, with * representing the current channel. X XEach user is indicated on a separate line with their nickname, channel, login Xname, host and real name. The first column indicates their status -- X' ' for here, '-' for away, '*' for an operator, '=' for an away operator Xand '#' for someone being ignored. Servers don't propogate the information Xabout who is away so you will probably only see people on your server Xcorrectly marked regarding their presence. X XUsers who are either on a channel greater than 1000 or who are on no channel Xhave nothing listed in the Chan column. Users who are on channels less than Xzero do not appear in the list. X XIf this function is called interactively then the prefix argument is used Xas the channel to query. No argument means all of them and an argument of - Xmeans the current channel." X (interactive (if current-prefix-arg X (if (eq current-prefix-arg '-) '("*") X (list (int-to-string X (prefix-numeric-value current-prefix-arg)))) X '("0"))) X ;; make * be the current channel, even though the server groks it. X (if (string-match "^\\s *\\*\\(\\s .*\\)?$" channel) X (setq channel (list (int-to-string irc-channel)))) X ;; if channel converts to 0 then we will get fresh information about X ;; who is present. X (if (zerop (string-to-int channel)) X (setq irc-wholist nil)) X (irc-send (concat "WHO " channel)) X ;; a nice blank line at the top of the list X (irc-insert "")) X X(defun irc-execute-list (&optional channel) X "Usage: /LIST [ channel ] X XGet a list of the discussions that are on IRC. The optional channel argument Xis supposed to show just that channel but this is not currently supported Xby most servers." X ;; according to Comms LIST can take an optional channel number. X ;; don't believe it -- it doesn't. I send one anyway just in case it X ;; gets fixed; in the meantime servers seem to ignore any extra stuff X (interactive) X (irc-send (concat "LIST " channel)) X ;; put a blank line before the list X (irc-insert "")) X X(defun irc-execute-links (&optional cruft) X "Usage: /LINKS X XShow the names of all the servers which can communicate with your server. XThe links can go down isolating different parts of the IRC-net, so this Xis a good way to find out how extensive it is at the moment. Any arguments Xto this command are ignored." X (interactive) X (irc-send "LINKS") X (irc-insert "")) X X(defun irc-execute-admin (server) ; what an evil thought X "Usage: /ADMIN [ server ] X XGet information about the IRC administrator for 'server'; if server is not Xsupplied just query for the server to which you are connected." X (interactive "sAdministrative info about which server? ") X (irc-send (concat "ADMIN " server)) X (irc-insert "")) X X(defun irc-execute-time (&optional server) X "Usage: /TIME [ server ] X XGet the current time on 'server'; is no server is provided use the one to which Xyou are connected. When called with a interactively with a prefix-argument Xthe server name is read using the minibuffer. X XQuerying other servers can be handy given that people on IRC are spread out X from the west coast of the United States to Finland. The question \"What Xtime is it in Finland?\" comes up so frequently that an alias -- /TF -- has Xbeen provided by default to get the answer. This alias should work as long Xas tut.fi is connected to your IRC-net." X (interactive (if current-prefix-arg X (list (read-string "Get time at which server? ")) X '(""))) X (irc-send (concat "TIME " server))) X X(defun irc-execute-join (channel) X "Usage: /JOIN channel X XJoin 'channel' on IRC. If channel is not provided it is requested in the Xminibuffer; when called interactively channel is set to the prefix argument if Xone is present. Use /LEAVE to exit the channel." X (interactive (if current-prefix-arg X (list (int-to-string X (prefix-numeric-value current-prefix-arg))) X '(""))) X (if (string= channel "") X (setq channel (read-string "Channel to join? "))) X (if (string-match "^\\s *$" channel) () ; well, so much for that X ;; the seeming no-op is nice for turning random garbage into "0" X (irc-send (concat "CHANNEL " (int-to-string (string-to-int channel)))) X ;; this is only here so we can give a "left channel" message X (put 'irc-channel 'o-chan irc-channel) X (setq irc-channel (string-to-int channel)))) X X(defun irc-execute-leave (&optional cruft) X "Usage: /LEAVE X XLeave your current channel and join no other. Any arguments to this command Xare ignored." X (interactive) X ;; for the left channel n message X (put 'irc-channel 'o-chan irc-channel) X (setq irc-channel 0) X (irc-send "CHANNEL 0")) X X(defun irc-execute-nick (name) X "Usage: /NICKNAME name X XChange your nickname in IRC. A nickname can contain alphanumeric characters, Xunderscores (_), hyphens (-) or the special characters vertical bar (|) and Xleft brace ({), which are alphabetic characters in Finnish. The name cannot Xstart with a hyphen or number and only the first nine characters are used. X XUnfortunately, due to the way confirmation from the servers work, it might be Xfalsely reported that your nickname was successfully changed when it was not. XThe server will come back and say so and finally irc-mode will wise-up and Xnote that your nickname was not changed." X (interactive "sNew nickname? ") X (while (not (string-match "^\\([a-zA-Z|{_][a-zA-Z0-9-_|{]*\)$" name)) X (setq name (read-string X (format "\"%s\" is not valid. New nickname? " name)))) X (if (> (length name) 9) (setq name (substring name 0 9))) X (if (string= "" name) X (if (interactive-p) X (irc-insert "Nickname not changed.") X (call-interactively 'irc-execute-nick)) X (irc-insert "You will now be known as \"%s\"." name) X (put 'irc-nick 'o-nick irc-nick) X (setq irc-nick name) X (set-buffer-modified-p (buffer-modified-p)) X (irc-send (concat "NICK " name)))) X X(defun irc-execute-quit (&optional text) X "Usage: /QUIT X XExit IRC. The connexion is closed but the buffer is left behind. XArguments to this command are not ignored; if any are present then Xthe session is not exited as a safety precaution against seemingly Xunintentional use of the command." X (interactive) X (if (and text (string< "" text)) X (irc-insert "/QUIT takes no arguments.") X (irc-send "QUIT"))) X X(defun irc-execute-away (&optional text) X "Usage: /AWAY message X XMark yourself as away, giving TEXT to people who send you private messages. XWithout any arguments it will just insert a message about your current status." X (interactive "sReason for being away: ") X (if (string= "" text) X (if irc-away X (irc-insert "You are marked as away: '%s'." irc-away) X (irc-insert "You are not currently marked as being away.")) X (irc-send (concat "AWAY " text)) X (setq irc-away (concat " [" text "]"))) X (set-buffer-modified-p (buffer-modified-p))) X X(defun irc-execute-here (&optional cruft) X "Usage: /HERE X XMark yourself as present (ie, not \"away\") on IRC. Any arguments to this Xcommand are ignored." X (interactive) X (irc-send "AWAY") X (setq irc-away nil) X (set-buffer-modified-p (buffer-modified-p))) X X(defun irc-execute-whois (user) X "Usage: /WHOIS user X XGet a two line description of who and where 'user' is. If user is not Xprovided it is read from the minibuffer with a completing-read." X (interactive '("")) X (setq user (irc-read-user "Who is who? " user)) X (if (string< "" user) (irc-send (concat "WHOIS " user)))) X X(defun irc-execute-topic (topic) X "Usage: /TOPIC topic X XMake 'topic' the description of the current channel; this description is Xshown to people looking at the channel listing." X (interactive (list (if (zerop irc-channel) "" X (read-string (format "Topic for channel %d? " X irc-channel))))) X (if (zerop irc-channel) X (irc-insert "You aren't on any channel.") X (if (and (not (interactive-p)) (string-match "^\\s *$" topic)) X (call-interactively 'irc-execute-topic) X (irc-send (concat "TOPIC " topic))))) X X(defun irc-execute-oper (oper) ; for crimes against humanity X "Usage: /OPER [ name [ password ]] X XAttempt to become an IRC Operator. Can take the name of the operator Xand the password as arguments. If name is missing then it will be read Xfrom the minibuffer; if password is missing it will be read and hidden Xin the minibuffer. X XIf you become an operator then the word \"Operator\" will appear in the Xminibuffer along with the mode name." X (interactive "sOperator name? ") X (string-match "^\\s *\\(\\S *\\)\\s *\\(\\S *\\).*$" oper) X (let* ((name (substring oper (match-beginning 1) (match-end 1))) X (passwd (substring oper (match-beginning 2) (match-end 2))) X (noname (string= "" name))) X (if (and (interactive-p) noname) () ; just drop right through X (if noname (call-interactively 'irc-execute-oper) X (if (string= "" passwd) X (setq passwd X (irc-read-passwd (format "Password for operator %s? " X name)))) X (irc-send (concat "OPER " name " " passwd)))))) X X(defun irc-execute-summon (user) X "Usage: /SUMMON user X XSummon a user not on IRC to join IRC. The argument provided may either be Xa user name on the local machine or user@server, where server is another Xmachine on the IRC-net. The user must be signed on to the specified server." X (interactive "sUser to summon to IRC? ") X (let ((nouser (string-match "^\\s *$" user))) X (if (and (interactive-p) nouser) () ; guess s/he didn't really mean it ... X (if nouser (call-interactively 'irc-execute-summon) X (irc-send (concat "SUMMON " user)))))) X X(defun irc-execute-users (host) ; this is entirely too violent X "Usage: /USERS [ server ] X XGet a list of the users signed on to 'server'. If no server name is provided Xthen the server to which you are connected is used. When called interactively Xa prefix argument means to prompt for the server to query." X (interactive (if current-prefix-arg X (list (read-string "List users on which host? ")) X '(""))) X (irc-insert "") X (irc-send (concat "USERS " host))) X X(defun irc-execute-info (&optional cruft) X "Usage: /INFO X XShow some information about the programmer of IRC. Arguments to this command Xare ignored." X (interactive) (irc-send "INFO")) X X(defun irc-execute-kill (user) X "Usage: /KILL user X XForcibly remove a user from IRC. This command is reserved for IRC Operators." X (interactive '("")) X (setq user (irc-read-user "Nuke which user? " user)) X (if (string< "" user) (irc-send (concat "KILL " user)))) X X(defun irc-execute-invite (user) X "Usage: /INVITE user [ channel ] X XAsk 'user' on IRC to join 'channel'. If channel is 0, * or not provided then Xthe invitation defaults to your current channel. If you are not on any channel Xand channel is 0 or not provided then no invitation is sent -- you can't Xinvite someone to go private. When called interactively channel is set to Xthe prefix argument; with no argument or - the current channel is assumed." X (interactive (list X (int-to-string X (if (and current-prefix-arg (not (eq current-prefix-arg '-))) X (prefix-numeric-value current-prefix-arg) X irc-channel)))) X (if (interactive-p) X (progn X (if (and (zerop irc-channel) (string= "0" user)) X (setq user (read-string "Invite to which channel? "))) X ;; this is so irc-read-user will force a completing-read X ;; something needs to come up as "name" so that "channel" comes up in X ;; the right place. a tiny kludge but the results are the same X (setq user (concat ". " user)))) X (string-match "^\\s *\\(\\S *\\)\\s *\\(\\S *\\).*$" user) X (let* ((name (substring user (match-beginning 1) (match-end 1))) X (channel (substring user (match-beginning 2) (match-end 2))) X (noname (string= "" name))) X (cond X (noname (call-interactively 'irc-execute-invite)) ; no arguments ... X ((and (zerop irc-channel) (zerop (string-to-int channel))) X (irc-insert "You are not on any channel. No invitation sent.")) X (t (setq name (irc-read-user (format "Invite whom to channel %d? " X (string-to-int channel)) X (if (string= "." name) "" name))) X (if (string< "" name) X (irc-send (concat "INVITE " name " " channel))))))) X X(defun irc-execute-names (channel) X "Usage: /NAMES [ channel ] X XShow which channels everyone is on. Optional argument 'channel' (which can Xbe provided as a prefix argument if called interactively) means to show Xjust the users on that channel. * or an interactive prefix argument of - Xmeans to show people on the current channel. X XEach line starts with a column for the channel number and is followed by the Xnicknames of the people on that channel. Users who are on private channels Xor who are not on any channel are listed as \"Private\". Users who are Xon secret channels (channels less than 0) are not shown at all." X (interactive (if current-prefix-arg X (list X (if (eq current-prefix-arg '-) '("*") X (list (int-to-string X (prefix-numeric-value current-prefix-arg))))) X '("0"))) X ;; server doesn't understand * for current channel. but we want to be X ;; nice and consistent in the client so we take it. X (if (string-match "^\\s *\\*\\(\\s .*\\)?$" channel) X (setq channel (int-to-string irc-channel))) X ;; have to do some weird things here. servers don't grok a NAMES 0 X ;; at all so have to make anything that appears to be 0 really disappear. X ;; names also provides us with fresh information on who is around. X (if (zerop (string-to-int channel)) X (setq irc-wholist nil channel "")) X (irc-send (concat "NAMES " channel)) X ;; need a header here. server is not gratuitous as in WHOREPLY. X (irc-insert "\nChannel Users")) X X(defun irc-execute-wall (msg) X "Usage: /WALL message X XSend 'message' to everyone on IRC. This can only be done by IRC Operators." X (interactive "sMessage for everyone: ") X (if (and (not (interactive-p)) (string= "" msg)) X (call-interactively irc-execute-wall) X (if (string< "" msg) X (irc-send (concat "WALL " msg))))) X X(defun irc-execute-rehash (&optional cruft) X "Usage: /REHASH X XForce the server to which you are connected to reread it's irc.conf file. XArguments are ignored. This command is only available to IRC Operators." X ;; what a joy this was to write X (interactive) (irc-send "REHASH")) X X(defun irc-execute-trace (server) X "Usage: /TRACE [ server ] X XFind the route from the server to which you are attached to 'server'; if the Xserver argument is not provided then the servers to which the current server Xis directly connected are listed. This command is only available to IRC XOperators." X (interactive (list (if current-prefix-arg X (read-string "Trace route to which server? ") X ""))) X (string-match "^\\s *\\(\\S *\\).*$" server) X (irc-send (concat "TRACE " X (substring server (match-beginning 1) (match-end 1)))) X (irc-insert "")) X X;; /command just for the client (need /stamp /alias /unalias) X(defun irc-execute-send (slist) X "Usage: /SEND [ sendlist | - ] X XSet the default sendlist for IRC messages. This is a comma separated list Xof the intended recipient(s) of messages which do not have an explicit Xsendlist. '-' as an argument means to disable the default sendlist; every Xmessage sent then must have an explicit recipient provided with the message. XWithout any arguments this command just displays the current default sendlist. X XEach item specified is checked to see whether you can send there; ambiguous Xreferences to users are not allowed nor are channels which you are not on. X\"*\" is always allowed and means to send to the current channel. XIf no item in the new list can be set then the sendlist is not changed." X (interactive "sDefault recipient(s) for messages? ") X ;; blast some whitespace X (setq slist (irc-nuke-whitespace slist)) X (let (matches) X ;; first the easiest case X (if (string= "-" slist) (setq irc-default-to nil) X (setq matches X (delq nil ; more indentation fun. can someone X (mapcar ; recommend a good style manual? X (function X (lambda (arg) X (setq matches (irc-check-list irc-wholist arg)) X (cond X ((string= arg "*") arg) END_OF_FILE if test 38561 -ne `wc -c <'irc-2'`; then echo shar: \"'irc-2'\" unpacked with wrong size! fi # end of 'irc-2' fi echo shar: End of archive 2 \(of 3\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 3 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0