;;; erc-init.el --- Various ERC hacks and configuration
;; This file is part of Michael Olson's Emacs settings.
;; The code in this file may be used, distributed, and modified
;; without restriction.
;; I use initsplit.el to separate customize settings on a per-project
;; basis.
;; Add working directories to load path
(add-to-list 'load-path "/home/mwolson/proj/emacs/erc/git-erc")
;; Load ERC
(require 'erc)
;; Load authentication info from an external source
(load "~/.emacs.d/.erc-auth")
;;; New ERC commands
(autoload 'doctor-doc "doctor")
(autoload 'make-doctor-variables "doctor")
(defvar erc-doctor-id "{Emacs doctor} ")
(defun erc-cmd-DOCTOR (&optional last-sender &rest ignore)
"Get the last message in the channel and doctor it."
(let ((limit (- (point) 1000))
(pos (point))
data
doctor-buffer
last-message
text)
;; Make sure limit is not negative
(when (< limit 0) (setq limit 0))
;; Search backwards for text from someone
(while (and pos
(not (and (setq data
(get-text-property pos 'erc-parsed))
(string= (aref data 3) "PRIVMSG")
(or (not last-sender)
(string= (car (split-string
(aref data 2) "!"))
last-sender)))))
(setq pos (previous-single-property-change
pos 'erc-parsed nil limit))
(when (= pos limit)
(error "No appropriate previous message to doctor")))
(when pos
(setq last-sender (car (split-string
(aref (get-text-property
pos 'erc-parsed) 2) "!"))
doctor-buffer (concat "*ERC Doctor: " last-sender "*")
last-message (split-string
;; Remove punctuation from end of sentence
(replace-regexp-in-string
"[ .?!;,/]+$" ""
(aref (get-text-property pos
'erc-parsed) 5)))
text (mapcar (lambda (s)
(intern (downcase s)))
;; Remove salutation if it exists
(if (string-match
(concat "^" erc-valid-nick-regexp
"[:,]*$\\|[:,]+$")
(car last-message))
(cdr last-message)
last-message))))
(erc-send-message
(concat erc-doctor-id
;; Only display sender if not in a query buffer
(if (not (erc-query-buffer-p))
(concat last-sender ": "))
(save-excursion
(if (get-buffer doctor-buffer)
(set-buffer doctor-buffer)
(set-buffer (get-buffer-create doctor-buffer))
(make-doctor-variables))
(erase-buffer)
(doctor-doc text)
(buffer-string))))))
(defun erc-cmd-EMMS (&rest ignore)
"Display the current emms track to the current ERC buffer."
(emms-player-mpd-show nil (lambda (buffer desc)
(with-current-buffer buffer
(erc-send-message desc)))))
(defalias 'erc-cmd-NP 'erc-cmd-EMMS)
(defun erc-cmd-UNAME (&rest ignore)
"Display the result of running `uname -a' to the current ERC
buffer."
(let ((uname-output
(replace-regexp-in-string
"[ \n]+$" "" (shell-command-to-string "uname -a"))))
(erc-send-message
(concat "{uname -a} [" uname-output "]"))))
(defun erc-cmd-UPTIME (&rest ignore)
"Display the uptime of the system, as well as some load-related
stuff, to the current ERC buffer."
(let ((uname-output
(replace-regexp-in-string
", load average: " "] {Load average} ["
;; Collapse spaces, remove
(replace-regexp-in-string
" +" " "
;; Remove beginning and trailing whitespace
(replace-regexp-in-string
"^ +\\|[ \n]+$" ""
(shell-command-to-string "uptime"))))))
(erc-send-message
(concat "{Uptime} [" uname-output "]"))))
(defun erc-cmd-WTF (term &rest ignore)
"Look up definition for TERM."
(let ((def (wtf-is term)))
(if def
(erc-send-message
(concat "{Term} " (upcase term) " is " def))
(message (concat "No definition found for " (upcase term))))))
(defun erc-cmd-XMMS (&rest ignore)
"Display the current xmms track to the current ERC buffer."
(let* ((xmms-output (shell-command-to-string
"xmms-shell -e current-track"))
(case-fold-search t)
(current-track
(replace-regexp-in-string
"[ \n]+$" "" (mapconcat
'identity
(nthcdr 3 (split-string xmms-output " "))
" "))))
(if (null (string-match "current" xmms-output))
(message xmms-output)
(erc-send-message
(concat "NP: [" current-track "]")))))
(defun erc-cmd-YOW (&rest ignore)
"Display some pinhead wisdom into the current ERC buffer. I'd
rather not see it messaged to me, just sent out."
(let ((yow-msg (replace-regexp-in-string "\n" "" (yow nil nil))))
(erc-send-message
(concat "{Pinhead wisdom} "
yow-msg))))
;;; Misc. hacks
;; Change fill column according to the width of the current frame
(defun my-erc-mode-stuff ()
"Set fill column according to `frame-width'."
(set (make-local-variable 'erc-fill-column) (- (frame-width) 10))
(set (make-local-variable 'erc-timestamp-right-column)
(1+ erc-fill-column)))
(add-hook 'erc-mode-hook 'my-erc-mode-stuff)
;;; Notify me when a keyword is matched (someone wants to reach me)
(defvar my-erc-page-message "%s is calling your name."
"Format of message to display in dialog box")
(defvar my-erc-page-nick-alist nil
"Alist of nicks and the last time they tried to trigger a
notification")
(defvar my-erc-page-timeout 30
"Number of seconds that must elapse between notifications from
the same person.")
(defun my-erc-page-popup-notification (nick)
(when window-system
;; must set default directory, otherwise start-process is unhappy
;; when this is something remote or nonexistent
(let ((default-directory "~/"))
;; 8640000 milliseconds = 1 day
(start-process "page-me" nil "notify-send"
"-u" "normal" "-t" "8640000" "ERC"
(format my-erc-page-message nick)))))
(defun my-erc-page-allowed (nick &optional delay)
"Return non-nil if a notification should be made for NICK.
If DELAY is specified, it will be the minimum time in seconds
that can occur between two notifications. The default is
`my-erc-page-timeout'."
(unless delay (setq delay my-erc-page-timeout))
(let ((cur-time (time-to-seconds (current-time)))
(cur-assoc (assoc nick my-erc-page-nick-alist))
(last-time nil))
(if cur-assoc
(progn
(setq last-time (cdr cur-assoc))
(setcdr cur-assoc cur-time)
(> (abs (- cur-time last-time)) delay))
(push (cons nick cur-time) my-erc-page-nick-alist)
t)))
(defun my-erc-page-me (match-type nick message)
"Notify the current user when someone sends a message that
matches a regexp in `erc-keywords'."
(interactive)
(when (and (eq match-type 'keyword)
;; I don't want to see anything from the erc server
(not (string-match "\\`\\([sS]erver\\|localhost\\|root\\)" nick))
;; or bots
(not (string-match "\\(^CIA[^!]*\\|bot\\|serv\\)!" nick))
;; or from those who abuse the system
(my-erc-page-allowed nick))
(my-erc-page-popup-notification nick)))
(add-hook 'erc-text-matched-hook 'my-erc-page-me)
(defun my-erc-page-me-PRIVMSG (proc parsed)
(let ((nick (car (erc-parse-user (erc-response.sender parsed))))
(target (car (erc-response.command-args parsed)))
(msg (erc-response.contents parsed)))
(when (and (erc-current-nick-p target)
(not (erc-is-message-ctcp-and-not-action-p msg))
(my-erc-page-allowed nick))
(my-erc-page-popup-notification nick)
nil)))
(add-hook 'erc-server-PRIVMSG-functions 'my-erc-page-me-PRIVMSG)
;;; Remove trailing whitespace in messages
(defun my-erc-remove-trailing-whitespace (proc parsed)
"Remove trailing whitespace from the current message.
Some IM clients use an OTR plug-in that sends some annoying
trailing space to the screen, so we want to mop that up."
(let ((msg (erc-response.contents parsed)))
(when (stringp msg)
(setf (erc-response.contents parsed)
(erc-replace-regexp-in-string "[[:space:]]+\\'" "" msg))
nil)))
(add-hook 'erc-server-PRIVMSG-functions 'my-erc-remove-trailing-whitespace)
;;; Key customizations
(global-set-key "\C-cea" (lambda () (interactive)
(erc :server "irc.arstechnica.com" :port "6667"
:nick "mwolson"
:full-name "http://mwolson.org")))
(global-set-key "\C-ceb" (lambda () (interactive)
(erc :server "localhost" :port "6668"
:nick "mwolson")))
(global-set-key "\C-cee" (lambda () (interactive)
(erc :server "irc.servercentral.net" :port "ircd"
:nick "mwolson")))
(global-set-key "\C-cef" (lambda () (interactive)
; (erc :server "irc.us.freenode.net" :port "ircd"
(erc :server "niven.freenode.net" :port "ircd"
:nick "mwolson")))
(global-set-key "\C-cer" (lambda () (interactive)
(erc-tls :server "irc.rizon.net" :port "6697"
:nick "mwolson"
:full-name "mwolson")))
(global-set-key "\C-ceo" (lambda () (interactive)
(erc :server "irc.oftc.net" :port "ircd"
:nick "bigmike160")))
(global-set-key "\C-cez" (lambda () (interactive)
(erc :server "irc.zirc.net" :port "ircd"
:nick "bigmike160")))
;; temporary
;; (global-set-key "\C-cet" #'(lambda nil
;; (interactive)
;; (message "%s" erc-autoaway-last-sent-time)))
;; Make C-c RET (or C-c C-RET) send messages instead of RET
(define-key erc-mode-map (kbd "RET") nil)
(define-key erc-mode-map (kbd "C-c RET") 'erc-send-current-line)
(define-key erc-mode-map (kbd "C-c C-RET") 'erc-send-current-line)
;; Disable some commands that I never want to execute
(define-key erc-mode-map "\C-c\C-c" nil)
(define-key erc-mode-map "\C-c\C-e" nil)
(define-key erc-mode-map "\C-c\C-f" nil)
(define-key erc-mode-map "\C-c\C-p" nil)
(define-key erc-mode-map "\C-c\C-q" nil)
(define-key erc-mode-map "\C-c\C-r" nil)
;;; Customization variables
(custom-set-variables
'(erc-anonymous-login nil)
'(erc-auto-query (quote bury))
'(erc-autoaway-idle-seconds 1200)
'(erc-autojoin-channels-alist (quote (("servercentral.net" "#gp2xdev") ("mwolson.org" "&bitlbee") ("freenode.net" "#erc" "#hcoop" "##metaconference" "#muse" "#tyrian"))))
'(erc-bbdb-auto-create-on-whois-p t)
'(erc-bbdb-popup-type nil)
'(erc-beep-match-types nil)
'(erc-current-nick-highlight-type nil)
'(erc-dcc-get-default-directory "~/sandbox/")
'(erc-dcc-listen-host nil)
'(erc-dcc-port-range (quote (6888 . 6889)))
'(erc-dcc-public-host nil)
'(erc-email-userid "mwolson")
'(erc-enable-logging (quote erc-log-all-but-server-buffers))
'(erc-fool-highlight-type (quote all))
'(erc-fools (quote ("AnalphaBestie" "ayrnieu" "DISABLEDconsolers" "rahul" "\\bams\\b" "dalias" "jerware" "jeramey")))
'(erc-hide-prompt t)
'(erc-hide-timestamps nil)
'(erc-ignore-list (quote ("julian@pdpc/supporter/sustaining/ayrnieu")))
'(erc-interpret-mirc-color t)
'(erc-join-buffer (quote bury))
'(erc-keywords (quote ("\\b\\(mike\\|mwolson\\)[!?.,;]*$" "\\(mike\\|mwolson\\)[:!?,;]+" "\\b\\([hH]ey\\|[hH]i\\) \\(mike\\|mwolson\\|man\\)\\b")))
'(erc-kill-buffer-on-part t)
'(erc-kill-queries-on-quit t)
'(erc-kill-server-buffer-on-quit t)
'(erc-log-write-after-insert t)
'(erc-modules (quote (autoaway autojoin button capab-identify completion dcc fill identd irccontrols list log match menu move-to-prompt netsplit networks noncommands notify readonly ring scrolltobottom services stamp spelling track)))
'(erc-nick "mwolson")
'(erc-nicklist-icons-directory "/home/mwolson/proj/emacs/erc/arch-head/images/")
'(erc-notify-list (quote ("docelic" "forcer" "Smerdyakov" "johnw" "sachac" "strfryed" "disumu" "megacz")))
'(erc-notify-signoff-hook (quote (erc-notify-signoff)))
'(erc-notify-signon-hook (quote (erc-notify-signon)))
'(erc-pals (quote ("comcor" "deego" "docelic" "forcer" "johnsu01" "^johnw!" "^Luke!" "Sigma\\[Mtp\\]" "sachac" "strfryed")))
'(erc-part-reason (quote erc-part-reason-various))
'(erc-part-reason-various-alist (quote (("^np$" emms-show) ("zippy" erc-part-reason-zippy))))
'(erc-prompt-for-nickserv-password nil)
'(erc-prompt-for-password nil)
'(erc-query-display (quote bury))
'(erc-quit-reason (quote erc-quit-reason-various))
'(erc-quit-reason-various-alist (quote (("^np$" emms-show) ("zippy" erc-part-reason-zippy))))
'(erc-server "localhost")
'(erc-server-send-ping-interval nil)
'(erc-status-icon-file "/usr/local/share/emacs/23.0.50/etc/images/icons/hicolor/48x48/apps/emacs.png")
'(erc-text-matched-hook (quote (my-erc-page-me erc-log-matches)))
'(erc-timestamp-right-align-by-pixel t)
'(erc-track-exclude-types (quote ("JOIN" "NICK" "PART" "QUIT" "333" "353")))
'(erc-track-remove-disconnected-buffers t)
'(erc-track-switch-direction (quote importance))
'(erc-user-full-name (quote user-full-name))
'(erc-verbose-dcc nil)
'(erc-whowas-on-nosuchnick t))
(custom-set-faces
'(erc-default-face ((t (:foreground "dark blue" :slant oblique))))
'(erc-fool-face ((t (:foreground "LightBlue"))))
'(erc-input-face ((t (:foreground "dim gray"))))
'(erc-keyword-face ((t (:foreground "blue" :underline t :weight bold))))
'(erc-timestamp-face ((t (:foreground "dark green" :weight bold)))))
;; Do only certain channels temporarily
;; (setq erc-autojoin-channels-alist
;; '(("freenode.net" "#pulug" "#plugbot"))
;; erc-nick "mwolson`")
;; (setq erc-modules (quote (autojoin button fill irccontrols log
;; match netsplit noncommands
;; pcomplete readonly ring stamp
;; spelling track)))
;;; erc-init.el ends here