# Events `src/event/` mediates between the XMPP protocol layer and consumers (UI, config, chatlog). Two main directions plus one common module. ## Files | File | Purpose | |---|---| | `server_events.c/h` | `sv_ev_*` — events triggered by inbound stanzas. | | `client_events.c/h` | `cl_ev_*` — events triggered locally (UI / commands). | | `common.c/h` | Shared helpers used by both. | ## Server events (`sv_ev_*`) Called from `src/xmpp/` parsers (`message.c`, `presence.c`, `iq.c`, `muc.c`, `roster.c`) once a stanza has been validated and decomposed. Each `sv_ev_*`: 1. Updates persistent state (chatlog, roster, accounts). 2. Pushes UI updates (`chatwin_*`, `mucwin_*`, `cons_*`, `console_*`). 3. May invoke plugin callbacks (`src/plugins/callbacks.c`). Examples (current symbols, grep `sv_ev_` in `server_events.c`): - `sv_ev_incoming_message` — chat message arrived. - `sv_ev_room_message` — MUC message. - `sv_ev_presence_update` — presence change. - `sv_ev_roster_received` — roster pushed by server. ## Client events (`cl_ev_*`) Called from `cmd_funcs.c` and UI code when the user does something locally that needs the same downstream fan-out as a server event. Examples: - `cl_ev_send_msg` — outgoing chat message. - `cl_ev_send_presence` — presence update from `/status` or autoaway. - `cl_ev_disconnect` — `/disconnect` initiated locally. ## Adding an event handler 1. Decide direction: inbound (server) or outbound (client). 2. Add `sv_ev_` or `cl_ev_` in the matching `.c` and declare in the matching `.h`. 3. Call it from the trigger site (a parser in `src/xmpp/` for server events; a command handler or UI input handler for client events). 4. Inside, perform the fan-out: state update → UI → plugin callback. 5. If unit-tested, add a stub for it in `tests/unittests/event/stub_*.c` (or extend the existing stub). See `playbooks/add-event-handler.md`. ## Conventions - Keep XMPP-protocol concerns in `src/xmpp/`. The event module is a *dispatcher*, not a parser. - Keep UI rendering decisions in `src/ui/`. The event module *invokes* UI functions but does not draw. - Plugin callbacks are the **last** step — state must already be consistent before they run, since plugins may re-enter the codebase.