forked from jshiffer/go-xmpp
Fetch latest changes
This commit is contained in:
@@ -32,8 +32,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *username == "" || *password == "" {
|
if *username == "" || *password == "" {
|
||||||
|
if *debug && *username == "" && *password == "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "no username or password were given; attempting ANONYMOUS auth\n")
|
||||||
|
} else if *username != "" || *password != "" {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !*notls {
|
if !*notls {
|
||||||
xmpp.DefaultConfig = tls.Config{
|
xmpp.DefaultConfig = tls.Config{
|
||||||
|
|||||||
65
xmpp.go
65
xmpp.go
@@ -273,11 +273,14 @@ func (c *Client) init(o *Options) error {
|
|||||||
c.p = xml.NewDecoder(c.conn)
|
c.p = xml.NewDecoder(c.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var domain string
|
||||||
a := strings.SplitN(o.User, "@", 2)
|
a := strings.SplitN(o.User, "@", 2)
|
||||||
|
if len(o.User) > 0 {
|
||||||
if len(a) != 2 {
|
if len(a) != 2 {
|
||||||
return errors.New("xmpp: invalid username (want user@domain): " + o.User)
|
return errors.New("xmpp: invalid username (want user@domain): " + o.User)
|
||||||
}
|
}
|
||||||
domain := a[1]
|
domain = a[1]
|
||||||
|
} // Otherwise, we'll be attempting ANONYMOUS
|
||||||
|
|
||||||
// Declare intent to be a jabber client and gather stream features.
|
// Declare intent to be a jabber client and gather stream features.
|
||||||
f, err := c.startStream(o, domain)
|
f, err := c.startStream(o, domain)
|
||||||
@@ -290,6 +293,19 @@ func (c *Client) init(o *Options) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.User == "" && o.Password == "" {
|
||||||
|
foundAnonymous := false
|
||||||
|
for _, m := range f.Mechanisms.Mechanism {
|
||||||
|
if m == "ANONYMOUS" {
|
||||||
|
fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='ANONYMOUS' />\n", nsSASL)
|
||||||
|
foundAnonymous = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundAnonymous {
|
||||||
|
return fmt.Errorf("ANONYMOUS authentication is not an option and username and password were not specified")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// Even digest forms of authentication are unsafe if we do not know that the host
|
// Even digest forms of authentication are unsafe if we do not know that the host
|
||||||
// we are talking to is the actual server, and not a man in the middle playing
|
// we are talking to is the actual server, and not a man in the middle playing
|
||||||
// proxy.
|
// proxy.
|
||||||
@@ -371,7 +387,7 @@ func (c *Client) init(o *Options) error {
|
|||||||
if mechanism == "" {
|
if mechanism == "" {
|
||||||
return fmt.Errorf("PLAIN authentication is not an option: %v", f.Mechanisms.Mechanism)
|
return fmt.Errorf("PLAIN authentication is not an option: %v", f.Mechanisms.Mechanism)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Next message should be either success or failure.
|
// Next message should be either success or failure.
|
||||||
name, val, err := next(c.p)
|
name, val, err := next(c.p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -514,10 +530,19 @@ type Chat struct {
|
|||||||
Remote string
|
Remote string
|
||||||
Type string
|
Type string
|
||||||
Text string
|
Text string
|
||||||
|
Roster Roster
|
||||||
Other []string
|
Other []string
|
||||||
Stamp time.Time
|
Stamp time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Roster []Contact
|
||||||
|
|
||||||
|
type Contact struct {
|
||||||
|
Remote string
|
||||||
|
Name string
|
||||||
|
Group []string
|
||||||
|
}
|
||||||
|
|
||||||
// Presence is an XMPP presence notification.
|
// Presence is an XMPP presence notification.
|
||||||
type Presence struct {
|
type Presence struct {
|
||||||
From string
|
From string
|
||||||
@@ -541,13 +566,19 @@ func (c *Client) Recv() (stanza interface{}, err error) {
|
|||||||
v.Delay.Stamp,
|
v.Delay.Stamp,
|
||||||
)
|
)
|
||||||
chat := Chat{
|
chat := Chat{
|
||||||
v.From,
|
Remote: v.From,
|
||||||
v.Type,
|
Type: v.Type,
|
||||||
v.Body,
|
Text: v.Body,
|
||||||
v.Other,
|
Other: v.Other,
|
||||||
stamp,
|
Stamp: stamp,
|
||||||
}
|
}
|
||||||
return chat, nil
|
return chat, nil
|
||||||
|
case *clientQuery:
|
||||||
|
var r Roster
|
||||||
|
for _, item := range v.Item {
|
||||||
|
r = append(r, Contact{item.Jid, item.Name, item.Group})
|
||||||
|
}
|
||||||
|
return Chat{Type: "roster", Roster: r}, nil
|
||||||
case *clientPresence:
|
case *clientPresence:
|
||||||
return Presence{v.From, v.To, v.Type, v.Show}, nil
|
return Presence{v.From, v.To, v.Type, v.Show}, nil
|
||||||
}
|
}
|
||||||
@@ -574,6 +605,12 @@ func (c *Client) SendHtml(chat Chat) (n int, err error) {
|
|||||||
xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text), chat.Text)
|
xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text), chat.Text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Roster asks for the chat roster.
|
||||||
|
func (c *Client) Roster() error {
|
||||||
|
fmt.Fprintf(c.conn, "<iq from='%s' type='get' id='roster1'><query xmlns='jabber:iq:roster'/></iq>\n", xmlEscape(c.jid))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// RFC 3920 C.1 Streams name space
|
// RFC 3920 C.1 Streams name space
|
||||||
type streamFeatures struct {
|
type streamFeatures struct {
|
||||||
XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"`
|
XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"`
|
||||||
@@ -700,11 +737,23 @@ type clientError struct {
|
|||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type clientQuery struct {
|
||||||
|
Item []rosterItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type rosterItem struct {
|
||||||
|
XMLName xml.Name `xml:"jabber:iq:roster item"`
|
||||||
|
Jid string `xml:",attr"`
|
||||||
|
Name string `xml:",attr"`
|
||||||
|
Subscription string `xml:",attr"`
|
||||||
|
Group []string
|
||||||
|
}
|
||||||
|
|
||||||
// Scan XML token stream to find next StartElement.
|
// Scan XML token stream to find next StartElement.
|
||||||
func nextStart(p *xml.Decoder) (xml.StartElement, error) {
|
func nextStart(p *xml.Decoder) (xml.StartElement, error) {
|
||||||
for {
|
for {
|
||||||
t, err := p.Token()
|
t, err := p.Token()
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF || t == nil {
|
||||||
return xml.StartElement{}, err
|
return xml.StartElement{}, err
|
||||||
}
|
}
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
|
|||||||
20
xmpp_subscription.go
Normal file
20
xmpp_subscription.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package xmpp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c* Client) ApproveSubscription(jid string) {
|
||||||
|
fmt.Fprintf(c.conn, "<presence to='%s' type='subscribed'/>",
|
||||||
|
xmlEscape(jid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c* Client) RevokeSubscription(jid string) {
|
||||||
|
fmt.Fprintf(c.conn, "<presence to='%s' type='unsubscribed'/>",
|
||||||
|
xmlEscape(jid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c* Client) RequestSubscription(jid string) {
|
||||||
|
fmt.Fprintf(c.conn, "<presence to='%s' type='subscribe'/>",
|
||||||
|
xmlEscape(jid))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user