From de20fc8d904643ffe6957febfc6a24e57c12b512 Mon Sep 17 00:00:00 2001 From: Timo Wilken Date: Sat, 9 Mar 2024 14:52:56 +0100 Subject: Separate home service into PIM, dev env and graphical parts This means we only instantiate Shepherd and mcron services if we really need them, to avoid annoyance on servers. --- tw/services/files/aerc/accounts.conf | 97 ++++++++++++++ tw/services/files/aerc/accounts.work.conf | 26 ++++ tw/services/files/aerc/aerc.conf | 157 ++++++++++++++++++++++ tw/services/files/aerc/binds.conf | 194 +++++++++++++++++++++++++++ tw/services/files/aerc/filters/colorize.ansi | 134 ++++++++++++++++++ 5 files changed, 608 insertions(+) create mode 100644 tw/services/files/aerc/accounts.conf create mode 100644 tw/services/files/aerc/accounts.work.conf create mode 100644 tw/services/files/aerc/aerc.conf create mode 100644 tw/services/files/aerc/binds.conf create mode 100755 tw/services/files/aerc/filters/colorize.ansi (limited to 'tw/services/files/aerc') diff --git a/tw/services/files/aerc/accounts.conf b/tw/services/files/aerc/accounts.conf new file mode 100644 index 00000000..5325ee03 --- /dev/null +++ b/tw/services/files/aerc/accounts.conf @@ -0,0 +1,97 @@ +# Note: when adding/removing/editing an account name here, edit +# [messages:account=] and [messages:folder=] sections in binds.conf to match! + +[Mythic] +source = imaps://timo%40twilken.net@oncilla.mythic-beasts.com +outgoing = smtps+plain://timo%40twilken.net@smtp-auth.mythic-beasts.com +source-cred-cmd = pass www/mythic-beasts/email/timo | head -1 +outgoing-cred-cmd = pass www/mythic-beasts/email/timo | head -1 +default = INBOX +from = Timo Wilken +archive = Archive +copy-to = Sent +postpone = Drafts +folders-sort = INBOX,Archive,Sent,Drafts +cache-headers = true +pgp-auto-sign = true +pgp-key-id = 53EC3C06856883DD92355BC22FC78504681F69B0 +pgp-opportunistic-encrypt = true + +[CERN] +# https://man.sr.ht/~rjarry/aerc/providers/microsoft.md#office365-with-xoauth2 +source = imaps+xoauth2://timo.wilken%40cern.ch@outlook.office365.com?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/token&scope=https://outlook.office.com/SMTP.Send https://outlook.office.com/IMAP.AccessAsUser.All offline_access +outgoing = smtp+xoauth2://timo.wilken%40cern.ch@smtp.office365.com:587?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/token&scope=https://outlook.office.com/SMTP.Send https://outlook.office.com/IMAP.AccessAsUser.All offline_access +# To authorize for the first time (to get refresh token): +# mutt_oauth2.py ~/.local/share/aerc/cern.tokens --authorize --authflow authcode --provider microsoft \ +# --email timo.wilken@cern.ch --client-id 9e5f94bc-e8a4-4e73-b8be-63364c29d753 --client-secret '' \ +# --encryption-pipe 'gpg --encrypt --recipient timo@twilken.net' +# Confirm empty client secret. When done, copy-paste ?code= value from final URL to the command-line. +# Then, to store the refresh token: +# gpg --decrypt ~/.local/share/aerc/cern.tokens | jq -r .refresh_token | pass insert -e -f cern/exol/refresh-token +source-cred-cmd = pass cern/exol/refresh-token +outgoing-cred-cmd = pass cern/exol/refresh-token +default = INBOX +from = Timo Wilken +aliases = twilken@cern.ch +archive = Archive +copy-to = Sent Items +postpone = Drafts +folders-sort = INBOX,Archive,Sent Items,Drafts +folders-exclude = Calendar,~Calendar/.*,Contacts,Conversation History,Journal,Notes,Tasks +cache-headers = true +pgp-auto-sign = true +pgp-key-id = C2249BBE5E8761C943A0CFA1B7B3914BF63ACD7C +# Don't auto-encrypt mail, even if we have the keys of all recipients. +pgp-opportunistic-encrypt = false + +[Gmail] +source = imaps://timo.21.wilken%40gmail.com@imap.gmail.com +outgoing = smtps+login://timo.21.wilken%40gmail.com@smtp.gmail.com +source-cred-cmd = pass www/google/app-passwords/mutt | head -1 +outgoing-cred-cmd = pass www/google/app-passwords/mutt | head -1 +default = INBOX +from = Timo Wilken +archive = [Gmail]/All Mail +copy-to = [Gmail]/Sent Mail +postpone = [Gmail]/Drafts +folders-sort = INBOX,[Gmail]/All Mail,[Gmail]/Sent Mail,[Gmail]/Drafts +folders-exclude = [Gmail],[Gmail]/Chats,[Gmail]/Important +cache-headers = true +trusted-authres = mx.google.com +pgp-auto-sign = true +pgp-key-id = 53EC3C06856883DD92355BC22FC78504681F69B0 +pgp-opportunistic-encrypt = true + +[Cantab] +source = imaps+xoauth2://tw466%40cantab.ac.uk@outlook.office365.com?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/token&scope=https://outlook.office.com/SMTP.Send https://outlook.office.com/IMAP.AccessAsUser.All offline_access +outgoing = smtp+xoauth2://tw466%40cantab.ac.uk@smtp-mail.outlook.com:587?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/token&scope=https://outlook.office.com/SMTP.Send https://outlook.office.com/IMAP.AccessAsUser.All offline_access +source-cred-cmd = pass cambridge/exol-refresh-token +outgoing-cred-cmd = pass cambridge/exol-refresh-token +default = INBOX +from = Timo Wilken +archive = Archive +copy-to = Sent Items +postpone = Drafts +folders-sort = INBOX,Archive,Sent Items,Drafts +folders-exclude = Calendar,~Calendar/.*,Contacts,Conversation History,Journal,Notes,Tasks +cache-headers = true +pgp-auto-sign = true +pgp-key-id = 53EC3C06856883DD92355BC22FC78504681F69B0 +pgp-opportunistic-encrypt = true + +[Outlook] +source = imaps+xoauth2://timo_wilken%40live.co.uk@outlook.office365.com?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/token&scope=https://outlook.office.com/SMTP.Send https://outlook.office.com/IMAP.AccessAsUser.All offline_access +outgoing = smtp+xoauth2://timo_wilken%40live.co.uk@smtp-mail.outlook.com:587?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/token&scope=https://outlook.office.com/SMTP.Send https://outlook.office.com/IMAP.AccessAsUser.All offline_access +source-cred-cmd = pass www/microsoft/exol-refresh-token +outgoing-cred-cmd = pass www/microsoft/exol-refresh-token +default = INBOX +from = Timo Wilken +archive = Archive +copy-to = Sent +postpone = Drafts +folders-sort = INBOX,Archive,Sent,Drafts +folders-exclude = Notes +cache-headers = true +pgp-auto-sign = true +pgp-key-id = 53EC3C06856883DD92355BC22FC78504681F69B0 +pgp-opportunistic-encrypt = true diff --git a/tw/services/files/aerc/accounts.work.conf b/tw/services/files/aerc/accounts.work.conf new file mode 100644 index 00000000..5d2fa7c7 --- /dev/null +++ b/tw/services/files/aerc/accounts.work.conf @@ -0,0 +1,26 @@ +[CERN] +# https://man.sr.ht/~rjarry/aerc/providers/microsoft.md#office365-with-xoauth2 +source = imaps+xoauth2://timo.wilken%40cern.ch@outlook.office365.com?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/token&scope=https://outlook.office.com/SMTP.Send https://outlook.office.com/IMAP.AccessAsUser.All offline_access +outgoing = smtp+xoauth2://timo.wilken%40cern.ch@smtp.office365.com:587?client_id=9e5f94bc-e8a4-4e73-b8be-63364c29d753&token_endpoint=https://login.microsoftonline.com/common/oauth2/v2.0/token&scope=https://outlook.office.com/SMTP.Send https://outlook.office.com/IMAP.AccessAsUser.All offline_access +# To authorize for the first time (to get refresh token): +# mutt_oauth2.py ~/.local/share/aerc/twilken.tokens --authorize --authflow authcode --provider microsoft \ +# --email timo.wilken@cern.ch --client-id 9e5f94bc-e8a4-4e73-b8be-63364c29d753 --client-secret '' \ +# --encryption-pipe 'gpg --encrypt --recipient C2249BBE5E8761C943A0CFA1B7B3914BF63ACD7C' +# Confirm empty client secret. When done, copy-paste ?code= value from final URL to the command-line. +# Then, to store the refresh token: +# gpg --decrypt ~/.local/share/aerc/twilken.tokens | jq -r .refresh_token | pass insert -e -f cern/exol/refresh-token +source-cred-cmd = pass cern/exol/refresh-token +outgoing-cred-cmd = pass cern/exol/refresh-token +default = INBOX +from = Timo Wilken +aliases = twilken@cern.ch +archive = Archive +copy-to = Sent Items +postpone = Drafts +folders-sort = INBOX,Archive,Sent Items,Drafts +folders-exclude = Calendar,~Calendar/.*,Contacts,Conversation History,Journal,Notes,Tasks +cache-headers = true +pgp-auto-sign = true +pgp-key-id = C2249BBE5E8761C943A0CFA1B7B3914BF63ACD7C +# Don't auto-encrypt mail, even if we have the keys of all recipients. +pgp-opportunistic-encrypt = false diff --git a/tw/services/files/aerc/aerc.conf b/tw/services/files/aerc/aerc.conf new file mode 100644 index 00000000..7473bc8b --- /dev/null +++ b/tw/services/files/aerc/aerc.conf @@ -0,0 +1,157 @@ +# aerc main configuration + +[general] +#default-save-path= +# Allow world-readable accounts.conf. This is fine as I don't store any +# passwords there, only "pass" commands. +unsafe-accounts-conf=true + +[ui] +# Describes the format for each row in a mailbox view. This field is compatible +# with mutt's printf-like syntax. +index-columns=num>4,flags>4,date<21,peers<17,subject<* +column-num={{.Number}} +column-flags={{.Flags | join ""}} +column-date={{.DateAutoFormat .Date.Local}} +column-peers={{.Peer | names | join ", "}} +column-subject={{.ThreadPrefix}}{{.Subject}} + +# See time.Time#Format at https://godoc.org/time#Time.Format +timestamp-format=Mon _2 Jan 2006 15:04 + +# List of space-separated criteria to sort the messages by, see *sort* +# command in *aerc*(1) for reference. Prefixing a criterion with "-r " +# reverses that criterion. +sort=-r date + +threading-enabled=true + +next-message-on-delete=false + +sidebar-width=24 + +styleset-name=catppuccin +pinned-tab-marker='πŸ“Œ' +# Use box-drawing characters for vertical and horizontal borders. +border-char-vertical=β”‚ +border-char-horizontal=─ +# Use UTF-8 symbols to indicate PGP status of messages +icon-unencrypted= +icon-encrypted=πŸ”’ +icon-signed=βœ” +icon-signed-encrypted=βœ”πŸ”’ +icon-unknown=✘ +icon-invalid=⚠ + +# Activates fuzzy search in commands and their arguments: the typed string is +# searched in the command or option in any position, and need not be +# consecutive characters in the command or option. +#fuzzy-complete=false + +[statusline] +status-columns=left<*,centre>=,right>* +column-left=[{{.Account}}] {{.StatusInfo}} +column-centre={{.PendingKeys}} +column-right={{.ContentInfo}} {{.TrayInfo}} + +# Defines the mode for displaying the status elements. +# Options: text, icon +display-mode=icon + +[viewer] +# Specifies the pager to use when displaying emails. Note that some filters +# may add ANSI codes to add color to rendered emails, so you may want to use a +# pager which supports ANSI codes. +pager='env LESSKEYIN=/dev/null less -iRM' + +# If an email offers several versions (multipart), you can configure which +# mimetype to prefer. For example, this can be used to prefer plaintext over +# html emails. +alternatives=text/plain,text/html + +# Layout of headers when viewing a message. To display multiple headers in the +# same row, separate them with a pipe, e.g. "From|To". Rows will be hidden if +# none of their specified headers are present in the message. +#header-layout=From|To,Cc|Bcc,Date,Subject + +[compose] +# Default header fields to display when composing a message. To display +# multiple headers in the same row, separate them with a pipe, e.g. "To|From". +#header-layout=To|From,Subject + +# Specifies the command to be used to tab-complete email addresses. Any +# occurrence of "%s" in the address-book-cmd will be replaced with what the +# user has typed so far. +# +# The command must output the completions to standard output, one completion +# per line. Each line must be tab-delimited, with an email address occurring as +# the first field. Only the email address field is required. The second field, +# if present, will be treated as the contact name. Additional fields are +# ignored. +# +# This parameter can also be set per account in accounts.conf. +address-book-cmd=khard email --parsable %s + +# Allow to address yourself when replying +reply-to-self=false + +# Warn before sending an email that matches the specified regexp but does not +# have any attachments. Leave empty to disable this feature. +# Uses Go's regexp syntax, documented at https://golang.org/s/re2syntax. The +# "(?im)" flags are set by default (case-insensitive and multi-line). +no-attachment-warning=^[^>]*(attach|Anhang|angehΓ€ngt) + +[filters] +# Filters allow you to pipe an email body through a shell command to render +# certain emails differently, e.g. highlighting them with ANSI escape codes. +# +# The commands are invoked with sh -c. The following folders are appended to +# the system $PATH to allow referencing filters from their name only: +# +# ${XDG_CONFIG_HOME:-~/.config}/aerc/filters +# ${XDG_DATA_HOME:-~/.local/share}/aerc/filters +# $PREFIX/share/aerc/filters +# /usr/share/aerc/filters +# +# The following variables are defined in the filter command environment: +# +# AERC_MIME_TYPE the part MIME type/subtype +# AERC_FILENAME the attachment filename (if any) +# +# The first filter which matches the email's mimetype will be used, so order +# them from most to least specific. +# +# You can also match on non-mimetypes, by prefixing with the header to match +# against (non-case-sensitive) and a comma, e.g. subject,text will match a +# subject which contains "text". Use header,~regex to match against a regex. +text/plain=colorize.ansi +text/calendar=calendar +message/delivery-status=colorize.ansi +message/rfc822=colorize.ansi +#text/html=pandoc -f html -t plain | colorize +#text/html=html | colorize +text/html=lynx -display_charset=UTF-8 -force_html -dump -stdin +#text/*=bat -fP --file-name="$AERC_FILENAME" +#application/x-sh=bat -fP -l sh +#image/*=catimg -w $(tput cols) - +#subject,~Git(hub|lab)=lolcat -f +#from,thatguywhodoesnothardwraphismessages=fmt -w 72 | colorize + +[openers] +# Openers allow you to specify the command to use for the :open action on a +# per-MIME-type basis. +# +# {} is expanded as the temporary filename to be opened. If it is not +# encountered in the command, the temporary filename will be appened to the end +# of the command. +# +# Examples: +# text/html=surf -dfgms +# text/plain=gvim {} +125 +# message/rfc822=thunderbird +application/pdf=zathura +image/*=imv + +[hooks] +# Executed when a new email arrives in the selected folder +new-email=dunstify -a aerc -i mail-unread "New mail from $AERC_FROM_NAME" "$AERC_SUBJECT" diff --git a/tw/services/files/aerc/binds.conf b/tw/services/files/aerc/binds.conf new file mode 100644 index 00000000..0e88b571 --- /dev/null +++ b/tw/services/files/aerc/binds.conf @@ -0,0 +1,194 @@ +# Binds are of the form = +# To use '=' in a key sequence, substitute it with "Eq": "" +# If you wish to bind #, you can wrap the key sequence in quotes: "#" = quit + = :prev-tab + = :next-tab + = :term +? = :help keys + +[messages] +q = :quit + +j = :next + = :next + = :next 50% + = :next 100% + = :next 100% + +k = :prev + = :prev + = :prev 50% + = :prev 100% + = :prev 100% +g = :select 0 +G = :select -1 +"#" = :select + +J = :next-folder +K = :prev-folder +H = :collapse-folder +L = :expand-folder + +"*" = :mark -a +v = :mark -t +V = :mark -T +F = :flag -tx Flagged + = :read -t + = :remark + +T = :toggle-threads + + = :view +A = :archive flat +p = :split 25 +e = :envelope + +m = :compose +M = :mkdir + +f = :forward -F +a = :reply -aq +r = :reply -q + +C = :copy +S = :save +s = :move +E = :export-mbox +I = :import-mbox + +c = :cf +$ = :check-mail +! = :term +| = :pipe + +/ = :search +l = :filter +n = :next-result +N = :prev-result + = :clear:unmark -a + +[messages:folder=Drafts] + = :recall + +[view:account=Mythic] +D = :move Rubbish +[messages:account=Mythic] +d = :move Rubbish +D = :move Rubbish +# We can't use both :account= and :folder= at the same time, unfortunately. +[messages:folder=Rubbish] +d = :delete +D = :delete + +[view:account=Wilken] +D = :move Rubbish +[messages:account=Wilken] +d = :move Rubbish +D = :move Rubbish +[messages:folder=Rubbish] +d = :delete +D = :delete + +[view:account=CERN] +D = :move Deleted Items +[messages:account=CERN] +d = :move Deleted Items +D = :move Deleted Items +[messages:folder=Deleted Items] +d = :delete +D = :delete + +[view:account=Gmail] +D = :move [Gmail]/Bin +[messages:account=Gmail] +d = :move [Gmail]/Bin +D = :move [Gmail]/Bin +[messages:folder=[Gmail]/Bin] +d = :delete +D = :delete +[messages:folder=[Gmail]/Drafts] + = :recall + +[view:account=Cantab] +D = :move Deleted Items +[messages:account=Cantab] +d = :move Deleted Items +D = :move Deleted Items +[messages:folder=Deleted Items] +d = :delete +D = :delete + +[view:account=Outlook] +D = :move Deleted +[messages:account=Outlook] +d = :move Deleted +D = :move Deleted +[messages:folder=Deleted] +d = :delete +D = :delete + +[view] +/ = :toggle-key-passthrough/ +q = :close +O = :open +S = :save +| = :pipe +A = :archive flat + + = :open-link + = :toggle-key-passthrough + +f = :forward -F +a = :reply -aq +r = :reply -q + +H = :toggle-headers + = :prev-part + = :next-part +J = :next +K = :prev + +[view::passthrough] +$noinherit = true +$ex = + = :toggle-key-passthrough + +[compose] +# Keybindings used when the embedded terminal is not selected in the compose view. +$noinherit = true +$ex = + = :prev-field + = :next-field + = :switch-account -p + = :switch-account -n + = :next-field + = :prev-tab + = :next-tab + +[compose::editor] +# Keybindings used when the embedded terminal is selected in the compose view. +$noinherit = true +$ex = + = :prev-field + = :next-field + = :prev-tab + = :next-tab + +[compose::review] +# Keybindings used when reviewing a message to be sent +y = :send +n = :abort +p = :postpone +q = :choose -o d discard abort -o p postpone postpone +e = :edit +a = :attach +d = :detach +v = :preview +s = :sign +c = :encrypt + +[terminal] +$noinherit = true +$ex = + = :prev-tab + = :next-tab diff --git a/tw/services/files/aerc/filters/colorize.ansi b/tw/services/files/aerc/filters/colorize.ansi new file mode 100755 index 00000000..c21fd804 --- /dev/null +++ b/tw/services/files/aerc/filters/colorize.ansi @@ -0,0 +1,134 @@ +#!/usr/bin/env -S awk -f +# Copyright (c) 2022 Robin Jarry +# Adapted for standard ANSI colors (for catppuccin theme) by Timo Wilken. + +BEGIN { + url = "\033[32m" # green + header = "\033[35m" # pink + signature = "\033[38m" # Surface 2 + diff_meta = "\033[1;37m" # bold white + diff_chunk = "\033[36m" # teal + diff_add = "\033[32m" # green + diff_del = "\033[31m" # red + quote_1 = "\033[38;5;15m" # Subtext 0 + quote_2 = "\033[37m" # Subtext 1 + quote_3 = "\033[38m" # Surface 2 + quote_4 = "\033[30m" # Surface 1 + quote_x = "\033[30m" # Surface 1 + bold = "\033[1m" + reset = "\033[0m" + # state + in_diff = 0 + in_signature = 0 + in_headers = 0 + in_body = 0 + # patterns + header_pattern = @/^[A-Z][[:alnum:]-]+:/ + url_pattern = @/[a-z]{2,6}:\/\/[[:graph:]]+|(mailto:)?[[:alnum:]_\+\.~\/-]*[[:alnum:]_]@[[:lower:]][[:alnum:]\.-]*[[:lower:]]/ + meta_pattern = @/^(diff --git|(new|deleted) file|similarity index|(rename|copy) (to|from)|index|---|\+\+\+) / +} +function color_quote(line) { + level = 0 + quotes = "" + while (line ~ /^>/) { + level += 1 + quotes = quotes ">" + line = substr(line, 2) + while (line ~ /^ /) { + quotes = quotes " " + line = substr(line, 2) + } + } + if (level == 1) { + color = quote_1 + } else if (level == 2) { + color = quote_2 + } else if (level == 3) { + color = quote_3 + } else if (level == 4) { + color = quote_4 + } else { + color = quote_x + } + if (line ~ meta_pattern) { + return color quotes bold line reset + } else if (line ~ /^\+/) { + return color quotes diff_add line reset + } else if (line ~ /^-/) { + return color quotes diff_del line reset + } + gsub(url_pattern, url "&" color, line) + return color quotes line reset +} +{ + # Strip carriage returns from line + sub(/\r$/, "") + + if (in_diff) { + if ($0 ~ /^-- ?$/) { + in_diff = 0 + in_signature = 1 + $0 = signature $0 reset + } else if ($0 ~ /^@@ /) { + gsub(/^@@[^@]+@@/, diff_chunk "&" reset) + } else if ($0 ~ meta_pattern) { + $0 = diff_meta $0 reset + } else if ($0 ~ /^\+/) { + $0 = diff_add $0 reset + } else if ($0 ~ /^-/) { + $0 = diff_del $0 reset + } else if ($0 !~ /^ / && $0 !~ /^$/) { + in_diff = 0 + in_body = 1 + if ($0 ~ /^>/) { + $0 = color_quote($0) + } else { + gsub(url_pattern, url "&" reset) + } + } + } else if (in_signature) { + gsub(url_pattern, url "&" signature) + $0 = signature $0 reset + } else if (in_headers) { + if ($0 ~ /^$/) { + in_headers = 0 + in_body = 1 + } else { + sub(header_pattern, header "&" reset) + gsub(url_pattern, url "&" reset) + } + } else if (in_body) { + if ($0 ~ /^>/) { + $0 = color_quote($0) + } else if ($0 ~ /^diff --git /) { + in_body = 0 + in_diff = 1 + $0 = diff_meta $0 reset + } else if ($0 ~ /^-- ?$/) { + in_body = 0 + in_signature = 1 + $0 = signature $0 reset + } else { + gsub(url_pattern, url "&" reset) + } + } else if ($0 ~ /^diff --git /) { + in_diff = 1 + $0 = diff_meta $0 reset + } else if ($0 ~ /^-- ?$/) { + in_signature = 1 + $0 = signature $0 reset + } else if ($0 ~ header_pattern) { + in_headers = 1 + sub(header_pattern, header "&" reset) + gsub(url_pattern, url "&" reset) + } else { + in_body = 1 + if ($0 ~ /^>/) { + $0 = color_quote($0) + } else { + gsub(url_pattern, url "&" reset) + } + } + + print +} -- cgit v1.2.3