Add config for glangci-lint, lint, handle "wire" errors fo auth procedure

This commit is contained in:
Sergei
2023-09-24 14:06:38 -07:00
parent af169899cd
commit 6c0bb895d9
12 changed files with 679 additions and 225 deletions

66
.golangci.yml Normal file
View File

@@ -0,0 +1,66 @@
run:
tests: false
skip-dirs:
- _example
modules-download-mode: readonly
allow-parallel-runners: true
go: '1.21'
output:
sort-results: true
linters-settings:
gosec:
excludes:
# Оно не используется для повышения безопасности или каких-то таких секъюрых вещей, оно используется для выборки
# произвольного элемента из массива, так что ИДИ НАХУЙ с этой проверкой и не еби мозги липовой безопасностью.
- G404 # Insecure random number source (rand)
linters:
disable-all: true
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unused
- asasalint
- asciicheck
- bodyclose
- containedctx
- contextcheck
- decorder
- durationcheck
- errchkjson
- errorlint
- exhaustive
- exportloopref
- gci
- ginkgolinter
- gocheckcompilerdirectives
- gocritic
- godot
- gofmt
- goimports
- gosec
- gosmopolitan
- grouper
- importas
- ireturn
- makezero
- mirror
- nakedret
- nilerr
- nilnil
- nlreturn
- noctx
- nolintlint
- nonamedreturns
- predeclared
- promlinter
- reassign
- revive
- rowserrcheck
- stylecheck
- unconvert
- wastedassign
- whitespace
- wsl

View File

