ObjXMPP  Check-in [db8adef472]

Overview
Comment:Add classes to support Service Discovery
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: db8adef472901dcb67d4779dc567f9b124421269f60c76d3c6e4c99cda6eadc0
User & Date: florob@babelmonkeys.de on 2013-03-23 17:21:05
Other Links: manifest | tags
Context
2013-03-23
18:59
Add support for calculating caps hashes check-in: 0d43c61dbc user: florob@babelmonkeys.de tags: trunk
17:21
Add classes to support Service Discovery check-in: db8adef472 user: florob@babelmonkeys.de tags: trunk
2013-03-03
16:30
Fix up -[XMPPJID isEqual:] and -[XMPPJID hash] check-in: 8bc32c2743 user: florob@babelmonkeys.de tags: trunk
Changes

Modified src/Makefile from [ad510f6243] to [db78187a2c].

1
2
3
4
5
6
7
8
9
10
11
12



13
14
15
16
17
18
19
include ../extra.mk

SHARED_LIB = ${OBJXMPP_SHARED_LIB}
STATIC_LIB = ${OBJXMPP_STATIC_LIB}
LIB_MAJOR = 0
LIB_MINOR = 0

SRCS = XMPPAuthenticator.m	\
       XMPPCallback.m		\
       XMPPConnection.m		\
       XMPPContact.m		\
       XMPPContactManager.m	\



       XMPPExceptions.m		\
       XMPPEXTERNALAuth.m	\
       XMPPIQ.m			\
       XMPPJID.m		\
       XMPPFileStorage.m	\
       XMPPMessage.m		\
       XMPPMulticastDelegate.m	\












>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
include ../extra.mk

SHARED_LIB = ${OBJXMPP_SHARED_LIB}
STATIC_LIB = ${OBJXMPP_STATIC_LIB}
LIB_MAJOR = 0
LIB_MINOR = 0

SRCS = XMPPAuthenticator.m	\
       XMPPCallback.m		\
       XMPPConnection.m		\
       XMPPContact.m		\
       XMPPContactManager.m	\
       XMPPDiscoEntity.m	\
       XMPPDiscoIdentity.m	\
       XMPPDiscoNode.m		\
       XMPPExceptions.m		\
       XMPPEXTERNALAuth.m	\
       XMPPIQ.m			\
       XMPPJID.m		\
       XMPPFileStorage.m	\
       XMPPMessage.m		\
       XMPPMulticastDelegate.m	\

Added src/XMPPDiscoEntity.h version [50bb8252e5].





























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2013, Florian Zeitz <florob@babelmonkeys.de>
 *
 * https://webkeks.org/git/?p=objxmpp.git
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import <ObjFW/ObjFW.h>

#import "XMPPConnection.h"
#import "XMPPDiscoNode.h"

@class XMPPJID;

/**
 * \brief A class representing an entity responding to Service Discovery
 *	  queries
 */
@interface XMPPDiscoEntity: XMPPDiscoNode <XMPPConnectionDelegate>
{
	OFMutableDictionary *_discoNodes;
	XMPPConnection *_connection;
}
#ifdef OF_HAVE_PROPERTIES
/**
 * \brief The XMPPDiscoNodes this entity provides Services Discovery
 *	  responses for
 *
 * This usually contains at least all immediate child nodes, but may contain
 * any number of nodes nested more deeply.
 */
@property (readonly) OFDictionary *discoNodes;
#endif

/**
 * \brief Creates a new autoreleased XMPPDiscoEntity with the specified
 *	  connection.
 *
 * \param connection The XMPPConnection to serve responses on.
 *	  This must already be bound to a resource)
 * \return A new autoreleased XMPPDiscoEntity
 */
+ discoEntityWithConnection: (XMPPConnection*)connection;

/**
 * \brief Initializes an already allocated XMPPDiscoEntity with the specified
 *	  connection.
 *
 * \param connection The XMPPConnection to serve responses on.
 *	  This must already be bound to a resource)
 * \return An initialized XMPPDiscoEntity
 */
- initWithConnection: (XMPPConnection*)connection;

