Bitlbee and Emacs

As part of switching to bitlbee as my primary IM client, I ended up making a lot of customizations to my erc configuration, both for general use and for bitlbee-specific stuff. I didn’t really have any beforehand, since I don’t use IRC very much, but these make it a lot more usable with bitlbee. Bitlbee can be pretty annoying at the start; these help to make it much less so. Most of the general ERC customizations came from the emacs-Viki, but most of the bitlbee-related code is mine.

The first customization I made was to set the header-line of disconnected buffers to be a different face than normal. The header line is just the top line of the buffer; some modes, such as ERC, use it for displaying information about the current context. This just makes it easier to tell which ERC buffers are still connected to the server.

(defface erc-header-line-disconnected
  '((t (:foreground "black" :background "indianred")))
  "Face to use when ERC has been disconnected.")
 
(defun erc-update-header-line-show-disconnected ()
  "Use a different face in the header-line when disconnected."
  (erc-with-server-buffer
    (cond ((erc-server-process-alive) 'erc-header-line)
          (t 'erc-header-line-disconnected))))
          (setq erc-header-line-face-method 'erc-update-header-line-show-disconnected)
 
(setq erc-header-line-face-method 'erc-update-header-line-show-disconnected)

I like to log my IM messages. I often have useful discussions with people, or receive information from them, that I want to refer to later. The following sets my log directory and updates them whenever the ERC buffer is updated, ensuring I never lose information.

(setq erc-log-channels-directory "~/.emacs.d/logs/")
(setq erc-save-buffer-on-part nil)
(setq erc-save-queries-on-quit nil
      erc-log-write-after-send t
      erc-log-write-after-insert t)

IRC in general will give a lot of messages that you don’t care about, and there are some bitlbee-specific ones as well. erc-hide-list is a list of types of messages that ERC will hide, and erc-ignore-unimportant is a function I wrote to suppress other information I don’t want to see. This includes mode changes for people and reconnection attempts when an account is already online.

(setq erc-hide-list '("MODE"))
(defun erc-ignore-unimportant (msg)
  (if (or (string-match "*** localhost has changed mode for &bitlbee to" msg)
          (string-match "Account already online" msg)
          (string-match "Unknown error while loading configuration" msg))
      (setq erc-insert-this nil)))
(add-hook 'erc-insert-pre-hook 'erc-ignore-unimportant)

Speaking of reconnection attempts when an account is online, I have ERC automatically connect me to my accounts whenever I log on as well as every 60 seconds. This simulates the behaviour of other IM clients, which will auto-reconnect when disconnected.

(defvar bitlbee-password "<SECRET>")
(defun bitlbee-identify ()
  "If we're on the bitlbee server, send the identify command to the
 &bitlbee channel."
  (when (and (string= "localhost" erc-session-server)
             (string= "&bitlbee" (buffer-name)))
    (erc-message "PRIVMSG" (format "%s identify %s"
                                   (erc-default-target)
                                   bitlbee-password))))
(add-hook 'erc-join-hook 'bitlbee-identify)
 
(defun bitlbee-connect ()
  (interactive)
  (save-window-excursion
    (when (get-buffer "&bitlbee")
      (switch-to-buffer "&bitlbee")
      (erc-message "PRIVMSG" (concat (erc-default-target) " identify " bitlbee-password))
      (erc-message "PRIVMSG" (concat (erc-default-target) " account on 0")
      (erc-message "PRIVMSG" (concat (erc-default-target) " account on 1"))))))
(setq bitlbee-reconnect-timer (run-with-timer 0 60 'bitlbee-connect))

The ‘blist’ command for bitlbee will list your buddies and their statuses. However, by it doesn’t do any color-coding for your Friends who are online vs who are away, so I had to add this. It isn’t very difficult; erc-keywords is a list of keyword-face pairs that the keyword is matched with. All you need to do to perform any type of highlighting is be able to match the message you want highlighted with a regular expression.

(setq erc-keywords '((".*Online.*" (:foreground "green"))
                     (".*Busy" (:foreground "red"))
                     (".*Away" (:foreground "red"))
                     (".*Idle" (:foreground "orange"))
                     ))

One of the reasons I switched from Pidgin to Bitlbee was that Pidgin was no longer notifying me of new messages; I decided to try seeing if I could implement this for bitlbee. It actually turned out to be pretty easy, although there is one problem: it only occurs for messages sent to the public channel, not private messages, so it won’t inform me when someone starts a conversation with me. I’m still looking into how to fix this.

(defun erc-notify-on-msg (msg)
  (if (string-match "nflath:" msg)
      (shell-command (concat "notify-send \"" msg "\""))))
(add-hook 'erc-insert-pre-hook 'erc-notify-on-msg)

The last customization I have to bitlbee is so that I don’t have to type the user I’m addressing each time in the public channel. Usually, you have to prepend each message with user: in order for it to be sent to them; this code will auto-prepend messages with the last user you addressed. It’s a work in progress, as a lot of cases I don’t want this to happen - for example, when I’m listing my buddies - but it’s pretty good right now.

(setq bitlbee-target "")
(defun bitlbee-update-target (msg)
  (if (string-match "\\([^:]*: \\)" msg)
      (setq bitlbee-target (match-string 1 msg))
    (if (not (or
              (string-match "account" msg)
              (string-match "help" msg)
              (string-match "identify" msg)
              (string-match "blist" msg)))
        (setq str (concat bitlbee-target msg)))))
(add-hook 'erc-send-pre-hook 'bitlbee-update-target)

I generally want to be logged into IM, so I just start it up on emacs start.

(erc :server "localhost" :port "6667" :nick "nflath" :password bitlbee-password)

If you have any other customizations or improvements to suggest, please let me know in the comments.

Tags: , ,

4 Responses to “Bitlbee and Emacs”

  1. Peter Jones says:

    Nathaniel, you don’t have to worry about prepending nicks in the public channel if you start a new private message with people. This will place each IM conversation into a dedicated buffer. It also helps you figure out who just talked to you in IM.

    You do this in the public channel by issuing a “/q nick” command. I also have ERC configured to create a new buffer when someone messages me.

  2. Seth says:

    EmacsWiki has a couple of methods for getting alerts when you get a private message.

    http://www.emacswiki.org/cgi-bin/wiki/ErcPageMe

    I opted for the my-erc-page-me-PRIVMSG route.

  3. Seth says:

    And to follow up with what Peter said, putting

    (setq erc-auto-query ‘buffer)

    will create a new buffer for each IM to you.

  4. quodlibetor says:

    Thanks for the tips, nearly all of them ended up in my .emacs.

    I modified your erc-notify-on-msg to message me for any private bitlbee buffers, and to stick the name of the sender as the header line:

    (defun erc-notify-on-msg (msg)
    “Send a message via notify-send if a message specifically to me”
    (if (or (string-match “MY-NICK:” msg)
    (and (string= “localhost” erc-session-server)
    (not (string-match “\\*\\*\\*” msg))
    (not (string-match “\” msg))))
    (let ((nameless-msg (replace-regexp-in-string “^\ ” “” msg)))
    (shell-command (concat “notify-send \”" (buffer-name) “\” \”" nameless-msg “\”")))))
    (add-hook ‘erc-insert-pre-hook ‘erc-notify-on-msg)

    Since I have erc open up a new buffer for chats this works pretty well for me. If you’ve got bitlbee set up to use a fancy server instead of localhost you’d need to change that line, but otherwise it should work.

Leave a Reply