#+TITLE: jabber.el Developer Documentation

* Description
:PROPERTIES:
:CUSTOM_ID: description
:END:
** Debugging tips
:PROPERTIES:
:CUSTOM_ID: debugging-tips
:END:
Useful tips for debugging:

- There is a buffer called ~*fsm-debug*~ that displays all transitions and errors during the event handling.
- There is a =jabber-debug= customization group.
- You can set the [[file:jabber.org::#debug-log-xml][jabber-debug-log-xml]] custom variable to ~t~ to enable the XML debug console.
- The XML console is a buffer called ~*-jabber-console-ACCOUNT-*~ by default. Enable ~jabber-debug-log-xml~ and switch to that buffer to see the incoming and outgoing XML stanzas. See [[file:jabber.org::#xml-console-mode][xml-console-mode]].

** fsm.el - the Finite State Machine library
:PROPERTIES:
:CUSTOM_ID: fsm
:END:
fsm.el implements functions to define multiple [[https://en.wikipedia.org/wiki/Finite-state_machine][finite state machines]] (FSM), their states, and all the events associated to each of them.

The following is a list of the most important functions or macros defined in this library:

- ~(define-state-machine name &key start sleep)~
- ~(define-state fsm-name state-name arglist &body body)~
- ~(define-enter-state fsm-name state-name arglist &body body)~
- ~(define-fsm name &key strat sleep states ...)~
- ~(fsm-send fsm event &optional callback)~
- ~(fsm-call fsm event)~

It is required a name and the starting state to define a new FSM. The ~define-state-machine~ creates a new function called ~start-NAME~. Its ~start~ argument is a function argument and body definition used by the created function. The result of the new function must be a list ~(STATE STATE-DATA [TIMEOUT])~ which is the starting state of the machine.

See [[file:jabber.org::*jabber-connection][jabber-connection]] section for an example. Its ~:start~ parameter explicitly mentioned, and its value is a list with the arguments ( ~(username server resource ...)~ ), a docstring ( ~"Start a jabber connection."~ ) and the body of the ~start-jabber-connection~ function.

The machine requires states. They are defined with the ~define-state~ function.

** The jabber-connection FSM
:PROPERTIES:
:CUSTOM_ID: jabber-connection-fsm
:END:
jabber.el use a finite state machine (FSM) to track the current Jabber connection step. It defines a FSM called [[file:jabber.org::#fsm-connection][jabber-connection]] (or ~jc~ when it is used as parameter in functions) and several states along with their sentinels. The Org-mode tag ~:fsm:~ is used at jabber.org headlines to describe FSM definitions.

*** States
:PROPERTIES:
:CUSTOM_ID: states
:END:
The following graph shows the states and their transitions, as of commit [[https://codeberg.org/emacs-jabber/emacs-jabber/commit/dddcccb926f422b03d22a66b60db46f1266eb141][dddcccb926]] (2021-03-20). The nodes represent the states and the arrows are events.

All states have filter and sentinel events that do not change the FSM state. Also, they have a ~:do-disconnect~ event that change the FSM to the ~nil~ state except for the ~connecting~ state.

Some state changes depend on the event and the data received, in this case, the event name has a number added. For instance, ~:stream-start1~, ~:stream-start2~ and ~:stream-start3~ is the same event (~:stream-start~) but triggers different states changes depending on the data received.

#+name: fig:states
#+BEGIN_SRC graphviz-dot :file images/states-dot.png :exports results :tangle no
  digraph "jabber-connection" {
          nil;

          connecting -> connected [label=":connected"];
          connecting -> nil [label=":connection-failed"];
          connecting -> defer [label=":do-disconnect"];

          connected -> "connected" [label=":filter, :sentinel, :stream-start1,"];
          connected -> "register-account" [label=":stream-start2, :stanza1"];
          connected -> "legacy-auth" [label=":stream-start3"];
          connected -> "starttls" [label=":stanza2"];
          connected -> "sasl-auth" [label=":stanza3"];

          "register-account" -> "register-account" [label=":stanza"];

          starttls -> connected [label=":stanza"];

          "legacy-auth" -> "legacy-auth" [label=":stanza"];
          "legacy-auth" -> "session-established" [label=":authontication-success"];
          "legacy-auth" -> "nil" [label=":authentication-failure"];

          "sasl-auth" -> "sasl-auth" [label=":stanza"];
          "sasl-auth" -> "legacy-auth" [label=":use-legacy-auth-instead"];
          "sasl-auth" -> bind [label=":authentication-success"];
          "sasl-auth" -> nil [label=":authentication-failure"];

          bind -> bind [label=":stream-start, :stanza1"];
          bind -> nil [label=":stanza2, :bind-failure, :session-failure"];
          bind -> "session-established" [label=":bind-success, :session-success"];

          "session-established" -> "session-established" [label=":stanza; :roster-update, :timeout, :send-if-connected"];
  }
#+END_SRC

#+caption: Implemented states in the Jabber FSM.
#+RESULTS: fig:states
[[file:images/states-dot.png]]

** Stanza processing
:PROPERTIES:
:CUSTOM_ID: stanza-processing
:END:
The following is a brief summary about the stanza processing.

1. The ~:session-established~ state is reached.
2. The FSM receives the event ~:stanza~ at the ~:session-established~ state.
3. If no error has been found, call ~jabber-process-input~. See [[file:jabber.org::*jabber-process-input][jabber-process-input]] section.
4. Select one of the following variables depending on the type of message received: ~jabber-iq-chain~, ~jabber-presence-chain~ and ~jabber-message-chain~. All of them contains a list of functions that process its type of message.
5. Call all of their functions with the jabber connection and XML data as parameters .
6. Continue in the same state.

* How-to guides
:PROPERTIES:
:CUSTOM_ID: how-to-guides
:END:
** How to contribute to jabber.el
:PROPERTIES:
:CUSTOM_ID: how-to-contribute
:END:
# TODO - add steps for developers on Windows

1. Fork the repository, then clone your fork.
   #+BEGIN_SRC shell :tangle no
     mkdir ~/git/ && cd ~/git/
     git clone https://codeberg.org/YOUR-ACCOUNT/emacs-jabber
   #+END_SRC
   + You can also send patches to [[mailto:wgreenhouse@tilde.club][wgreenhouse@tilde.club]], using [[https://git-send-email.io/][git-send-email]]. In that case, you don't need to fork the repository or create an account.

2. Optionally, evaluate the following to install additional development tools (requires MELPA to be set up as package source) -
      #+BEGIN_SRC emacs-lisp :tangle no
        (mapcar #'package-install
                '(package-lint relint nameless))
      #+END_SRC

3. Make your edits, then run =make dev= to run the byte compiler and linters. Try to address any warnings they emit.

4. Try to follow [[https://cbea.ms/git-commit/#seven-rules][the seven rules of a great Git commit message]] in your commits.

5. Update the documentation.
   1. Add your name to the [[#contributors][list of contributors]].
   2. Document user-facing changes in [[file:CHANGELOG.org][CHANGELOG.org]] and .
   3. Update the [[file:README.org][user-facing documentation]] (this file).
      + Try to follow the [[https://diataxis.fr/][Diataxis Framework]].
   4. Update the [[file:DEV.org][developer documentation]].
      + Try to follow the [[https://diataxis.fr/][Diataxis Framework]].

6. Push and create your PR.