/**
 * \brief Adds a XMPPDiscoNode to provide responses for.
 *
 * \param node The XMPPDiscoNode to provide responses for
 */
- (void)addDiscoNode: (XMPPDiscoNode*)node;

- (OFDictionary*)discoNodes;
@end

Added src/XMPPDiscoEntity.m version [ada5800aa3].











































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2013, Florian Zeitz <florob@babelmonkeys.de>
 *
 * https://webkeks.org/git/?p=objxmpp.git
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import "XMPPDiscoEntity.h"
#import "XMPPIQ.h"
#import "namespaces.h"

@implementation XMPPDiscoEntity
+ discoEntityWithConnection: (XMPPConnection*)connection
{
	return [[[self alloc] initWithConnection: connection] autorelease];
}

- initWithConnection: (XMPPConnection*)connection
{
	self = [super initWithJID: [connection JID]
			     node: nil];

	@try {
		_discoNodes = [OFMutableDictionary new];
		_connection = connection;

		[_connection addDelegate: self];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_connection removeDelegate: self];
	[_discoNodes release];

	[super dealloc];
}

- (OFDictionary*)discoNodes;
{
	OF_GETTER(_discoNodes, YES);
}

- (void)addDiscoNode: (XMPPDiscoNode*)node
{
	[_discoNodes setObject: node
			forKey: [node node]];
}

- (BOOL)connection: (XMPPConnection*)connection
      didReceiveIQ: (XMPPIQ*)IQ
{
	of_log(@"Called connection:didReceiveIQ:... %@ %@", [IQ to], _JID);
	if (![[IQ to] isEqual: _JID])
		return NO;

	of_log(@"...that is for us");

	OFXMLElement *query = [IQ elementForName: @"query"
				       namespace: XMPP_NS_DISCO_ITEMS];

	if (query != nil) {
		OFString *node =
		    [[query attributeForName: @"node"] stringValue];
		if (node == nil)
			return [self XMPP_handleItemsIQ: IQ
					     connection: connection];

		XMPPDiscoNode *responder = [_discoNodes objectForKey: node];
		if (responder != nil)
			return [responder XMPP_handleItemsIQ: IQ
						  connection: connection];

		return NO;
	}

	query = [IQ elementForName: @"query"
			 namespace: XMPP_NS_DISCO_INFO];

	if (query != nil) {
		OFString *node =
		    [[query attributeForName: @"node"] stringValue];
		if (node == nil)
			return [self XMPP_handleInfoIQ: IQ
					    connection: connection];

		XMPPDiscoNode *responder = [_discoNodes objectForKey: node];
		if (responder != nil)
			return [responder XMPP_handleInfoIQ: IQ
						 connection: connection];

		return NO;
	}

	return NO;
}
@end

Added src/XMPPDiscoIdentity.h version [5d9f1df6e9].





























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2013, Florian Zeitz <florob@babelmonkeys.de>
 *
 * https://webkeks.org/git/?p=objxmpp.git
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import <ObjFW/ObjFW.h>

/**
 * \brief A class describing a Service Discovery Identity
 */
@interface XMPPDiscoIdentity: OFObject <OFComparing>
{
	OFString *_category;
	OFString *_name;
	OFString *_type;
}
#ifdef OF_HAVE_PROPERTIES
/// \brief The category of the identity
@property (readonly) OFString *category;
/// \brief The name of the identity, might be unset
@property (readonly) OFString *name;
/// \brief The type of the identity
@property (readonly) OFString *type;
#endif

/**
 * \brief Creates a new autoreleased XMPPDiscoIdentity with the specified
 *	  category, type and name.
 *
 * \param category The category of the identity
 * \param type The type of the identity
 * \param name The name of the identity
 * \return A new autoreleased XMPPDiscoIdentity
 */
+ identityWithCategory: (OFString*)category
		  type: (OFString*)type
		  name: (OFString*)name;

/**
 * \brief Creates a new autoreleased XMPPDiscoIdentity with the specified
 *	  category and type.
 *
 * \param category The category of the identity
 * \param type The type of the identity
 * \return A new autoreleased XMPPDiscoIdentity
 */
