;;; bandali-gnus.el --- bandali's Gnus setup         -*- lexical-binding: t; -*-

;; Copyright (C) 2018-2022  Amin Bandali

;; Author: Amin Bandali <bandali@gnu.org>
;; Keywords: mail, news

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; My trusty super awesome Gnus setup.

;;; Code:

(defvar b/maildir (expand-file-name "~/mail/"))
(with-eval-after-load 'recentf
  (add-to-list 'recentf-exclude b/maildir))

(defvar b/gnus-init-file (b/etc "gnus"))

(eval-when-compile
  (progn
    (defvar nndraft-directory)
    (defvar gnus-read-newsrc-file)
    (defvar gnus-save-newsrc-file)
    (defvar gnus-gcc-mark-as-read)
    (defvar nnmail-split-abbrev-alist)))

(declare-function article-make-date-line "gnus-art" (date type))

(setq
 mail-user-agent 'gnus-user-agent
 read-mail-command 'gnus

 gnus-select-method '(nnnil "")
 gnus-secondary-select-methods
 `(,@(if (member (system-name) '("darya" "nostalgia"))
         '((nnimap
            "canonical"
            (nnimap-stream plain)
            (nnimap-address "127.0.0.1")
            (nnimap-server-port 143)
            (nnimap-authenticator plain)
            (nnimap-user "bandali@canonical.local")))
       '((nnimap
          "kelar"
          (nnimap-stream plain)
          (nnimap-address "127.0.0.1")
          (nnimap-server-port 143)
          (nnimap-authenticator plain)
          (nnimap-user "bandali@kelar.local"))
         (nnimap
          "shemshak"
          (nnimap-stream plain)
          (nnimap-address "127.0.0.1")
          (nnimap-server-port 143)
          (nnimap-authenticator plain)
          (nnimap-user "bandali@shemshak.local"))
         (nnimap
          "gnu"
          (nnimap-stream plain)
          (nnimap-address "127.0.0.1")
          (nnimap-server-port 143)
          (nnimap-authenticator plain)
          (nnimap-user "bandali@gnu.local")
          (nnimap-inbox "INBOX")
          (nnimap-split-methods 'nnimap-split-fancy)
          (nnimap-split-fancy
           (|
            ;; (: gnus-registry-split-fancy-with-parent)
            ;; (: gnus-group-split-fancy "INBOX" t "INBOX")
            ;; spam
            ("X-Spam_action" "reject" "Junk")
            ;; keep debbugs emails in INBOX
            (list ".*<\\(.*\\)\\.debbugs\\.gnu\\.org>.*" "INBOX")
            ;; list moderation emails
            (from ".+-\\(owner\\|bounces\\)@\\(non\\)?gnu\\.org" "listmod")
            ;; gnu
            (list ".*<\\(.*\\)\\.\\(non\\)?gnu\\.org>.*" "l.\\1")
            ("Envelope-To" "emacsconf-donations@gnu.org" "l.emacsconf-donations")
            ;; board-eval
            (|
             (list ".*<.*\\.board-eval\\.fsf\\.org>.*" "l.board-eval")
             (from ".*@board-eval\\.fsf\\.org" "l.board-eval"))
            ;; fsf
            (list ".*<\\(.*\\)\\.fsf\\.org>.*" "l.\\1")
            ;; cfarm
            (from "cfarm-.*@lists\\.tetaneutral\\.net" "l.cfarm")
            ;; debian
            (list ".*<\\(.*\\)\\.\\(lists\\|other\\)\\.debian\\.org>.*" "l.\\1")
            (list ".*<\\(.*\\)\\.alioth-lists\\.debian\\.net>.*" "l.\\1")
            ;; gnus
            (list ".*<\\(.*\\)\\.gnus\\.org>.*" "l.\\1")
            ;; libreplanet
            (list ".*<\\(.*\\)\\.libreplanet\\.org>.*" "l.\\1")
            ;; iana (e.g. tz-announce)
            (list ".*<\\(.*\\)\\.iana\\.org>.*" "l.\\1")
            ;; mailop
            (list ".*<\\(.*\\)\\.mailop\\.org>.*" "l.\\1")
            ;; sdlu
            (list ".*<\\(.*\\)\\.spammers\\.dontlike\\.us>.*" "l.sdlu")
            ;; bitfolk
            (from ".*@\\(.+\\)?bitfolk\\.com>.*" "bitfolk")
            ;; haskell
            (list ".*<\\(.*\\)\\.haskell\\.org>.*" "l.\\1")
            ;; webmasters
            (from "webmasters\\(-comment\\)?@gnu\\.org" "webmasters")
            ;; other
            (list ".*atreus.freelists.org" "l.atreus")
            (list ".*deepspec.lists.cs.princeton.edu" "l.deepspec")
            ;; (list ".*haskell-art.we.lurk.org" "l.haskell.art") ;d
            ;; (list ".*notmuch.notmuchmail.org" "l.notmuch") ;u
            (list ".*dev.lists.parabola.nu" "l.parabola-dev")
            ;; ----------------------------------
            ;; legend: (u)nsubscribed | (d)ead
            ;; ----------------------------------
            ;; otherwise, leave mail in INBOX
            "INBOX")))
         (nnimap
          "csc"
          (nnimap-stream plain)
          (nnimap-address "127.0.0.1")
          (nnimap-server-port 143)
          (nnimap-authenticator plain)
          (nnimap-user "abandali@csclub.uwaterloo.local")
          (nnimap-inbox "INBOX")
          (nnimap-split-methods 'nnimap-split-fancy)
          (nnimap-split-fancy
           (|
            ;; cron reports and other messages from root
            (from "root@\\(.*\\.\\)?csclub\\.uwaterloo\\.ca" "INBOX")
            ;; spam
            ("X-Spam-Flag" "YES" "Junk")
            ;; catch-all
            "INBOX")))
         (nnimap
          "sfl"
          (nnimap-stream plain)
          (nnimap-address "127.0.0.1")
          (nnimap-server-port 143)
          (nnimap-authenticator plain)
          (nnimap-user "amin.bandali@savoirfairelinux.local")))))
 gnus-message-archive-group "nnimap+gnu:INBOX"
 gnus-parameters
 '(("l\\.deepspec"
    (to-address . "deepspec@lists.cs.princeton.edu")
    (to-list    . "deepspec@lists.cs.princeton.edu")
    (list-identifier . "\\[deepspec\\]"))
   ("l\\.fencepost-users"
    (to-address . "fencepost-users@gnu.org")
    (to-list    . "fencepost-users@gnu.org")
    (list-identifier . "\\[Fencepost-users\\]"))
   ("l\\.haskell-cafe"
    (to-address . "haskell-cafe@haskell.org")
    (to-list    . "haskell-cafe@haskell.org")
    (list-identifier . "\\[Haskell-cafe\\]"))
   ("gnu.*"
    (gcc-self . t)))
 ;; nnimap-record-commands t
 ;; gnus-large-newsgroup  50
 ;; gnus-process-mark-toggle t
 gnus-home-directory   (b/var "gnus/")
 gnus-directory        (concat gnus-home-directory "news/")
 message-directory     (concat gnus-home-directory "mail/")
 nndraft-directory     (concat gnus-home-directory "drafts/")
 gnus-save-newsrc-file nil
 gnus-read-newsrc-file nil
 gnus-search-use-parsed-queries t
 gnus-interactive-exit nil
 gnus-gcc-mark-as-read t)

(with-eval-after-load 'gnus
  (when (version< emacs-version "27")
    (with-eval-after-load 'nnmail
      (add-to-list
       'nnmail-split-abbrev-alist
       '(list . "list-id\\|list-post\\|x-mailing-list\\|x-beenthere\\|x-loop")
       t)))

  (setq gnus-user-agent '(emacs gnus type))

  ;; (require 'gnus-registry)
  ;; (setq gnus-registry-max-entries 2500)
  ;; (setq gnus-registry-ignored-groups
  ;;       (append gnus-registry-ignored-groups
  ;;               '(("^nnimap:gnu\\.l" t)
  ;;                 ("webmasters$" t))))
  ;; (gnus-registry-initialize)

  (with-eval-after-load 'recentf
    (add-to-list 'recentf-exclude gnus-home-directory))

  ;; hooks
  (add-hook 'gnus-group-mode-hook #'gnus-topic-mode)
  (add-hook 'gnus-group-mode-hook #'gnus-agent-mode))
;; global key bindings
(global-set-key (kbd "C-c g") #'gnus-plugged)
(global-set-key (kbd "C-c G") #'gnus-unplugged)

(with-eval-after-load 'gnus-art
  (setq
   gnus-buttonized-mime-types '("multipart/\\(signed\\|encrypted\\)")
   gnus-sorted-header-list '("^From:"
                             "^X-RT-Originator"
                             "^Newsgroups:"
                             "^Subject:"
                             "^Date:"
                             "^Envelope-To:"
                             "^Followup-To:"
                             "^Reply-To:"
                             "^Organization:"
                             "^Summary:"
                             "^Abstract:"
                             "^Keywords:"
                             "^To:"
                             "^[BGF]?Cc:"
                             "^Posted-To:"
                             "^Mail-Copies-To:"
                             "^Mail-Followup-To:"
                             "^Apparently-To:"
                             "^Resent-From:"
                             "^User-Agent:"
                             "^X-detected-operating-system:"
                             "^X-Spam_action:"
                             "^X-Spam_bar:"
                             "^Message-ID:"
                             ;; "^References:"
                             "^List-Id:"
                             "^Gnus-Warning:")
   gnus-visible-headers (mapconcat #'identity
                                   gnus-sorted-header-list
                                   "\\|"))
  ;; local key bindings
  (declare-function org-store-link "ol" (arg &optional interactive?))
  (define-key gnus-article-mode-map (kbd "M-L") #'org-store-link))

(with-eval-after-load 'gnus-sum
  (setq gnus-thread-sort-functions '(gnus-thread-sort-by-number
                                     gnus-thread-sort-by-subject
                                     gnus-thread-sort-by-date))
  (with-eval-after-load 'message
    (setq gnus-ignored-from-addresses message-dont-reply-to-names))
  ;; local key bindings
  (define-key gnus-summary-mode-map (kbd "M-L") #'org-store-link)
  ;; (define-key gnus-summary-mode-map (kbd "r")
  ;;   #'gnus-summary-reply-with-original)
  ;; (define-key gnus-summary-mode-map (kbd "R")
  ;;   #'gnus-summary-wide-reply-with-original)
  (defvar b/gnus-summary-prefix-map)
  (define-prefix-command 'b/gnus-summary-prefix-map)
  (define-key gnus-summary-mode-map (kbd "v")
    'b/gnus-summary-prefix-map)
  (define-key b/gnus-summary-prefix-map (kbd "r")
    #'gnus-summary-reply)
  (define-key b/gnus-summary-prefix-map (kbd "w")
    #'gnus-summary-wide-reply)
  (define-key b/gnus-summary-prefix-map (kbd "v")
    #'gnus-summary-show-raw-article))
;; hooks
(add-hook 'gnus-summary-mode-hook #'b/no-mouse-autoselect-window)

(defvar b/sfl-p nil)
(with-eval-after-load 'gnus-msg
  (let ((bandali "Amin Bandali%s - https://www.gnu.ca/~bandali/"))
    (defvar b/csc-signature
      (mapconcat
       #'identity
       `(,(format bandali ", MMath")
         "Systems Committee <syscom@csclub.uwaterloo.ca>"
         "Computer Science Club of the University of Waterloo")
       "\n"))
    (defvar b/sfl-signature
      (mapconcat
       #'identity
       `(,bandali
         "Volunteer, Savoir-faire Linux"
         "jami:bandali")
       "\n")
      ""))                              ; the "" is for bandali's %s
  (setq
   gnus-message-replysign t
   gnus-posting-styles
   '((".*"
      (address "bandali@gnu.org")
      ("X-Message-SMTP-Method" "smtp fencepost.gnu.org 587"))
     ((header "subject" "ThankCRM")
      (to "webmasters-comment@gnu.org")
      (body ""))
     ("nnimap\\+kelar:.*"
      (address "bandali@kelar.org")
      ("X-Message-SMTP-Method" "smtp mail.kelar.org 587")
      (gcc "nnimap+kelar:Sent"))
     ("nnimap\\+shemshak:.*"
      (address "amin@shemshak.org")
      ("X-Message-SMTP-Method" "smtp mail.shemshak.org 587")
      (gcc "nnimap+shemshak:Sent"))
     ("nnimap\\+canonical:.*"
      (address "bandali@canonical.com")
      ("X-Message-SMTP-Method" "smtp smtp.canonical.com 587")
      (signature nil)
      (gcc "nnimap+canonical:Sent"))
     ((header "to" "amin\\.bandali@canonical\\.com")
      (address "amin.bandali@canonical.com"))
     ((header "cc" "amin\\.bandali@canonical\\.com")
      (address "amin.bandali@canonical.com"))
     ("nnimap\\+.*:l\\.ubuntu-.*"
      (address "bandali@ubuntu.com")
      ("X-Message-SMTP-Method" "smtp mail.kelar.org 587"))
     ((header "list-id" ".*\\.lists.ubuntu.com")
      (address "bandali@ubuntu.com")
      ("X-Message-SMTP-Method" "smtp mail.kelar.org 587"))
     ("nnimap\\+csc:.*"
      (address "bandali@csclub.uwaterloo.ca")
      ("X-Message-SMTP-Method" "smtp mail.csclub.uwaterloo.ca 587")
      (signature b/csc-signature)
      (gcc "nnimap+csc:Sent"))
     ("nnimap\\+sfl:.*"
      (address "amin.bandali@savoirfairelinux.com")
      ("X-Message-SMTP-Method" "smtp mail.savoirfairelinux.com 587")
      (signature b/sfl-signature)
      (eval (setq-local b/sfl-p t))
      (gcc "nnimap+sfl:Sent")))))
;; hooks
;; (with-eval-after-load 'gnus
;;   (add-hook 'gnus-message-setup-hook
;;             (lambda ()
;;               (unless (or (mml-secure-is-encrypted-p)
;;                           b/sfl-p)
;;                 (mml-secure-message-sign)))))

(with-eval-after-load 'gnus-topic
  (setq
   gnus-topic-line-format "%i[ %A: %(%{%n%}%) ]%v\n"
   gnus-topic-topology
   `(("Gnus" visible nil nil)
     (("misc" visible nil nil))
     ,@(if (member (system-name) '("darya" "nostalgia"))
           '((("canonical" visible nil nil)))
         '((("csc" visible nil nil))
           (("kelar" visible nil nil))
           (("shemshak" visible nil nil))
           (("gnu" visible nil nil))
           ;(("old-gnu" visible nil nil))
           (("sfl" visible nil nil)))))))

(with-eval-after-load 'gnus-agent
  (setq gnus-agent-synchronize-flags 'ask))

(with-eval-after-load 'gnus-group
  (setq gnus-permanently-visible-groups "\\(:INBOX$\\|:gnu$\\)"))

(with-eval-after-load 'gnus-win
  (setq gnus-use-full-window nil))

(with-eval-after-load 'gnus-dired
  (add-hook 'dired-mode-hook 'gnus-dired-mode))

(with-eval-after-load 'mm-archive
  (add-to-list
   'mm-archive-decoders
   '("application/gzip" nil "gunzip" "-S" ".zip" "-kd" "%f" "-r")))

(with-eval-after-load 'gnus-start
  (add-hook 'gnus-after-getting-new-news-hook #'gnus-notifications))

(with-eval-after-load 'mm-decode
  (setq
   ;; mm-attachment-override-types `("text/x-diff" "text/x-patch"
   ;;                                ,@mm-attachment-override-types)
   mm-discouraged-alternatives '("text/html" "text/richtext")
   mm-decrypt-option 'known
   mm-verify-option 'known)
  (add-to-list
   'mm-inline-media-tests
   `("application/gzip" mm-archive-dissect-and-inline identity))
  (add-to-list 'mm-inlined-types "application/gzip" 'append))

(with-eval-after-load 'mm-uu
  (when (version< "27" emacs-version)
    (set-face-attribute 'mm-uu-extract nil :extend t))
  (when (version< emacs-version "27")
    (setq mm-uu-diff-groups-regexp ".")))

(with-eval-after-load 'mml
  (setq
   mml-attach-file-at-the-end t
   mml-content-disposition-alist
   '((text
      (markdown . "attachment")
      (rtf . "attachment")
      (t . "inline"))
     (t. "attachment"))))

(with-eval-after-load 'mml-sec
  (setq mml-secure-openpgp-encrypt-to-self t
        mml-secure-openpgp-sign-with-sender t))

(provide 'bandali-gnus)
;;; bandali-gnus.el ends here