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 3 of 3) Message-ID: <8908021319.AA15338@pawl.rpi.edu> Date: 2 Aug 89 13:19:03 GMT Sender: daemon@tut.cis.ohio-state.edu Distribution: gnu Organization: GNUs Not Usenet Lines: 848 #! /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-3' <<'END_OF_FILE' X ((string= arg "0") X (irc-insert "You can't send to channel 0.") nil) X ((not (zerop (string-to-int arg))) X (if (= (string-to-int arg) irc-channel) arg X (irc-insert "You are not on channel %s." arg) nil)) X ((= (length matches) 1) (car matches)) X ((eq matches nil) X (irc-insert "No names found to match \"%s\"." arg) nil) X (t X (irc-insert "Ambiguous recipient \"%s\"; could be %s." X to (irc-subst-comma X (mapconcat 'eval matches ", ") "or")) X nil)))) (irc-burst-comma slist)))) X (if matches X (setq irc-default-to (concat (mapconcat 'eval matches ",") ";")) X (or (string= "" slist) ; only print the error if tried to set it. X (irc-insert "(no matches -- sendlist not changed)")))) X (if (not irc-default-to) (irc-insert "Your default sendlist is disabled.") X (irc-insert X "You are sending to %s." X (irc-subst-comma X (mapconcat 'eval X (irc-burst-comma X (substring irc-default-to 0 X (1- (length irc-default-to)))) ", ") "and"))))) X X(defun irc-execute-notify (notify) X "Usage: /NOTIFY [ [+]event | -event ] [...] X XSet the list of events to notify you about with a message. Notification Xis a one-line message inserted when someone causes that event to occur. XEvents are added with +event or simply event; they are removed with -event. X+ adds all supported events and - removes all supported events. More than Xone event can be specified in the arguments. In case of conflict, the argument Xwhich appears later overrides the argument with which it conflicts. X XCurrently supported by /NOTIFY are the 'join' and 'nick' events. Join happens Xwhenever someone enters or leaves a channel which you are on. Nick occurs Xwhen someone changes nicknames; recognition of this event is currently limited Xto when the person making the change is on the same channel as you." X (interactive "sNotify for events: ") X ;; die scurvy whitespace X (setq notify (irc-nuke-whitespace notify)) X (let ((recog '(join nick)) (str notify) sym off event) X (while (string< "" notify) X ;; multiple args are okay. we'll do one at a time. X (setq str (substring notify 0 (string-match "\\s +\\|$" notify)) X notify (substring notify (match-end 0))) X (string-match "^\\([-+]?\\)\\(.*\\)$" str) X (setq off (string= "-" (substring str (match-beginning 1) (match-end 1))) X event (substring str (match-beginning 2) (match-end 2)) X sym (if (string= "" event) nil X (car (delq nil ; do some minor pattern matching X (mapcar ; to find the intended event X (function X (lambda (arg) X (if (string-match X (concat "^" (regexp-quote event)) X (prin1-to-string arg)) X arg))) recog))))) X (cond X ((and (string= "" event) off) (setq irc-notifies nil)) X ;; the only way for this to happen and not the above is str == "+" X ((string= "" event) (setq irc-notifies recog)) X ((null sym) (irc-insert "Notify: Unknown argument '%s'." event)) X (t (setq irc-notifies (if off (delq sym irc-notifies) X (if (not (memq sym irc-notifies)) ; avoid X (cons sym irc-notifies) ; redundancy X irc-notifies)))))) X (if irc-notifies X (irc-insert "Notification is currently enabled for %s." X (irc-subst-comma (mapconcat 'prin1-to-string irc-notifies X ", ") "and")) X (irc-insert "Notification is currently disabled.")))) X X(defun irc-execute-confirm (str) X "Usage: /CONFIRM [ + | - ] X XTurn on message confirmation with + or off with -. Any other arguments or no Xarguments just gives a message about the current setting. X XMessage confirmation is a line indicating to whom a message was sent. XOccasionally this will say that a message has been sent to someone who Xwas not present but another message soon after will set the record straight." X (interactive "sSet confimation on (+) or off (-)? ") X ;; grab the first arg X (string-match "^\\s *\\(\\S *\\).*$" str) X (setq str (match-beginning 1) (match-end 1)) X (cond ((string= str "+") (setq irc-confirm t)) X ((string= str "-") (setq irc-confirm nil))) X (irc-insert "Message confirmation is %s." (if irc-confirm "on" "off"))) X X(defun irc-execute-ignore (user) X "Usage: /IGNORE user X XIgnore another user on IRC. Any events by this person (except for WALL) Xare not displayed. With no arguments a list of all currently ignored people. X XIRC-mode will track the ignored user across nickname changes if it notices the Xchange. If the user sends either a private message or an invitation to you Xwhile being ignored a message will be sent to that person saying \"You are Xbeing ignored.\" To undo this command, use /UNIGNORE." X (interactive '("")) X (if (or (interactive-p) (not (string= "" user))) X (setq user (irc-read-user "Ignore which user? " user))) X (if (string= "" user) X (if irc-ignores X (irc-insert "You are currently ignoring %s." X (irc-subst-comma (mapconcat 'eval irc-ignores ", ") X "and")) X (irc-insert "You are not ignoring anyone.")) X (irc-insert "You are now ignoring %s." user) X (irc-maintain-list 'irc-ignores user 'add))) X X(defun irc-execute-unignore (user) X "Usage: /UNIGNORE user | + | - X XStop ignoring a user who has been /IGNOREd. The special arguments + or - Xmean to stop ignoring everyone who is being ignored." X ;; how long a doc string could I write for this? X (interactive '("")) X (if (null irc-ignores) X (irc-insert "You are not ignoring anyone.") X (if (string-match "^\\s *\\([-+]\\)\\(\\s |$\\)") X (progn (setq irc-ignores nil) X (irc-insert "You are no longer ignoring anyone.")) X (setq user (irc-read-user "Stop ignoring whom? " user irc-ignores)) X (if (string= "" user) () X (irc-insert "You are no longer ignoring %s." user) X (irc-maintain-list 'irc-ignores user 'remove))))) X X(defun irc-execute-signal (sigs) X "Usage: /SIGNAL [ + | - | [+]event | -event ] [...] X XSet the events which will get signals (aks bells or dings) when they Xoccur. Events supported are: X X private -- private messages join -- channel joining/leaving X public -- public messages invite -- invitations X wall -- broadcast messages nick -- nickname changes X XWithout any arguments /SIGNAL simply prints a message about what signals Xare currently enabled. With event or +event turn on all signalling for that Xevent. Remove all signals for an event with -event. /SIGNAL + or /SIGNAL - Xadds or removes all signals respectively. Multiple arguments are accepted; Xlater ones take precedence over the ones which came before them. For example, X'/SIGNAL - +w +i' would turn off all signals and then turn on signalling only Xfor wall messages and invitations." X (interactive "sSet signal: ") X ;; blow some whitespace away. curiously this doesn't work correctly in debug X (setq sigs (irc-nuke-whitespace sigs)) X (let ((recog '(private public wall invite join nick)) str sym on off event) X (while (string< "" sigs) X ;; take one argument at a time X (setq str (substring sigs 0 (string-match "\\s +\\|$" sigs)) X sigs (substring sigs (match-end 0))) X (string-match "^\\([-+]?\\)\\(.*\\)$" str) X (setq off (string= "-" (substring str (match-beginning 1) (match-end 1))) X event (substring str (match-beginning 2) (match-end 2)) X sym (if (string= "" event) nil X (car (delq nil X (mapcar X (function X (lambda (arg) X (if (string-match X (concat "^" (regexp-quote event)) X (prin1-to-string arg)) X arg))) recog))))) X (cond X ((and (string= "" event) off) X (setq irc-signals (mapcar 'list recog))) X ((string= "" event) X (setq irc-signals (mapcar X (function (lambda (arg) (list arg t))) recog))) X ((null sym) (irc-insert "Signal: Unknown argument '%s'." event)) X (t (if off (setcdr (assoc sym irc-signals) nil) X (setcdr (assoc sym irc-signals) '(t)))))) X (setq on (delq nil X (mapcar ; test against t because I have plans X (function ; to couple users and events X (lambda (arg) X (if (eq (nth 1 (assoc arg irc-signals)) t) X arg))) recog))) X (if on X (irc-insert (concat "Signalling is enabled for " X (irc-subst-comma X (mapconcat 'prin1-to-string on ", ") "and") ".")) X (irc-insert "All signalling is currently disabled.")))) X X(defun irc-execute-stamp (stamp) X "Usage: /STAMP [ + | - | [+]event | -event | interval ] [...] X XSet time-stamping for IRC. + means to turn it on for all messages from users Xand - means to turn it off for them. +event or just event will turn it on for Xthat class of message and -event means to disable it for those messages. An Xinteger interval means to insert a message indicating the time every N minutes, Xwhere N is the interval. With no arguments simply insert a message indicating Xthe current time-stamps. X XThe current time in HH:MM format can appear two different ways in IRC. One is Xto have it associate with 'event'; two events, 'private' and 'public' messages, Xare supported this way. The other is to have it as a stand-alone message Xindicating the current time. Both can be very useful in noting when someone Xactually sent you a message or when another event happened if you happen to be Xaway for a while. The accuracy of the interval timer is currently limited to X0-2 minutes beyond the interval. It can be turned off by setting the interval Xto 0." X (interactive "sSet time-stamp: ") X ;; whee. napalm would feel particularly good here. X (setq stamp (irc-nuke-whitespace stamp)) X (let (str sym event off) X (while (string< "" stamp) X ;; as the args go marching one by one the last one stopped ... X (setq str (substring stamp 0 (string-match "\\s +\\|$" stamp)) X stamp (substring stamp (match-end 0))) X (string-match "^\\([-+]?\\)\\(.*\\)$" str) X (setq off (string= "-" (substring str (match-beginning 1) (match-end 1))) X event (substring str (match-beginning 2) (match-end 2)) X sym (cond ((string= "" event) nil) X ((string-match (concat "^" (regexp-quote event)) X "private") 'private) X ((string-match (concat "^" (regexp-quote event)) X "public") 'public) X ((natnump (car (read-from-string event))) X (car (read-from-string event))))) X ;; the following cond is really what sets eveything X (cond ((and (string= "" event) off) (setq irc-message-stamp nil)) X ((string= "" event) (setq irc-message-stamp t)) X ((null sym) (irc-insert "Stamp: Unknown argument '%s'." event)) X ((natnump sym) (setq irc-time-stamp sym)) X (off (setq irc-message-stamp X (car (delq sym (if (eq irc-message-stamp t) X '(private public) X (list irc-message-stamp)))))) X (t (setq irc-message-stamp X (cond ((null irc-message-stamp) sym) X ((or (eq irc-message-stamp t) X (eq irc-message-stamp sym)) irc-message-stamp) X (t t))))))) X (irc-insert "%s messages get time-stamps.%s" X (cond ((eq irc-message-stamp t) "Private and public") X ((null irc-message-stamp) "No") X (t (capitalize (prin1-to-string irc-message-stamp)))) X (if (zerop irc-time-stamp) "" X (format " The time-stamp interval is %d minutes." X irc-time-stamp)))) X X(defun irc-execute-alias (alias) X "Usage: /ALIAS [ alias [ command [ args for command ]]] X XAllow 'alias' to be equivalent to 'command'. XFor example, \"/ALIAS tf time tut.fi\" will make typing \"/tf\" be equivalent Xto having issued the command \"/time tut.fi\". Aliases can only be made Xto existing commands not other aliases. They are also only recognized when Xin the command name position of a line. If given with no arguments then Xall aliases are displayed; if given with just an alias name then the alias Xwith that name will be shown. Aliases can be removed with /UNALIAS." X (interactive "sName for alias? ") X (if (interactive-p) X (setq alias (concat alias " " X (read-string (format "Alias '%s' to which command? " X alias))))) X (setq alias (irc-nuke-whitespace alias)) X (string-match "^/?\\(\\S *\\)\\s */?\\(\\S *\\)\\s *\\(.*\\)$" alias) X (let ((new (upcase (substring alias (match-beginning 1) (match-end 1)))) X (cmd (upcase (substring alias (match-beginning 2) (match-end 2)))) X (arg (substring alias (match-beginning 3) (match-end 3))) X match) X (cond X ((string= "" new) X (let ((aliases irc-alias-alist)) X (while aliases X (irc-insert "\"/%s\" is aliased to \"/%s\"." X (car (car aliases)) (cdr (car aliases))) X (setq aliases (cdr aliases))))) X ((string= "" cmd) X (let ((alias (assoc new irc-alias-alist))) X (if alias X (irc-insert "\"/%s\" is aliased to \"/%s\"." X (car alias) (cdr alias)) X ;; this could possibly have done some matching to see whether X ;; just an abbrev was being given, but we'll just take it as given X (irc-insert "\"/%s\" is not aliased." new)))) X (t ; okay, we've got at least a command. let's try and make this as X ; painless as possible. X (setq match X (irc-check-list (mapcar 'car (append irc-command-alist X (if irc-operator X irc-operator-alist))) X cmd 'start-only)) X ;; try not to confuse a regular user with commands he couldn't use X ;; anyway, but let him at it if that's what he really wants. it'll X ;; just come through as an error from the server in the long run ... X (if (and (not match) (not irc-operator)) X (setq match (irc-check-list (mapcar 'car irc-operator) cmd t))) X (if (/= (length match) 1) X (if match X (irc-insert "'/%s' is an ambiguous command. Could be %s." cmd X (irc-subst-comma (mapconcat 'eval match ", ") "or")) X (irc-insert "Command not found: '/%s'." cmd)) X ;; alias might be in the list already; if it is, just replace it X (if (assoc new irc-alias-alist) X (setcdr (assoc new irc-alias-alist) ; no trailing space if no arg X (concat (downcase (car match)) X (if (string= "" arg) "" " ") arg)) X (setq irc-alias-alist X (cons (cons new (concat (downcase (car match)) X (if (string= "" arg) "" " ") arg)) X irc-alias-alist))) X (irc-insert "\"/%s\" has been aliased to \"/%s\"." new X (cdr (assoc new irc-alias-alist)))))))) X X(defun irc-execute-unalias (alias) X "Usage: /UNALIAS alias X XRemove the 'alias' for a command." X ;; well, that's a pretty dull doc string. X (interactive (list (completing-read "Unalias which command? " X (cons '("" . "") irc-alias-alist) X nil t))) X (string-match "^\\s *\\(\\S *\\)\\s *$" alias) X (setq alias (substring alias (match-beginning 1) (match-end 1))) X (if (string= "" alias) X (if (not (interactive-p)) X (call-interactively 'irc-execute-unalias)) X (let ((match (irc-check-list (mapcar 'car irc-alias-alist) alias t))) X (if (/= (length match) 1) X (if match X (irc-insert "'%s' is an ambiguous alias. Could be %s." X (upcase alias) X (irc-subst-comma (mapconcat 'eval match ", ") "or")) X (irc-insert "No alias found to match '%s'." (upcase alias))) X (setq irc-alias-alist (delq (assoc (car match) irc-alias-alist) X irc-alias-alist)) X (irc-insert "'%s' is no longer aliased." (car match)))))) X X(defun irc-execute-help (topic) X "Usage: /HELP topic X XGet the documentation for 'command'. If no command is given then a list Xof the possible topics is shown. Note that commands for IRC Operators will Xnot appear in the help topics when not an IRC Operator." X (interactive "sHelp for which command? ") X (string-match "^\\s *\\(\\S *\\)\\s *$" topic) X (setq topic (substring topic (match-beginning 1) (match-end 1))) X (if (string= topic "") X (let ((str "Help is available for the following IRC-mode commands:\n") X (topics (mapcar 'car X (append irc-command-alist X (if irc-operator irc-operator-alist))))) X (while topics X (setq str X (concat str X (format "\n%14s%14s%14s%14s%14s" X (nth 0 topics) X (or (nth 1 topics) "") (or (nth 2 topics) "") X (or (nth 3 topics) "") (or (nth 4 topics) ""))) X topics (nthcdr 5 topics))) X (with-output-to-temp-buffer "*Help*" (princ str))) X (let ((match (irc-check-list (mapcar 'car (append irc-command-alist X (if irc-operator X irc-operator-alist))) X topic 'start-only))) X (if (and (not match) (not irc-operator)) X (setq match X (irc-check-list (mapcar 'car irc-operator-alist) topic t))) X (if (/= (length match) 1) X (if match X (irc-insert "Ambiguous help topic '%s'; could be %s." X (upcase topic) X (irc-subst-comma (mapconcat 'eval match ", ") "or")) X (irc-insert "No help is available for '%s'." (upcase topic))) X (setq match (car match)) X (with-output-to-temp-buffer "*Help*" X (princ (documentation X (intern-soft X (concat "irc-execute-" X (cdr (assoc match X (if (assoc match irc-command-alist) X irc-command-alist X irc-operator-alist)))))))))))) X X;; miscellaneous irc-* commands X(defun irc-truncate-buffer (size) X "Remove as many lines from the beginning of the buffer as is necessary Xto get it under SIZE characters. This function is used by irc-mode Xto prevent an irc-session from consuming gross amounts of space." X (if (< (buffer-size) size) () X (save-excursion X ;; first go to the lowest point posssible that would do it X (goto-char (- (point-max) size)) X ;; get to the end of this line X (end-of-line) X (if (< (point) irc-mark) X ;; just to make sure we don't toast pending input X (delete-region 1 (1+ (point))) X (message "Warning: %s exceeding %s characters. Couldn't truncate." X (buffer-name (current-buffer)) size))))) X X(defun irc-read-passwd (&optional prompt) X "Allow user to type a string without it showing. Returns string. XIf optional PROMPT non-nil, use it as the prompt string in the minibuffer." X ;; this is based on a similar function in telnet.el X ;; the major drawback is that while being prompted for a password X ;; it stays in this routine until C-g, RET or LFD is typed. X (let ((passwd "") (echo-keystrokes 0) char) X (if prompt (message prompt)) X (while (not (or (= (setq char (read-char)) 13) (= char 10))) X ;; naughty bit. take C-h to mean DEL. X (if (or (= char 8) (= char 127)) X (if (> (length passwd) 0) X (setq passwd (substring passwd 0 (1- (length passwd))))) X (setq passwd (concat passwd (char-to-string char)))) X (if prompt (message (concat prompt (make-string (length passwd) ?*))))) X (if prompt (message "")) X passwd)) X X(defun irc-read-user (prompt user &optional list) X "Prompting with PROMPT, read an IRC nickname from the minibuffer. XSecond argument USER is a string which is checked for a non-ambiguous match Xbefore the minibuffer read is done. Optional third argument LIST is a Xlist to use for checking rather than the irc-wholist. X XIt returns either the name of a user or an empty string (\"\")." X (string-match "^\\s *\\(\\S *\\)" user) ; just want one name X (setq user (substring user (match-beginning 1) (match-end 1))) X (let ((completion-ignore-case t) (list (if list list irc-wholist)) match) X (if (or (string= "" user) X (/= (length (setq match (irc-check-list list user))) 1)) X (completing-read (format "%s%s" X (if (string= "" user) "" X (format (if (zerop (length match)) X "No names match '%s'. " X "'%s' is ambiguous. ") X user)) X prompt) X ;; build the list for completing-read. a X ;; null string is there so that it can exit X ;; without anything, since we require matches X (mapcar 'list (cons "" list)) X nil t user) X (car match)))) X X(defun irc-nuke-whitespace (str) X "One string argument. Returns it with surrounding whitespace removed." X ;; i hate stupid extra spaces when parsing X (string-match "^\\s *" str) X (substring str (match-end 0) (string-match "\\s *$" str))) X X(defun irc-subst-comma (str newsep) X "Return the string formed by substituting for the last \", \" in STR Xthe string NEWSEP followed by a space. For example: X (irc-subst-comma \"1, 2, 3\" \"or\") => \"1, 2 or 3\" X XThis function is especially designed for making message from irc-mode Xmore grammatically correct and the strings which it operates on should Xbe carefully chosen so as to avoid possibly blowing away a comma that Xreally wasn't separating elements in a list." X ;; did you know that example up there can't appear starting in column 0 X ;; without screwing up lisp-indent-line? X (if (string-match ", [^,]*$" str) X (concat (substring str 0 (match-beginning 0)) " " newsep X (substring str (1+ (match-beginning 0)))) X str)) X X(defun irc-get-time () X "Return the hour and minutes of the current time in the form \"HH:MM\"." X (let ((time (current-time-string))) X (substring time (string-match "..:.." time) (match-end 0)))) X X(defun irc-check-time () X "Check to see whether it is time to insert a current-time message into Xthe *IRC* buffer." X (let* ((time (irc-get-time)) X (old-minute (string-to-int (substring irc-last-time 3))) X (new-minute (string-to-int (substring time 3)))) X (if (zerop irc-time-stamp) () X ;; check the time sentinel X (if (string= irc-last-time time) () X ;; time has gone stomping on by ... X (setq new-minute (+ new-minute (if (< new-minute old-minute) 60 0)) X irc-last-time time X irc-total-time (+ irc-total-time (- new-minute old-minute))) X (if (< (- irc-total-time irc-last-stamp) irc-time-stamp) () X ;; it's time for a new message X (irc-insert "*** It is now %s ***" time) X (setq irc-last-stamp irc-total-time)))))) X X(defun irc-signal (user event) X "Return t if a ding should be issued for a USER/EVENT pair. XCurrently only the event part of things is supported by /SIGNAL." X (let ((signal (cdr (assoc event irc-signals)))) X (or (memq t signal) (member-general user signal 'string=) X (member-general user (cdr (assoc 'user irc-signals)) 'string=)))) X X(defun irc-check-list (list item &optional start-only) X "See if LIST has string ITEM. Returns a list of possible matches. The list Xreturned is based on the following precedence rules: if there is an exact Xmatch, it is returned. If there are any strings in the list whose beginning Xmatch the item, they are returned. If that fails and optional argument XSTART-ONLY is missing or nil, strings which have the item match anywhere are Xreturned. As a last resort, nil is returned. XThis function is not case-sensitive." X (let (return (case-fold-search t) (item (regexp-quote item))) X (if (setq return X (delq nil ; whole words X (mapcar (function X (lambda (arg) X (if (string-match (concat "^" item "$") arg) X arg))) list))) X return X (if (setq return X (delq nil ; beginnings X (mapcar (function X (lambda (arg) X (if (string-match (concat "^" item) arg) X arg))) list))) X return X (if start-only X nil X (delq nil X (mapcar (function ; anywhere X (lambda (arg) X (if (string-match (concat "." item) arg) arg))) X list))))))) X X(defun irc-maintain-list (list item func) X "Maintain a LIST of strings by adding or removing string ITEM. XThird argument FUNC should be 'add or t or to make sure the item is in Xthe list or 'remove or nil to make sure item is out of the list." X (cond X ((memq func '(add t)) X (if (member-general item (eval list) 'string=) () X ;; sigh. with random adding of names via sending messages to people X ;; that irc-mode doesn't know about a name can be here in the wrong X ;; case. this has the potential to screw things up big so we'll ditch X ;; the old one in favour of whatever is being added. X (let* ((case-fold-search t) X (old (delq nil X (mapcar X (function X (lambda (arg) X (if (string-match (concat "^" (regexp-quote item) X "$") arg) X arg))) (eval list))))) X (while old X (irc-maintain-list list (car old) 'remove) X (setq old (cdr old))) X (set list (cons item (eval list)))))) X ((memq func '(remove nil)) X (set list X (delq nil (mapcar (function (lambda (arg) X (if (string= item arg) nil arg))) X (eval list))))))) X X(defun irc-burst-comma (str) X "Take a comma or space separated STR and turn it into a list of its elements. XExample: \"1, 2,3,4, 6 7\" becomes the list (\"7\" \"6\" \"4\" \"3\" \"2\" \"1\")." X (let (list sub (beg 0)) X (string-match "" str) X (while (string-match ",+\\|\\s +\\|,+\\s +" str beg) X (if (not (string= (setq sub (substring str beg (match-beginning 0))) "")) X (setq list (cons sub list))) X (setq beg (match-end 0))) X (if (/= (length str) beg) (cons (substring str beg) list) list))) X X;; miscellaneous other commands (usually from other sources) X X;; this makes up for not being able to provide a :test to memq. X;; member-general by Bard Bloom X(defun member-general (x l comparison) X "Is X a member of L under COMPARISON?" X (let ((not-found t)) X (while (and l not-found) X (setq not-found (not (funcall comparison x (car l))) X l (cdr-safe l))) X (not not-found))) X X;; wish i could remember who I got this from; I had to patch it to work X;; with the minibuffer correctly but it is mostly untouched. X(defun walk-windows (proc &optional no-mini) X "Applies PROC to each visible window (after selecting it, for convenience). XOptional arg NO-MINI non-nil means don't apply PROC to the minibuffer Xeven if it is active." X (let* ((real-start (selected-window)) X (start (next-window real-start no-mini)) X (current start) done) X (while (not done) X (select-window current) X (funcall proc) X (setq current (next-window current no-mini)) X (setq done (eq current start))) X (select-window real-start))) X X(defun count-windows (&optional no-mini) X "Returns the number of visible windows. XOptional arg NO-MINI non-nil means don't count the minibuffer Xeven if it is active." X (let ((count 0)) X (walk-windows (function (lambda () (setq count (1+ count)))) no-mini) X count)) X X;; swiped from minibuf.el, but made exclusive to * Minibuf-n*. X(defun minibuffer-message (format &rest args) X "Print a temporary message at the end of the Minibuffer. XAfter 2 seconds or when a key is typed, erase it." X (if (zerop (minibuffer-depth)) (apply 'message format args) X (let (p) X (save-excursion X (set-buffer (concat " *Minibuf-" (1- (minibuffer-depth)) "*")) X (unwind-protect X (progn X (setq p (goto-char (point-max))) X (insert (apply 'format format args)) X (sit-for 2)) X (delete-region p (point-max))))))) X X(defun irc-find-to (str &optional explicit) X "Find the part of STRING that IRC-mode will interpret as the sendlist. XIf no explicit list is found, irc-default-to is returned. The string returned Xis either : or ; terminated. X XIf optional EXPLICIT is non-nil, then return t if a sendlist was explicitly Xspecified, nil if the sendlist was implicit." X (let ((matched (string-match "^[A-Za-z0-9-_|{,*]*[;:]" str))) X (if matched (if explicit t (substring str 0 (match-end 0))) X (if explicit nil irc-default-to)))) X X(defun irc-find-message (string) X "Find the message that IRC will see if STR were sent. For messages Xsent with explicit lists, this is everything following the colon or Xsemi-colon. For everything else, it is just the string." X (substring string (length (irc-find-to string)))) X X;; functions for the irc-history list X(defun irc-add-to-hist (str) X "Put STRing at the head of the irc-history list." X (if (string-match "^[:;]" str) X (setq str X (concat irc-last-explicit (substring str 1 (length str))))) X (setq irc-history (append (list str) irc-history)) X (and (> (length irc-history) irc-max-history) X (setq irc-history (reverse (cdr (reverse irc-history)))))) X X(defun irc-yank-prev-command () X "Put the last IRC /command in the input-region." X (interactive) X (delete-region irc-mark (goto-char (point-max))) X (insert "/" irc-last-command) X (goto-char (1+ irc-mark))) X X(defun irc-history-prev (arg) X "Select the previous message in the IRC history list. ARG means Xselect that message out of the list (0 is the first)." X (interactive "P") X (let ((str (nth (or arg (1+ irc-history-index)) irc-history))) X (if (not str) X (message "No message %d in history." (or arg (1+ irc-history-index))) X (delete-region irc-mark (goto-char (point-max))) X (insert str) X (goto-char irc-mark) X (setq irc-history-index (or arg (1+ irc-history-index)))))) X X(defun irc-history-next (arg) X "Select the next message in the IRC history list. With prefix ARG Xselect that message out of the list (same as irc-history-prev if Xcalled with a prefix arg)." X (interactive "P") X (if arg (irc-history-prev arg) X (if (= irc-history-index -1) X (message "No next message in history.") X (delete-region irc-mark (goto-char (point-max))) X (insert (if (zerop irc-history-index) "" X (nth (1- irc-history-index) irc-history))) X (setq irc-history-index (1- irc-history-index))))) X X(defun irc-kill-input () X "Delete the input region and start out fresh. This function is recommended Xover any other way of killing the input-region interactively because it Xalso resets the index for the history list." X (interactive) X (delete-region irc-mark (goto-char (point-max))) X (setq irc-history-index -1)) X X(defun irc-history-menu () X "List the history of messages kept by irc-mode in another buffer." X (interactive) X (let ((pop-up-windows t) (hist irc-history) (line 0)) X (save-excursion X (set-buffer (get-buffer-create "*IRC History*")) X (fundamental-mode) X (erase-buffer) X (while hist X (insert (format "%2d: %s\n" line (car hist))) X (setq hist (cdr hist)) X (setq line (1+ line))) X (if (zerop line) X (insert "No messages have been sent to IRC yet.")) X (set-buffer-modified-p nil) X (goto-char (point-min))) X (display-buffer "*IRC History*"))) X X;; stuff about irc-mode X(defun irc-version (&optional arg) X "Print the current version of irc.el in the minibuffer. With optional XARG, insert it in the current buffer." X (interactive "P") X (if arg (insert irc-version) (princ irc-version))) X X(defun irc-news () X "Shows news about latest changes to irc.el. Even shows news about Xold changes to irc.el -- what a wonderous function indeed." X (interactive) X (save-excursion X (set-buffer (get-buffer-create "*IRC-mode News*")) X (erase-buffer) X (insert "Latest changes to Irc mode: X XFor functions, use C-h f to describe the function. Variables use C-h v. X X 2 Aug 89 -- IRC-mode has gotten some enhancements and a few small bugs X fixed. The bug with sending messages greater than 255 characters to X an implicit sendlist was fixed. A small bug with setting the window X point of a non-selected *IRC* buffer was fixed. The command parser X was cleaned up a little so the commands /WHO and /WHOIS can live happily X together. X X M-x irc now makes a little bit more sense to have bound to a key. By X default it will just go to the buffer of the IRC process if one exists. X If none does then buffer *IRC* will be used or re-used and a new connexion X opened. With a prefix argument then a new IRC process is created in X addition to any pre-existing ones. Multiple IRC sessions should be X able to co-exist peacefully in one Emacs. X X Public messages which were sent by the server as private messages are X now represented as public to lower the confusion level. X X New commands were added: X X o /NAMES to show the nicknames of users on a per-channel basis. X o /TRACE for IRC Operators to monitor the links between servers. X o /STAMP for including time-stamping in IRC messages and at intervals. X o /ALIAS to add preferred names for commands. X o /REHASH for IRC Operators to reread their server configuration file. X X /HELP for commands has been improved. Each command now includes a X \"Usage\" line to show any arguments for the command. X X : now behaves differently than ; when typed as the first character on a X line in the input region. It will insert the name of the last person who X sent a private message. X X Now when you are ignoring someone a message to that effect will be sent X out if that user sends a private message or invitation to you. X X If a message recipient's name is not found it is now sent to whatever X was provided. This should make sending to people hiding on channels X less than 0 a slightly less aggravating experience. X X Many of the functions have been changed to improve the way they get X called interactively. For commands expecting a channel number (optional X or not) a prefix argument will do. Most commands which take a user's X name as an argument will now accept it via a completing-read. X X There are more default bindings for commands. X X A texinfo manual on IRC and IRC-mode should be available shortly. X X My thanks to Scanner, Nathan Glasser, Fred Douglis, Geoff Goodfellow and X Chris Davis for their helpful comments regarding IRC-mode. Further comments X are welcome. X X22 Jun 89 -- I would have to put everything in here for the first entry in X order to have something to reference against \"Latest changes\". I X shan't do that. This first entry shall just say that this is IRC-mode X version 1.0Gimel, in its first distribution to testers. Play with the X /HELP command to see what it can offer you. Send comments/bug reports X to me (Dave Lawrence, ) and I will try to tend to X them as quickly as possible. X X One thing to note that I don't think is documented in any functions is X is how sending works. Basically, any line that you send which does not X start with a / gets processed in the following way: if you have a string X which is all alpha-numeric characters (with items seperated by commas) X up to and including a colon or semi-colon, it is called your explicit X sendlist. The elements of that list will be processed for sending to the X recipients you name. Partial matching of names is also done. If a line X starts with a colon or semi-colon then that last used explicit sendlist X is considered the sendlist for the message. If no such prefix list exists X then something called your implicit sendlist is used. This list is set X with /SEND (aka /QUERY). In all of these lists the character \"*\" is X recognized as meaning \"whatever channel I happen to be on when I am X sending\". X X Look at some of the bindings in C-h m (describe-mode). Since C-p is a X normal movement command, scrolling through your message history is X instead bound to C-c C-p (and C-c C-n for going the other way). C-c C-u X will always kill the current line of input no matter what your position. X While a user-variable (irc-max-history) is available to determine how X many messages should be retained in the history, only the last command X is remembered for command-history. It is available with C-c p. X X One last suggestion -- try M-x edit-options followed by a search through X the options buffer for irc. This should put you in an area where the X available irc user-variables are all together, with their documentation X strings and current values. X X I hope you enjoy my implementation of an IRC client.") X (goto-char (point-min))) X (display-buffer "*IRC-mode News*")) END_OF_FILE if test 39278 -ne `wc -c <'irc-3'`; then echo shar: \"'irc-3'\" unpacked with wrong size! fi # end of 'irc-3' fi echo shar: End of archive 3 \(of 3\). cp /dev/null ark3isdone 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