+ identityWithCategory: (OFString*)category
		  type: (OFString*)type;

/**
 * \brief Initializes an already allocated XMPPDiscoIdentity with the specified
 *	  category, type and name.
 *
 * \param category The category of the identity
 * \param type The type of the identity
 * \param name The name of the identity
 * \return An initialized XMPPDiscoIdentity
 */
- initWithCategory: (OFString*)category
	      type: (OFString*)type
	      name: (OFString*)name;

/**
 * \brief Initializes an already allocated XMPPDiscoIdentity with the specified
 *	  category and type.
 *
 * \param category The category of the identity
 * \param type The type of the identity
 * \return An initialized XMPPDiscoIdentity
 */
- initWithCategory: (OFString*)category
	      type: (OFString*)type;

- (OFString*)category;
- (OFString*)name;
- (OFString*)type;
@end

Added src/XMPPDiscoIdentity.m version [886ac061d4].





















































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * Copyright (c) 2013, Florian Zeitz <florob@babelmonkeys.de>
 *
 * https://webkeks.org/git/?p=objxmpp.git
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import "XMPPDiscoIdentity.h"

@implementation XMPPDiscoIdentity
+ identityWithCategory: (OFString*)category
		  type: (OFString*)type
		  name: (OFString*)name
{
	return [[[self alloc] initWithCategory: category
					  type: type 
					  name: name] autorelease];
}

+ identityWithCategory: (OFString*)category
		  type: (OFString*)type
{
	return [[[self alloc] initWithCategory: category
					  type: type] autorelease];
}

