Forgot a paren or two
[syinit] / 16-riece.el
1 ;; 16-riece.el --- Riece (IRC) Settings
2
3 ;; Copyright (C) 2007 - 2020 Steve Youngs
4
5 ;;     Author: Steve Youngs <steve@sxemacs.org>
6 ;; Maintainer: Steve Youngs <steve@sxemacs.org>
7 ;;    Created: <2007-12-02>
8 ;; Time-stamp: <Thursday Apr  9, 2020 19:11:39 steve>
9 ;;   Download: <https://downloads.sxemacs.org/SYinits>
10 ;;   HTMLised: <https://www.sxemacs.org/SYinits/16-riece.html>
11 ;;   Git Repo: git clone https://git.sxemacs.org/syinit
12 ;;   Keywords: init, compile
13
14 ;; This file is part of SYinit
15
16 ;; Redistribution and use in source and binary forms, with or without
17 ;; modification, are permitted provided that the following conditions
18 ;; are met:
19 ;;
20 ;; 1. Redistributions of source code must retain the above copyright
21 ;;    notice, this list of conditions and the following disclaimer.
22 ;;
23 ;; 2. Redistributions in binary form must reproduce the above copyright
24 ;;    notice, this list of conditions and the following disclaimer in the
25 ;;    documentation and/or other materials provided with the distribution.
26 ;;
27 ;; 3. Neither the name of the author nor the names of any contributors
28 ;;    may be used to endorse or promote products derived from this
29 ;;    software without specific prior written permission.
30 ;;
31 ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
32 ;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 ;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 ;; DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35 ;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
38 ;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39 ;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
40 ;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
41 ;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
43 ;;; Commentary:
44 ;;
45 ;;   My Riece settings.
46 ;;
47 ;;   Riece is a very nice IRC client for emacs.  Unlike ERC which
48 ;;   tries to be like "traditional" IRC clients, Riece is much more
49 ;;   emacs like.
50 ;;
51
52 ;;; Credits:
53 ;;
54 ;;   The HTML version of this file was created with Hrvoje Niksic's
55 ;;   htmlize.el which is part of the XEmacs "text-modes" package.
56 ;;
57
58 ;;; Todo:
59 ;;
60 ;;     
61
62 ;;; Code:
63 (require 'riece-options)
64 (require 'riece-biff)
65 (require 'riece-log)
66 (require 'riece)
67
68 ;; For flyspell in the command buffer.  See `sy-riece-command-mode-hooks'.
69 (or (featurep 'overlay)
70     (ignore-errors (require 'overlay)))
71 (or (featurep 'flyspell)
72     (ignore-errors (require 'flyspell)))
73
74 ;; Misc setq's
75 (setq riece-alias-percent-hack-mask "*.net"
76       riece-biff-check-channels '("#sxemacs"
77                                   "#emchat"
78                                   "#xemacs")
79       riece-channel-buffer-mode t
80       riece-ctlseq-colors
81             '("white" "black" "blue" "green" "red" "brown"
82               "purple" "orange" "yellow" "lightgreen" "darkcyan"
83               "cyan" "lightblue" "HotPink" "grey35" "grey")
84       riece-default-channel-binding nil
85       riece-default-coding-system 'utf-8
86       riece-desktop-notify-always t
87       riece-gather-channel-modes t
88       riece-hide-list '(joins parts quits)
89       riece-ignore-discard-message nil
90       riece-keywords
91       '("Bastard" "EMchat" "eMoney" "Gnus" "LFS" "LinuxFromScratch"
92         "LineageOS" "Lineage" "Linux From Scratch" "Riece" "SteveYoungs"
93         "SXEmacs" "XEmacs" "Youngs" "Steve Youngs" "SYWriting"
94         "SY Writing" "Gaiman" "Neil Gaiman" "xwem")
95       riece-layout '"bottom-right"
96       riece-retry-with-new-nickname t
97       riece-server-alist
98       '(("roddenberry.freenode.net" :host "roddenberry.freenode.net")
99         ("irc.sxemacs.org" :host "irc.sxemacs.org")
100         ("irc.freenode.net" :host "irc.freenode.net")
101         ("irc.au.freenode.net" :host "irc.au.freenode.net")
102         ("irc.nac.net" :host "irc.nac.net")
103         ("irc.efnet.org" :host "irc.efnet.org")
104         ("irc.efnet.net" :host "irc.efnet.net"))
105       riece-user-agent 'emacs-riece-config
106       riece-user-list-buffer-mode t)
107
108 ;; Addons
109 (riece-command-insinuate-addon 'riece-yank)
110 (riece-command-insinuate-addon 'riece-hangman)
111 (riece-command-insinuate-addon 'riece-keepalive)
112 (riece-command-insinuate-addon 'riece-shrink-buffer)
113 (riece-command-insinuate-addon 'riece-xfaceb)
114 (riece-command-insinuate-addon 'riece-button)
115 (riece-command-insinuate-addon 'riece-epg)
116
117 (riece-command-enable-addon 'riece-hangman)
118
119 ;; Leave this OFF it is too annoying.  Fun, but annoying.
120 ;; (riece-command-insinuate-addon 'riece-doctor)
121 ;; (riece-command-enable-addon 'riece-doctor)
122
123 ;; A few handy functions that extend Riece's features a bit.
124 (defvar riece-unread-channels)
125 (defun sy-riece-clear-unread-chans ()
126   "Get rid of the unread mark on all channels."
127   (interactive)
128   (let ((current riece-current-channel))
129     (setq riece-unread-channels nil)
130     (riece-switch-to-channel current)))
131
132 (defun sy-riece-relist-chans-clear-blanks ()
133   "Relist the channel buffer removing any blanks in the sequence.
134
135 When you part from a channel/user you are left with a gap in the
136 sequence of channel numbers in the channels buffer.  This removes
137 those gaps."
138   (interactive)
139   (let ((current riece-current-channel))
140     (setq riece-current-channels
141           (remove-if #'null riece-current-channels))
142     (riece-switch-to-channel current)))
143
144 (defun sy-riece-command-memoserv (command)
145   "Send COMMAND, a string, to MEMOSERV.
146
147 With prefix arg, also /join."
148   (interactive "sMemoserv: ")
149   (when current-prefix-arg
150     (riece-command-join (list ["MemoServ" ""])))
151   (riece-send-string (format "MEMOSERV %s\r\n" command)))
152
153 (defun sy-riece-command-chanserv (command)
154   "Send COMMAND, a string, to CHANSERV.
155
156 With prefix arg, also /join."
157   (interactive "sChanserv: ")
158   (when current-prefix-arg
159     (riece-command-join (list ["ChanServ" ""])))
160   (riece-send-string (format "CHANSERV %s\r\n" command)))
161
162 (defun sy-riece-command-nickserv (command)
163   "Send COMMAND, a string, to NICKSERV.
164
165 With prefix arg, also /join."
166   (interactive "sNickserv: ")
167   (when current-prefix-arg
168     (riece-command-join (list ["NickServ" ""])))
169   (riece-send-string (format "NICKSERV %s\r\n" command)))
170
171 ;; Seems to not exist anymore. :-(
172 (defun sy-riece-command-seenserv (command)
173   "Send COMMAND, a string, to SEENSERV.
174
175 SeenServ doesn't actually exist anymore, so this sends `info nick' to
176 NickServ which gives us the same info.
177
178 With prefix arg, also /join."
179   (interactive "sLast saw who (nick): ")
180   (when current-prefix-arg
181     (riece-command-join (list ["NickServ" ""])))
182   (riece-send-string (format "NICKSERV info %s\r\n" command)))
183
184 (defun sy-riece-command-quick-op ()
185   "Request Ops from ChanServ in the current channel."
186   (interactive)
187   (let ((chan (riece-identity-prefix riece-current-channel)))
188     (sy-riece-command-chanserv (format "OP %s" chan))))
189
190 (defun sy-riece-command-mute-user (&optional user unmute)
191   "Set mode +q on USER, effectively muting them.
192
193 Optional prefix arg, UNMUTE to let them speak again."
194   (interactive "i\nP")
195   (let ((user (or user
196                   (completing-read
197                    "(Un)Mute user: "
198                    (riece-with-server-buffer
199                        (riece-identity-server riece-current-channel)
200                      (riece-channel-get-users (riece-identity-prefix
201                                                riece-current-channel)))))))
202     (riece-send-string 
203      (format "MODE %s %sq %s\r\n"
204              (riece-identity-prefix riece-current-channel)
205              (if (or unmute
206                      current-prefix-arg)
207                  "-"
208                "+")
209              user))))
210
211 (defun sy-riece-list-banned (channel)
212   "List the banned users on CHANNEL, current if omitted."
213   (interactive "P")
214   (let ((channel (if current-prefix-arg
215                      (vector (read-string "Channel: ") "")
216                    riece-current-channel)))
217     (riece-send-string
218      (format "MODE %s b\r\n" (riece-identity-prefix channel)))))
219
220 (defun sy-riece-command-ban-user (&optional user unban)
221   "Ban USER from current channel.
222
223 Optional prefix arg, UNBAN removes the ban."
224   (interactive "i\nP")
225   (let ((user (or user
226                   (completing-read
227                    "(Un)Ban user: "
228                    (riece-with-server-buffer
229                        (riece-identity-server riece-current-channel)
230                      (riece-channel-get-users (riece-identity-prefix
231                                                riece-current-channel))))))
232         reason)
233     (if (or unban
234             current-prefix-arg)
235         (riece-send-string
236          (format "MODE %s -b %s\r\n"
237                  (riece-identity-prefix riece-current-channel)
238                  user))
239       (setq reason (read-string "Reason: " nil nil
240                                 "Need a reason?  Look in a mirror!"))
241       (riece-send-string
242        (format "MODE %s +b %s\r\n"
243                (riece-identity-prefix riece-current-channel)
244                user))
245       (riece-command-kick user reason))))
246
247 ;; Share the muzak!
248 (defun sy-riece-say-now-playing (&optional notice)
249   "Say into the current channel what mp3 is playing.
250
251 With non-nil optional prefix arg, NOTICE, send it as a notice."
252   (interactive "P")
253   (riece-command-send-message
254    (format "NP: %s" (mpd-now-playing)) 
255    (and current-prefix-arg
256         'notice)))
257
258 (defun sy-riece-say-all-purpose (&optional notice)
259   "Send the all-purpose answer to everything."
260   (interactive "P")
261   (riece-command-send-message "Adolf Hitler in fishnets"
262                               (if current-prefix-arg
263                                   'notice
264                                 nil)))
265   
266
267 ;; Tell the world what we're using.
268 (defun sy-riece-say-version (&optional notice)
269   "Say the version of Riece we are running.
270
271 With non-nil prefix arg, NOTICE, send as a notice."
272   (interactive "P")
273   (riece-command-send-message
274    (format "I'm using: %s" (riece-extended-version))
275    (if current-prefix-arg
276        'notice
277      nil)))
278
279 ;; say (foo) => bar
280 (defun sy-riece-send-form ()
281   "Sends a form and it's eval"
282   (interactive)
283   (let* ((form (read-string "sexp: "))
284          (value (eval (read form))))
285     (riece-command-send-message (format "%s => %s" form value)
286                                 (if current-prefix-arg
287                                     'notice
288                                   nil))))
289
290 (defun sy-make-rot13-translation-table ()
291   "Create a rot13 table."
292   (let ((i -1)
293         (table (make-string 256 0))
294         (a (char-to-int ?a))
295         (A (char-to-int ?A)))
296     (while (< (incf i) 256)
297       (aset table i i))
298     (concat
299      (substring table 0 A)
300      (substring table (+ A 13) (+ A 13 (- 26 13)))
301      (substring table A (+ A 13))
302      (substring table (+ A 26) a)
303      (substring table (+ a 13) (+ a 13 (- 26 13)))
304      (substring table a (+ a 13))
305      (substring table (+ a 26) 255))))
306
307 (defun sy-rot13-string (string)
308   "Convert TEXT to rot13-ese."
309   (let ((table (sy-make-rot13-translation-table)))
310     (with-temp-buffer
311       (insert string)
312       (translate-region (point-min) (point-max) table)
313       (buffer-string))))
314
315 (defun sy-riece-send-rot13 (text)
316   "Talk in rot13-ese."
317   (interactive "srot13: ")
318   (riece-command-send-message
319    (sy-rot13-string text)
320    (if current-prefix-arg
321        'notice
322      nil)))
323
324 (defun sy-morse-string (string)
325   "Return STRING in morse code."
326   (with-temp-buffer
327     (insert string)
328     (morse-region (point-min) (point-max))
329     (goto-char (point-min))
330     (while (re-search-forward "/" nil t)
331       (replace-match " "))
332     (buffer-string)))
333
334 (defun sy-riece-send-morse (text)
335   "Talk in morse code."
336   (interactive "sMorse: ")
337   (riece-command-send-message
338    (sy-morse-string text)
339    (if current-prefix-arg
340        'notice
341      nil)))
342
343 ;; Show off!
344 (autoload 'riece-command-ctcp-action "riece-ctcp" nil t)
345 (defun sy-riece-show-off ()
346   "Brag about how many channels/people we're talking to."
347   (interactive)
348   (sy-riece-relist-chans-clear-blanks)
349   (let* ((channels riece-current-channels)
350          (numchans (length channels))
351          (numppl 0)
352          currchan)
353     (while channels
354       (setq currchan (car channels))
355       (setq numppl (+ numppl
356                       (length (riece-with-server-buffer
357                                   (riece-identity-server currchan)
358                                 (riece-channel-get-users 
359                                  (riece-identity-prefix currchan))))))
360       (setq channels (cdr channels)))
361     (riece-command-ctcp-action
362      riece-current-channel
363      (format
364       "is in %d channels, talking to %d people :-P"
365       numchans numppl))))
366
367 ;; Brag about how long SXEmacs has been up
368 (defun sy-riece-sxe-uptime ()
369   "Display as action SXEmacs uptime."
370   (interactive)
371   (let* ((ut (uptime))
372          (days (car ut))
373          (hours (cadr ut))
374          (minutes (caddr ut))
375          (seconds (cadddr ut)))
376     (riece-command-ctcp-action
377      riece-current-channel
378      (concat "-=[ SXEmacs Uptime: "
379              (unless (zerop days)
380                (if (eq days 1)
381                    "1 day, "
382                  (concat (number-to-string days) " days, ")))
383              (unless (zerop hours)
384                (if (eq hours 1)
385                    "1 hour, "
386                  (concat (number-to-string hours) " hours, ")))
387              (unless (zerop minutes)
388                (if (eq minutes 1)
389                    "1 minute, "
390                  (concat (number-to-string minutes) " minutes, ")))
391              (if (zerop seconds)
392                  "and 0 seconds"
393                (if (eq seconds 1)
394                    "and 1 second."
395                  (concat "and "
396                          (number-to-string seconds)
397                          " seconds")))
398              " ]=-"))))
399       
400
401 ;; segassem desrever eikeeg ylbirreT
402 (defun sy-riece-reverse ()
403   ".sdrawkcab kaepS"
404   (interactive)
405   (let ((str (read-string "Say backwards: ")))
406     (riece-command-send-message
407      (concat (nreverse (string-to-list str))) nil)))
408
409 ;; .oO0{ what's he thinking? }
410 (defun sy-riece-think ()
411   "Send a .oO0{ think balloon action }."
412   (interactive)
413   (let ((think (read-string "What are you thinking? ")))
414     (riece-command-ctcp-action
415      riece-current-channel
416      (format ".oO0{ %s }" think))))
417
418 ;; When pictures speak louder than words...
419 (defun sy-riece-fuck-you (&optional upyours)
420   "For those occasions where... you know what I mean."
421   (interactive "P")
422   (let ((fuckyou "
423      _                         _
424     |_|                       |_|
425     | |         /^^^\\         | |
426    _| |_      (| \"o\" |)      _| |_
427  _| | | | _    (_---_)    _ | | | |_
428 | | | | |' |    _| |_    | `| | | | |
429 |          |   /     \\   |          |
430  \\        /  / /(. .)\\ \\  \\        /
431    \\    /  / /  | . |  \\ \\  \\    /
432      \\  \\/ /    ||Y||    \\ \\/  /
433       \\__/      || ||      \\__/
434                 () ()
435                 || ||
436                ooO Ooo")
437         (upyours "
438     .-.    
439     |U|    
440     | |    
441     | |    
442    _| |_   
443   | | | |-.
444  /|     ` |
445 | |       |
446 |         |
447 \\         /
448  |       | 
449  |       |")
450         (riece-yank-tick 0.1))
451     (with-temp-buffer
452       (if current-prefix-arg 
453           (insert upyours)
454         (insert fuckyou))
455       (kill-region (point-min) (point-max)))
456     (riece-command-yank nil nil)))
457
458 ;; Nick completion.  Lets face it, compared to other IRC clients like
459 ;; BitchX or even ERC, Riece's nick completion is pretty sucky. :-(
460 ;; This is my vain attempt to improve it.
461 (defun sy-riece-command-complete-user ()
462   "Like `riece-command-complete-user' but restrict to current chan.
463
464 This version of nick completion maintains the original case of the
465 nick being completed.  The version in Riece downcases the completion
466 \(could be a bug\).
467
468 If the completion is being inserted at column zero, `: ' is appended,
469 otherwise ` ' is added.
470
471 The following is not yet implemented, but I'd also like to be able to
472 complete from the middle of a nick...
473
474   Nickname     User Types      Expands To
475   --------     ----------      ----------
476   MyNick        nic<TAB>       MyNick:<SPC>"
477   (interactive)
478   (let* ((completion-ignore-case t)
479          (table (riece-with-server-buffer
480                     (riece-identity-server riece-current-channel)
481                   (riece-channel-get-users (riece-identity-prefix
482                                             riece-current-channel))))
483          (current (or (current-word) ""))
484          (completion (try-completion current table))
485          (all (all-completions current table)))
486     (if (eq completion t)
487         nil
488       (if (null completion)
489           (message "Can't find completion for \"%s\"" current)
490         (if (equal current completion)
491             (with-output-to-temp-buffer "*Help*"
492               (display-completion-list all))
493           (re-search-forward "\\>" nil t)
494           (delete-region (point) (- (point) (length current)))
495           (if (eq (point) (point-at-bol))
496               (insert completion ": ")
497             (insert completion " ")))))))
498
499 ;(defalias 'riece-command-complete-user 'sy-riece-command-complete-user)
500
501 ;; "schme" <marcus@sxemacs.org> funky cycling completion
502 ;; Reworked to support cycling in both directions using dllists, plus
503 ;; other misc improvements by me. --SY.
504 (defvar riece-me:completion-time 3
505   "Time in seconds before completion list is reset.")
506 (defvar riece-me:*completion-timer* (make-itimer)
507   "Completion timer.")
508 (defvar riece-me:*completion-list* nil
509   "Completion list.")
510
511 (defvar sy-riece-nick-syntax-table
512   (let ((table (copy-syntax-table text-mode-syntax-table)))
513     (modify-syntax-entry ?~  "w " table)
514     (modify-syntax-entry ?`  "w " table)
515     (modify-syntax-entry ?-  "w " table)
516     (modify-syntax-entry ?_  "w " table)
517     (modify-syntax-entry ?+  "w " table)
518     (modify-syntax-entry ?{  "w " table)
519     (modify-syntax-entry ?[  "w " table)
520     (modify-syntax-entry ?}  "w " table)
521     (modify-syntax-entry ?]  "w " table)
522     (modify-syntax-entry ?\\ "w " table)
523     (modify-syntax-entry ?|  "w " table)
524     (modify-syntax-entry ?:  "w " table)
525     (modify-syntax-entry ?\; "w " table)
526     (modify-syntax-entry ?'  "w " table)
527     (modify-syntax-entry ?<  "w " table)
528     (modify-syntax-entry ?,  "w " table)
529     (modify-syntax-entry ?>  "w " table)
530     table)
531   "Syntax table used in funky nick cycling completion.")
532
533 (defun sy-riece-init-completion-timer ()
534   "Initialise the completion timer."
535   (let ((timer riece-me:*completion-timer*))
536     (set-itimer-function timer #'(lambda ()
537                                    (setq riece-me:*completion-list* nil)))
538     (set-itimer-value timer riece-me:completion-time)))
539 (add-hook 'riece-after-login-hook #'sy-riece-init-completion-timer)
540
541 (defsubst sy-riece-cycle-list (list &optional reverse)
542   "Return a list of head of LIST, and LIST rotated 1 place forward.
543
544 If optional argument, REVERSE is non-nil, rotate the list in the other
545 direction."
546   (let ((list (apply #'dllist list))
547         name)
548     (if reverse
549         (dllist-rrotate list)
550       (dllist-lrotate list))
551     (setq name (dllist-car list))
552     (list name (dllist-to-list list))))
553
554 (defsubst sy-riece-set-completion-timer ()
555   "(Re)set completion timer's value."
556   (let ((timer riece-me:*completion-timer*))
557     (and (itimerp timer)
558          (set-itimer-value timer riece-me:completion-time))))
559
560 (defun sy-riece-complete-user-backwards ()
561   "Complete nick, cycling backwards.
562 See `riece-me:command-complete-user'."
563   (interactive)
564   (riece-me:command-complete-user 'reverse))
565
566 (defun sy-riece-command-mode-hooks ()
567   "Add some nice stuff in Riece's command buffer."
568   (when (eq major-mode 'riece-command-mode)
569     ;; Define a few keys here so they don't have the `C-c' prefix
570     (local-set-key [iso-left-tab] #'sy-riece-complete-user-backwards)
571     (local-set-key [(super next)] #'riece-command-user-list-scroll-up)
572     (local-set-key [(super prior)] #'riece-command-user-list-scroll-down)
573     (local-set-key [(hyper next)] #'riece-command-scroll-up)
574     (local-set-key [(hyper prior)] #'riece-command-scroll-down)
575     ;; Turn on flyspell mode if available
576     (and (featurep (and 'overlay 'flyspell))
577          (flyspell-mode 1))))
578
579 (add-hook 'riece-command-mode-hook #'sy-riece-command-mode-hooks)
580
581
582 (defun riece-me:command-complete-user (&optional reverse)
583   "Like `riece-command-complete-user' but restrict to current chan.
584
585 This completion does not pop up any completion buffers, instead it
586 cycles through the user names \"in-place\" with each successive TAB.
587
588 With non-nil optional argument, REVERSE, the cycling goes in the other
589 direction.
590
591 If the completion is being inserted at column zero, \": \" is appended,
592 otherwise \" \" is added. "
593   (interactive)
594   (unless riece-me:*completion-list*
595     (unless (itimer-live-p riece-me:*completion-timer*)
596       (sy-riece-set-completion-timer)
597       (activate-itimer riece-me:*completion-timer*))
598     (let* ((completion-ignore-case t)
599            (table (riece-with-server-buffer
600                       (riece-identity-server riece-current-channel)
601                     (riece-channel-get-users (riece-identity-prefix
602                                               riece-current-channel))))
603            (current (current-word))
604            (completion (try-completion current table))
605            (all (all-completions current table)))
606       (if (null completion)
607           (message "Can't find completion for \"%s\"" current)
608         (setq riece-me:*completion-list* all))))
609   (when riece-me:*completion-list*
610     (multiple-value-bind (completion newlist)
611         (sy-riece-cycle-list riece-me:*completion-list* reverse)
612       (setq riece-me:*completion-list* newlist)
613       (with-syntax-table sy-riece-nick-syntax-table
614         (unless (string= "" (current-word))
615           (backward-delete-word))
616         (insert completion)
617         (let ((nicksuffix " "))
618           (save-excursion
619             (backward-word)
620             (and (bolp)
621                  (setq nicksuffix ": ")))
622           (insert nicksuffix)))
623       (sy-riece-set-completion-timer))))
624
625 (defalias 'riece-command-complete-user 'riece-me:command-complete-user)
626 ;;;
627
628 (defun sy-riece-add-rem-biff-channel (&optional remove)
629   "Add the current channel to the list of channels for riece-biff.
630
631 With optional prefix arg, REMOVE, remove the current channel from the
632 biff list."
633   (interactive "P")
634   (if (or current-prefix-arg
635           remove)
636       ;; Remove chan.
637       (progn
638         (setq riece-biff-check-channels
639               (remove (riece-identity-prefix riece-current-channel)
640                       riece-biff-check-channels))
641         (message "Channel: %s removed from riece-biff channel list."
642                  (riece-identity-prefix riece-current-channel)))
643     ;; Add chan.
644     (add-to-list 'riece-biff-check-channels
645                  (riece-identity-prefix riece-current-channel))
646     (message "Channel: %s added to riece-biff channel list."
647              (riece-identity-prefix riece-current-channel))))
648
649 (defun sy-riece-get-sxemacs-topic-version ()
650   "Return the \"version\" section of #sxemacs topic."
651   (let* ((topic (riece-with-server-buffer
652                     (riece-identity-server riece-current-channel)
653                   (riece-channel-get-topic "#sxemacs")))
654          (ver (third (split-string-by-char topic ?\ ))))
655     ver))
656
657 (defun sy-riece-sxemacs-topic-version-update (&optional newver)
658   "*Updates the \"version\" section of #sxemacs topic with NEWVER.
659 With a prefix arg, prompt for the new version string."
660   (interactive "P")
661   (let* ((oldver (sy-riece-get-sxemacs-topic-version))
662          (gitver (substring (shell-command-to-string
663                              "( cd ${SXEWD}; git describe master )")
664                             0 -1))
665          (newver (or (and current-prefix-arg
666                           (read-string "New Version: "
667                                        sxemacs-git-version nil
668                                        sxemacs-git-version))
669                      gitver))
670         (chan (riece-identity-prefix riece-current-channel)))
671     (unless (string= chan "#sxemacs")
672       (error 'invalid-argument "Wrong channel" chan))
673     (riece-command-send-message
674      (format ",topic change 1 s/%s/%s/" oldver newver) nil)))
675
676 ;; Define keys for those functions.
677 (define-key riece-command-map (kbd "C-c C") #'sy-riece-clear-unread-chans)
678 (define-key riece-command-map (kbd "C-c r")
679   #'sy-riece-relist-chans-clear-blanks)
680 (define-key riece-command-map (kbd "C-c m") #'sy-riece-command-mute-user)
681 (define-key riece-command-map (kbd "C-b") #'sy-riece-command-ban-user)
682 (define-key riece-command-map (kbd "C-o") #'sy-riece-command-quick-op)
683 (define-key riece-command-map (kbd "C-c n") #'sy-riece-say-now-playing)
684 (define-key riece-command-map (kbd "C-c V") #'sy-riece-say-version)
685 (define-key riece-command-map (kbd "C-c s") #'sy-riece-show-off)
686 (define-key riece-command-map (kbd "C-c f") #'sy-riece-fuck-you)
687 (define-key riece-command-map (kbd "C-c b") #'sy-riece-add-rem-biff-channel)
688 (define-key riece-command-map (kbd "C-c ?") #'sy-riece-think)
689 (define-key riece-command-map (kbd "C-c R") #'sy-riece-reverse)
690 (define-key riece-command-map (kbd "C-c T") #'sy-riece-sxemacs-topic-version-update)
691 (define-key riece-command-map (kbd "C-c U") #'sy-riece-sxe-uptime)
692 (define-key riece-command-map [a] #'sy-riece-say-all-purpose)
693
694 ;; So I can start Riece in a new frame
695 (defvar riece-frame nil
696   "Frame for Riece.")
697
698 (defun sy-riece (&optional ask)
699   "Run Riece in a new frame.
700
701 With non-nil optional prefix ASK Riece will prompt for a server to
702 connect to."
703   (interactive "P")
704   (let ((riece-server (if current-prefix-arg
705                           nil
706                         "irc.sxemacs.org")))
707     (setq riece-frame (new-frame '((name . "RieceFrame")
708                                    (width . 110))))
709     (select-frame riece-frame)
710     (call-interactively 'riece)
711     (focus-frame riece-frame)))
712
713 (defun sy-riece-exit-hook ()
714   (when (frame-live-p riece-frame)
715     (delete-frame riece-frame))
716   (setq riece-frame nil))
717
718 (add-hook 'riece-exit-hook #'sy-riece-exit-hook)
719
720 ;; riece-startup-channel-list doesn't fit in with the way I do things
721 ;; and the way freenode functions.  It gets called too damned early.
722 ;; What follows is my attempt to make Riece behave better with logging
723 ;; into freenode, registering to nickserv, joining initial channels,
724 ;; and getting ops with chanserv.
725 (defvar sy-riece-startup-channel-list
726   '("#sxemacs"
727     "#emchat"
728     "#xemacs"
729     "#emacs"
730     ;"#kde"
731     ;"#kde-devel"
732     "#LineageOS"
733     ;"#LineageOS-dev"
734     "#lxqt"
735     ;"#postgresql"
736     ;"#systemd"
737     "#zsh"
738     )
739   "List of channels to join after logging in and identifying to nickserv.")
740
741 ;; Set up channel coding systems
742 ;;
743 ;; This is a PITA... turn on utf and can't read iso-8859-1 special
744 ;; chars, turn it off and can't read utf.  Have I mentioned how much I
745 ;; hate this crap? --SY.
746 (mapcar
747  #'(lambda (chan)
748      (if (string-match #r"#\(sxemacs\|emchat\)" chan)
749          (push (cons chan 'iso-8859-1) riece-channel-coding-system-alist)
750        (push (cons chan 'utf-8) riece-channel-coding-system-alist)))
751  sy-riece-startup-channel-list)
752
753 (defun sy-riece-login ()
754   (progn
755     (riece-send-string (format "PRIVMSG NickServ :identify %s\r\n"
756                                (getenv "IRCPASSWD")))
757     (sleep-for 15))
758   (let ((channel-list sy-riece-startup-channel-list)
759         entry identity)
760     (while channel-list
761       (unless (listp (setq entry (car channel-list)))
762         (setq entry (list (car channel-list))))
763       (if (equal (riece-identity-server
764                   (setq identity (riece-parse-identity (car entry))))
765                  riece-server-name)
766           (riece-command-join-channel identity (nth 1 entry)))
767       (setq channel-list (cdr channel-list))))
768   (riece-send-string "PRIVMSG ChanServ :op #sxemacs\r\n")
769   (riece-send-string "PRIVMSG ChanServ :op #emchat\r\n")
770   (riece-send-string "PRIVMSG ChanServ :op #xemacs\r\n")
771   (riece-send-string
772    (format "PRIVMSG SXEbot :identify SteveYoungs %s\r\n"
773            (getenv "BOTPASSWD"))))
774
775 (add-hook 'riece-after-login-hook #'sy-riece-login)
776
777 ;; Until I can find a solution to my hook problem (login hook not
778 ;; running to completion) I use this to finish the job
779 (defun sy-riece-cleanup-login ()
780   (interactive)
781   (let ((metachans
782          #r".*\.freenode\.net\|\(Chan\|Nick\|Memo\|Seen\)Serv\|SXEbot\|freenode-connect"))
783     (mapcar
784      #'(lambda (chan-vect)
785          (mapcar
786           #'(lambda (chan)
787               (and (string-match metachans chan)
788                    (riece-part-channel chan-vect)))
789           chan-vect))
790      riece-current-channels)
791     (sy-riece-relist-chans-clear-blanks)
792     (riece-command-switch-to-channel-by-number 1)))
793
794 ;; CANNOT get this to work from the hook.  I suspect it is a
795 ;; networking/async/timing thing.  I have it bound to a key
796 ;; seq... `C-c C-c l', a PITA though.
797 ;(add-hook 'riece-after-login-hook #'sy-riece-cleanup-login 'append)
798 (define-key riece-command-map (kbd "C-c l") 'sy-riece-cleanup-login)
799
800 ;; Automatically clear Riece Biff indicator by switching to the right
801 ;; window/frame
802 (defun sy-riece-check-command-buffer ()
803   (and (get-buffer-window (or riece-command-buffer "*Command*"))
804        (riece-biff-clear)))
805
806 (defadvice switch-to-buffer (after riece-update (&rest args) activate)
807   "After switching buffers, check to see if riece-biff should be cleared.
808 The riece-biff modeline indicator will only be cleared if
809 `riece-command-buffer' is visible in the selected frame."
810   (sy-riece-check-command-buffer))
811
812 (add-hook 'select-frame-hook #'sy-riece-check-command-buffer)
813
814 ;; Easier switch to Riece when running on TTY.
815 (defun sy-switch-to-riece ()
816   "I use this to switch to Riece when I'm on a tty."
817   (interactive)
818   (when (buffer-live-p riece-command-buffer)
819     (pop-to-buffer riece-command-buffer)
820     (riece-command-configure-windows)))
821
822 (define-key global-tty-map [(control ?c) ?r] #'sy-switch-to-riece)
823
824 ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
825 (message "Riece settings loaded successfully")
826