AtlatestRepositorysigil-xmpp
sigil-xmpp / tree / docsxmpp.md
1
# XMPP3
> XMPP client library with STARTTLS, SASL authentication, roster, presence, and MUC support.5
```scheme6
(import (sigil xmpp))7
```9
## Connecting11
```scheme12
(define conn (make-xmpp-connection13
server: "example.com"14
jid: "[email protected]"15
password: "secret"16
resource: "bot"))18
;; Install roster, presence, and MUC tracking19
(xmpp-install-features conn)21
;; Connect (TCP -> STARTTLS -> SASL -> resource bind)22
(xmpp-connect conn)24
;; Announce availability25
(xmpp-send-presence conn)27
;; Run the event loop (blocks until disconnected)28
(xmpp-run conn)29
```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.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`.35
## Sending Messages37
```scheme38
;; Chat message39
(xmpp-send conn40
(xmpp-message to: "[email protected]" body: "Hello!"))42
;; Message with subject43
(xmpp-send conn44
(xmpp-message to: "[email protected]"45
body: "Check this out"46
subject: "Interesting"))47
```49
## Handling Events (Callbacks)51
Register handlers for specific event types with `xmpp-on`:53
```scheme54
(xmpp-on conn 'message55
(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"))))))61
(xmpp-on conn 'presence62
(lambda (stanza)63
(display (string-append (stanza-from stanza) " is now "64
(or (stanza-attr stanza 'type) "available") "\n"))))66
(xmpp-on conn 'connected67
(lambda (conn)68
(display "Connected!\n")))70
(xmpp-on conn 'disconnected71
(lambda (conn)72
(display "Disconnected.\n")))73
```75
Event types: `message`, `presence`, `iq`, `stanza`, `connected`, `disconnected`, `error`.77
`xmpp-on-stanza` registers a handler for all incoming stanzas regardless of type.79
## Handling Events (Channels)81
For sequential, composable event processing use `xmpp-channel`:83
```scheme84
(import (sigil xmpp)85
(sigil async)86
(sigil channels))88
(with-async89
(go (xmpp-run conn))91
(let ((msgs (xmpp-channel conn 'message)))92
(for-channel msgs93
(lambda (stanza)94
(let ((body (message-body stanza)))95
(when body96
(xmpp-send conn97
(xmpp-message to: (stanza-from stanza)98
body: (string-append "Echo: " body)))))))))99
```101
Channels work with `channel-receive`, `for-channel`, and `channel-select` for multiplexing:103
```scheme104
(with-async105
(go (xmpp-run conn))107
(let ((msgs (xmpp-channel conn 'message))108
(pres (xmpp-channel conn 'presence)))109
(let loop ()110
(channel-select111
(msgs => (lambda (s) (handle-message s)))112
(pres => (lambda (s) (handle-presence s))))113
(loop))))114
```116
## IQ Requests118
Send IQ stanzas with automatic response correlation:120
```scheme121
(xmpp-send-iq conn122
(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
```129
The callback is invoked once when the server replies with a matching IQ result or error.131
## Roster133
```scheme134
;; Fetch the roster135
(xmpp-request-roster conn136
(lambda (items)137
(for-each (lambda (item)138
(display (string-append (roster-item-jid item) "\n")))139
items)))141
;; Access cached roster (after fetch)142
(xmpp-roster conn) ; => list of roster-item, or #f143
(xmpp-roster-item conn "[email protected]") ; => roster-item or #f145
;; Add a contact146
(xmpp-roster-add conn "[email protected]" name: "Friend")148
;; Remove a contact149
(xmpp-roster-remove conn "[email protected]")150
```152
### Roster Item Accessors154
```scheme155
(roster-item-jid item) ; => "[email protected]"156
(roster-item-name item) ; => "Alice" or #f157
(roster-item-subscription item) ; => "both", "from", "to", "none"158
(roster-item-groups item) ; => ("Friends" "Work")159
```161
### Subscriptions163
```scheme164
(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
```170
## Presence172
```scheme173
;; Send available presence174
(xmpp-send-presence conn)176
;; Set status177
(xmpp-set-status conn show: "away" status: "Be right back")179
;; Go offline and disconnect180
(xmpp-go-offline conn)181
```183
### Querying Presence185
With `xmpp-install-features`, presence is tracked automatically:187
```scheme188
;; Get presence for a full JID189
(xmpp-presence-of conn "[email protected]/mobile")190
; => #<presence-info jid: "..." show: "available" status: #f>192
;; Get all online resources for a bare JID193
(xmpp-resources-of conn "[email protected]")194
; => ("[email protected]/mobile" "[email protected]/laptop")195
```197
### Presence Info Accessors199
```scheme200
(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 #f203
(presence-info-priority info) ; => 0204
```206
## Multi-User Chat (MUC)208
```scheme209
;; Join a room210
(xmpp-muc-join conn "[email protected]" "mynick")212
;; Send a message to the room213
(xmpp-muc-message conn "[email protected]" "Hello room!")215
;; Private message to an occupant216
(xmpp-muc-private-message conn "[email protected]" "alice" "Hi!")218
;; Set room subject219
(xmpp-muc-set-subject conn "[email protected]" "New topic")221
;; Leave the room222
(xmpp-muc-leave conn "[email protected]")223
```225
### Room Administration227
```scheme228
;; Kick an occupant (requires moderator role)229
(xmpp-muc-kick conn "[email protected]" "troublemaker"230
reason: "Disruptive behavior")232
;; Invite a user233
(xmpp-muc-invite conn "[email protected]" "[email protected]"234
reason: "Come join us!")236
;; Get current occupants237
(xmpp-muc-occupants conn "[email protected]")238
; => list of muc-occupant records239
```241
### MUC Occupant Accessors243
```scheme244
(muc-occupant-nick occ) ; => "alice"245
(muc-occupant-jid occ) ; => "[email protected]/res" or #f246
(muc-occupant-affiliation occ) ; => "owner", "admin", "member", "none"247
(muc-occupant-role occ) ; => "moderator", "participant", "visitor", "none"248
```250
## JIDs252
```scheme253
;; Parse a JID string254
(define j (parse-jid "[email protected]/mobile"))255
(jid-local j) ; => "user"256
(jid-domain j) ; => "example.com"257
(jid-resource j) ; => "mobile"259
;; Convert back to string260
(jid->string j) ; => "[email protected]/mobile"262
;; Bare JID (without resource)263
(jid-bare "[email protected]/mobile") ; => "[email protected]"264
(jid-bare j) ; => "[email protected]"265
```267
## Stanza Constructors269
All stanzas are represented as SXML and auto-generate unique IDs:271
```scheme272
(xmpp-message to: "[email protected]" body: "Hi" type: "chat")273
; => (message (@ (to "[email protected]") (type "chat") (id "s1-...")) (body "Hi"))275
(xmpp-presence show: "away" status: "BRB")276
; => (presence (@ (id "s2-...")) (show "away") (status "BRB"))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
```283
## Stanza Inspection285
```scheme286
(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 #f292
(stanza-child stanza 'body) ; => (body "Hello") or #f293
(stanza-children stanza 'item) ; => list of matching child elements294
```296
## Common Patterns298
### Echo Bot300
```scheme301
(import (sigil xmpp))303
(define conn (make-xmpp-connection304
server: "example.com"305
jid: "[email protected]"306
password: "secret"))308
(xmpp-install-features conn)310
(xmpp-on conn 'message311
(lambda (stanza)312
(let ((body (message-body stanza))313
(from (stanza-from stanza)))314
(when (and body from)315
(xmpp-send conn316
(xmpp-message to: from body: (string-append "Echo: " body)))))))318
(xmpp-connect conn)319
(xmpp-send-presence conn)320
(xmpp-run conn)321
```323
### MUC Bot with Channels325
```scheme326
(import (sigil xmpp)327
(sigil async)328
(sigil channels))330
(define conn (make-xmpp-connection331
server: "example.com"332
jid: "[email protected]"333
password: "secret"))335
(xmpp-install-features conn)336
(xmpp-connect conn)337
(xmpp-send-presence conn)338
(xmpp-muc-join conn "[email protected]" "bot")340
(with-async341
(go (xmpp-run conn))343
(let ((msgs (xmpp-channel conn 'message)))344
(for-channel msgs345
(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 conn350
"[email protected]" "pong!"))))))))351
```