~samwhited/xmpp

ref: 419d6d466133ee3a90f6deaa9e136dc39fad9c73 xmpp/stream/stream.go -rw-r--r-- 3.8 KiB
419d6d46Sam Whited Remove old handler code 5 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2015 Sam Whited.
// Use of this source code is governed by the BSD 2-clause license that can be
// found in the LICENSE file.

package stream

import (
	"encoding/xml"
	"errors"

	"bitbucket.org/mellium/xmpp/jid"
	"golang.org/x/text/language"
)

// A Stream is a container for the exchange of XML elements between two
// endpoints. It maintains state about stream-level features, and handles
// decoding and routing incoming XMPP stanza's and other elements, as well as
// encoding outgoing XMPP elements. Each XMPP connection has two streams, one
// for input, and one for output.
type Stream struct {
	options
	to      *jid.JID
	from    *jid.JID
	version Version
	id      string
	authed  bool
	bound   bool
}

// New creats an XMPP stream that will be used to initiate a new XMPP
// connection. This should always be used by clients to create a new stream, and
// by the initiating server in a server-to-server connection.
func New(to, from jid.JID, opts ...Option) Stream {
	return Stream{
		to:      &to,
		from:    &from,
		version: DefaultVersion,
		options: getOpts(opts...),
	}
}

// ReadResponse constructs a new Steam that acts as a response stream to the
// provided initiating stream. Respond should always be used by clients and
// servers to to initiate new streams after receiving a client-to-server or
// server-to-server connection.
func ReadResponse(responds, replaces *Stream, opts ...Option) (Stream, error) {
	s := Stream{
		options: getOpts(opts...),
	}

	switch {
	case replaces != nil:
		s.version = replaces.version
	// RFC 6120 §4.7.5  version.
	//    2.  The receiving entity MUST set the value of the 'version'
	//        attribute in the response stream header to either the value
	//        supplied by the initiating entity or the highest version number
	//        supported by the receiving entity, whichever is lower.
	case replaces == nil && responds.version.Less(DefaultVersion):
		s.version = responds.version
	default:
		s.version = DefaultVersion
	}

	if responds.from != nil {
		s.to = responds.from
	}

	if responds.to != nil {
		// TODO: Verify that we serve this domain, possibly set this to a canonical
		// domain if there is one.
		s.from = responds.to
	}

	return s, nil
}

// fromStartElement constructs a new Stream from the given xml.StartElement.
func fromStartElement(start xml.StartElement) (*Stream, error) {

	if start.Name.Local != "stream" || start.Name.Space != "stream" {
		return nil, errors.New("Incorrect XML name on stream start element.")
	}

	stream := Stream{}
	for _, attr := range start.Attr {
		switch attr.Name.Local {
		case "from":
			j, err := jid.ParseString(attr.Value)
			if err != nil {
				return nil, err
			}
			stream.from = j
		case "to":
			j, err := jid.ParseString(attr.Value)
			if err != nil {
				return nil, err
			}
			stream.to = j
		case "xmlns":
			stream.xmlns = attr.Value
		case "lang":
			if attr.Name.Space == "xml" {
				stream.lang = language.Make(attr.Value)
			}
		case "id":
			stream.id = attr.Value
		}
	}

	return &stream, nil
}

// // StartElement creates an XML start element from the given stream which is
// // suitable for starting an XMPP stream.
// func (s *Stream) StartElement() xml.StartElement {
// 	return xml.StartElement{
// 		Name: xml.Name{"stream", "stream"},
// 		Attr: []xml.Attr{
// 			xml.Attr{
// 				xml.Name{"", "to"},
// 				s.to.String(),
// 			},
// 			xml.Attr{
// 				xml.Name{"", "from"},
// 				s.from.String(),
// 			},
// 			xml.Attr{
// 				xml.Name{"", "version"},
// 				s.version,
// 			},
// 			xml.Attr{
// 				xml.Name{"xml", "lang"},
// 				s.lang,
// 			},
// 			xml.Attr{
// 				xml.Name{"", "id"},
// 				s.id,
// 			},
// 			xml.Attr{
// 				xml.Name{"", "xmlns"},
// 				s.xmlns,
// 			},
// 		},
// 	}
// }

// func (s *Stream) Handle(encoder *xml.Encoder, decoder *xml.Decoder) error {
// 	return errors.New("Test me")
// }