- initWithCategory: (OFString*)category
	      type: (OFString*)type
	      name: (OFString*)name
{
	self = [super init];

	@try {
		if (category == nil || type == nil)
			@throw [OFInvalidArgumentException
			    exceptionWithClass: [self class]
				      selector: _cmd];

		_category = [category copy];
		_name = [name copy];
		_type = [type copy];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- initWithCategory: (OFString*)category
	      type: (OFString*)type
{
	return [self initWithCategory: category
				 type: type
				 name: nil];
}

- init
{
	@try {
		[self doesNotRecognizeSelector: _cmd];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	abort();
}

- (void)dealloc
{
	[_category release];
	[_name release];
	[_type release];

	[super dealloc];
}

- (OFString*)category
{
	OF_GETTER(_category, YES);
}

- (OFString*)name
{
	OF_GETTER(_name, YES);
}

- (OFString*)type
{
	OF_GETTER(_type, YES);
}

- (bool)isEqual: (id)object
{
	XMPPDiscoIdentity *identity;

	if (object == self)
		return YES;

	if (![object isKindOfClass: [XMPPDiscoIdentity class]])
		return NO;

	identity = object;

	if ([_category isEqual: identity->_category] &&
	    (_name == identity->_name || [_name isEqual: identity->_name]) &&
	    [_type isEqual: identity->_type])
		return YES;

	return NO;
}

- (uint32_t) hash
{
	uint32_t hash;

	OF_HASH_INIT(hash);

	OF_HASH_ADD_HASH(hash, [_category hash]);
	OF_HASH_ADD_HASH(hash, [_type hash]);
	OF_HASH_ADD_HASH(hash, [_name hash]);

	OF_HASH_FINALIZE(hash);

	return hash;
}

- (of_comparison_result_t)compare: (id <OFComparing>)object
{
	XMPPDiscoIdentity *identity;
	of_comparison_result_t categoryResult;
	of_comparison_result_t typeResult;

	if (object == self)
		return OF_ORDERED_SAME;

	if (![object isKindOfClass: [XMPPDiscoIdentity class]])
		@throw [OFInvalidArgumentException
		    exceptionWithClass: [self class]
			      selector: _cmd];

	identity = (XMPPDiscoIdentity*)object;

	categoryResult = [_category compare: identity->_category];
	if (categoryResult != OF_ORDERED_SAME)
		return categoryResult;

	typeResult = [_type compare: identity->_type];
	if (typeResult != OF_ORDERED_SAME)
		return typeResult;

	return [_name compare: identity->_name];
}
@end

Added src/XMPPDiscoNode.h version [f9cb5ba330].













































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2013, Florian Zeitz <florob@babelmonkeys.de>
 *
 * https://webkeks.org/git/?p=objxmpp.git
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import <ObjFW/ObjFW.h>

@class XMPPDiscoIdentity;
@class XMPPJID;

/**
 * \brief A class describing a Service Discovery Node
 */
@interface XMPPDiscoNode: OFObject
{
	XMPPJID *_JID;
	OFString *_node;
	OFString *_name;
	OFSortedList *_identities;
	OFSortedList *_features;
	OFMutableDictionary *_childNodes;
}
#ifdef OF_HAVE_PROPERTIES
/// \brief The JID this node lives on
@property (readonly) XMPPJID *JID;
/// \brief The node's opaque name of the node
@property (readonly) OFString *node;
/// \brief The node's human friendly name (may be unspecified)
@property (readonly) OFString *name;
/// \brief The node's list of identities
@property (readonly) OFSortedList *identities;
/// \brief The node's list of features
@property (readonly) OFSortedList *features;
/// \brief The node's children
@property (readonly) OFDictionary *childNodes;
#endif

/**
 * \brief Creates a new autoreleased XMPPDiscoNode with the specified
 *	  JID and node
 *
 * \param JID The JID this node lives on
 * \param node The node's opaque name
 * \return A new autoreleased XMPPDiscoNode
 */
+ discoNodeWithJID: (XMPPJID*)JID
	      node: (OFString*)node;

/**
 * \brief Creates a new autoreleased XMPPDiscoNode with the specified
 *	  JID, node and name
 *
 * \param JID The JID this node lives on
 * \param node The node's opaque name
 * \param name The node's human friendly name
 * \return A new autoreleased XMPPDiscoNode
 */
+ discoNodeWithJID: (XMPPJID*)JID
	      node: (OFString*)node
	      name: (OFString*)name;

/**
 * \brief Initializes an already allocated XMPPDiscoNode with the specified
 *	  JID and node
 *
 * \param JID The JID this node lives on
 * \param node The node's opaque name
 * \return An initialized XMPPDiscoNode
 */
- initWithJID: (XMPPJID*)JID
	 node: (OFString*)node;

/**
 * \brief Initializes an already allocated XMPPDiscoNode with the specified
 *	  JID, node and name
 *
 * \param JID The JID this node lives on
 * \param node The node's opaque name
 * \param name The node's human friendly name
 * \return An initialized XMPPDiscoNode
 */
- initWithJID: (XMPPJID*)JID
	 node: (OFString*)node
	 name: (OFString*)name;

 /**
  * \brief Adds an XMPPDiscoIdentity to the node
  *
  * \param identity The XMPPDiscoIdentity to add
  */
- (void)addIdentity: (XMPPDiscoIdentity*)identity;

 /**
  * \brief Adds a feature to the node
  *
  * \param feature The feature to add
  */
- (void)addFeature: (OFString*)feature;

 /**
  * \brief Adds a XMPPDiscoNode as child of the node
  *
  * \param node The XMPPDiscoNode to add as child
  */
- (void)addChildNode: (XMPPDiscoNode*)node;

- (XMPPJID*)JID;
- (OFString*)node;
- (OFSortedList*)identities;
- (OFSortedList*)features;
- (OFDictionary*)childNodes;

- (BOOL)XMPP_handleItemsIQ: (XMPPIQ*)IQ
		connection: (XMPPConnection*)connection;
- (BOOL)XMPP_handleInfoIQ: (XMPPIQ*)IQ
	       connection: (XMPPConnection*)connection;
@end

Added src/XMPPDiscoNode.m version [49dce66da1].

























































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/*
 * Copyright (c) 2013, Florian Zeitz <florob@babelmonkeys.de>
 *
 * https://webkeks.org/git/?p=objxmpp.git
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice is present in all copies.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#import "XMPPConnection.h"
#import "XMPPIQ.h"
#import "XMPPJID.h"
#import "XMPPDiscoNode.h"
#import "XMPPDiscoIdentity.h"
#import "namespaces.h"

@implementation XMPPDiscoNode
+ discoNodeWithJID: (XMPPJID*)JID
	      node: (OFString*)node;
{
	return [[[self alloc] initWithJID: JID
				     node: node] autorelease];
}


+ discoNodeWithJID: (XMPPJID*)JID
	      node: (OFString*)node
	      name: (OFString*)name
{
	return [[[self alloc] initWithJID: JID
				     node: node
				     name: name] autorelease];
}

- initWithJID: (XMPPJID*)JID
	 node: (OFString*)node
{
	return [self initWithJID: JID
			    node: node
			    name: nil];
}

- initWithJID: (XMPPJID*)JID
	 node: (OFString*)node
	 name: (OFString*)name
{
	self = [super init];

	@try {
		if (JID == nil)
			@throw [OFInvalidArgumentException
			    exceptionWithClass: [self class]
				      selector: _cmd];

		_JID = [JID copy];
		_node= [node copy];
		_name = [name copy];
		_identities = [OFSortedList new];
		_features = [OFSortedList new];
		_childNodes = [OFMutableDictionary new];

		[self addFeature: XMPP_NS_DISCO_ITEMS];
		[self addFeature: XMPP_NS_DISCO_INFO];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_JID release];
	[_node release];
	[_name release];
	[_identities release];
	[_features release];
	[_childNodes release];

	[super dealloc];
}

- (XMPPJID*)JID
{
	OF_GETTER(_JID, YES);
}

- (OFString*)node
{
	OF_GETTER(_node, YES);
}

- (OFString*)name
{
	OF_GETTER(_name, YES);
}

- (OFSortedList*)identities
{
	OF_GETTER(_identities, YES);
}

- (OFSortedList*)features
{
	OF_GETTER(_features, YES);
}

- (OFDictionary*)childNodes
{
	OF_GETTER(_childNodes, YES);
}

- (void)addIdentity: (XMPPDiscoIdentity*)identity
{
	[_identities insertObject: identity];
}

- (void)addFeature: (OFString*)feature
{
	[_features insertObject: feature];
}

- (void)addChildNode: (XMPPDiscoNode*)node
{
	[_childNodes setObject: node
			forKey: [node node]];
}

- (BOOL)XMPP_handleItemsIQ: (XMPPIQ*)IQ
		connection: (XMPPConnection*)connection
{
	XMPPIQ *resultIQ;
	OFXMLElement *response;
	XMPPDiscoNode *child;
	OFEnumerator *enumerator;
	OFXMLElement *query = [IQ elementForName: @"query"
				       namespace: XMPP_NS_DISCO_ITEMS];
	OFString *node = [[query attributeForName: @"node"] stringValue];

	if (!(node == _node) && ![node isEqual: _node])
		return NO;

	resultIQ = [IQ resultIQ];
	response = [OFXMLElement elementWithName: @"query"
				       namespace: XMPP_NS_DISCO_ITEMS];
	[resultIQ addChild: response];

	enumerator = [_childNodes objectEnumerator];
	while ((child = [enumerator nextObject])) {
		OFXMLElement *item =
		    [OFXMLElement elementWithName: @"item"
					namespace: XMPP_NS_DISCO_ITEMS];

		[item addAttributeWithName: @"jid"
			       stringValue: [[child JID] fullJID]];
		if ([child node] != nil)
			[item addAttributeWithName: @"node"
				       stringValue: [child node]];
		if ([child name] != nil)
			[item addAttributeWithName: @"name"
				       stringValue: [child name]];

		[response addChild: item];
	}

	[connection sendStanza: resultIQ];

	return YES;
}

- (BOOL)XMPP_handleInfoIQ: (XMPPIQ*)IQ
	       connection: (XMPPConnection*)connection
{
	XMPPIQ *resultIQ;
	OFXMLElement *response;
	OFEnumerator *enumerator;
	OFString *feature;
	XMPPDiscoIdentity *identity;
	OFXMLElement *query = [IQ elementForName: @"query"
				       namespace: XMPP_NS_DISCO_INFO];
	OFString *node = [[query attributeForName: @"node"] stringValue];

	if (!(node == _node) && ![node isEqual: _node])
		return NO;

	resultIQ = [IQ resultIQ];
	response = [OFXMLElement elementWithName: @"query"
				       namespace: XMPP_NS_DISCO_INFO];
	[resultIQ addChild: response];

	enumerator = [_identities objectEnumerator];
	while ((identity = [enumerator nextObject])) {
		OFXMLElement *identityElement =
		    [OFXMLElement elementWithName: @"identity"
					namespace: XMPP_NS_DISCO_INFO];

		[identityElement addAttributeWithName: @"category"
					  stringValue: [identity category]];
		[identityElement addAttributeWithName: @"type"
					  stringValue: [identity type]];
		if ([identity name] != nil)
			[identityElement addAttributeWithName: @"name"
						  stringValue: [identity name]];

		[response addChild: identityElement];
	}

	enumerator = [_features objectEnumerator];
	while ((feature = [enumerator nextObject])) {
		OFXMLElement *featureElement =
		    [OFXMLElement elementWithName: @"feature"
					namespace: XMPP_NS_DISCO_INFO];
		[featureElement addAttributeWithName: @"var"
					 stringValue: feature];
		[response addChild: featureElement];
	}

	[connection sendStanza: resultIQ];

	return YES;
}
@end

Modified src/XMPPJID.m from [ced62b3025] to [70fd287265].

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
}

- (OFString*)description
{
	return [self fullJID];
}

- (BOOL)isEqual: (id)object
{
	XMPPJID *JID;

	if (object == self)
		return YES;

	if (![object isKindOfClass: [XMPPJID class]])







|







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
}

- (OFString*)description
{
	return [self fullJID];
}

- (bool)isEqual: (id)object
{
	XMPPJID *JID;

	if (object == self)
		return YES;

	if (![object isKindOfClass: [XMPPJID class]])

Modified src/namespaces.h from [28e73e8b28] to [ea4713ca5d].

18
19
20
21
22
23
24


25
26
27
28
29
30
31
32
33
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#define XMPP_NS_BIND @"urn:ietf:params:xml:ns:xmpp-bind"
#define XMPP_NS_CLIENT @"jabber:client"


#define XMPP_NS_ROSTER @"jabber:iq:roster"
#define XMPP_NS_ROSTERVER @"urn:xmpp:features:rosterver"
#define XMPP_NS_SASL @"urn:ietf:params:xml:ns:xmpp-sasl"
#define XMPP_NS_SESSION @"urn:ietf:params:xml:ns:xmpp-session"
#define XMPP_NS_SM @"urn:xmpp:sm:3"
#define XMPP_NS_STARTTLS @"urn:ietf:params:xml:ns:xmpp-tls"
#define XMPP_NS_STANZAS @"urn:ietf:params:xml:ns:xmpp-stanzas"
#define XMPP_NS_STREAM @"http://etherx.jabber.org/streams"
#define XMPP_NS_XMPP_STREAM @"urn:ietf:params:xml:ns:xmpp-streams"







>
>









18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#define XMPP_NS_BIND @"urn:ietf:params:xml:ns:xmpp-bind"
#define XMPP_NS_CLIENT @"jabber:client"
#define XMPP_NS_DISCO_INFO @"http://jabber.org/protocol/disco#info"
#define XMPP_NS_DISCO_ITEMS @"http://jabber.org/protocol/disco#items"
#define XMPP_NS_ROSTER @"jabber:iq:roster"
#define XMPP_NS_ROSTERVER @"urn:xmpp:features:rosterver"
#define XMPP_NS_SASL @"urn:ietf:params:xml:ns:xmpp-sasl"
#define XMPP_NS_SESSION @"urn:ietf:params:xml:ns:xmpp-session"
#define XMPP_NS_SM @"urn:xmpp:sm:3"
#define XMPP_NS_STARTTLS @"urn:ietf:params:xml:ns:xmpp-tls"
#define XMPP_NS_STANZAS @"urn:ietf:params:xml:ns:xmpp-stanzas"
#define XMPP_NS_STREAM @"http://etherx.jabber.org/streams"
#define XMPP_NS_XMPP_STREAM @"urn:ietf:params:xml:ns:xmpp-streams"

Modified tests/test.m from [ef9f547a18] to [50ffe289bb].

22
23
24
25
26
27
28


29
30
31
32
33
34
35
 */

#include <assert.h>

#import <ObjFW/ObjFW.h>

#import "XMPPConnection.h"


#import "XMPPJID.h"
#import "XMPPStanza.h"
#import "XMPPIQ.h"
#import "XMPPMessage.h"
#import "XMPPPresence.h"
#import "XMPPRoster.h"
#import "XMPPStreamManagement.h"







>
>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 */

#include <assert.h>

#import <ObjFW/ObjFW.h>

#import "XMPPConnection.h"
#import "XMPPDiscoEntity.h"
#import "XMPPDiscoIdentity.h"
#import "XMPPJID.h"
#import "XMPPStanza.h"
#import "XMPPIQ.h"
#import "XMPPMessage.h"
#import "XMPPPresence.h"
#import "XMPPRoster.h"
#import "XMPPStreamManagement.h"
149
150
151
152
153
154
155











































156
157
158
159
160
161
162
- (void)connection: (XMPPConnection*)conn_
     wasBoundToJID: (XMPPJID*)jid
{
	of_log(@"Bound to JID: %@", [jid fullJID]);
	of_log(@"Supports SM: %@",
	    [conn_ supportsStreamManagement] ? @"YES" : @"NO");












































	[roster requestRoster];
}

- (void)rosterWasReceived: (XMPPRoster*)roster_
{
	XMPPPresence *pres;








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
- (void)connection: (XMPPConnection*)conn_
     wasBoundToJID: (XMPPJID*)jid
{
	of_log(@"Bound to JID: %@", [jid fullJID]);
	of_log(@"Supports SM: %@",
	    [conn_ supportsStreamManagement] ? @"YES" : @"NO");


	XMPPDiscoEntity *discoEntity =
	    [[XMPPDiscoEntity alloc] initWithConnection: conn];

	[discoEntity addIdentity:
	    [XMPPDiscoIdentity identityWithCategory: @"client"
					       type: @"pc"
					       name: @"ObjXMPP"]];

	XMPPDiscoNode *nodeMusic =
	    [XMPPDiscoNode discoNodeWithJID: jid
				       node: @"music"
				       name: @"My music"];
	[discoEntity addChildNode: nodeMusic];

	XMPPDiscoNode *nodeRHCP =
	    [XMPPDiscoNode discoNodeWithJID: jid
				       node: @"fa3b6"
				       name: @"Red Hot Chili Peppers"];
	[nodeMusic addChildNode: nodeRHCP];

	XMPPDiscoNode *nodeStop =
	    [XMPPDiscoNode discoNodeWithJID: jid
				       node: @"qwe87"
				       name: @"Can't Stop"];
	[nodeRHCP addChildNode: nodeStop];

	XMPPDiscoNode *nodeClueso = [XMPPDiscoNode discoNodeWithJID: jid
							       node: @"ea386"
							       name: @"Clueso"];
	[nodeMusic addChildNode: nodeClueso];

	XMPPDiscoNode *nodeChicago = [XMPPDiscoNode discoNodeWithJID: jid
							      node: @"qwr87"
							      name: @"Chicago"];
	[nodeClueso addChildNode: nodeChicago];

	[discoEntity addDiscoNode: nodeMusic];
	[discoEntity addDiscoNode: nodeRHCP];
	[discoEntity addDiscoNode: nodeClueso];
	[discoEntity addDiscoNode: nodeStop];
	[discoEntity addDiscoNode: nodeChicago];

	[roster requestRoster];
}

- (void)rosterWasReceived: (XMPPRoster*)roster_
{
	XMPPPresence *pres;