summaryrefslogtreecommitdiffhomepage
path: root/lib/net
diff options
context:
space:
mode:
Diffstat (limited to 'lib/net')
-rw-r--r--lib/net/jao-eww-session.el2
-rw-r--r--lib/net/jao-notmuch-gnus.el15
-rw-r--r--lib/net/jao-notmuch.el2
-rw-r--r--lib/net/jao-proton-utils.el34
-rw-r--r--lib/net/jao-r2e.el231
-rw-r--r--lib/net/randomsig.el82
6 files changed, 286 insertions, 80 deletions
diff --git a/lib/net/jao-eww-session.el b/lib/net/jao-eww-session.el
index adbe98f..76da717 100644
--- a/lib/net/jao-eww-session.el
+++ b/lib/net/jao-eww-session.el
@@ -68,7 +68,7 @@
(car (or s (jao-eww-session--current))))
(defun jao-eww-session-titles (&optional s)
- (let ((s (or s jao-eww-current-session)))
+ (let ((s (or s (jao-eww-session--current))))
(mapcar 'cdr (cadr s))))
(defun jao-eww-session--update ()
diff --git a/lib/net/jao-notmuch-gnus.el b/lib/net/jao-notmuch-gnus.el
index 9a17841..9b408c2 100644
--- a/lib/net/jao-notmuch-gnus.el
+++ b/lib/net/jao-notmuch-gnus.el
@@ -237,21 +237,6 @@ Example:
(org-link-set-parameters "gnus" :store #'ignore)
(org-link-set-parameters "notmuch" :store #'ignore)
-;;; consult-notmuch
-
-(with-eval-after-load "consult-notmuch"
- (defun jao-notmuch-gnus--open-candidate (candidate)
- "Open a notmuch-search completion candidate email in Gnus."
- (message "candidate: %S" candidate)
- (jao-notmuch-gnus-goto-message (consult-notmuch--candidate-id candidate)))
-
- (defun jao-gnus-consult-notmuch ()
- "Run a consult-notmuch query that opens candidates in Gnus."
- (interactive)
- (jao-notmuch-gnus--open-candidate (consult-notmuch--search)))
-
- (consult-customize jao-gnus-consult-notmuch :preview-key 'any))
-
;;; tags and flags
(defun jao-notmuch-gnus-flag-current (&rest _)
diff --git a/lib/net/jao-notmuch.el b/lib/net/jao-notmuch.el
index 625c8e6..40db88d 100644
--- a/lib/net/jao-notmuch.el
+++ b/lib/net/jao-notmuch.el
@@ -34,7 +34,7 @@
;;; targetting the displayed message from the tree view
(defvar-local jao-notmuch--tree-buffer nil)
-(declare eww--url-at-point "eww")
+(declare-function eww--url-at-point "eww")
(defun jao-notmuch-goto-message-buffer (&optional and-click no-record)
(interactive "P")
diff --git a/lib/net/jao-proton-utils.el b/lib/net/jao-proton-utils.el
index 0a08f5d..a8f13eb 100644
--- a/lib/net/jao-proton-utils.el
+++ b/lib/net/jao-proton-utils.el
@@ -1,4 +1,4 @@
-;; jao-proton-utils.el -- simple interaction with Proton mail and vpn
+;; jao-proton-utils.el -- simple interaction with Proton mail and vpn -*- lexical-binding: t; -*-
;; Copyright (c) 2018, 2019, 2020, 2023, 2026 Jose Antonio Ortega Ruiz
@@ -54,6 +54,22 @@
(defvar jao-proton-vpn-font-lock-keywords '("\\[.+\\]"))
+(defvar proton-vpn-mode-map
+ (let ((map (make-keymap)))
+ (suppress-keymap map)
+ (define-key map [?q] 'bury-buffer)
+ (define-key map [?n] 'next-line)
+ (define-key map [?p] 'previous-line)
+ (define-key map [?g] 'proton-vpn-status)
+ (define-key map [?r] 'proton-vpn-reconnect)
+ (define-key map [?d] (lambda ()
+ (interactive)
+ (when (y-or-n-p "Disconnect?")
+ (proton-vpn-disconnect))))
+ (define-key map [?c] 'proton-vpn-connect)
+ map))
+
+
;;;###autoload
(defun proton-vpn-mode ()
"A very simple mode to show the output of ProtonVPN commands"
@@ -121,21 +137,5 @@
(interactive)
(jao-proton-vpn--do "d"))
-(setq proton-vpn-mode-map
- (let ((map (make-keymap)))
- (suppress-keymap map)
- (define-key map [?q] 'bury-buffer)
- (define-key map [?n] 'next-line)
- (define-key map [?p] 'previous-line)
- (define-key map [?g] 'proton-vpn-status)
- (define-key map [?r] 'proton-vpn-reconnect)
- (define-key map [?d] (lambda ()
- (interactive)
- (when (y-or-n-p "Disconnect?")
- (proton-vpn-disconnect))))
- (define-key map [?c] 'proton-vpn-connect)
- map))
-
-
(provide 'jao-proton-utils)
;;; jao-proton.el ends here
diff --git a/lib/net/jao-r2e.el b/lib/net/jao-r2e.el
new file mode 100644
index 0000000..f28b66b
--- /dev/null
+++ b/lib/net/jao-r2e.el
@@ -0,0 +1,231 @@
+;;; jao-r2e.el --- List of rss2email subscriptions -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025, 2026 Jose Antonio Ortega Ruiz
+
+;; Author: Jose Antonio Ortega Ruiz <mail@jao.io>
+;; Keywords: 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/>.
+
+(require 'multisession)
+(require 'jao-url)
+
+(autoload 'View-quit "view")
+(autoload 'eww-view-source "eww")
+(autoload 'jao-notmuch-subtags "jao-notmuch")
+
+(defvar jao-r2e-command "r2e")
+(defvar jao-r2e-confirm-toggle nil)
+
+(defconst jao-r2e--buffer "*r2e*")
+(defun jao-r2e--buffer ()
+ (with-current-buffer (get-buffer-create jao-r2e--buffer)
+ (unless (derived-mode-p 'jao-r2e-mode)
+ (jao-r2e-mode))
+ (current-buffer)))
+
+(defvar jao-r2e-mode-map
+ (let ((map (make-keymap)))
+ (suppress-keymap map)
+ (define-key map [?q] 'bury-buffer)
+ (define-key map [?n] 'next-line)
+ (define-key map [?p] 'previous-line)
+ (define-key map [?N] 'jao-r2e-next)
+ (define-key map [?P] 'jao-r2e-prev)
+ (define-key map [?g] 'jao-r2e-list)
+ (define-key map [?s] 'jao-r2e-subscribe)
+ (define-key map [?t] 'jao-r2e-toggle)
+ (define-key map [?D] 'jao-r2e-delete)
+ (define-key map [?u] 'jao-r2e-recover)
+ (define-key map [?y] 'jao-r2e-kill-url)
+ (define-key map [?x] 'jao-r2e-list-subscribed)
+ map))
+
+;;;###autoload
+(defun jao-r2e-mode ()
+ "A very simple mode to show the output of r2e commands."
+ (interactive)
+ (kill-all-local-variables)
+ (buffer-disable-undo)
+ (use-local-map jao-r2e-mode-map)
+ ;; (setq-local font-lock-defaults '(jao-r2e-font-lock-keywords))
+ (setq-local truncate-lines t)
+ (setq-local next-line-add-newlines nil)
+ (setq major-mode 'jao-r2e-mode)
+ (setq mode-name "r2e")
+ (read-only-mode 1))
+
+(defun jao-r2e--do (things &optional buffer)
+ "Execute a r2e command THINGS in the given BUFFER."
+ (let ((b (or buffer (pop-to-buffer (jao-r2e--buffer)))))
+ (let ((inhibit-read-only t)
+ (cmd (format "%s %s" jao-r2e-command things)))
+ (unless buffer
+ (with-current-buffer b (delete-region (point-min) (point-max))))
+ (with-temp-message (format "Running: %s ...." cmd)
+ (shell-command cmd b))
+ (unless buffer (read-only-mode 1)))))
+
+(defconst jao-r2e--feed-rx
+ "^\\([0-9]+\\): \\[\\( \\|\\*\\)\\] \\([^ ]+\\) (\\(.+\\) -> \\(.+\\))")
+
+(defun jao-r2e--feed-at-point ()
+ (beginning-of-line)
+ (when-let* ((m (looking-at jao-r2e--feed-rx)))
+ (list (match-string 1)
+ (match-string 3)
+ (string= "*" (match-string 2))
+ (match-string 4)
+ (match-string 5))))
+
+(defun jao-r2e ()
+ (interactive)
+ (pop-to-buffer (jao-r2e--buffer))
+ (when (looking-at-p "^$")
+ (jao-r2e-list)))
+
+(defun jao-r2e-list ()
+ (interactive)
+ (jao-r2e--do "list"))
+
+(defun jao-r2e-list-subscribed (arg)
+ "Show only subscribed (unsubscribed with arg) feeds."
+ (interactive "P")
+ (jao-r2e-list)
+ (let ((inhibit-read-only t))
+ (flush-lines (if arg ".*\\[\\*\\].*" ".*\\[ \\].*"))))
+
+(defun jao-r2e--srx (opp)
+ (when-let* ((f (jao-r2e--feed-at-point)))
+ (let ((a (if opp (not (caddr f)) (caddr f))))
+ (format "^[0-9]+: \\[%s\\] " (if a "\\*" " ")))))
+
+(defun jao-r2e-next (opp)
+ "Next feed with the same (or opposite) status."
+ (interactive "P")
+ (when-let* ((rx (jao-r2e--srx opp)))
+ (forward-line)
+ (when (re-search-forward rx nil t)
+ (beginning-of-line))))
+
+(defun jao-r2e-prev (opp)
+ "Previous feed with the same (or opposite) status."
+ (interactive "P")
+ (when-let* ((rx (jao-r2e--srx opp)))
+ (when (re-search-backward rx nil t)
+ (beginning-of-line))))
+
+(defun jao-r2e-kill-url ()
+ "Copy as kill the URL of the feed at point."
+ (interactive)
+ (let ((url (cadddr (jao-r2e--feed-at-point))))
+ (if (not url)
+ (error "No feed at point")
+ (kill-new url)
+ (message "%s" url))))
+
+(defun jao-r2e-toggle ()
+ (interactive)
+ (let ((f (jao-r2e--feed-at-point)))
+ (unless f (error "No feed at point"))
+ (let ((p (point))
+ (no (car f))
+ (name (cadr f))
+ (act (if (caddr f) "pause" "unpause")))
+ (when (or (not jao-r2e-confirm-toggle)
+ (yes-or-no-p (format "%s '%s'? " act name)))
+ (with-temp-buffer
+ (jao-r2e--do (format "%s %s" act no) (current-buffer)))
+ (jao-r2e-list)
+ (goto-char p)))))
+
+(define-multisession-variable jao-r2e-deleted-feeds '()
+ "List of rss2email feeds deleted at some point.")
+
+(defun jao-r2e--deleted () (multisession-value jao-r2e-deleted-feeds))
+
+(defun jao-r2e-delete ()
+ "Delete feed at point. Use `jao-r2e-recover' to undelete."
+ (interactive)
+ (let ((f (jao-r2e--feed-at-point)))
+ (unless f (error "No feed at point"))
+ (let ((p (point))
+ (no (car f))
+ (entry (cdr f)))
+ (when (yes-or-no-p (format "Delete feed '%s'" (car entry)))
+ (setf (multisession-value jao-r2e-deleted-feeds)
+ (cons entry (remove entry (jao-r2e--deleted))))
+ (with-temp-buffer
+ (jao-r2e--do (format "delete %s" no) (current-buffer)))
+ (jao-r2e-list)
+ (goto-char p)))))
+
+(defun jao-r2e-recover ()
+ (interactive)
+ (when (seq-empty-p (jao-r2e--deleted))
+ (error "No feeds recoverable at this point."))
+ (let* ((entries (jao-r2e--deleted))
+ (feed (completing-read "Recover feed: " entries)))
+ (when-let* ((ps (assoc feed entries))
+ (url (caddr ps))
+ (mail (car (last ps)))
+ (cat (when (string-match "feeds\\.\\(.+\\)@localhost" mail)
+ (match-string 1 mail))))
+ (jao-r2e-subscribe (list url feed) cat t)
+ (setf (multisession-value jao-r2e-deleted-feeds) (remove ps entries)))))
+
+(defun jao-r2e--find-url ()
+ (save-excursion
+ (when (derived-mode-p 'w3m-mode 'eww-mode)
+ (if (fboundp 'w3m-view-source) (w3m-view-source) (eww-view-source)))
+ (goto-char (point-min))
+ (when (re-search-forward
+ "type=\"application/\\(?:atom\\|rss\\)\\+xml\" +" nil t)
+ (let ((url (save-excursion
+ (when (re-search-forward
+ "href=\"\\([^\n\"]+\\)\"" nil t)
+ (match-string-no-properties 1))))
+ (title (when (re-search-forward
+ "\\(?:title=\"\\([^\n\"]+\\)\" +\\)" nil t)
+ (match-string-no-properties 1))))
+ (when (string-match-p ".*\\*eww-source\\b.*" (buffer-name))
+ (View-quit))
+ (when url (cons url (or title "")))))))
+
+(defun jao-r2e-subscribe (url &optional cat relist)
+ "Subscribe to a given RSS URL. If URL not given, look for it."
+ (interactive (list (or (jao-url-around-point)
+ (jao-r2e--find-url)
+ (read-string "Feed URL: "))))
+ (let* ((url+title (ensure-list url))
+ (url (car url+title))
+ (title (cdr url+title)))
+ (unless url (error "No feeds found"))
+ (let ((url (if (string-match "^feed:" url) (substring url 5) url)))
+ (when (y-or-n-p (format "Subscribe to <%s>? " url))
+ (let* ((name (read-string "Feed name: " title))
+ (cats (cons "prog" (jao-notmuch-subtags "feeds")))
+ (cat (completing-read "Category: " cats nil t cat))
+ (sfmt (format "%%s add %s '%s' mail+feeds_%s@jao.io" name url cat)))
+ (with-temp-message "Subscribing..."
+ (shell-command-to-string (format sfmt "r2e"))
+ (when (not (string= jao-r2e-command "r2e"))
+ (shell-command-to-string (format sfmt jao-r2e-command))))
+ (when (y-or-n-p "Retrieve feeds now? ")
+ (with-temp-message "Retrieving feed..."
+ (shell-command (format "%s run %s" jao-r2e-command name))))
+ (when relist (jao-r2e-list)))))))
+
+(provide 'jao-r2e)
+;;; jao-r2e.el ends here
diff --git a/lib/net/randomsig.el b/lib/net/randomsig.el
index 9029f13..e3c735b 100644
--- a/lib/net/randomsig.el
+++ b/lib/net/randomsig.el
@@ -308,7 +308,7 @@ You probably want to have a newline at the end of it."
;; get a list with file names of signature files
(let ((sigfiles (randomsig-files-to-list files)))
;; Insert all files into the newly created buffer
- (mapcar
+ (mapc
(lambda (fname)
(let ((pos (point-max)))
@@ -348,10 +348,10 @@ You probably want to have a newline at the end of it."
(defun randomsig-goto-signature ()
-;; This function is stolen fom message-goto signature.
-;; Go to beginnig of the signature, and return t.
-;; If there is no signature in current buffer, go to end of buffer,
-;; and return nil.
+ ;; This function is stolen fom message-goto signature.
+ ;; Go to beginnig of the signature, and return t.
+ ;; If there is no signature in current buffer, go to end of buffer,
+ ;; and return nil.
(goto-char (point-min))
(if (re-search-forward "^-- $" nil t)
(progn
@@ -383,30 +383,25 @@ Else a signature out of `randomsig-files' will be choosen."
(randomsig-read-signatures-to-buffer randomsig-buffer-name files)
(goto-char (point-min))
- (let '(count 0) 'selected
-
- ;; Count number of signatures
- (while (search-forward-regexp randomsig-delimiter-pattern nil t)
- (setq count (1+ count)))
-
- ;; Select random signature out out these
- (setq selected (1+ (random count)))
- (goto-char (point-min))
- (if (search-forward-regexp randomsig-delimiter-pattern nil t selected)
- (forward-char))
-
- ;; Cut signature and return it
- (let '(here (point)) 'signature-string
-
- (if (not (search-forward-regexp randomsig-delimiter-pattern
- nil t))
- (goto-char (point-max))
- (beginning-of-line))
- (setq signature-string
- (concat randomsig-static-string
- (buffer-substring here (point))))
- (kill-buffer randomsig-buffer-name)
- signature-string))))
+ (let ((count 0) (selected nil))
+ ;; Count number of signatures
+ (while (search-forward-regexp randomsig-delimiter-pattern nil t)
+ (setq count (1+ count)))
+ ;; Select random signature out out these
+ (setq selected (1+ (random count)))
+ (goto-char (point-min))
+ (if (search-forward-regexp randomsig-delimiter-pattern nil t selected)
+ (forward-char))
+ ;; Cut signature and return it
+ (let ((here (point))
+ (signature-string nil))
+ (if (not (search-forward-regexp randomsig-delimiter-pattern nil t))
+ (goto-char (point-max))
+ (beginning-of-line))
+ (setq signature-string
+ (concat randomsig-static-string (buffer-substring here (point))))
+ (kill-buffer randomsig-buffer-name)
+ signature-string))))
(defun randomsig-replace-sig (arg)
@@ -415,34 +410,31 @@ When called with prefix, read the filename of the signature-file
that should be used"
(interactive "P")
(save-excursion
-
(randomsig-replace-signature
(randomsig-signature
(if arg
(randomsig-prompt "read from signature-lib: ")
randomsig-files)))))
-
-
(defun randomsig-message-read-sig (arg)
"Get the signature of current message and copy it to a file.
If mark is active, get the marked region instead.
When called with prefix, let the user edit the signature before saving"
(interactive "P")
(save-excursion
- (let '(signature-string
+ (let ((signature-string
(if (randomsig-mark-active-p)
(buffer-substring (point) (mark))
(progn
(if (randomsig-goto-signature)
- (let `(here (point))
+ (let ((here (point)))
(goto-char (point-max))
(while (char-equal (char-before) 10)
(backward-char))
(buffer-substring here (point)))
- nil))))
+ nil)))))
(when signature-string
(if arg
(progn
@@ -451,7 +443,6 @@ When called with prefix, let the user edit the signature before saving"
(randomsig-edit signature-string))
(randomsig-write-signature signature-string))))))
-
(defun randomsig-write-signature (signature-string)
(set-buffer (find-file-noselect
(expand-file-name
@@ -465,14 +456,13 @@ When called with prefix, let the user edit the signature before saving"
(save-buffer))
-(defun gnus/randomsig-summary-read-sig (arg)
- "Get the signature of current message and copy it to a file"
- (interactive "P")
- (progn ;save-excursion
- ;; FIXME: Doesn't return to summary buffer (save-excursion should do this)
- (gnus-summary-select-article-buffer)
- (randomsig-message-read-sig arg)))
-
+;; (defun gnus/randomsig-summary-read-sig (arg)
+;; "Get the signature of current message and copy it to a file"
+;; (interactive "P")
+;; (progn ;save-excursion
+;; ;; FIXME: Doesn't return to summary buffer (save-excursion should do this)
+;; (gnus-summary-select-article-buffer)
+;; (randomsig-message-read-sig arg)))
(defun randomsig-search-sigfiles (&optional file)
"Scan `randomsig-dir' and its subdirectories for regular files.
@@ -489,7 +479,7 @@ If FILE is given, only FILE and its subdirectory will be searched."
;; unwanted...
nil
- (let '(path (expand-file-name file randomsig-dir))
+ (let ((path (expand-file-name file randomsig-dir)))
(if (file-directory-p path)
(mapcan (lambda (f)
(randomsig-search-sigfiles (if (string= file "")
@@ -571,7 +561,7 @@ You most likely do not want to call `randomsig-edit-mode' directly.
\\{randomsig-edit-mode-map}"
(define-key randomsig-edit-mode-map
- (kbd "C-c C-c") 'randomsig-edit-done))
+ (kbd "C-c C-c") 'randomsig-edit-done))
;;; Commands for randomsig-select-mode