branch: elpa/jabber
commit 8dcdc39c9de2b5a4f84cb09a340805abcc10cbe9
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>

    core: Separate lifecycle effects
---
 lisp/jabber-bookmarks.el |  7 ++++++
 lisp/jabber-core.el      | 40 +++++++++------------------------
 lisp/jabber-lifecycle.el | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
 lisp/jabber-modeline.el  | 10 +++++++++
 lisp/jabber-muc.el       |  8 +++++++
 lisp/jabber-presence.el  | 12 ++++++++++
 lisp/jabber-register.el  |  8 +++++++
 7 files changed, 114 insertions(+), 29 deletions(-)

diff --git a/lisp/jabber-bookmarks.el b/lisp/jabber-bookmarks.el
index e85ddf08a5..58cc043a58 100644
--- a/lisp/jabber-bookmarks.el
+++ b/lisp/jabber-bookmarks.el
@@ -30,6 +30,7 @@
 (require 'fsm)
 
 (require 'jabber-disco)
+(require 'jabber-lifecycle)
 (require 'jabber-private)
 (require 'jabber-pubsub)
 (require 'jabber-muc-state)
@@ -243,6 +244,10 @@ If REFRESH is non-nil, always fetch from server and 
re-detect protocol."
         (run-with-timer 0 nil cont jc (when (listp bookmarks) bookmarks))
       (jabber-bookmarks--detect-and-fetch jc cont refresh))))
 
+(defun jabber-bookmarks--prefetch (jc)
+  "Populate the bookmarks cache for a new session on JC."
+  (jabber-get-bookmarks jc #'ignore))
+
 (defun jabber-bookmarks--detect-and-fetch (jc cont &optional refresh)
   "Detect bookmark protocol on JC via disco and fetch via CONT.
 Query bare JID for the `#compat' feature.  If present, use XEP-0402
@@ -714,6 +719,8 @@ NICK, if non-nil, is stored in the bookmark."
   (clrhash jabber-bookmarks--legacy-accounts))
 
 (add-hook 'jabber-pre-disconnect-hook #'jabber-bookmarks--on-disconnect)
+(add-hook 'jabber-lifecycle-session-bootstrap-functions
+          #'jabber-bookmarks--prefetch 10)
 
 (provide 'jabber-bookmarks)
 
diff --git a/lisp/jabber-core.el b/lisp/jabber-core.el
index 863c644e77..29924488d7 100644
--- a/lisp/jabber-core.el
+++ b/lisp/jabber-core.el
@@ -36,6 +36,8 @@
 (require 'jabber-xml)
 (require 'jabber-conn)
 (require 'jabber-iq)
+(require 'jabber-lifecycle)
+(require 'jabber-presence-events)
 (require 'jabber-sasl)
 (require 'jabber-console)
 (require 'jabber-sm)
@@ -130,18 +132,6 @@ problems."
 ;; jabber-connect and jabber-connect-all should load jabber.el, not
 ;; just jabber-core.el, when autoloaded.
 
-;; Global reference declarations
-
-(declare-function jabber-muc-connection-closed "jabber-muc.el" (bare-jid))
-(declare-function jabber-roster-update "jabber-roster.el"
-                  (jc new-items changed-items deleted-items))
-(declare-function jabber-process-roster "jabber-presence.el"
-                  (jc xml-data closure-data))
-(declare-function jabber-initial-roster-failure "jabber-presence.el"
-                  (jc xml-data _closure-data))
-(declare-function jabber-get-register "jabber-register.el" (jc to))
-(declare-function jabber-mode-line-presence-update "jabber-modeline.el" (&rest 
_))
-(declare-function jabber-get-bookmarks "jabber-bookmarks.el" (jc cont 
&optional refresh))
 (defvar jabber-debug-keep-process-buffers) ; jabber.el
 (defvar jabber-silent-mode)             ; jabber.el
 (defvar jabber-account-list)            ; jabber.el
@@ -149,8 +139,6 @@ problems."
 (defvar jabber-xml-data)                ; jabber.el
 (defvar jabber-default-connection-type) ; jabber-conn.el
 (defvar jabber-connect-methods)         ; jabber-conn.el
-(defvar jabber-modeline-mode)           ; jabber-modeline.el
-(defvar jabber-roster-xmlns)           ; jabber-xml.el
 
 ;;
 
@@ -330,7 +318,7 @@ override the defaults from `jabber-account-list'."
                      (if (and sm-resumable (not expected))
                          (setq state-data (plist-put state-data :sm-resuming 
t))
                        ;; Otherwise clear MUC data and SM state.
-                       (jabber-muc-connection-closed 
(jabber-connection-bare-jid fsm))
+                       (jabber-lifecycle-dispatch-session-reset fsm)
                        (setq state-data (jabber-sm--reset state-data)))
 
                      (unless expected
@@ -350,8 +338,7 @@ override the defaults from `jabber-account-list'."
                        ;; of connections.
                        (setq jabber-connections
                              (delq fsm jabber-connections))
-                       (when jabber-modeline-mode
-                         (jabber-mode-line-presence-update))
+                       (jabber-lifecycle-dispatch-connection-list-changed)
                        ;; And let the FSM sleep...
                        (list state-data nil))))
 
@@ -542,7 +529,7 @@ override the defaults from `jabber-account-list'."
 
 (define-enter-state jabber-connection :register-account
                    (fsm state-data)
-                   (jabber-get-register fsm nil)
+                   (jabber-lifecycle-dispatch-registration fsm)
                    (list state-data nil))
 
 (define-state jabber-connection :register-account
@@ -690,7 +677,7 @@ override the defaults from `jabber-account-list'."
                       (list :sm-resume state-data))
                      ;; SM resume was hoped for but server doesn't offer SM 
here.
                      ((plist-get state-data :sm-resuming)
-                      (jabber-muc-connection-closed 
(jabber-connection-bare-jid fsm))
+                      (jabber-lifecycle-dispatch-session-reset fsm)
                       (setq state-data (jabber-sm--reset state-data))
                       (setq state-data (plist-put state-data :sm-resuming nil))
                       ;; Fall through to normal bind.
@@ -853,7 +840,7 @@ override the defaults from `jabber-account-list'."
                    ((jabber-sm--failed-p stanza)
                     (message "Stream Management resume failed, falling back to 
auth")
                     ;; Resume failed: clean up MUC state now, reset SM, do 
full auth.
-                    (jabber-muc-connection-closed (jabber-connection-bare-jid 
fsm))
+                    (jabber-lifecycle-dispatch-session-reset fsm)
                     (setq state-data (jabber-sm--reset state-data))
                     (setq state-data (plist-put state-data :sm-resuming nil))
                     (list :sasl-auth state-data))
@@ -882,14 +869,8 @@ override the defaults from `jabber-account-list'."
                            (setq state-data (jabber-sm--start-r-timer fsm 
state-data)))
                          (setq state-data (plist-put state-data :sm-resumed 
nil))
                          (run-hook-with-args 'jabber-post-resume-hooks fsm))
-                     ;; Normal connect: fetch roster (which triggers 
post-connect hooks
-                     ;; from the roster callback) and prefetch bookmarks.
-                     (jabber-send-iq fsm nil
-                                     "get"
-                                     `(query ((xmlns . ,jabber-roster-xmlns)))
-                                     #'jabber-process-roster 'initial
-                                     #'jabber-initial-roster-failure nil)
-                     (jabber-get-bookmarks fsm #'ignore))
+                     ;; Normal connect: feature modules fetch initial session 
data.
+                     (jabber-lifecycle-dispatch-session-bootstrap fsm))
                    (list (plist-put state-data :ever-session-established t) 
nil))
 
 (define-state jabber-connection :session-established
@@ -946,7 +927,8 @@ override the defaults from `jabber-account-list'."
                 ;; Update roster
                 (let ((pending-updates (plist-get state-data 
:roster-pending-updates)))
                   (setq state-data (plist-put state-data 
:roster-pending-updates nil))
-                  (jabber-roster-update fsm nil pending-updates nil)
+                  (jabber-presence-events-dispatch-roster-update
+                   fsm nil pending-updates nil)
                   (list :session-established state-data)))
 
                (:send-if-connected
diff --git a/lisp/jabber-lifecycle.el b/lisp/jabber-lifecycle.el
new file mode 100644
index 0000000000..cd6ca71cb7
--- /dev/null
+++ b/lisp/jabber-lifecycle.el
@@ -0,0 +1,58 @@
+;;; jabber-lifecycle.el --- Connection lifecycle effect dispatch  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2026  Thanos Apollo
+
+;; Maintainer: Thanos Apollo <[email protected]>
+
+;; This file is a part of jabber.el.
+
+;; 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 2 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, write to the Free Software
+;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+;;; Commentary:
+
+;; Keeps the connection FSM independent from feature lifecycle effects.
+
+;;; Code:
+
+(defvar jabber-lifecycle-session-reset-functions nil
+  "Functions called with a connection when its logical session is lost.")
+
+(defvar jabber-lifecycle-session-bootstrap-functions nil
+  "Functions called with a connection after a new session is established.")
+
+(defvar jabber-lifecycle-registration-functions nil
+  "Functions called with a connection entering account registration.")
+
+(defvar jabber-lifecycle-connection-list-changed-functions nil
+  "Functions called after the live connection list changes.")
+
+(defun jabber-lifecycle-dispatch-session-reset (jc)
+  "Dispatch logical session reset effects for JC."
+  (run-hook-with-args 'jabber-lifecycle-session-reset-functions jc))
+
+(defun jabber-lifecycle-dispatch-session-bootstrap (jc)
+  "Dispatch new session bootstrap effects for JC."
+  (run-hook-with-args 'jabber-lifecycle-session-bootstrap-functions jc))
+
+(defun jabber-lifecycle-dispatch-registration (jc)
+  "Dispatch account registration startup for JC."
+  (run-hook-with-args 'jabber-lifecycle-registration-functions jc))
+
+(defun jabber-lifecycle-dispatch-connection-list-changed ()
+  "Dispatch effects of a change to the live connection list."
+  (run-hooks 'jabber-lifecycle-connection-list-changed-functions))
+
+(provide 'jabber-lifecycle)
+;;; jabber-lifecycle.el ends here
diff --git a/lisp/jabber-modeline.el b/lisp/jabber-modeline.el
index eaf41801f7..e328cc9f11 100644
--- a/lisp/jabber-modeline.el
+++ b/lisp/jabber-modeline.el
@@ -30,6 +30,7 @@
 (require 'jabber-presence-display)
 (require 'jabber-alert)
 (require 'jabber-activity)
+(require 'jabber-lifecycle)
 (eval-when-compile (require 'cl-lib))
 
 (defgroup jabber-mode-line nil
@@ -51,6 +52,7 @@ Available sections: `presence', `contacts', `activity'."
 ;; Global reference declarations
 
 (defvar jabber-current-show)          ; jabber.el
+(defvar jabber-modeline-mode)
 
 ;; Activity variables (defined in jabber-activity.el)
 
@@ -87,6 +89,14 @@ Available sections: `presence', `contacts', `activity'."
             (cdr (assoc jabber-current-show jabber-presence-strings))
           "Offline")))
 
+(defun jabber-modeline--connection-list-changed ()
+  "Refresh presence display after a live connection list update."
+  (when jabber-modeline-mode
+    (jabber-mode-line-presence-update)))
+
+(add-hook 'jabber-lifecycle-connection-list-changed-functions
+          #'jabber-modeline--connection-list-changed)
+
 (defvar jabber-mode-line--recount-timer nil
   "Pending timer for a debounced `jabber-mode-line--do-count-contacts' call.")
 
diff --git a/lisp/jabber-muc.el b/lisp/jabber-muc.el
index f74758a58f..ff6a2aa4c6 100644
--- a/lisp/jabber-muc.el
+++ b/lisp/jabber-muc.el
@@ -33,6 +33,7 @@
 (require 'jabber-widget)
 (require 'jabber-buffer-registry)
 (require 'jabber-disco)
+(require 'jabber-lifecycle)
 (require 'jabber-muc-protocol)
 (require 'jabber-muc-state)
 (require 'jabber-presence-events)
@@ -461,6 +462,13 @@ entry is removed."
             (remhash room jabber-muc--nonanonymous-rooms)))))
     (setq jabber-muc--rooms-before-disconnect snapshot)))
 
+(defun jabber-muc--session-reset (jc)
+  "Clear room state belonging to the lost logical session on JC."
+  (jabber-muc-connection-closed (jabber-connection-bare-jid jc)))
+
+(add-hook 'jabber-lifecycle-session-reset-functions
+          #'jabber-muc--session-reset)
+
 (defun jabber-muc--self-ping-failed (jc xml-data closure-data)
   "Handle failed MUC self-ping per XEP-0410 error classification.
 JC is the connection.  XML-DATA is the IQ error stanza.
diff --git a/lisp/jabber-presence.el b/lisp/jabber-presence.el
index e122065e1b..30b2c5dede 100644
--- a/lisp/jabber-presence.el
+++ b/lisp/jabber-presence.el
@@ -30,6 +30,7 @@
 (require 'jabber-core)
 (require 'jabber-disco)
 (require 'jabber-iq)
+(require 'jabber-lifecycle)
 (require 'jabber-alert)
 (require 'jabber-util)
 (require 'jabber-muc-protocol)
@@ -149,6 +150,17 @@ obtained from `xml-parse-region'."
   (jabber-report-success jc xml-data "Initial roster retrieval")
   (run-hook-with-args 'jabber-post-connect-hooks jc))
 
+(defun jabber-presence--request-initial-roster (jc)
+  "Request the initial roster for JC."
+  (jabber-send-iq jc nil
+                  "get"
+                  `(query ((xmlns . ,jabber-roster-xmlns)))
+                  #'jabber-process-roster 'initial
+                  #'jabber-initial-roster-failure nil))
+
+(add-hook 'jabber-lifecycle-session-bootstrap-functions
+          #'jabber-presence--request-initial-roster)
+
 (defun jabber-presence--extract-metadata (xml-data)
   "Parse presence metadata from XML-DATA.
 Return a plist (:show :status :priority :error)."
diff --git a/lisp/jabber-register.el b/lisp/jabber-register.el
index 79bbf26d13..e65ef35b28 100644
--- a/lisp/jabber-register.el
+++ b/lisp/jabber-register.el
@@ -28,6 +28,7 @@
 ;;; Code:
 
 (require 'jabber-iq)
+(require 'jabber-lifecycle)
 (require 'jabber-widget)
 (require 'jabber-xdata)
 
@@ -60,6 +61,13 @@ JC is the Jabber connection."
                  #'jabber-process-data #'jabber-process-register-or-search
                  #'jabber-report-success "Registration"))
 
+(defun jabber-register--start-account-registration (jc)
+  "Start in-band account registration on JC."
+  (jabber-get-register jc nil))
+
+(add-hook 'jabber-lifecycle-registration-functions
+          #'jabber-register--start-account-registration)
+
 (defun jabber-process-register-or-search (jc xml-data)
   "Display results from jabber:iq:{register,search} query as a form.
 

Reply via email to