One day, I might organize this better. But in the mean time...

Spam filtering in Gnus

I use spam.el for spam filtering. I also want to whitelist everyone in my BBDB address book, so I wrote the following functions:

(defun hc:gnus-spam-if-not-in-bbdb ()
  "gnus fancy split function;
     if the senders address is not in bbdb, check if spam"
  (let ((who (or (message-fetch-field "from")
		 (message-fetch-field "sender")
		 (message-fetch-field "reply-to"))))
    (if (string-match all-my-addresses-regexp who)
	(spam-split)
      (if (gnus-if-not-in-bbdb t)
	  (spam-split)))))

Note that I anti-whitelist my own addresses, using the all-my-addresses-regexp variable, because spammers sometimes make the From: header the same as the To: header.

The gnus-if-not-in-bbdb is based on a lisp recipe from my.gnus.org that I am no longer able to locate, and is defined as follows:

(defun gnus-if-not-in-bbdb (target)
  "gnus fancy split function;
     if the senders address is not in bbdb, return TARGET"
  (let ((who (bbdb-canonicalize-address
              (cadr (gnus-extract-address-components
                     (or (message-fetch-field "from")
                         (message-fetch-field "sender")
                         (message-fetch-field "reply-to")
                         "[email protected]"
                         )))))
        )
    (unless (bbdb-search-simple nil who)
      target
      )
    )
  )

I use the SpamAssassin backend, so I have the following definitions. (I'm using spamc, communicating with spamd over a UNIX domain socket.)

(setq spam-use-spamassassin t)
(setq spam-split-group "spamkill")
(setq spam-spamassassin-path "spamc")
(setq spam-spamassassin-arguments '("-U" "/var/run/spamd_sock"))
(require 'spam)
(spam-initialize)

Gnus splitting and SpamAssassin

[DEPRECATED] spam.el from gnus now supports SpamAssassin, so this is no longer needed with recent versions of gnus.

You need to use fancy splitting for this.

Add this code to your .gnus file:

(defun hc:fancy-split-spamassassin ()
  (save-excursion
    (set-buffer " *nnmail incoming*")
    (call-process-region (point-min) (point-max) "spamc" t t nil "-f")
    (goto-char (point-min))
    (when (re-search-forward "^x-spam-flag: yes$" nil t) "spamkill")))

Then add a rule to your nnmail-split-fancy variable:

    (: hc:fancy-split-spamassassin)

My key bindings

;;; match parentheses (e.g. on a close-paren, hit M-] to jump to the
;;; corresponding open-paren)
(global-set-key "\e[" 'forward-list)
(global-set-key "\e]" 'backward-list)
;;; cycle through windows with C-M-next (C-M-pgdn) and C-M-prior
(global-set-key [\C-\M-next] 'other-window)
(global-set-key [\C-\M-prior] (lambda nil (interactive) (other-window -1)))

Setting the mail server by my IP address

Since I'm on a laptop, my Internet connection changes, and so does my SMTP server. So in my .emacs, I check my IP address and set my SMTP server.

(let ((address (shell-command-to-string "ifconfig eth0 | awk '/inet addr/{split($2,x,\":\");print x[2]}'")))
  (cond ((string-match "^129\\.97\\." address)
	 ;; UW
	 (setq message-send-mail-function 'smtpmail-send-it
	       send-mail-function 'smtpmail-send-it
	       smtpmail-default-smtp-server "mail.math.uwaterloo.ca"
	       smtpmail-smtp-server "mail.math.uwaterloo.ca"))
	((string-equal "129.128.207.8\n" address)
	 ;; U of A
	 (setq message-send-mail-function 'smtpmail-send-it
	       send-mail-function 'smtpmail-send-it
	       smtpmail-default-smtp-server "mailbox.math.ualberta.ca"
	       smtpmail-smtp-server "mailbox.math.ualberta.ca"))
	;;((string-match "^24\\." address)
	 ;; Rogers (in Waterloo) (their mail server uses AUTH SMTP - not
	 ;; supported (yet) by Gnus)
	 ;;(setq smtpmail-default-smtp-server "smtp.ktchnr.phub.net.cable.rogers.com")
	 ;;(setq smtpmail-smtp-server "smtp.ktchnr.phub.net.cable.rogers.com"))
	((string-match "^142\\." address)
	 ;; Telus (in Edmonton)
	 (setq message-send-mail-function 'smtpmail-send-it
	       send-mail-function 'smtpmail-send-it
	       smtpmail-default-smtp-server "smtp.telusplanet.net"
	       smtpmail-smtp-server "smtp.telusplanet.net"))
	(t
	 ;; anywhere else -- send through UW's server over ssh
	 (setq message-send-mail-function 'feedmail-send-it
	       send-mail-function 'feedmail-send-it
	       feedmail-binmail-template "ssh hopper -e none /bin/mail %s"))))

Copying filenames from dired

Mark a bunch of files, and copy their filenames to the kill ring, and paste them into another buffer. I find it handy in eshell sometimes.

(defun my:dired-kill-ring-save-filenames (&optional arg)
  "Puts all marked (or next ARG) filenames to the kill ring."
  (interactive "P")
  (kill-new (mapconcat
	     #'(lambda (x) x)
	     (dired-map-over-marks (dired-get-filename 'verbatim)
				   arg) " ")))
;; dired-find-file is already mapped to "e" and "<RET>", so we can remap
;; "f" to dired-show-file-type, and map "w" to
;; my:dired-kill-ring-save-filenames
(add-hook 'dired-load-hook #'(lambda ()
			       (define-key dired-mode-map "w"
				 'my:dired-kill-ring-save-filenames)
			       (define-key dired-mode-map "f"
				 'dired-show-file-type)))