f6f4438b321505a88c32697a781ab1304e6a8bc7
[profile] / dot / gnus.el
1 ;;; -*- mode: emacs-lisp; coding: utf-8 -*-
2 ;;;
3 ;;; GNUS configuration
4 ;;;
5 ;;; (c) 2009 Mark Wooding
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This program is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 2 of the License, or
13 ;;; (at your option) any later version.
14 ;;;
15 ;;; This program is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
19 ;;;
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with this program; if not, write to the Free Software
22 ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
23
24 ;;;--------------------------------------------------------------------------
25 ;;; General Gnus preferences.
26
27 ;; Divide the main groups list by topics.
28 (add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
29 (setq gnus-subscribe-newsgroup-method 'gnus-subscribe-topics)
30
31 ;; Use hacky movemail program to move mail.
32 (setq mail-source-movemail-program "~/bin/movemail-hack")
33
34 ;; Don't force use of a full window.
35 (setq gnus-use-full-window nil)
36
37 ;; Display a slrn-like tree view in the summary window.
38 (setq gnus-use-trees nil)
39 (setq gnus-summary-make-false-root 'dummy)
40 (setq gnus-summary-line-format
41 "%U%R%z%4L %(%[%-16,16f%]%): %B %s\n"
42 gnus-summary-dummy-line-format
43 " %(%[----------------%]%): * %S\n")
44 (setq gnus-sum-thread-tree-root ">"
45 gnus-sum-thread-tree-false-root ">"
46 gnus-sum-thread-tree-single-indent "="
47 gnus-sum-thread-tree-indent " ")
48 (if (memq (coding-system-get (terminal-coding-system) 'mime-charset)
49 '(nil utf-8))
50 (setq gnus-sum-thread-tree-leaf-with-other "├─>"
51 gnus-sum-thread-tree-vertical "│ "
52 gnus-sum-thread-tree-single-leaf "╰─>")
53 (setq gnus-sum-thread-tree-leaf-with-other "|->"
54 gnus-sum-thread-tree-vertical "| "
55 gnus-sum-thread-tree-single-leaf "`->"))
56
57 ;; Sort threads in a useful way.
58 (setq gnus-thread-sort-functions
59 '(gnus-thread-sort-by-number
60 gnus-thread-sort-by-subject
61 gnus-thread-sort-by-total-score))
62
63 ;; Configure the crypto.
64 (setq mm-verify-option 'known
65 mm-sign-option 'guided
66 mm-decrypt-option 'never)
67
68 ;; Tracking available groups. These should work for sane servers, but maybe
69 ;; they'll need hacking in the local file.
70 (setq gnus-save-killed-list nil
71 gnus-check-bogus-newsgroups nil
72 gnus-read-active-file 'ask-server)
73
74 ;; Don't skip unread groups.
75 (setq gnus-group-goto-unread nil
76 gnus-summary-next-group-on-exit nil)
77
78 ;; Use one article buffer per group.
79 (setq gnus-single-article-buffer nil)
80
81 ;; Don't expand threads on initial opening.
82 (setq gnus-thread-hide-subtree t)
83
84 ;; Don't use strange icons instead of traditional smileys.
85 (setq gnus-treat-display-smileys nil)
86
87 ;; Fairly large numbers of articles are OK; don't bother warning me.
88 (setq gnus-large-newsgroup 500)
89
90 ;; When splitting articles, crossposting is a reasonable thing to do.
91 (setq nnimap-split-crosspost t)
92
93 ;; We may have the misfortune to talk to an Exchange server.
94 (setq imap-enable-exchange-bug-workaround t)
95
96 ;; Save articles in mbox format by default, of course, and save an entire
97 ;; batch with the same name.
98 (setq gnus-prompt-before-saving t
99 gnus-default-article-saver 'gnus-summary-save-in-mail)
100
101 ;; Clean up properly when closing the summary.
102 (defadvice gnus-summary-exit (before mdw-kill-debris compile activate)
103 (gnus-summary-expand-window))
104
105 ;; Configure article display a bit.
106 (defun mdw-gnus-article-setup ()
107 (setq truncate-lines nil
108 truncate-partial-width-windows nil
109 word-wrap t
110 wrap-prefix (concat (propertize "..." 'face 'mdw-ellipsis-face)
111 " ")))
112 (add-hook 'gnus-article-mode-hook #'mdw-gnus-article-setup)
113
114 ;; Don't expire articles on selection if they're alread read. This provides
115 ;; a handy way to prevent expiry, and actually forcing expiry isn't
116 ;; significantly harder.
117 (remove-hook 'gnus-mark-article-hook
118 'gnus-summary-mark-read-and-unread-as-read)
119 (add-hook 'gnus-mark-article-hook 'gnus-summary-mark-unread-as-read)
120
121 ;; Leave an oubliette level 7 for broken things which look like mailboxes.
122 ;; Otherwise Gnus keeps on resurrecting them and later realising that they're
123 ;; bogus.
124 (setq gnus-level-unsubscribed 6)
125
126 ;; Reconfigure the `nnmail-split-fancy' syntax table to be less mad.
127 (setq nnmail-split-fancy-syntax-table
128 (let ((table (make-syntax-table)))
129
130 ;; This is from upstream. I don't know what it's for.
131 (modify-syntax-entry ?% "." table)
132
133 ;; Email addresses are often wrapped in `<...>', so don't consider
134 ;; those to be part of the address.
135 (modify-syntax-entry ?< "(>" table)
136 (modify-syntax-entry ?> ")<" table)
137
138 ;; Email addresses definitely contain `.'.
139 (modify-syntax-entry ?. "_" table)
140
141 ;; Done.
142 table))
143
144 ;;;--------------------------------------------------------------------------
145 ;;; Magic for sending mail the correct way.
146
147 (defvar mdw-send-mail-alist nil
148 "An alist containing ways of sending email.
149 The keys are symbols naming mail-sending methods. The values are
150 alists mapping Lisp variable names to values which will be bound
151 around a call to the underlying `send-mail-function'. See
152 `mdw-message-send-it'.")
153
154 (defvar mdw-guess-send-mail-alist nil
155 "An alist for guessing the right way to send mail from a `From' address.
156 The keys are (Emacs-style) regular expressions. The values are
157 strings naming mail-sending methods, to be used if there is no
158 `mdw-send-mail-header-name' mail header.")
159
160 (defvar mdw-send-mail-header-name "X-mdw-Send-Mail"
161 "Mail header used to override the mail-sending method.
162 If a header with this name exists, then `mdw-message-send-it'
163 will look its value up in `mdw-send-mail-alist' to find out how
164 to send the message. The idea is that you can set this header
165 from `gnus-posting-styles'. The header will be stripped on
166 sending.")
167
168 (defvar mdw-default-send-mail-method nil
169 "The name of the default mail-sending method.")
170
171 (defun mdw-message-send-it ()
172 "Send mail using the appropriate mail sending method.
173 Firstly, a mail-sending method name is determined. If
174 `mdw-send-mail-header-name' has a non-nil value, and a header
175 with this name exists in the message being sent, then its value
176 is used as the name. Otherwise, the email address from the
177 `From' header is matched against the named of the association in
178 `mdw-guess-send-mail-alist', and if any of them match then the
179 corresponding value is used as the name. Otherwise, the value of
180 `mdw-default-send-mail-method' is used.
181
182 The name is then looked up in `mdw-send-mail-alist' to find an
183 alist of temporary variable bindings; an error is reported if no
184 matching entry is found. The variables are temporarily bound to
185 their corresponding values, and the (possibly freshly rebound)
186 `send-mail-function' is invoked with no parameters.
187
188 If the method name is `nil', then `send-mail-function' is simply
189 invoked without doing anything else very special. This can
190 therefore be left as a useful default, if it's generally the
191 right thing."
192
193 (let* ((method-name
194 (or
195
196 ;; Firstly, if there's an explicit header in the message, then
197 ;; we'd better use that.
198 (let ((method (message-fetch-field mdw-send-mail-header-name)))
199 (and method (intern method)))
200
201 ;; Look up the sender's address in the guess list.
202 (let* ((sender (some #'message-fetch-field
203 '("resent-sender" "resent-from"
204 "sender" "from")))
205 (addr (cadr (mail-extract-address-components sender)))
206 (alist mdw-guess-send-mail-alist)
207 assoc)
208 (catch 'found
209 (while alist
210 (setq assoc (pop alist))
211 (when (string-match (car assoc) addr)
212 (throw 'found (cdr assoc))))
213 nil))
214
215 ;; Otherwise use the default.
216 mdw-default-send-mail-method))
217
218 (method (and method-name
219 (let ((assoc (assq method-name mdw-send-mail-alist)))
220 (if assoc (cdr assoc)
221 (error "Unknown send-mail method `%s'."
222 method-name))))))
223
224 ;; Bind the appropriate variables.
225 (progv
226 (mapcar #'car method)
227 (mapcar #'cdr method)
228
229 ;; Make a copy of the buffer and strip out our magic header. (If the
230 ;; message send fails, it would be annoying to have lost the magic
231 ;; token which tells us how to retry properly.)
232 (let ((buf (current-buffer)))
233 (with-temp-buffer
234 (insert-buffer buf)
235 (message-remove-header mdw-send-mail-header-name)
236 (funcall send-mail-function))))))
237
238 (setq message-send-mail-function 'mdw-message-send-it)
239
240 ;;;--------------------------------------------------------------------------
241 ;;; Local configuration.
242
243 ;; Fetching news from the local news server seems sensible.
244 (setq gnus-select-method
245 (let ((server (mdw-config 'nntp-server)))
246 (if server
247 `(nntp ,server)
248 '(nnnil ""))))
249
250 ;; Now load a local configuration file.
251 (load "~/.gnus-local.el")
252
253 ;;;----- That's all, folks --------------------------------------------------