ObjXMPP  Check-in [423434d147]

Overview
Comment:Adjust to newest ObjFW and greatly improve XML handling.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 423434d147dabe90fa497a17a626ec1138af1a37f84b6e9b61540ce56e7e8768
User & Date: js on 2011-03-31 12:25:41
Other Links: manifest | tags
Context
2011-04-01
01:09
Change how roster items are stored. check-in: e53970f55f user: js tags: trunk
2011-03-31
12:25
Adjust to newest ObjFW and greatly improve XML handling. check-in: 423434d147 user: js tags: trunk
2011-03-30
18:35
Set the default namespace and prefixes when creating a new XMPPStanza. check-in: efd0127bff user: js tags: trunk
Changes

Modified src/XMPPConnection.m from [a4f8793bd7] to [8c6dc2da09].

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
			   withSize: len];
	}
}

- (void)sendStanza: (OFXMLElement*)elem
{
	of_log(@"Out: %@", elem);
	[sock writeString: [elem stringValue]];
}

- (OFString*)generateStanzaID
{
	return [OFString stringWithFormat: @"objxmpp_%u", lastID++];
}








|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
			   withSize: len];
	}
}

- (void)sendStanza: (OFXMLElement*)elem
{
	of_log(@"Out: %@", elem);
	[sock writeString: [elem XMLString]];
}

- (OFString*)generateStanzaID
{
	return [OFString stringWithFormat: @"objxmpp_%u", lastID++];
}

341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
	}

	if ([[elem namespace] isEqual: XMPP_NS_SASL]) {
		if ([[elem name] isEqual: @"challenge"]) {
			OFXMLElement *responseTag;
			OFDataArray *challenge =
			    [OFDataArray dataArrayWithBase64EncodedString:
			    [[[elem children] firstObject] stringValue]];
			OFDataArray *response = [authModule
			    calculateResponseWithChallenge: challenge];

			responseTag = [OFXMLElement
			    elementWithName: @"response"
				  namespace: XMPP_NS_SASL];
			[responseTag addChild:
			    [OFXMLElement elementWithCharacters:
			    [response stringByBase64Encoding]]];

			[self sendStanza: responseTag];
			return;
		}

		if ([[elem name] isEqual: @"success"]) {
			[authModule parseServerFinalMessage:
			    [OFDataArray dataArrayWithBase64EncodedString:
				[[[elem children] firstObject] stringValue]]];

			if ([delegate respondsToSelector:
			    @selector(connectionWasAuthenticated:)])
				[delegate connectionWasAuthenticated: self];

			/* Stream restart */
			[parser setDelegate: self];
			[self XMPP_startStream];
			return;
		}

		if ([[elem name] isEqual: @"failure"]) {
			of_log(@"Auth failed!");
			// FIXME: Do more parsing/handling
			@throw [XMPPAuthFailedException
			    newWithClass: isa
			      connection: self
				  reason: [elem stringValue]];
		}

		assert(0);
	}

	assert(0);
}







|

















|

















|







341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
	}

	if ([[elem namespace] isEqual: XMPP_NS_SASL]) {
		if ([[elem name] isEqual: @"challenge"]) {
			OFXMLElement *responseTag;
			OFDataArray *challenge =
			    [OFDataArray dataArrayWithBase64EncodedString:
			    [elem stringValue]];
			OFDataArray *response = [authModule
			    calculateResponseWithChallenge: challenge];

			responseTag = [OFXMLElement
			    elementWithName: @"response"
				  namespace: XMPP_NS_SASL];
			[responseTag addChild:
			    [OFXMLElement elementWithCharacters:
			    [response stringByBase64Encoding]]];

			[self sendStanza: responseTag];
			return;
		}

		if ([[elem name] isEqual: @"success"]) {
			[authModule parseServerFinalMessage:
			    [OFDataArray dataArrayWithBase64EncodedString:
				[elem stringValue]]];

			if ([delegate respondsToSelector:
			    @selector(connectionWasAuthenticated:)])
				[delegate connectionWasAuthenticated: self];

			/* Stream restart */
			[parser setDelegate: self];
			[self XMPP_startStream];
			return;
		}

		if ([[elem name] isEqual: @"failure"]) {
			of_log(@"Auth failed!");
			// FIXME: Do more parsing/handling
			@throw [XMPPAuthFailedException
			    newWithClass: isa
			      connection: self
				  reason: [elem XMLString]];
		}

		assert(0);
	}

	assert(0);
}
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
	     @selector(connection:didReceivePresence:)])
		[delegate connection: self
		  didReceivePresence: pres];
}