@@ -3,12 +3,12 @@ go-xmpp
go xmpp library. go xmpp library.
[Original](https://github.com/rsc/rsc/blob/master/xmpp/xmpp.go) was done by [Russ Cox](https://github.com/rsc), then [Original](https://github.com/rsc/rsc/blob/master/xmpp/xmpp.go) work done by [Russ Cox](https://github.com/rsc),
forked by [Yasuhiro Matsumoto](https://github.com/mattn). then [Yasuhiro Matsumoto](https://github.com/mattn) fork it and continue to improve it.
Since both of them have amost zero interest in continuing develop of this lib, i decide to fork it. Since both of them have almost zero interest to continue develop this lib, I decide to fork it.
Documentation can be found at [godoc project](https://godoc.org/github.com/eleksir/go-xmpp) Documentation can be found at [godoc project](https://godoc.org/github.com/eleksir/go-xmpp)
This fork mainains my needs for xmpp protocol. Feel free to contribute via PR-s if you find it interesing too and feel This fork maintains my needs for xmpp protocol. Feel free to contribute via PR-s if you find it interesting too and feel
that it needs more love than it already has. that it needs more love than it already has. And of course fell free to for it if needed.

5
go.mod
View File

@@ -2,4 +2,7 @@ module github.com/eleksir/go-xmpp
go 1.20 go 1.20
require golang.org/x/crypto v0.10.0 require (
golang.org/x/crypto v0.10.0
golang.org/x/text v0.10.0
)

2
go.sum
View File

@@ -1,2 +1,4 @@
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=

672
xmpp.go

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
package xmpp package xmpp
import ( import (
"crypto/sha1" "crypto/sha1" //nolint:gosec // go fuck yourself, gosec. You don't even fucking read rfc. So shout the fuck up.
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"encoding/xml" "encoding/xml"
@@ -10,8 +10,8 @@ import (
) )
const ( const (
XMPPNS_AVATAR_PEP_DATA = "urn:xmpp:avatar:data" XMPPNS_AVATAR_PEP_DATA = "urn:xmpp:avatar:data" //nocritic:revive
XMPPNS_AVATAR_PEP_METADATA = "urn:xmpp:avatar:metadata" XMPPNS_AVATAR_PEP_METADATA = "urn:xmpp:avatar:metadata" //nocritic:revive
) )
type clientAvatarData struct { type clientAvatarData struct {
@@ -52,8 +52,8 @@ type AvatarMetadata struct {
func handleAvatarData(itemsBody []byte, from, id string) (AvatarData, error) { func handleAvatarData(itemsBody []byte, from, id string) (AvatarData, error) {
var data clientAvatarData var data clientAvatarData
err := xml.Unmarshal(itemsBody, &data)
if err != nil { if err := xml.Unmarshal(itemsBody, &data); err != nil {
return AvatarData{}, err return AvatarData{}, err
} }
@@ -64,8 +64,9 @@ func handleAvatarData(itemsBody []byte, from, id string) (AvatarData, error) {
return AvatarData{}, err return AvatarData{}, err
} }
hash := sha1.Sum(dataRaw) hash := sha1.Sum(dataRaw) //nolint:gosec // go fuck yourself, gosec. This exact mechanics described in standard.
hashStr := hex.EncodeToString(hash[:]) hashStr := hex.EncodeToString(hash[:])
if hashStr != id { if hashStr != id {
return AvatarData{}, errors.New("SHA1 hashes do not match") return AvatarData{}, errors.New("SHA1 hashes do not match")
} }
@@ -77,9 +78,12 @@ func handleAvatarData(itemsBody []byte, from, id string) (AvatarData, error) {
} }
func handleAvatarMetadata(body []byte, from string) (AvatarMetadata, error) { func handleAvatarMetadata(body []byte, from string) (AvatarMetadata, error) {
var meta clientAvatarMetadata var (
err := xml.Unmarshal(body, &meta) meta clientAvatarMetadata
if err != nil { err error
)
if err = xml.Unmarshal(body, &meta); err != nil {
return AvatarMetadata{}, err return AvatarMetadata{}, err
} }
@@ -91,10 +95,10 @@ func handleAvatarMetadata(body []byte, from string) (AvatarMetadata, error) {
ID: meta.Info.ID, ID: meta.Info.ID,
Type: meta.Info.Type, Type: meta.Info.Type,
URL: meta.Info.URL, URL: meta.Info.URL,
}, nil }, err
} }
// A wrapper for atoi which just returns -1 if an error occurs // atoiw is a wrapper for atoi which just returns -1 if an error occurs.
func atoiw(str string) int { func atoiw(str string) int {
i, err := strconv.Atoi(str) i, err := strconv.Atoi(str)
if err != nil { if err != nil {
@@ -104,22 +108,22 @@ func atoiw(str string) int {
return i return i
} }
func (c *Client) AvatarSubscribeMetadata(jid string) { func (c *Client) AvatarSubscribeMetadata(jid string) (string, error) {
c.PubsubSubscribeNode(XMPPNS_AVATAR_PEP_METADATA, jid) return c.PubsubSubscribeNode(XMPPNS_AVATAR_PEP_METADATA, jid)
} }
func (c *Client) AvatarUnsubscribeMetadata(jid string) { func (c *Client) AvatarUnsubscribeMetadata(jid string) (string, error) {
c.PubsubUnsubscribeNode(XMPPNS_AVATAR_PEP_METADATA, jid) return c.PubsubUnsubscribeNode(XMPPNS_AVATAR_PEP_METADATA, jid)
} }
func (c *Client) AvatarRequestData(jid string) { func (c *Client) AvatarRequestData(jid string) (string, error) {
c.PubsubRequestLastItems(XMPPNS_AVATAR_PEP_DATA, jid) return c.PubsubRequestLastItems(XMPPNS_AVATAR_PEP_DATA, jid)
} }
func (c *Client) AvatarRequestDataByID(jid, id string) { func (c *Client) AvatarRequestDataByID(jid, id string) (string, error) {
c.PubsubRequestItem(XMPPNS_AVATAR_PEP_DATA, jid, id) return c.PubsubRequestItem(XMPPNS_AVATAR_PEP_DATA, jid, id)
} }
func (c *Client) AvatarRequestMetadata(jid string) { func (c *Client) AvatarRequestMetadata(jid string) (string, error) {
c.PubsubRequestLastItems(XMPPNS_AVATAR_PEP_METADATA, jid) return c.PubsubRequestLastItems(XMPPNS_AVATAR_PEP_METADATA, jid)
} }

View File

@@ -5,8 +5,8 @@ import (
) )
const ( const (
XMPPNS_DISCO_ITEMS = "http://jabber.org/protocol/disco#items" XMPPNS_DISCO_ITEMS = "http://jabber.org/protocol/disco#items" //nocritic:revive
XMPPNS_DISCO_INFO = "http://jabber.org/protocol/disco#info" XMPPNS_DISCO_INFO = "http://jabber.org/protocol/disco#info" //nocritic:revive
) )
type clientDiscoFeature struct { type clientDiscoFeature struct {
@@ -90,6 +90,7 @@ func clientIdentitiesToReturn(identities []clientDiscoIdentity) []DiscoIdentity
func clientDiscoItemsToReturn(items []clientDiscoItem) []DiscoItem { func clientDiscoItemsToReturn(items []clientDiscoItem) []DiscoItem {
var ret []DiscoItem var ret []DiscoItem
for _, item := range items { for _, item := range items {
ret = append(ret, DiscoItem{ ret = append(ret, DiscoItem{
Jid: item.Jid, Jid: item.Jid,

View File

@@ -14,22 +14,25 @@ const IQTypeError = "error"
func (c *Client) Discovery() (string, error) { func (c *Client) Discovery() (string, error) {
// use getCookie for a pseudo random id. // use getCookie for a pseudo random id.
reqID := strconv.FormatUint(uint64(getCookie()), 10) reqID := strconv.FormatUint(uint64(getCookie()), 10)
return c.RawInformationQuery(c.jid, c.domain, reqID, IQTypeGet, XMPPNS_DISCO_ITEMS, "") return c.RawInformationQuery(c.jid, c.domain, reqID, IQTypeGet, XMPPNS_DISCO_ITEMS, "")
} }
// DiscoverNodeInfo discovers information about a node. Empty node queries info about server itself. // DiscoverNodeInfo discovers information about a node. Empty node queries info about server itself.
func (c *Client) DiscoverNodeInfo(node string) (string, error) { func (c *Client) DiscoverNodeInfo(node string) (string, error) {
query := fmt.Sprintf("<query xmlns='%s' node='%s'/>", XMPPNS_DISCO_INFO, node) query := fmt.Sprintf("<query xmlns='%s' node='%s'/>", XMPPNS_DISCO_INFO, node)
return c.RawInformation(c.jid, c.domain, "info3", IQTypeGet, query) return c.RawInformation(c.jid, c.domain, "info3", IQTypeGet, query)
} }
// DiscoverInfo discovers information about given item from given jid. // DiscoverInfo discovers information about given item from given jid.
func (c *Client) DiscoverInfo(from string, to string) (string, error) { func (c *Client) DiscoverInfo(from string, to string) (string, error) {
query := fmt.Sprintf("<query xmlns='%s'/>", XMPPNS_DISCO_INFO) query := fmt.Sprintf("<query xmlns='%s'/>", XMPPNS_DISCO_INFO)
return c.RawInformation(from, to, "info3", IQTypeGet, query) return c.RawInformation(from, to, "info3", IQTypeGet, query)
} }
// DiscoverServerItems discover items that the server exposes // DiscoverServerItems discover items that the server exposes.
func (c *Client) DiscoverServerItems() (string, error) { func (c *Client) DiscoverServerItems() (string, error) {
return c.DiscoverEntityItems(c.domain) return c.DiscoverEntityItems(c.domain)
} }
@@ -37,6 +40,7 @@ func (c *Client) DiscoverServerItems() (string, error) {
// DiscoverEntityItems discovers items that an entity exposes. // DiscoverEntityItems discovers items that an entity exposes.
func (c *Client) DiscoverEntityItems(jid string) (string, error) { func (c *Client) DiscoverEntityItems(jid string) (string, error) {
query := fmt.Sprintf("<query xmlns='%s'/>", XMPPNS_DISCO_ITEMS) query := fmt.Sprintf("<query xmlns='%s'/>", XMPPNS_DISCO_ITEMS)
return c.RawInformation(c.jid, jid, "info1", IQTypeGet, query) return c.RawInformation(c.jid, jid, "info1", IQTypeGet, query)
} }
@@ -44,6 +48,7 @@ func (c *Client) DiscoverEntityItems(jid string) (string, error) {
func (c *Client) RawInformationQuery(from, to, id, iqType, requestNamespace, body string) (string, error) { func (c *Client) RawInformationQuery(from, to, id, iqType, requestNamespace, body string) (string, error) {
const xmlIQ = "<iq from='%s' to='%s' id='%s' type='%s'><query xmlns='%s'>%s</query></iq>" const xmlIQ = "<iq from='%s' to='%s' id='%s' type='%s'><query xmlns='%s'>%s</query></iq>"
_, err := fmt.Fprintf(StanzaWriter, xmlIQ, xmlEscape(from), xmlEscape(to), id, iqType, requestNamespace, body) _, err := fmt.Fprintf(StanzaWriter, xmlIQ, xmlEscape(from), xmlEscape(to), id, iqType, requestNamespace, body)
return id, err return id, err
} }
@@ -51,6 +56,7 @@ func (c *Client) RawInformationQuery(from, to, id, iqType, requestNamespace, bod
func (c *Client) RawInformation(from, to, id, iqType, body string) (string, error) { func (c *Client) RawInformation(from, to, id, iqType, body string) (string, error) {
const xmlIQ = "<iq from='%s' to='%s' id='%s' type='%s'>%s</iq>" const xmlIQ = "<iq from='%s' to='%s' id='%s' type='%s'>%s</iq>"
_, err := fmt.Fprintf(StanzaWriter, xmlIQ, xmlEscape(from), xmlEscape(to), id, iqType, body) _, err := fmt.Fprintf(StanzaWriter, xmlIQ, xmlEscape(from), xmlEscape(to), id, iqType, body)
return id, err return id, err
} }
@@ -64,7 +70,7 @@ func (c *Client) IqVersionResponse(v IQ, name, version, os string) (string, erro
version = "undefined" version = "undefined"
} }
query := "<query xmlns=\"jabber:iq:version\">" //nolint:wsl query := "<query xmlns=\"jabber:iq:version\">"
query += fmt.Sprintf("<name>%s</name>", name) query += fmt.Sprintf("<name>%s</name>", name)
query += fmt.Sprintf("<version>%s</version>", version) query += fmt.Sprintf("<version>%s</version>", version)
@@ -100,9 +106,9 @@ func (c *Client) JabberIqLastResponse(v IQ, lastActivity int64) (string, error)
) )
} }
// UrnXmppTimeResponse implements response to query entity's current time (xep-0202). // UrnXMPPTimeResponse implements response to query entity's current time (xep-0202).
// TimezoneOffset have format +HH:MM or -HH:MM // TimezoneOffset have format +HH:MM or -HH:MM.
func (c *Client) UrnXmppTimeResponse(v IQ, timezoneOffset string) (string, error) { func (c *Client) UrnXMPPTimeResponse(v IQ, timezoneOffset string) (string, error) {
query := fmt.Sprintf( query := fmt.Sprintf(
"<time xmlns=\"urn:xmpp:time\"><tzo>%s</tzo><utc>%s</utc></time>", "<time xmlns=\"urn:xmpp:time\"><tzo>%s</tzo><utc>%s</utc></time>",
timezoneOffset, timezoneOffset,

View File

@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// TODO(flo): // TODO(flo):
// - support password protected MUC rooms
// - cleanup signatures of join/leave functions // - cleanup signatures of join/leave functions
package xmpp package xmpp
@@ -23,16 +22,18 @@ const (
SinceHistory = 4 SinceHistory = 4
) )
// Send sends room topic wrapped inside an XMPP message stanza body. // SendTopic sends room topic wrapped inside an XMPP message stanza body.
func (c *Client) SendTopic(chat Chat) (n int, err error) { func (c *Client) SendTopic(chat Chat) (int, error) {
return fmt.Fprintf(StanzaWriter, "<message to='%s' type='%s' xml:lang='en'>"+"<subject>%s</subject></message>", return fmt.Fprintf(StanzaWriter, "<message to='%s' type='%s' xml:lang='en'>"+"<subject>%s</subject></message>",
xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text)) xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
} }
func (c *Client) JoinMUCNoHistory(jid, nick string) (n int, err error) { // JoinMUCNoHistory joins room and instructs server that no history data required.
func (c *Client) JoinMUCNoHistory(jid, nick string) (int, error) {
if nick == "" { if nick == "" {
nick = c.jid nick = c.jid
} }
return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+ return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+
"<x xmlns='%s'>"+ "<x xmlns='%s'>"+
"<history maxchars='0'/></x>\n"+ "<history maxchars='0'/></x>\n"+
@@ -40,12 +41,13 @@ func (c *Client) JoinMUCNoHistory(jid, nick string) (n int, err error) {
xmlEscape(jid), xmlEscape(nick), nsMUC) xmlEscape(jid), xmlEscape(nick), nsMUC)
} }
// xep-0045 7.2 // JoinMUC joins room, xep-0045 7.2.
func (c *Client) JoinMUC(jid, nick string, history_type, history int, history_date *time.Time) (n int, err error) { func (c *Client) JoinMUC(jid, nick string, historyType, history int, historyDate *time.Time) (int, error) {
if nick == "" { if nick == "" {
nick = c.jid nick = c.jid
} }
switch history_type {
switch historyType {
case NoHistory: case NoHistory:
return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+ return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+
"<x xmlns='%s' />\n"+ "<x xmlns='%s' />\n"+
@@ -70,23 +72,25 @@ func (c *Client) JoinMUC(jid, nick string, history_type, history int, history_da
"</presence>", "</presence>",
xmlEscape(jid), xmlEscape(nick), nsMUC, history) xmlEscape(jid), xmlEscape(nick), nsMUC, history)
case SinceHistory: case SinceHistory:
if history_date != nil { if historyDate != nil {
return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+ return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+
"<x xmlns='%s'>\n"+ "<x xmlns='%s'>\n"+
"<history since='%s'/></x>\n"+ "<history since='%s'/></x>\n"+
"</presence>", "</presence>",
xmlEscape(jid), xmlEscape(nick), nsMUC, history_date.Format(time.RFC3339)) xmlEscape(jid), xmlEscape(nick), nsMUC, historyDate.Format(time.RFC3339))
} }
} }
return 0, errors.New("Unknown history option")
return 0, errors.New("unknown history option")
} }
// xep-0045 7.2.6 // JoinProtectedMUC joins password protected room, xep-0045 7.2.6.
func (c *Client) JoinProtectedMUC(jid, nick string, password string, history_type, history int, history_date *time.Time) (n int, err error) { func (c *Client) JoinProtectedMUC(jid, nick string, password string, historyType, history int, historyDate *time.Time) (int, error) {
if nick == "" { if nick == "" {
nick = c.jid nick = c.jid
} }
switch history_type {
switch historyType {
case NoHistory: case NoHistory:
return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+ return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+
"<x xmlns='%s'>\n"+ "<x xmlns='%s'>\n"+
@@ -116,20 +120,21 @@ func (c *Client) JoinProtectedMUC(jid, nick string, password string, history_typ
"</presence>", "</presence>",
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history) xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history)
case SinceHistory: case SinceHistory:
if history_date != nil { if historyDate != nil {
return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+ return fmt.Fprintf(StanzaWriter, "<presence to='%s/%s'>\n"+
"<x xmlns='%s'>\n"+ "<x xmlns='%s'>\n"+
"<password>%s</password>\n"+ "<password>%s</password>\n"+
"<history since='%s'/></x>\n"+ "<history since='%s'/></x>\n"+
"</presence>", "</presence>",
xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), history_date.Format(time.RFC3339)) xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password), historyDate.Format(time.RFC3339))
} }
} }
return 0, errors.New("Unknown history option")
return 0, errors.New("unknown history option")
} }
// xep-0045 7.14 // LeaveMUC quits from room xep-0045 7.14.
func (c *Client) LeaveMUC(jid string) (n int, err error) { func (c *Client) LeaveMUC(jid string) (int, error) {
return fmt.Fprintf(StanzaWriter, "<presence from='%s' to='%s' type='unavailable' />", return fmt.Fprintf(StanzaWriter, "<presence from='%s' to='%s' type='unavailable' />",
c.jid, xmlEscape(jid)) c.jid, xmlEscape(jid))
} }

View File

@@ -8,13 +8,16 @@ func (c *Client) PingC2S(jid, server string) error {
if jid == "" { if jid == "" {
jid = c.jid jid = c.jid
} }
if server == "" { if server == "" {
server = c.domain server = c.domain
} }
_, err := fmt.Fprintf(StanzaWriter, "<iq from='%s' to='%s' id='c2s1' type='get'>\n"+ _, err := fmt.Fprintf(StanzaWriter, "<iq from='%s' to='%s' id='c2s1' type='get'>\n"+
"<ping xmlns='urn:xmpp:ping'/>\n"+ "<ping xmlns='urn:xmpp:ping'/>\n"+
"</iq>", "</iq>",
xmlEscape(jid), xmlEscape(server)) xmlEscape(jid), xmlEscape(server))
return err return err
} }
@@ -23,16 +26,18 @@ func (c *Client) PingS2S(fromServer, toServer string) error {
"<ping xmlns='urn:xmpp:ping'/>\n"+ "<ping xmlns='urn:xmpp:ping'/>\n"+
"</iq>", "</iq>",
xmlEscape(fromServer), xmlEscape(toServer)) xmlEscape(fromServer), xmlEscape(toServer))
return err return err
} }
func (c *Client) SendResultPing(id, toServer string) error { func (c *Client) SendResultPing(id, toServer string) error {
_, err := fmt.Fprintf(StanzaWriter, "<iq type='result' to='%s' id='%s'/>", _, err := fmt.Fprintf(StanzaWriter, "<iq type='result' to='%s' id='%s'/>",
xmlEscape(toServer), xmlEscape(id)) xmlEscape(toServer), xmlEscape(id))
return err return err
} }
// PingResponse responding to ping query according to xep-0199 // PingResponse responding to ping query according to xep-0199.
func (c *Client) PingResponse(v IQ) (string, error) { func (c *Client) PingResponse(v IQ) (string, error) {
return c.RawInformation( return c.RawInformation(
v.To, v.To,

View File

@@ -6,8 +6,8 @@ import (
) )
const ( const (
XMPPNS_PUBSUB = "http://jabber.org/protocol/pubsub" XMPPNS_PUBSUB = "http://jabber.org/protocol/pubsub" //nolint:revive
XMPPNS_PUBSUB_EVENT = "http://jabber.org/protocol/pubsub#event" XMPPNS_PUBSUB_EVENT = "http://jabber.org/protocol/pubsub#event" //nolint:revive
) )
type clientPubsubItem struct { type clientPubsubItem struct {
@@ -67,7 +67,7 @@ type PubsubItems struct {
Items []PubsubItem Items []PubsubItem
} }
// Converts []clientPubsubItem to []PubsubItem // Converts []clientPubsubItem to []PubsubItem.
func pubsubItemsToReturn(items []clientPubsubItem) []PubsubItem { func pubsubItemsToReturn(items []clientPubsubItem) []PubsubItem {
var tmp []PubsubItem var tmp []PubsubItem
for _, i := range items { for _, i := range items {
@@ -96,6 +96,7 @@ func pubsubSubscriptionStanza(node, jid string) string {
body := fmt.Sprintf("<subscribe node='%s' jid='%s'/>", body := fmt.Sprintf("<subscribe node='%s' jid='%s'/>",
xmlEscape(node), xmlEscape(node),
xmlEscape(jid)) xmlEscape(jid))
return pubsubStanza(body) return pubsubStanza(body)
} }
@@ -103,6 +104,7 @@ func pubsubUnsubscriptionStanza(node, jid string) string {
body := fmt.Sprintf("<unsubscribe node='%s' jid='%s'/>", body := fmt.Sprintf("<unsubscribe node='%s' jid='%s'/>",
xmlEscape(node), xmlEscape(node),
xmlEscape(jid)) xmlEscape(jid))
return pubsubStanza(body) return pubsubStanza(body)
} }
@@ -124,10 +126,12 @@ func (c *Client) PubsubUnsubscribeNode(node, jid string) (string, error) {
func (c *Client) PubsubRequestLastItems(node, jid string) (string, error) { func (c *Client) PubsubRequestLastItems(node, jid string) (string, error) {
body := fmt.Sprintf("<items node='%s'/>", node) body := fmt.Sprintf("<items node='%s'/>", node)
return c.RawInformation(c.jid, jid, "items1", "get", pubsubStanza(body)) return c.RawInformation(c.jid, jid, "items1", "get", pubsubStanza(body))
} }
func (c *Client) PubsubRequestItem(node, jid, id string) (string, error) { func (c *Client) PubsubRequestItem(node, jid, id string) (string, error) {
body := fmt.Sprintf("<items node='%s'><item id='%s'/></items>", node, id) body := fmt.Sprintf("<items node='%s'><item id='%s'/></items>", node, id)
return c.RawInformation(c.jid, jid, "items3", "get", pubsubStanza(body)) return c.RawInformation(c.jid, jid, "items3", "get", pubsubStanza(body))
} }

View File

@@ -4,22 +4,30 @@ import (
"fmt" "fmt"
) )
func (c *Client) ApproveSubscription(jid string) { func (c *Client) ApproveSubscription(jid string) error {
fmt.Fprintf(StanzaWriter, "<presence to='%s' type='subscribed'/>", _, err := fmt.Fprintf(StanzaWriter, "<presence to='%s' type='subscribed'/>",
xmlEscape(jid)) xmlEscape(jid))
return err
} }
func (c *Client) RevokeSubscription(jid string) { func (c *Client) RevokeSubscription(jid string) error {
fmt.Fprintf(StanzaWriter, "<presence to='%s' type='unsubscribed'/>", _, err := fmt.Fprintf(StanzaWriter, "<presence to='%s' type='unsubscribed'/>",
xmlEscape(jid)) xmlEscape(jid))
return err
} }
func (c *Client) RetrieveSubscription(jid string) { func (c *Client) RetrieveSubscription(jid string) error {
fmt.Fprintf(c.conn, "<presence to='%s' type='unsubscribe'/>", _, err := fmt.Fprintf(c.conn, "<presence to='%s' type='unsubscribe'/>",
xmlEscape(jid)) xmlEscape(jid))
return err
} }
func (c *Client) RequestSubscription(jid string) { func (c *Client) RequestSubscription(jid string) error {
fmt.Fprintf(StanzaWriter, "<presence to='%s' type='subscribe'/>", _, err := fmt.Fprintf(StanzaWriter, "<presence to='%s' type='subscribe'/>",
xmlEscape(jid)) xmlEscape(jid))
return err
} }