diff --git a/users/simon/modules/default.nix b/users/simon/modules/default.nix index 635afe5..39fdd5c 100644 --- a/users/simon/modules/default.nix +++ b/users/simon/modules/default.nix @@ -10,6 +10,7 @@ ./gtk.nix ./htop.nix ./logitech.nix + ./mail ./makemkv.nix ./misc.nix ./mpd.nix diff --git a/users/simon/modules/mail/aerc/colorize b/users/simon/modules/mail/aerc/colorize new file mode 100755 index 0000000..cd7956f --- /dev/null +++ b/users/simon/modules/mail/aerc/colorize @@ -0,0 +1,143 @@ +#!/usr/bin/env -S awk -f +# Copyright (c) 2022 Robin Jarry +# Modified 2022-06-16 by Simon Bruder to use ANSI colors +# Modified 2022-06-16 by Simon Bruder to a /usr/bin/env shebang + +BEGIN { + url = "\x1b[33m" # yellow + header = "\x1b[35m" # purple + signature = "\x1b[35m" # purple + diff_meta = "\x1b[1;37m" # bold white + diff_chunk = "\x1b[36m" # cyan + diff_add = "\x1b[32m" # green + diff_del = "\x1b[31m" # red + quote_1 = "\x1b[34m" # blue + quote_2 = "\x1b[91m" # orange + quote_3 = "\x1b[35m" # purple + quote_4 = "\x1b[95m" # pink + quote_x = "\x1b[37m" # gray + reset = "\x1b[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:]]/ +} +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 ~ /^\+/) { + 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_signature = 1 + in_diff = 0 + in_headers = 0 + in_body = 0 + $0 = signature $0 reset + } else if ($0 ~ /^@@ /) { + $0 = diff_chunk $0 reset + } else if ($0 ~ /^(diff --git|index|---|\+\+\+) /) { + $0 = diff_meta $0 reset + } else if ($0 ~ /^\+/) { + $0 = diff_add $0 reset + } else if ($0 ~ /^-/) { + $0 = diff_del $0 reset + } + } else if (in_signature) { + gsub(url_pattern, url "&" signature) + $0 = signature $0 reset + } else if (in_headers) { + if ($0 ~ /^$/) { + in_signature = 0 + in_diff = 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_signature = 0 + in_diff = 1 + in_headers = 0 + in_body = 0 + $0 = diff_meta $0 reset + } else if ($0 ~ /^-- ?$/) { + in_signature = 1 + in_diff = 0 + in_headers = 0 + in_body = 0 + $0 = signature $0 reset + } else { + gsub(url_pattern, url "&" reset) + } + } else if ($0 ~ /^diff --git /) { + in_signature = 0 + in_diff = 1 + in_headers = 0 + in_body = 0 + $0 = diff_meta $0 reset + } else if ($0 ~ /^-- ?$/) { + in_signature = 1 + in_diff = 0 + in_headers = 0 + in_body = 0 + $0 = signature $0 reset + } else if ($0 ~ header_pattern) { + in_signature = 0 + in_diff = 0 + in_headers = 1 + in_body = 0 + sub(header_pattern, header "&" reset) + gsub(url_pattern, url "&" reset) + } else { + in_signature = 0 + in_diff = 0 + in_headers = 0 + in_body = 1 + if ($0 ~ /^>/) { + $0 = color_quote($0) + } else { + gsub(url_pattern, url "&" reset) + } + } + + print +} diff --git a/users/simon/modules/mail/aerc/default.nix b/users/simon/modules/mail/aerc/default.nix new file mode 100644 index 0000000..d5222ab --- /dev/null +++ b/users/simon/modules/mail/aerc/default.nix @@ -0,0 +1,278 @@ +{ lib, pkgs, ... }: +let + package = pkgs.aerc; + + accountDefaults = { + smtp-starttls = "yes"; + copy-to = "Sent"; + signature-file = pkgs.writeText "signature" '' + -- + Simon Bruder + Wallmersbach 42 + 97215 Uffenheim + + 🔑 (GPG): 47E7 559E 037A 3565 2DBB F8AA 8D3C 82F9 F309 F8EC + 📧 (E-Mail): simon@sbruder.de + 📱 (mobile): +49 152 56561414 + ''; + pgp-auto-sign = true; + pgp-key-id = "47E7559E037A35652DBBF8AA8D3C82F9F309F8EC"; + pgp-opportunistic-encrypt = true; + }; +in +{ + home.packages = [ + package + ]; + + xdg.configFile = { + "aerc/accounts.conf".text = lib.generators.toINI { } { + Personal = accountDefaults // { + source = "`imap://simon%40sbruder.de@vueko.sbruder.de`"; + source-cred-cmd = "`pass sbruder.de/mail`"; + outgoing = "`smtp+plain://simon%40sbruder.de@vueko.sbruder.de`"; + outgoing-cred-cmd = "`pass sbruder.de/mail`"; + from = "Simon Bruder "; + }; + + Riseup = accountDefaults // { + source = "`imap://sbruder@mail.riseup.net`"; + source-cred-cmd = "`pass web/riseup.net | head -n 1`"; + outgoing = "`smtp+plain://sbruder@mail.riseup.net`"; + outgoing-cred-cmd = "`pass web/riseup.net | head -n 1`"; + from = "Simon Bruder "; + }; + }; + + "aerc/aerc.conf".text = lib.generators.toINI { } { + general = { + pgp-provider = "gpg"; # internal does not work + + # Allow world-readable accounts.conf (passwords are not stored in it, so it is ok) + unsafe-accounts-conf = true; + }; + + ui = { + index-format = "%-17.17D %-20.20n %Z %s"; + + # See https://godoc.org/time#Time.Format + timestamp-format = "2006-01-02 15:04 MST"; + this-day-time-format = "15:04"; + this-week-time-format = "Monday 15:04"; + this-year-time-format = "02 January"; + + pinned-tab-marker = "車"; + + border-char-vertical = "│"; + border-char-horizontal = "─"; + + fuzzy-complete = true; + + threading-enabled = true; + + new-message-bell = false; + }; + + statusline = { + display-mode = "icon"; + }; + + viewer = { + header-layout = lib.concatStringsSep "," [ + "From|To" + "Cc|Bcc" + "Subject" + "Date" + "Reply-To" + "X-Mailer" + "User-Agent" + ]; + }; + + compose = { + editor = "nvim"; + + header-layout = lib.concatStringsSep "," [ + "To|From" + "Subject" + ]; + + address-book-cmd = "khard email --parsable --remove-first-line %s"; + }; + + filters = { + "subject,~^\\[PATCH" = "awk -f ${package}/share/aerc/filters/hldiff"; + "text/plain" = "${./colorize}"; # taken from upstream and patched + "text/html" = "html"; # internal filter + "text/calendar" = "${pkgs.python3.withPackages (ps: with ps; [ vobject ])}/bin/python ${package}/share/aerc/filters/show-ics-details.py"; # hacky fix for broken nix support + }; + + triggers = { + new-email = "exec notify-send -i mail-unread-symbolic 'New e-mail from %n' '%s'"; + }; + + templates = { }; + }; + + "aerc/binds.conf".text = lib.generators.toINIWithGlobalSection { } { + globalSection = { + # 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"; + }; + + sections = { + 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"; + + "J" = ":next-folder"; + "K" = ":prev-folder"; + "H" = ":collapse-folder"; + "L" = ":expand-folder"; + + "v" = ":mark -t"; + "V" = ":mark -v"; + + "T" = ":toggle-threads"; + + "" = ":view"; + "d" = ":prompt 'Really delete this message?' 'delete-message'"; + "D" = ":delete"; + "A" = ":archive flat"; + + "C" = ":compose"; + + "rr" = ":reply -a"; + "rq" = ":reply -aq"; + "Rr" = ":reply"; + "Rq" = ":reply -q"; + + "c" = ":cf"; + "$" = ":term"; + "!" = ":term"; + "|" = ":pipe"; + + "/" = ":search"; + "\\" = ":filter"; + "n" = ":next-result"; + "N" = ":prev-result"; + "" = ":clear"; + }; + + view = { + "/" = ":toggle-key-passthrough/"; + "q" = ":close"; + "O" = ":open"; + "S" = ":save"; + "|" = ":pipe"; + "D" = ":delete"; + "A" = ":archive flat"; + + "f" = ":forward"; + "rr" = ":reply -a"; + "rq" = ":reply -aq"; + "Rr" = ":reply"; + "Rq" = ":reply -q"; + + "H" = ":toggle-headers"; + "" = ":prev-part"; + "" = ":next-part"; + "J" = ":next"; + "K" = ":prev"; + }; + + "view::passthrough" = { + "$noinherit" = "true"; + "$ex" = ""; + "" = ":toggle-key-passthrough"; + }; + + # Keybindings used when the embedded terminal is not selected in the compose view" + compose = { + "$ex" = ""; + "" = ":prev-field"; + "" = ":next-field"; + "" = ":next-field"; + "" = ":prev-field"; + }; + + # Keybindings used when the embedded terminal is selected in the compose view + "compose::editor" = { + "$noinherit" = "true"; + "$ex" = ""; + "" = ":prev-field"; + "" = ":next-field"; + "" = ":prev-tab"; + "" = ":next-tab"; + }; + + # Keybindings used when reviewing a message to be sent + "compose::review" = { + "y" = ":send"; + "n" = ":abort"; + "p" = ":postpone"; + "q" = ":choose -o d discard abort -o p postpone postpone"; + "e" = ":edit"; + "a" = ":attach"; + "d" = ":detach"; + }; + + terminal = { + "$noinherit" = "true"; + "$ex" = ""; + + "" = ":prev-tab"; + "" = ":next-tab"; + }; + }; + }; + + "aerc/stylesets/default".text = lib.concatStrings + (lib.mapAttrsToList + (k: v: "${k} = ${if lib.isBool v then (if v then "true" else "false") else toString v}\n") + { + "*.selected.reverse" = true; + + "title.reverse" = true; + "header.bold" = true; + + "*error.bold" = true; + "error.fg" = 1; + "warning.fg" = 3; + "success.fg" = 2; + + "statusline_default.bg" = 0; + "statusline_error.fg" = 1; + "statusline_error.reverse" = true; + "statusline_success.fg" = 2; + "statusline_success.reverse" = true; + + "msglist_unread.bold" = true; + "msglist_deleted.fg" = 10; + + "tab.bg" = 11; + "tab.selected.reverse" = false; + "tab.selected.bg" = 12; + "tab.fg" = 0; + + "completion_default.bg" = 0; + }); + }; +} diff --git a/users/simon/modules/mail/default.nix b/users/simon/modules/mail/default.nix new file mode 100644 index 0000000..6a61e69 --- /dev/null +++ b/users/simon/modules/mail/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./aerc + ]; +}