Switch to EXWM
[~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 plain)
162 (nnimap-address "127.0.0.1")
163 (nnimap-server-port 143)
164 (nnimap-authenticator plain)
165 (nnimap-user "amin.bandali@savoirfairelinux.local")))))
166 gnus-message-archive-group "nnimap+gnu:INBOX"
167 gnus-parameters
168 '(("l\\.deepspec"
169 (to-address . "deepspec@lists.cs.princeton.edu")
170 (to-list . "deepspec@lists.cs.princeton.edu")
171 (list-identifier . "\\[deepspec\\]"))
172 ("l\\.fencepost-users"
173 (to-address . "fencepost-users@gnu.org")
174 (to-list . "fencepost-users@gnu.org")
175 (list-identifier . "\\[Fencepost-users\\]"))
176 ("l\\.haskell-cafe"
177 (to-address . "haskell-cafe@haskell.org")
178 (to-list . "haskell-cafe@haskell.org")
179 (list-identifier . "\\[Haskell-cafe\\]"))
180 ("gnu.*"
181 (gcc-self . t)))
182 ;; nnimap-record-commands t
183 ;; gnus-large-newsgroup 50
184 ;; gnus-process-mark-toggle t
185 gnus-home-directory (b/var "gnus/")
186 gnus-directory (concat gnus-home-directory "news/")
187 message-directory (concat gnus-home-directory "mail/")
188 nndraft-directory (concat gnus-home-directory "drafts/")
189 gnus-save-newsrc-file nil
190 gnus-read-newsrc-file nil
191 gnus-search-use-parsed-queries t
192 gnus-interactive-exit nil
193 gnus-gcc-mark-as-read t)
194
195 (with-eval-after-load 'gnus
196 (when (version< emacs-version "27")
197 (with-eval-after-load 'nnmail
198 (add-to-list
199 'nnmail-split-abbrev-alist
200 '(list . "list-id\\|list-post\\|x-mailing-list\\|x-beenthere\\|x-loop")
201 t)))
202
203 ;; (require 'gnus-registry)
204 ;; (setq gnus-registry-max-entries 2500)
205 ;; (setq gnus-registry-ignored-groups
206 ;; (append gnus-registry-ignored-groups
207 ;; '(("^nnimap:gnu\\.l" t)
208 ;; ("webmasters$" t))))
209 ;; (gnus-registry-initialize)
210
211 (with-eval-after-load 'recentf
212 (add-to-list 'recentf-exclude gnus-home-directory))
213
214 ;; hooks
215 (add-hook 'gnus-group-mode-hook #'gnus-topic-mode)
216 (add-hook 'gnus-group-mode-hook #'gnus-agent-mode))
217 ;; global key bindings
218 (global-set-key (kbd "C-c g") #'gnus-plugged)
219 (global-set-key (kbd "C-c G") #'gnus-unplugged)
220
221 (with-eval-after-load 'gnus-art
222 (setq
223 gnus-buttonized-mime-types '("multipart/\\(signed\\|encrypted\\)")
224 gnus-sorted-header-list '("^From:"
225 "^X-RT-Originator"
226 "^Newsgroups:"
227 "^Subject:"
228 "^Date:"
229 "^Envelope-To:"
230 "^Followup-To:"
231 "^Reply-To:"
232 "^Organization:"
233 "^Summary:"
234 "^Abstract:"
235 "^Keywords:"
236 "^To:"
237 "^[BGF]?Cc:"
238 "^Posted-To:"
239 "^Mail-Copies-To:"
240 "^Mail-Followup-To:"
241 "^Apparently-To:"
242 "^Resent-From:"
243 "^User-Agent:"
244 "^X-detected-operating-system:"
245 "^X-Spam_action:"
246 "^X-Spam_bar:"
247 "^Message-ID:"
248 ;; "^References:"
249 "^List-Id:"
250 "^Gnus-Warning:")
251 gnus-visible-headers (mapconcat #'identity
252 gnus-sorted-header-list
253 "\\|")
254 ;; local-lapsed article dates
255 ;; from https://www.emacswiki.org/emacs/GnusFormatting#toc11
256 gnus-article-date-headers '(user-defined)
257 gnus-article-time-format
258 (lambda (time)
259 (let* ((date (format-time-string "%a, %d %b %Y %T %z" time))
260 (local (article-make-date-line date 'local))
261 (combined-lapsed (article-make-date-line date
262 'combined-lapsed))
263 (lapsed (progn
264 (string-match " (.+" combined-lapsed)
265 (match-string 0 combined-lapsed))))
266 (concat local lapsed))))
267 ;; local key bindings
268 (declare-function org-store-link "ol" (arg &optional interactive?))
269 (define-key gnus-article-mode-map (kbd "M-L") #'org-store-link))
270
271 (with-eval-after-load 'gnus-sum
272 (setq gnus-thread-sort-functions '(gnus-thread-sort-by-number
273 gnus-thread-sort-by-subject
274 gnus-thread-sort-by-date))
275 ;; local key bindings
276 (define-key gnus-summary-mode-map (kbd "M-L") #'org-store-link)
277 ;; (define-key gnus-summary-mode-map (kbd "r")
278 ;; #'gnus-summary-reply-with-original)
279 ;; (define-key gnus-summary-mode-map (kbd "R")
280 ;; #'gnus-summary-wide-reply-with-original)
281 (defvar b/gnus-summary-prefix-map)
282 (define-prefix-command 'b/gnus-summary-prefix-map)
283 (define-key gnus-summary-mode-map (kbd "v")
284 'b/gnus-summary-prefix-map)
285 (define-key b/gnus-summary-prefix-map (kbd "r")
286 #'gnus-summary-reply)
287 (define-key b/gnus-summary-prefix-map (kbd "w")
288 #'gnus-summary-wide-reply)
289 (define-key b/gnus-summary-prefix-map (kbd "v")
290 #'gnus-summary-show-raw-article))
291 ;; hooks
292 (add-hook 'gnus-summary-mode-hook #'b/no-mouse-autoselect-window)
293
294 (defvar b/sfl-p nil)
295 (with-eval-after-load 'gnus-msg
296 (let ((bandali "Amin Bandali (https://kelar.org/~bandali)"))
297 (defvar b/canonical-signature
298 (mapconcat
299 #'identity
300 `(,bandali
301 "Software Engineer (Desktop), Canonical")
302 "\n"))
303 (defvar b/csc-signature
304 (mapconcat
305 #'identity
306 `(,bandali
307 "Systems Committee <syscom@csclub.uwaterloo.ca>"
308 "Computer Science Club of the University of Waterloo")
309 "\n"))
310 (defvar b/sfl-signature
311 (mapconcat
312 #'identity
313 `(,bandali
314 "Volunteer, Savoir-faire Linux"
315 "jami:bandali")
316 "\n")))
317 (setq
318 gnus-message-replysign t
319 gnus-posting-styles
320 '((".*"
321 (address "bandali@gnu.org")
322 ("X-Message-SMTP-Method" "smtp fencepost.gnu.org 587"))
323 ((header "subject" "ThankCRM")
324 (to "webmasters-comment@gnu.org")
325 (body ""))
326 ("nnimap\\+kelar:.*"
327 (address "bandali@kelar.org")
328 ("X-Message-SMTP-Method" "smtp mail.kelar.org 587")
329 (gcc "nnimap+kelar:Sent"))
330 ("nnimap\\+shemshak:.*"
331 (address "amin@shemshak.org")
332 ("X-Message-SMTP-Method" "smtp mail.shemshak.org 587")
333 (gcc "nnimap+shemshak:Sent"))
334 ("nnimap\\+canonical:.*"
335 (address "amin.bandali@canonical.com")
336 ("X-Message-SMTP-Method" "smtp smtp.canonical.com 587")
337 (signature b/canonical-signature)
338 (gcc "nnimap+canonical:Sent"))
339 ("nnimap\\+csc:.*"
340 (address "bandali@csclub.uwaterloo.ca")
341 ("X-Message-SMTP-Method" "smtp mail.csclub.uwaterloo.ca 587")
342 (signature b/csc-signature)
343 (gcc "nnimap+csc:Sent"))
344 ("nnimap\\+sfl:.*"
345 (address "amin.bandali@savoirfairelinux.com")
346 ("X-Message-SMTP-Method" "smtp mail.savoirfairelinux.com 587")
347 (signature b/sfl-signature)
348 (eval (setq-local b/sfl-p t))
349 (gcc "nnimap+sfl:Sent")))))
350 ;; hooks
351 ;; (with-eval-after-load 'gnus
352 ;; (add-hook 'gnus-message-setup-hook
353 ;; (lambda ()
354 ;; (unless (or (mml-secure-is-encrypted-p)
355 ;; b/sfl-p)
356 ;; (mml-secure-message-sign)))))
357
358 (with-eval-after-load 'gnus-topic
359 (setq
360 gnus-topic-line-format "%i[ %A: %(%{%n%}%) ]%v\n"
361 gnus-topic-topology
362 `(("Gnus" visible nil nil)
363 (("misc" visible nil nil))
364 ,@(if (string= (system-name) "darya")
365 '((("canonical" visible nil nil)))
366 '((("csc" visible nil nil))
367 (("uwaterloo" visible nil nil))
368 (("kelar" visible nil nil))
369 (("shemshak" visible nil nil))
370 (("gnu" visible nil nil))
371 (("old-gnu" visible nil nil))
372 (("sfl" visible nil nil)))))))
373
374 (with-eval-after-load 'gnus-agent
375 (setq gnus-agent-synchronize-flags 'ask))
376
377 (with-eval-after-load 'gnus-group
378 (setq gnus-permanently-visible-groups "\\(:INBOX$\\|:gnu$\\)"))
379
380 (with-eval-after-load 'gnus-win
381 (setq gnus-use-full-window nil))
382
383 (with-eval-after-load 'gnus-dired
384 (add-hook 'dired-mode-hook 'gnus-dired-mode))
385
386 (with-eval-after-load 'mm-decode
387 (setq
388 ;; mm-attachment-override-types `("text/x-diff" "text/x-patch"
389 ;; ,@mm-attachment-override-types)
390 mm-discouraged-alternatives '("text/html" "text/richtext")
391 mm-decrypt-option 'known
392 mm-verify-option 'known))
393
394 (with-eval-after-load 'mm-uu
395 (when (version< "27" emacs-version)
396 (set-face-attribute 'mm-uu-extract nil :extend t))
397 (when (version< emacs-version "27")
398 (setq mm-uu-diff-groups-regexp ".")))
399
400 (with-eval-after-load 'mml-sec
401 (setq mml-secure-openpgp-encrypt-to-self t
402 mml-secure-openpgp-sign-with-sender t))
403
404 (provide 'bandali-gnus)
405 ;;; bandali-gnus.el ends here