Commit48ff811eRecorded20 Feb 2026Repositorysigil-xmpp

docs: Add sigil-xmpp package documentation

Changed
 docs/xmpp.md | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 351 insertions(+)
Diff
docs/xmpp.mdadded
@@ -0,0 +1,351 @@
+1
# XMPP
+2
+3
> XMPP client library with STARTTLS, SASL authentication, roster, presence, and MUC support.
+4
+5
```scheme
+6
(import (sigil xmpp))
+7
```
+8
+9
## Connecting
+10
+11
```scheme
+12
(define conn (make-xmpp-connection
+13
server: "example.com"
+15
password: "secret"
+16
resource: "bot"))
+17
+18
;; Install roster, presence, and MUC tracking
+19
(xmpp-install-features conn)
+20
+21
;; Connect (TCP -> STARTTLS -> SASL -> resource bind)
+22
(xmpp-connect conn)
+23
+24
;; Announce availability
+25
(xmpp-send-presence conn)
+26
+27
;; Run the event loop (blocks until disconnected)
+28
(xmpp-run conn)
+29
```
+30
+31
`xmpp-connect` handles the full handshake: TCP connection, STARTTLS upgrade, SASL authentication (SCRAM-SHA-1 or PLAIN), and resource binding. Returns `#t` on success, `#f` on failure.
+32
+33
`xmpp-run` processes incoming stanzas. Inside a `with-async` context it cooperates with other tasks via `await-readable`; otherwise it blocks with `socket-select`.
+34
+35
## Sending Messages
+36
+37
```scheme
+38
;; Chat message
+39
(xmpp-send conn
+40
(xmpp-message to: "[email protected]" body: "Hello!"))
+41
+42
;; Message with subject
+43
(xmpp-send conn
+44
(xmpp-message to: "[email protected]"
+45
body: "Check this out"
+46
subject: "Interesting"))
+47
```
+48
+49
## Handling Events (Callbacks)
+50
+51
Register handlers for specific event types with `xmpp-on`:
+52
+53
```scheme
+54
(xmpp-on conn 'message
+55
(lambda (stanza)
+56
(let ((body (message-body stanza))
+57
(from (stanza-from stanza)))
+58
(when (and body from)
+59
(display (string-append from ": " body "\n"))))))
+60
+61
(xmpp-on conn 'presence
+62
(lambda (stanza)
+63
(display (string-append (stanza-from stanza) " is now "
+64
(or (stanza-attr stanza 'type) "available") "\n"))))
+65
+66
(xmpp-on conn 'connected
+67
(lambda (conn)
+68
(display "Connected!\n")))
+69
+70
(xmpp-on conn 'disconnected
+71
(lambda (conn)
+72
(display "Disconnected.\n")))
+73
```
+74
+75
Event types: `message`, `presence`, `iq`, `stanza`, `connected`, `disconnected`, `error`.
+76
+77
`xmpp-on-stanza` registers a handler for all incoming stanzas regardless of type.
+78
+79
## Handling Events (Channels)
+80
+81
For sequential, composable event processing use `xmpp-channel`:
+82
+83
```scheme
+84
(import (sigil xmpp)
+85
(sigil async)
+86
(sigil channels))
+87
+88
(with-async
+89
(go (xmpp-run conn))
+90
+91
(let ((msgs (xmpp-channel conn 'message)))
+92
(for-channel msgs
+93
(lambda (stanza)
+94
(let ((body (message-body stanza)))
+95
(when body
+96
(xmpp-send conn
+97
(xmpp-message to: (stanza-from stanza)
+98
body: (string-append "Echo: " body)))))))))
+99
```
+100
+101
Channels work with `channel-receive`, `for-channel`, and `channel-select` for multiplexing:
+102
+103
```scheme
+104
(with-async
+105
(go (xmpp-run conn))
+106
+107
(let ((msgs (xmpp-channel conn 'message))
+108
(pres (xmpp-channel conn 'presence)))
+109
(let loop ()
+110
(channel-select
+111
(msgs => (lambda (s) (handle-message s)))
+112
(pres => (lambda (s) (handle-presence s))))
+113
(loop))))
+114
```
+115
+116
## IQ Requests
+117
+118
Send IQ stanzas with automatic response correlation:
+119
+120
```scheme
+121
(xmpp-send-iq conn
+122
(xmpp-iq type: "get"
+123
to: "example.com"
+124
children: (list '(query (@ (xmlns "http://jabber.org/protocol/disco#info")))))
+125
(lambda (response)
+126
(display "Got disco response\n")))
+127
```
+128
+129
The callback is invoked once when the server replies with a matching IQ result or error.
+130
+131
## Roster
+132
+133
```scheme
+134
;; Fetch the roster
+135
(xmpp-request-roster conn
+136
(lambda (items)
+137
(for-each (lambda (item)
+138
(display (string-append (roster-item-jid item) "\n")))
+139
items)))
+140
+141
;; Access cached roster (after fetch)
+142
(xmpp-roster conn) ; => list of roster-item, or #f
+143
(xmpp-roster-item conn "[email protected]") ; => roster-item or #f
+144
+145
;; Add a contact
+146
(xmpp-roster-add conn "[email protected]" name: "Friend")
+147
+148
;; Remove a contact
+149
(xmpp-roster-remove conn "[email protected]")
+150
```
+151
+152
### Roster Item Accessors
+153
+154
```scheme
+155
(roster-item-jid item) ; => "[email protected]"
+156
(roster-item-name item) ; => "Alice" or #f
+157
(roster-item-subscription item) ; => "both", "from", "to", "none"
+158
(roster-item-groups item) ; => ("Friends" "Work")
+159
```
+160
+161
### Subscriptions
+162
+163
```scheme
+164
(xmpp-subscribe conn "[email protected]")
+165
(xmpp-accept-subscription conn "[email protected]")
+166
(xmpp-deny-subscription conn "[email protected]")
+167
(xmpp-unsubscribe conn "[email protected]")
+168
```
+169
+170
## Presence
+171
+172
```scheme
+173
;; Send available presence
+174
(xmpp-send-presence conn)
+175
+176
;; Set status
+177
(xmpp-set-status conn show: "away" status: "Be right back")
+178
+179
;; Go offline and disconnect
+180
(xmpp-go-offline conn)
+181
```
+182
+183
### Querying Presence
+184
+185
With `xmpp-install-features`, presence is tracked automatically:
+186
+187
```scheme
+188
;; Get presence for a full JID
+189
(xmpp-presence-of conn "[email protected]/mobile")
+190
; => #<presence-info jid: "..." show: "available" status: #f>
+191
+192
;; Get all online resources for a bare JID
+193
(xmpp-resources-of conn "[email protected]")
+194
; => ("[email protected]/mobile" "[email protected]/laptop")
+195
```
+196
+197
### Presence Info Accessors
+198
+199
```scheme
+200
(presence-info-jid info) ; => "[email protected]/mobile"
+201
(presence-info-show info) ; => "available", "away", "dnd", "xa", "chat"
+202
(presence-info-status info) ; => "Be right back" or #f
+203
(presence-info-priority info) ; => 0
+204
```
+205
+206
## Multi-User Chat (MUC)
+207
+208
```scheme
+209
;; Join a room
+210
(xmpp-muc-join conn "[email protected]" "mynick")
+211
+212
;; Send a message to the room
+213
(xmpp-muc-message conn "[email protected]" "Hello room!")
+214
+215
;; Private message to an occupant
+216
(xmpp-muc-private-message conn "[email protected]" "alice" "Hi!")
+217
+218
;; Set room subject
+219
(xmpp-muc-set-subject conn "[email protected]" "New topic")
+220
+221
;; Leave the room
+222
(xmpp-muc-leave conn "[email protected]")
+223
```
+224
+225
### Room Administration
+226
+227
```scheme
+228
;; Kick an occupant (requires moderator role)
+229
(xmpp-muc-kick conn "[email protected]" "troublemaker"
+230
reason: "Disruptive behavior")
+231
+232
;; Invite a user
+233
(xmpp-muc-invite conn "[email protected]" "[email protected]"
+234
reason: "Come join us!")
+235
+236
;; Get current occupants
+237
(xmpp-muc-occupants conn "[email protected]")
+238
; => list of muc-occupant records
+239
```
+240
+241
### MUC Occupant Accessors
+242
+243
```scheme
+244
(muc-occupant-nick occ) ; => "alice"
+245
(muc-occupant-jid occ) ; => "[email protected]/res" or #f
+246
(muc-occupant-affiliation occ) ; => "owner", "admin", "member", "none"
+247
(muc-occupant-role occ) ; => "moderator", "participant", "visitor", "none"
+248
```
+249
+250
## JIDs
+251
+252
```scheme
+253
;; Parse a JID string
+254
(define j (parse-jid "[email protected]/mobile"))
+255
(jid-local j) ; => "user"
+256
(jid-domain j) ; => "example.com"
+257
(jid-resource j) ; => "mobile"
+258
+259
;; Convert back to string
+260
(jid->string j) ; => "[email protected]/mobile"
+261
+262
;; Bare JID (without resource)
+263
(jid-bare "[email protected]/mobile") ; => "[email protected]"
+264
(jid-bare j) ; => "[email protected]"
+265
```
+266
+267
## Stanza Constructors
+268
+269
All stanzas are represented as SXML and auto-generate unique IDs:
+270
+271
```scheme
+272
(xmpp-message to: "[email protected]" body: "Hi" type: "chat")
+273
; => (message (@ (to "[email protected]") (type "chat") (id "s1-...")) (body "Hi"))
+274
+275
(xmpp-presence show: "away" status: "BRB")
+276
; => (presence (@ (id "s2-...")) (show "away") (status "BRB"))
+277
+278
(xmpp-iq type: "get" to: "example.com"
+279
children: (list '(query (@ (xmlns "jabber:iq:roster")))))
+280
; => (iq (@ (to "example.com") (type "get") (id "s3-...")) (query ...))
+281
```
+282
+283
## Stanza Inspection
+284
+285
```scheme
+286
(stanza-type stanza) ; => message, presence, iq (symbol)
+287
(stanza-to stanza) ; => "[email protected]"
+288
(stanza-from stanza) ; => "[email protected]/res"
+289
(stanza-id stanza) ; => "s1-abc123"
+290
(stanza-attr stanza 'type) ; => "chat"
+291
(message-body stanza) ; => "Hello" or #f
+292
(stanza-child stanza 'body) ; => (body "Hello") or #f
+293
(stanza-children stanza 'item) ; => list of matching child elements
+294
```
+295
+296
## Common Patterns
+297
+298
### Echo Bot
+299
+300
```scheme
+301
(import (sigil xmpp))
+302
+303
(define conn (make-xmpp-connection
+304
server: "example.com"
+305
jid: "[email protected]"
+306
password: "secret"))
+307
+308
(xmpp-install-features conn)
+309
+310
(xmpp-on conn 'message
+311
(lambda (stanza)
+312
(let ((body (message-body stanza))
+313
(from (stanza-from stanza)))
+314
(when (and body from)
+315
(xmpp-send conn
+316
(xmpp-message to: from body: (string-append "Echo: " body)))))))
+317
+318
(xmpp-connect conn)
+319
(xmpp-send-presence conn)
+320
(xmpp-run conn)
+321
```
+322
+323
### MUC Bot with Channels
+324
+325
```scheme
+326
(import (sigil xmpp)
+327
(sigil async)
+328
(sigil channels))
+329
+330
(define conn (make-xmpp-connection
+331
server: "example.com"
+332
jid: "[email protected]"
+333
password: "secret"))
+334
+335
(xmpp-install-features conn)
+336
(xmpp-connect conn)
+337
(xmpp-send-presence conn)
+338
(xmpp-muc-join conn "[email protected]" "bot")
+339
+340
(with-async
+341
(go (xmpp-run conn))
+342
+343
(let ((msgs (xmpp-channel conn 'message)))
+344
(for-channel msgs
+345
(lambda (stanza)
+346
(when (equal? (stanza-attr stanza 'type) "groupchat")
+347
(let ((body (message-body stanza)))
+348
(when (and body (string-starts-with? body "!ping"))
+349
(xmpp-muc-message conn
+350
"[email protected]" "pong!"))))))))
+351
```