d8949edaf97d6bcdee1e910fb91551e8a1ff901b
[~bandali/configs] / .emacs.d / lisp / bandali-gnus.el
1 ;;; bandali-gnus.el --- bandali's Gnus setup -*- lexical-binding: t; -*-
2
3 ;; Copyright (C) 2018-2022 Amin Bandali
4
5 ;; Author: Amin Bandali <bandali@gnu.org>
6 ;; Keywords: mail, news
7
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
12
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;; My trusty super awesome Gnus setup.
24
25 ;;; Code:
26
27 (defvar b/maildir (expand-file-name "~/mail/"))
28 (with-eval-after-load 'recentf
29 (add-to-list 'recentf-exclude b/maildir))
30
31 (defvar b/gnus-init-file (b/etc "gnus"))
32
33 (eval-when-compile
34 (progn
35 (defvar nndraft-directory)
36 (defvar gnus-read-newsrc-file)
37 (defvar gnus-save-newsrc-file)
38 (defvar gnus-gcc-mark-as-read)
39 (defvar nnmail-split-abbrev-alist)))
40
41 (declare-function article-make-date-line "gnus-art" (date type))
42
43 (setq
44 mail-user-agent 'gnus-user-agent
45 read-mail-command 'gnus
46
47 gnus-select-method '(nnnil "")
48 gnus-secondary-select-methods
49 `(,@(if (string= (system-name) "darya")
50 '((nnimap
51 "canonical"
52 (nnimap-stream plain)
53 (nnimap-address "127.0.0.1")
54 (nnimap-server-port 143)
55 (nnimap-authenticator plain)
56 (nnimap-user "bandali@canonical.local")))
57 '((nnimap
58 "kelar"
59 (nnimap-stream plain)
60 (nnimap-address "127.0.0.1")
61 (nnimap-server-port 143)
62 (nnimap-authenticator plain)
63 (nnimap-user "bandali@kelar.local"))
64 (nnimap
65 "shemshak"
66 (nnimap-stream plain)
67 (nnimap-address "127.0.0.1")
68 (nnimap-server-port 143)
69 (nnimap-authenticator plain)
70 (nnimap-user "bandali@shemshak.local"))
71 (nnimap
72 "gnu"
73 (nnimap-stream plain)
74 (nnimap-address "127.0.0.1")
75 (nnimap-server-port 143)
76 (nnimap-authenticator plain)
77 (nnimap-user "bandali@gnu.local")
78 (nnimap-inbox "INBOX")
79 (nnimap-split-methods 'nnimap-split-fancy)
80 (nnimap-split-fancy
81 (|
82 ;; (: gnus-registry-split-fancy-with-parent)
83 ;; (: gnus-group-split-fancy "INBOX" t "INBOX")
84 ;; spam
85 ("X-Spam_action" "reject" "Junk")
86 ;; keep debbugs emails in INBOX
87 (list ".*<\\(.*\\)\\.debbugs\\.gnu\\.org>.*" "INBOX")
88 ;; list moderation emails
89 (from ".+-\\(owner\\|bounces\\)@\\(non\\)?gnu\\.org" "listmod")
90 ;; gnu
91 (list ".*<\\(.*\\)\\.\\(non\\)?gnu\\.org>.*" "l.\\1")
92 ;; fsf
93 (list ".*<\\(.*\\)\\.fsf\\.org>.*" "l.\\1")
94 ;; gnus
95 (list ".*<\\(.*\\)\\.gnus\\.org>.*" "l.\\1")
96 ;; libreplanet
97 (list ".*<\\(.*\\)\\.libreplanet\\.org>.*" "l.\\1")
98 ;; iana (e.g. tz-announce)
99 (list ".*<\\(.*\\)\\.iana\\.org>.*" "l.\\1")
100 ;; mailop
101 (list ".*<\\(.*\\)\\.mailop\\.org>.*" "l.\\1")
102 ;; sdlu
103 (list ".*<\\(.*\\)\\.spammers\\.dontlike\\.us>.*" "l.sdlu")
104 ;; bitfolk
105 (from ".*@\\(.+\\)?bitfolk\\.com>.*" "bitfolk")
106 ;; haskell
107 (list ".*<\\(.*\\)\\.haskell\\.org>.*" "l.\\1")
108 ;; *.lists.sr.ht, omitting one dot if present
109 ;; add more \\.?\\([^.]*\\) if needed
110 (list ".*<~\\(.*\\)/\\([^.]*\\)\\.?\\([^.]*\\)\\.lists\\.sr\\.ht>.*" "l.~\\1.\\2\\3")
111 ;; webmasters
112 (from "webmasters\\(-comment\\)?@gnu\\.org" "webmasters")
113 ;; other
114 ("subject" "nagios-fsf:.*" "nagios-fsf")
115 (list ".*atreus.freelists.org" "l.atreus")
116 (list ".*deepspec.lists.cs.princeton.edu" "l.deepspec")
117 ;; (list ".*haskell-art.we.lurk.org" "l.haskell.art") ;d
118 ;; (list ".*notmuch.notmuchmail.org" "l.notmuch") ;u
119 (list ".*dev.lists.parabola.nu" "l.parabola-dev")
120 ;; ----------------------------------
121 ;; legend: (u)nsubscribed | (d)ead
122 ;; ----------------------------------
123 ;; otherwise, leave mail in INBOX
124 "INBOX")))
125 (nnimap
126 "uwaterloo"
127 (nnimap-stream plain)
128 (nnimap-address "127.0.0.1")
129 (nnimap-server-port 143)
130 (nnimap-authenticator plain)
131 (nnimap-user "abandali@uwaterloo.local")
132 (nnimap-inbox "INBOX")
133 (nnimap-split-methods 'nnimap-split-fancy)
134 (nnimap-split-fancy
135 (|
136 ;; (: gnus-registry-split-fancy-with-parent)
137 ;; se212-f19
138 ("subject" "SE\\s-?212" "course.se212-f19")
139 (from "SE\\s-?212" "course.se212-f19")
140 ;; catch-all
141 "INBOX")))
142 (nnimap
143 "csc"
144 (nnimap-stream plain)
145 (nnimap-address "127.0.0.1")
146 (nnimap-server-port 143)
147 (nnimap-authenticator plain)
148 (nnimap-user "abandali@csclub.uwaterloo.local")
149 (nnimap-inbox "INBOX")
150 (nnimap-split-methods 'nnimap-split-fancy)
151 (nnimap-split-fancy
152 (|
153 ;; cron reports and other messages from root
154 (from "root@\\(.*\\.\\)?csclub\\.uwaterloo\\.ca" "INBOX")
155 ;; spam
156 ("X-Spam-Flag" "YES" "Junk")
157 ;; catch-all
158 "INBOX")))
159 ;; (nnimap
160 ;; "sfl"
161 ;; (nnimap-stream tls)
162 ;; (nnimap-address "mail.savoirfairelinux.com")
163 ;; (nnimap-user "amin.bandali"))
164 )))
165 gnus-message-archive-group "nnimap+gnu:INBOX"
166 gnus-parameters
167 '(("l\\.deepspec"
168 (to-address . "deepspec@lists.cs.princeton.edu")
169 (to-list . "deepspec@lists.cs.princeton.edu")
170 (list-identifier . "\\[deepspec\\]"))
171 ("l\\.fencepost-users"
172 (to-address . "fencepost-users@gnu.org")
173 (to-list . "fencepost-users@gnu.org")
174 (list-identifier . "\\[Fencepost-users\\]"))
175 ("l\\.haskell-cafe"
176 (to-address . "haskell-cafe@haskell.org")
177 (to-list . "haskell-cafe@haskell.org")
178 (list-identifier . "\\[Haskell-cafe\\]"))
179 ("gnu.*"
180 (gcc-self . t)))
181 ;; nnimap-record-commands t
182 ;; gnus-large-newsgroup 50
183 ;; gnus-process-mark-toggle t
184 gnus-home-directory (b/var "gnus/")
185 gnus-directory (concat gnus-home-directory "news/")
186 message-directory (concat gnus-home-directory "mail/")
187 nndraft-directory (concat gnus-home-directory "drafts/")
188 gnus-save-newsrc-file nil
189 gnus-read-newsrc-file nil
190 gnus-search-use-parsed-queries t
191 gnus-interactive-exit nil
192 gnus-gcc-mark-as-read t)
193
194 (with-eval-after-load 'gnus
195 (when (version< emacs-version "27")
196 (with-eval-after-load 'nnmail
197 (add-to-list
198 'nnmail-split-abbrev-alist
199 '(list . "list-id\\|list-post\\|x-mailing-list\\|x-beenthere\\|x-loop")
200 t)))
201
202 ;; (require 'gnus-registry)
203 ;; (setq gnus-registry-max-entries 2500)
204 ;; (setq gnus-registry-ignored-groups
205 ;; (append gnus-registry-ignored-groups
206 ;; '(("^nnimap:gnu\\.l" t)
207 ;; ("webmasters$" t))))
208 ;; (gnus-registry-initialize)
209
210 (with-eval-after-load 'recentf
211 (add-to-list 'recentf-exclude gnus-home-directory))
212
213 ;; hooks
214 (add-hook 'gnus-group-mode-hook #'gnus-topic-mode)
215 (add-hook 'gnus-group-mode-hook #'gnus-agent-mode))
216 ;; global key bindings
217 (global-set-key (kbd "C-c g") #'gnus-plugged)
218 (global-set-key (kbd "C-c G") #'gnus-unplugged)
219
220 (with-eval-after-load 'gnus-art
221 (setq
222 gnus-buttonized-mime-types '("multipart/\\(signed\\|encrypted\\)")
223 gnus-sorted-header-list '("^From:"
224 "^X-RT-Originator"
225 "^Newsgroups:"
226 "^Subject:"
227 "^Date:"
228 "^Envelope-To:"
229 "^Followup-To:"
230 "^Reply-To:"
231 "^Organization:"
232 "^Summary:"
233 "^Abstract:"
234 "^Keywords:"
235 "^To:"
236 "^[BGF]?Cc:"
237 "^Posted-To:"
238 "^Mail-Copies-To:"
239 "^Mail-Followup-To:"
240 "^Apparently-To:"
241 "^Resent-From:"
242 "^User-Agent:"
243 "^X-detected-operating-system:"
244 "^X-Spam_action:"
245 "^X-Spam_bar:"
246 "^Message-ID:"
247 ;; "^References:"
248 "^List-Id:"
249 "^Gnus-Warning:")
250 gnus-visible-headers (mapconcat #'identity
251 gnus-sorted-header-list
252 "\\|")
253 ;; local-lapsed article dates
254 ;; from https://www.emacswiki.org/emacs/GnusFormatting#toc11
255 gnus-article-date-headers '(user-defined)
256 gnus-article-time-format
257 (lambda (time)
258 (let* ((date (format-time-string "%a, %d %b %Y %T %z" time))
259 (local (article-make-date-line date 'local))
260 (combined-lapsed (article-make-date-line date
261 'combined-lapsed))
262 (lapsed (progn
263 (string-match " (.+" combined-lapsed)
264 (match-string 0 combined-lapsed))))
265 (concat local lapsed))))
266 ;; local key bindings
267 (declare-function org-store-link "ol" (arg &optional interactive?))
268 (define-key gnus-article-mode-map (kbd "M-L") #'org-store-link))
269
270 (with-eval-after-load 'gnus-sum
271 (setq gnus-thread-sort-functions '(gnus-thread-sort-by-number
272 gnus-thread-sort-by-subject
273 gnus-thread-sort-by-date))
274 ;; local key bindings
275 (define-key gnus-summary-mode-map (kbd "M-L") #'org-store-link)
276 ;; (define-key gnus-summary-mode-map (kbd "r")
277 ;; #'gnus-summary-reply-with-original)
278 ;; (define-key gnus-summary-mode-map (kbd "R")
279 ;; #'gnus-summary-wide-reply-with-original)
280 (defvar b/gnus-summary-prefix-map)
281 (define-prefix-command 'b/gnus-summary-prefix-map)
282 (define-key gnus-summary-mode-map (kbd "v")
283 'b/gnus-summary-prefix-map)
284 (define-key b/gnus-summary-prefix-map (kbd "r")
285 #'gnus-summary-reply)
286 (define-key b/gnus-summary-prefix-map (kbd "w")
287 #'gnus-summary-wide-reply)
288 (define-key b/gnus-summary-prefix-map (kbd "v")
289 #'gnus-summary-show-raw-article))
290 ;; hooks
291 (add-hook 'gnus-summary-mode-hook #'b/no-mouse-autoselect-window)
292
293 (defvar b/sfl-p nil)
294 (with-eval-after-load 'gnus-msg
295 (let ((bandali "Amin Bandali (https://kelar.org/~bandali)"))
296 (defvar b/canonical-signature
297 (mapconcat
298 #'identity
299 `(,bandali
300 "Software Engineer (Desktop), Canonical")
301 "\n"))
302 (defvar b/csc-signature
303 (mapconcat
304 #'identity
305 `(,bandali
306 "Systems Committee <syscom@csclub.uwaterloo.ca>"
307 "Computer Science Club of the University of Waterloo")
308 "\n"))
309 (defvar b/sfl-signature
310 (mapconcat
311 #'identity
312 `(,bandali
313 "Volunteer, Savoir-faire Linux"
314 "jami:bandali")
315 "\n")))
316 (setq
317 gnus-message-replysign t
318 gnus-posting-styles
319 '((".*"
320 (address "bandali@gnu.org")
321 ("X-Message-SMTP-Method" "smtp fencepost.gnu.org 587"))
322 ((header "subject" "ThankCRM")
323 (to "webmasters-comment@gnu.org")
324 (body ""))
325 ("nnimap\\+kelar:.*"
326 (address "bandali@kelar.org")
327 ("X-Message-SMTP-Method" "smtp mail.kelar.org 587")
328 (gcc "nnimap+kelar:Sent"))
329 ("nnimap\\+shemshak:.*"
330 (address "amin@shemshak.org")
331 ("X-Message-SMTP-Method" "smtp mail.shemshak.org 587")
332 (gcc "nnimap+shemshak:Sent"))
333 ("nnimap\\+canonical:.*"
334 (address "amin.bandali@canonical.com")
335 ("X-Message-SMTP-Method" "smtp smtp.canonical.com 587")
336 (signature b/canonical-signature)
337 (gcc "nnimap+canonical:Sent"))
338 ("nnimap\\+csc:.*"
339 (address "bandali@csclub.uwaterloo.ca")
340 ("X-Message-SMTP-Method" "smtp mail.csclub.uwaterloo.ca 587")
341 (signature b/csc-signature)
342 (gcc "nnimap+csc:Sent"))
343 ("nnimap\\+sfl:.*"
344 (address "amin.bandali@savoirfairelinux.com")
345 ("X-Message-SMTP-Method" "smtp mail.savoirfairelinux.com 587")
346 (signature b/sfl-signature)
347 (eval (setq-local b/sfl-p t))
348 (gcc "nnimap+sfl:Sent")))))
349 ;; hooks
350 ;; (with-eval-after-load 'gnus
351 ;; (add-hook 'gnus-message-setup-hook
352 ;; (lambda ()
353 ;; (unless (or (mml-secure-is-encrypted-p)
354 ;; b/sfl-p)
355 ;; (mml-secure-message-sign)))))
356
357 (with-eval-after-load 'gnus-topic
358 (setq
359 gnus-topic-line-format "%i[ %A: %(%{%n%}%) ]%v\n"
360 gnus-topic-topology
361 `(("Gnus" visible nil nil)
362 (("misc" visible nil nil))
363 ,@(if (string= (system-name) "darya")
364 '((("canonical" visible nil nil)))
365 '((("csc" visible nil nil))
366 (("uwaterloo" visible nil nil))
367 (("kelar" visible nil nil))
368 (("shemshak" visible nil nil))
369 (("gnu" visible nil nil))
370 (("old-gnu" visible nil nil))
371 (("sfl" visible nil nil)))))))
372
373 (with-eval-after-load 'gnus-agent
374 (setq gnus-agent-synchronize-flags 'ask))
375
376 (with-eval-after-load 'gnus-group
377 (setq gnus-permanently-visible-groups "\\(:INBOX$\\|:gnu$\\)"))
378
379 (with-eval-after-load 'gnus-win
380 (setq gnus-use-full-window nil))
381
382 (with-eval-after-load 'gnus-dired
383 (add-hook 'dired-mode-hook 'gnus-dired-mode))
384
385 (with-eval-after-load 'mm-decode
386 (setq
387 ;; mm-attachment-override-types `("text/x-diff" "text/x-patch"
388 ;; ,@mm-attachment-override-types)
389 mm-discouraged-alternatives '("text/html" "text/richtext")
390 mm-decrypt-option 'known
391 mm-verify-option 'known))
392
393 (with-eval-after-load 'mm-uu
394 (when (version< "27" emacs-version)
395 (set-face-attribute 'mm-uu-extract nil :extend t))
396 (when (version< emacs-version "27")
397 (setq mm-uu-diff-groups-regexp ".")))
398
399 (with-eval-after-load 'mml-sec
400 (setq mml-secure-openpgp-encrypt-to-self t
401 mml-secure-openpgp-sign-with-sender t))
402
403 (provide 'bandali-gnus)
404 ;;; bandali-gnus.el ends here