- (void)XMPP_handleFeatures: (OFXMLElement*)elem
{
	OFXMLElement *starttls =
	    [[elem elementsForName: @"starttls"
			 namespace: XMPP_NS_STARTTLS] firstObject];
	OFXMLElement *bind = [[elem elementsForName: @"bind"
					  namespace: XMPP_NS_BIND] firstObject];
	OFXMLElement *session =
	    [[elem elementsForName: @"session"
			 namespace: XMPP_NS_SESSION] firstObject];
	OFArray *mechs = [elem elementsForName: @"mechanisms"
				     namespace: XMPP_NS_SASL];
	OFMutableArray *mechanisms = [OFMutableArray array];

	if (starttls != nil) {
		[self sendStanza:
		    [OFXMLElement elementWithName: @"starttls"
					namespace: XMPP_NS_STARTTLS]];
		return;
	}

	if ([mechs count] > 0) {
		OFEnumerator *enumerator;
		OFXMLElement *mech;

		enumerator = [[[mechs firstObject] children] objectEnumerator];
		while ((mech = [enumerator nextObject]) != nil)
			[mechanisms addObject:
			    [[[mech children] firstObject] stringValue]];

		if ([mechanisms containsObject: @"SCRAM-SHA-1"]) {
			authModule = [[XMPPSCRAMAuth alloc]
			    initWithAuthcid: username
				   password: password
				       hash: [OFSHA1Hash class]];
			[self XMPP_sendAuth: @"SCRAM-SHA-1"];







|
<
|
|
|
|
<
|
|
|









|



|

|
<







448
449
450
451
452
453
454
455

456
457
458
459

460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478

479
480
481
482
483
484
485
	     @selector(connection:didReceivePresence:)])
		[delegate connection: self
		  didReceivePresence: pres];
}

