Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f079a39cbc | |||
| edd18bafdd |
+1
-1
Submodule azos-core updated: 5f561f5408...45f3e20522
@@ -207,12 +207,9 @@ deprecation warning, and =elfeed-feeds= ends up with the bare URL
|
|||||||
and no =:password=, so requests silently authenticate with an empty
|
and no =:password=, so requests silently authenticate with an empty
|
||||||
password and nothing ever lands in the db.
|
password and nothing ever lands in the db.
|
||||||
|
|
||||||
This =:config= block runs synchronously the first time =elfeed= is
|
Fetching the password with =shell-command-to-string= used to
|
||||||
loaded (i.e. the first =M-x elfeed= of the session), with no user
|
deadlock Emacs whenever the GPG PIN cache had expired: that call
|
||||||
keypress behind it the way =azos/caldav-sync= has. Fetching the
|
blocks Emacs's single thread on the =pass|gpg= subprocess, but
|
||||||
password with =shell-command-to-string= there used to deadlock
|
|
||||||
Emacs whenever the GPG PIN cache had expired: that call blocks
|
|
||||||
Emacs's single thread on the =pass|gpg= subprocess, but
|
|
||||||
=pinentry-emacs= (see the GPG Pinentry section above) needs Emacs's
|
=pinentry-emacs= (see the GPG Pinentry section above) needs Emacs's
|
||||||
command loop running to answer its loopback prompt — so Emacs waits
|
command loop running to answer its loopback prompt — so Emacs waits
|
||||||
on gpg-agent while gpg-agent waits on Emacs. Fetching the password
|
on gpg-agent while gpg-agent waits on Emacs. Fetching the password
|
||||||
@@ -222,11 +219,27 @@ with =make-process= instead keeps the command loop alive, so
|
|||||||
fires. Same stderr-redirect reasoning as before, to keep a stray
|
fires. Same stderr-redirect reasoning as before, to keep a stray
|
||||||
gpg/pass warning off the captured password.
|
gpg/pass warning off the captured password.
|
||||||
|
|
||||||
|
The fetch is wrapped in a named, interactive function rather than
|
||||||
|
inlined in =:config= so a failed attempt (e.g. =pass= produced no
|
||||||
|
output because the YubiKey wasn't plugged in yet) can be retried
|
||||||
|
with =M-x azos/elfeed-protocol-init-feeds= — re-running =:config=
|
||||||
|
itself would require reloading the =elfeed-protocol= feature
|
||||||
|
entirely. An earlier version passed =(process-get proc 'output)=
|
||||||
|
straight to =string-trim=, which signals (not just returns nil) when
|
||||||
|
no output was ever read, aborting the sentinel before =elfeed-feeds=
|
||||||
|
or =elfeed-protocol-enable= ran — so a failed first attempt left
|
||||||
|
=elfeed-feeds= permanently =nil= for the rest of the session with no
|
||||||
|
visible error beyond a =*Messages*= line, and every subsequent
|
||||||
|
=elfeed-update= silently had nothing to fetch.
|
||||||
|
|
||||||
#+begin_src emacs-lisp
|
#+begin_src emacs-lisp
|
||||||
(use-package elfeed-protocol
|
(defun azos/elfeed-protocol-init-feeds ()
|
||||||
:after elfeed
|
"Fetch the Nextcloud password and (re)enable elfeed-protocol sync.
|
||||||
:config
|
Unlike the one-shot `use-package' :config form this is called from,
|
||||||
(setq elfeed-protocol-enabled-protocols '(owncloud))
|
safe to call again (e.g. via \\[azos/elfeed-protocol-init-feeds]) if
|
||||||
|
a previous attempt failed, such as the YubiKey not being plugged in
|
||||||
|
yet — it re-spawns the `pass' process and re-prompts for the PIN."
|
||||||
|
(interactive)
|
||||||
(make-process
|
(make-process
|
||||||
:name "elfeed-protocol-pass"
|
:name "elfeed-protocol-pass"
|
||||||
:command '("sh" "-c" "pass zakobar.com 2>/dev/null | head -1")
|
:command '("sh" "-c" "pass zakobar.com 2>/dev/null | head -1")
|
||||||
@@ -234,10 +247,20 @@ gpg/pass warning off the captured password.
|
|||||||
:filter (lambda (proc chunk)
|
:filter (lambda (proc chunk)
|
||||||
(process-put proc 'output (concat (or (process-get proc 'output) "") chunk)))
|
(process-put proc 'output (concat (or (process-get proc 'output) "") chunk)))
|
||||||
:sentinel (lambda (proc _event)
|
:sentinel (lambda (proc _event)
|
||||||
|
(let ((password (string-trim (or (process-get proc 'output) ""))))
|
||||||
|
(if (string-empty-p password)
|
||||||
|
(message "elfeed-protocol: `pass zakobar.com' produced no output; retry with M-x azos/elfeed-protocol-init-feeds")
|
||||||
(setq elfeed-feeds
|
(setq elfeed-feeds
|
||||||
`(("owncloud+https://aner@nextcloud.zakobar.com"
|
`(("owncloud+https://aner@nextcloud.zakobar.com"
|
||||||
:password ,(string-trim (process-get proc 'output)))))
|
:password ,password)))
|
||||||
(elfeed-protocol-enable))))
|
(elfeed-protocol-enable)
|
||||||
|
(elfeed-update))))))
|
||||||
|
|
||||||
|
(use-package elfeed-protocol
|
||||||
|
:after elfeed
|
||||||
|
:config
|
||||||
|
(setq elfeed-protocol-enabled-protocols '(owncloud))
|
||||||
|
(azos/elfeed-protocol-init-feeds))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
** Elfeed Full Article Fetch
|
** Elfeed Full Article Fetch
|
||||||
|
|||||||
@@ -25,6 +25,17 @@
|
|||||||
certificatesFile = "/etc/ssl/certs/ca-certificates.crt";
|
certificatesFile = "/etc/ssl/certs/ca-certificates.crt";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
# mbsync's PassCmd shells out to `pass`, which needs the GPG smartcard to
|
||||||
|
# decrypt. On a timer, a missing card would otherwise surface as a
|
||||||
|
# pinentry "please insert card" prompt every run. `gpg --card-status`
|
||||||
|
# only queries the card reader (no pinentry involved either way), so it's
|
||||||
|
# safe to use as a silent presence check: skip the sync entirely when the
|
||||||
|
# card isn't there, instead of letting mbsync hit that prompt.
|
||||||
|
mbsyncSafe = pkgs.writeShellScript "mbsync-safe" ''
|
||||||
|
if ${pkgs.gnupg}/bin/gpg --card-status >/dev/null 2>&1; then
|
||||||
|
exec ${pkgs.isync}/bin/mbsync -a
|
||||||
|
fi
|
||||||
|
'';
|
||||||
in {
|
in {
|
||||||
options.azos.mail.enable = lib.mkOption {
|
options.azos.mail.enable = lib.mkOption {
|
||||||
default = true;
|
default = true;
|
||||||
@@ -35,7 +46,6 @@
|
|||||||
mu.enable = true;
|
mu.enable = true;
|
||||||
mbsync.enable = true;
|
mbsync.enable = true;
|
||||||
msmtp.enable = true;
|
msmtp.enable = true;
|
||||||
lieer.enable = true;
|
|
||||||
};
|
};
|
||||||
home.activation.muInit = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
home.activation.muInit = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||||
if [ ! -d "$HOME/.cache/mu" ]; then
|
if [ ! -d "$HOME/.cache/mu" ]; then
|
||||||
@@ -46,7 +56,6 @@
|
|||||||
--my-address=anerz@post.bgu.ac.il
|
--my-address=anerz@post.bgu.ac.il
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
services.lieer.enable = true;
|
|
||||||
accounts.email.accounts = {
|
accounts.email.accounts = {
|
||||||
gmail =
|
gmail =
|
||||||
default_gmail_params
|
default_gmail_params
|
||||||
@@ -78,6 +87,21 @@
|
|||||||
passwordCommand = "pass privateemail.com | head -1";
|
passwordCommand = "pass privateemail.com | head -1";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
systemd.user.services.mbsync-timer = {
|
||||||
|
Unit.Description = "Sync mail via mbsync (skips silently if smartcard is absent)";
|
||||||
|
Service = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${mbsyncSafe}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
systemd.user.timers.mbsync-timer = {
|
||||||
|
Unit.Description = "Periodic mbsync mail sync";
|
||||||
|
Timer = {
|
||||||
|
OnStartupSec = "2m";
|
||||||
|
OnUnitActiveSec = "5m";
|
||||||
|
};
|
||||||
|
Install.WantedBy = ["timers.target"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user