- (void)XMPP_handleFeatures: (OFXMLElement*)elem
{
	OFXMLElement *starttls = [elem elementForName: @"starttls"

					    namespace: XMPP_NS_STARTTLS];
	OFXMLElement *bind = [elem elementForName: @"bind"
					namespace: XMPP_NS_BIND];
	OFXMLElement *session = [elem elementForName: @"session"

					   namespace: XMPP_NS_SESSION];
	OFXMLElement *mechs = [elem elementForName: @"mechanisms"
					 namespace: XMPP_NS_SASL];
	OFMutableArray *mechanisms = [OFMutableArray array];

	if (starttls != nil) {
		[self sendStanza:
		    [OFXMLElement elementWithName: @"starttls"
					namespace: XMPP_NS_STARTTLS]];
		return;
	}

	if (mechs != nil) {
		OFEnumerator *enumerator;
		OFXMLElement *mech;

		enumerator = [[mechs children] objectEnumerator];
		while ((mech = [enumerator nextObject]) != nil)
			[mechanisms addObject: [mech stringValue]];


		if ([mechanisms containsObject: @"SCRAM-SHA-1"]) {
			authModule = [[XMPPSCRAMAuth alloc]
			    initWithAuthcid: username
				   password: password
				       hash: [OFSHA1Hash class]];
			[self XMPP_sendAuth: @"SCRAM-SHA-1"];
547
548
549
550
551
552
553
554
555
556
557

558
559
560
561
562
563

564
565
566
567
568
569
570
571
572
}

- (void)XMPP_handleResourceBind: (XMPPIQ*)iq
{
	OFXMLElement *bindElem;
	OFXMLElement *jidElem;

	if (![[iq type] isEqual: @"result"])
		assert(0);

	bindElem = [[iq children] firstObject];


	if (![[bindElem name] isEqual: @"bind"] ||
	    ![[bindElem namespace] isEqual: XMPP_NS_BIND])
		assert(0);

	jidElem = [[bindElem children] firstObject];

	JID = [[XMPPJID alloc] initWithString:
	    [[[jidElem children] firstObject] stringValue]];

	[bindID release];
	bindID = nil;

	if (needsSession) {
		[self XMPP_sendSession];
		return;







|
<

|
>

<
<
|

|
>
|
<







544
545
546
547
548
549
550
551

552
553
554
555


556
557
558
559
560

561
562
563
564
565
566
567
}

- (void)XMPP_handleResourceBind: (XMPPIQ*)iq
{
	OFXMLElement *bindElem;
	OFXMLElement *jidElem;

	assert([[iq type] isEqual: @"result"]);


	bindElem = [iq elementForName: @"bind"
			    namespace: XMPP_NS_BIND];



	assert(bindElem != nil);

	jidElem = [bindElem elementForName: @"jid"
				 namespace: XMPP_NS_BIND];
	JID = [[XMPPJID alloc] initWithString: [jidElem stringValue]];


	[bindID release];
	bindID = nil;

	if (needsSession) {
		[self XMPP_sendSession];
		return;
619
620
621
622
623
624
625
626
627
628
629

630
631
632
633
634
635
636
637
638
639
640

- (void)XMPP_handleRoster: (XMPPIQ*)iq
{
	OFXMLElement *rosterElem;
	OFEnumerator *enumerator;
	OFXMLElement *elem;

	if (![[iq type] isEqual: @"result"])
		assert(0);

	rosterElem = [[iq children] firstObject];


	if (![[rosterElem name] isEqual: @"query"] ||
	    ![[rosterElem namespace] isEqual: XMPP_NS_ROSTER])
		assert(0);

	enumerator = [[rosterElem children] objectEnumerator];
	while ((elem = [enumerator nextObject]) != nil) {
		XMPPRosterItem *rosterItem;
		OFMutableArray *groups = [OFMutableArray array];
		OFEnumerator *groupEnumerator;
		OFXMLElement *groupElem;







|
<

|
>

<
<
|







614
615
616
617
618
619
620
621

622
623
624
625


626
627
628
629
630
631
632
633

- (void)XMPP_handleRoster: (XMPPIQ*)iq
{
	OFXMLElement *rosterElem;
	OFEnumerator *enumerator;
	OFXMLElement *elem;

	assert([[iq type] isEqual: @"result"]);


	rosterElem = [iq elementForName: @"query"
			      namespace: XMPP_NS_ROSTER];



	assert(rosterElem != nil);

	enumerator = [[rosterElem children] objectEnumerator];
	while ((elem = [enumerator nextObject]) != nil) {
		XMPPRosterItem *rosterItem;
		OFMutableArray *groups = [OFMutableArray array];
		OFEnumerator *groupEnumerator;
		OFXMLElement *groupElem;
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
		[rosterItem setSubscription:
		    [[elem attributeForName: @"subscription"] stringValue]];

		groupEnumerator =
		    [[elem elementsForName: @"group"
				 namespace: XMPP_NS_ROSTER] objectEnumerator];
		while ((groupElem = [groupEnumerator nextObject]) != nil)
			[groups addObject:
			    [[[groupElem children] firstObject] stringValue]];

		if ([groups count] > 0)
			[rosterItem setGroups: groups];

		[roster XMPP_addRosterItem: rosterItem];
	}








|
<







644
645
646
647
648
649
650
651

652
653
654
655
656
657
658
		[rosterItem setSubscription:
		    [[elem attributeForName: @"subscription"] stringValue]];

		groupEnumerator =
		    [[elem elementsForName: @"group"
				 namespace: XMPP_NS_ROSTER] objectEnumerator];
		while ((groupElem = [groupEnumerator nextObject]) != nil)
			[groups addObject: [groupElem stringValue]];


		if ([groups count] > 0)
			[rosterItem setGroups: groups];

		[roster XMPP_addRosterItem: rosterItem];
	}

Modified tests/test.m from [4765f2a59a] to [d26de2a21f].

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

	XMPPPresence *pres = [XMPPPresence presence];
	[pres addShow: @"chat"];
	[pres addStatus: @"Bored"];
	[pres addPriority: 20];
	[pres setTo: [XMPPJID JIDWithString: @"alice@example.com"]];
	[pres setFrom: [XMPPJID JIDWithString: @"bob@example.org"]];
	assert([[pres stringValue] isEqual: @"<presence to='alice@example.com' "
	    @"from='bob@example.org'><show>chat</show>"
	    @"<status>Bored</status><priority>20</priority>"
	    @"</presence>"]);

	XMPPMessage *msg = [XMPPMessage messageWithType: @"chat"];
	[msg addBody: @"Hello everyone"];
	[msg setTo: [XMPPJID JIDWithString: @"jdev@conference.jabber.org"]];
	[msg setFrom: [XMPPJID JIDWithString: @"alice@example.com"]];
	assert([[msg stringValue] isEqual: @"<message type='chat' "
	    @"to='jdev@conference.jabber.org' "
	    @"from='alice@example.com'><body>Hello everyone</body>"
	    @"</message>"]);

	XMPPIQ *iq = [XMPPIQ IQWithType: @"set" ID: @"128"];
	[iq setTo: [XMPPJID JIDWithString: @"juliet@capulet.lit"]];
	[iq setFrom: [XMPPJID JIDWithString: @"romeo@montague.lit"]];
	assert([[iq stringValue] isEqual: @"<iq type='set' id='128' "
	    @"to='juliet@capulet.lit' "
	    @"from='romeo@montague.lit'/>"]);

	OFXMLElement *elem = [OFXMLElement elementWithName: @"iq"];
	[elem addAttributeWithName: @"from"
		       stringValue: @"bob@localhost"];
	[elem addAttributeWithName: @"to"
		       stringValue: @"alice@localhost"];
	[elem addAttributeWithName: @"type"
		       stringValue: @"get"];
	[elem addAttributeWithName: @"id"
		       stringValue: @"42"];
	XMPPStanza *stanza = [XMPPStanza stanzaWithElement: elem];
	assert([[elem stringValue] isEqual: [stanza stringValue]]);
	assert(([[OFString stringWithFormat: @"%@, %@, %@, %@",
	    [[stanza from] fullJID], [[stanza to] fullJID], [stanza type],
	    [stanza ID]] isEqual: @"bob@localhost, alice@localhost, get, 42"]));

	conn = [[XMPPConnection alloc] init];
	[conn setDelegate: self];








|








|







|













|







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

	XMPPPresence *pres = [XMPPPresence presence];
	[pres addShow: @"chat"];
	[pres addStatus: @"Bored"];
	[pres addPriority: 20];
	[pres setTo: [XMPPJID JIDWithString: @"alice@example.com"]];
	[pres setFrom: [XMPPJID JIDWithString: @"bob@example.org"]];
	assert([[pres XMLString] isEqual: @"<presence to='alice@example.com' "
	    @"from='bob@example.org'><show>chat</show>"
	    @"<status>Bored</status><priority>20</priority>"
	    @"</presence>"]);

	XMPPMessage *msg = [XMPPMessage messageWithType: @"chat"];
	[msg addBody: @"Hello everyone"];
	[msg setTo: [XMPPJID JIDWithString: @"jdev@conference.jabber.org"]];
	[msg setFrom: [XMPPJID JIDWithString: @"alice@example.com"]];
	assert([[msg XMLString] isEqual: @"<message type='chat' "
	    @"to='jdev@conference.jabber.org' "
	    @"from='alice@example.com'><body>Hello everyone</body>"
	    @"</message>"]);

	XMPPIQ *iq = [XMPPIQ IQWithType: @"set" ID: @"128"];
	[iq setTo: [XMPPJID JIDWithString: @"juliet@capulet.lit"]];
	[iq setFrom: [XMPPJID JIDWithString: @"romeo@montague.lit"]];
	assert([[iq XMLString] isEqual: @"<iq type='set' id='128' "
	    @"to='juliet@capulet.lit' "
	    @"from='romeo@montague.lit'/>"]);

	OFXMLElement *elem = [OFXMLElement elementWithName: @"iq"];
	[elem addAttributeWithName: @"from"
		       stringValue: @"bob@localhost"];
	[elem addAttributeWithName: @"to"
		       stringValue: @"alice@localhost"];
	[elem addAttributeWithName: @"type"
		       stringValue: @"get"];
	[elem addAttributeWithName: @"id"
		       stringValue: @"42"];
	XMPPStanza *stanza = [XMPPStanza stanzaWithElement: elem];
	assert([[elem XMLString] isEqual: [stanza XMLString]]);
	assert(([[OFString stringWithFormat: @"%@, %@, %@, %@",
	    [[stanza from] fullJID], [[stanza to] fullJID], [stanza type],
	    [stanza ID]] isEqual: @"bob@localhost, alice@localhost, get, 42"]));

	conn = [[XMPPConnection alloc] init];
	[conn setDelegate: self];