Index: src/XMPPConnection.h ================================================================== --- src/XMPPConnection.h +++ src/XMPPConnection.h @@ -67,10 +67,11 @@ short port; /// Whether to use TLS BOOL useTLS; id delegate; XMPPAuthenticator *authModule; + BOOL needsSession; } @property (copy) OFString *username; @property (copy) OFString *password; @property (copy) OFString *server; Index: src/XMPPConnection.m ================================================================== --- src/XMPPConnection.m +++ src/XMPPConnection.m @@ -40,10 +40,11 @@ #define NS_BIND @"urn:ietf:params:xml:ns:xmpp-bind" #define NS_CLIENT @"jabber:client" #define NS_SASL @"urn:ietf:params:xml:ns:xmpp-sasl" #define NS_STARTTLS @"urn:ietf:params:xml:ns:xmpp-tls" +#define NS_SESSION @"urn:ietf:params:xml:ns:xmpp-session" #define NS_STREAM @"http://etherx.jabber.org/streams" @implementation XMPPConnection @synthesize username, password, server, resource, JID, port, useTLS, delegate; @@ -193,19 +194,18 @@ if (len < 1 && [delegate respondsToSelector: @selector(connectionWasClosed:)]) [delegate connectionWasClosed: self]; - [of_stdout writeNBytes: len - fromBuffer: buf]; [parser parseBuffer: buf withSize: len]; } } - (void)sendStanza: (OFXMLElement*)elem { + of_log(@"Out: %@", elem); [sock writeString: [elem stringValue]]; } - (void)parser: (OFXMLParser*)p didStartElement: (OFString*)name @@ -255,43 +255,70 @@ stringValue: resource]]; [iq addChild: bind]; [self sendStanza: iq]; } + +- (void)_sendSession +{ + XMPPIQ *iq = [XMPPIQ IQWithType: @"set" + ID: @"session0"]; + [iq addChild: [OFXMLElement elementWithName: @"session" + namespace: NS_SESSION]]; + [self sendStanza: iq]; +} - (void)_handleResourceBind: (XMPPIQ*)iq { OFXMLElement *bindElem = iq.children.firstObject; - - if ([bindElem.name isEqual: @"bind"] && - [bindElem.namespace isEqual: NS_BIND]) { - OFXMLElement *jidElem = bindElem.children.firstObject; - JID = [[XMPPJID alloc] initWithString: - [jidElem.children.firstObject stringValue]]; - - if ([delegate respondsToSelector: - @selector(connection:wasBoundToJID:)]) - [delegate connection: self - wasBoundToJID: JID]; - } + OFXMLElement *jidElem; + + if (![bindElem.name isEqual: @"bind"] || + ![bindElem.namespace isEqual: NS_BIND]) + assert(0); + + jidElem = bindElem.children.firstObject; + JID = [[XMPPJID alloc] initWithString: + [jidElem.children.firstObject stringValue]]; + + if (needsSession) { + [self _sendSession]; + return; + } + + if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)]) + [delegate connection: self + wasBoundToJID: JID]; +} + +- (void)_handleSession +{ + if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)]) + [delegate connection: self + wasBoundToJID: JID]; } - (void)_handleFeatures: (OFXMLElement*)elem { OFXMLElement *starttls = [elem elementsForName: @"starttls" namespace: NS_STARTTLS].firstObject; OFXMLElement *bind = [elem elementsForName: @"bind" namespace: NS_BIND].firstObject; + OFXMLElement *session = [elem elementsForName: @"session" + namespace: NS_SESSION].firstObject; OFArray *mechs = [elem elementsForName: @"mechanisms" namespace: NS_SASL]; OFMutableArray *mechanisms = [OFMutableArray array]; - if (starttls != nil) + if (starttls != nil) { [self sendStanza: [OFXMLElement elementWithName: @"starttls" namespace: NS_STARTTLS]]; - else if ([mechs count]) { + return; + } + + if ([mechs count] > 0) { for (OFXMLElement *mech in [mechs.firstObject children]) [mechanisms addObject: [mech.children.firstObject stringValue]]; if ([mechanisms containsObject: @"SCRAM-SHA-1"]) { @@ -298,27 +325,47 @@ authModule = [[XMPPSCRAMAuth alloc] initWithAuthcid: username password: password hash: [OFSHA1Hash class]]; [self _sendAuth: @"SCRAM-SHA-1"]; - } else if ([mechanisms containsObject: @"PLAIN"]) { + return; + } + + if ([mechanisms containsObject: @"PLAIN"]) { authModule = [[XMPPPLAINAuth alloc] initWithAuthcid: username password: password]; [self _sendAuth: @"PLAIN"]; + return; } - } else if (bind != nil) + + assert(0); + } + + if (session != nil) + needsSession = YES; + + if (bind != nil) { [self _sendResourceBind]; + return; + } + + assert(0); } - (void)_handleIQ: (XMPPIQ*)iq { // FIXME: More checking! if ([iq.ID isEqual: @"bind0"] && [iq.type isEqual: @"result"]) { [self _handleResourceBind: iq]; return; } + + if ([iq.ID isEqual: @"session0"] && [iq.type isEqual: @"result"]) { + [self _handleSession]; + return; + } if ([delegate respondsToSelector: @selector(connection:didReceiveIQ:)]) [delegate connection: self didReceiveIQ: iq]; } @@ -343,10 +390,12 @@ didBuildElement: (OFXMLElement*)elem { elem.defaultNamespace = NS_CLIENT; [elem setPrefix: @"stream" forNamespace: NS_STREAM]; + + of_log(@"In: %@", elem); if ([elem.namespace isEqual: NS_CLIENT]) { if ([elem.name isEqual: @"iq"]) { [self _handleIQ: [XMPPIQ stanzaWithElement: elem]]; return; Index: tests/test.m ================================================================== --- tests/test.m +++ tests/test.m @@ -31,20 +31,18 @@ #import "XMPPIQ.h" #import "XMPPMessage.h" #import "XMPPPresence.h" @interface AppDelegate: OFObject -{ - XMPPConnection *conn; -} @end OF_APPLICATION_DELEGATE(AppDelegate) @implementation AppDelegate - (void)applicationDidFinishLaunching { + XMPPConnection *conn; OFArray *arguments = [OFApplication arguments]; XMPPPresence *pres = [XMPPPresence presence]; [pres addShow: @"chat"]; [pres addStatus: @"Bored"]; @@ -111,11 +109,19 @@ } - (void)connection: (XMPPConnection*)conn wasBoundToJID: (XMPPJID*)jid { + XMPPPresence *pres; + of_log(@"Bound to JID: %@", [jid fullJID]); + + pres = [XMPPPresence presence]; + [pres addPriority: 10]; + [pres addStatus: @"ObjXMPP test is working!"]; + + [conn sendStanza: pres]; } - (void)connection: (XMPPConnection*)conn didReceiveIQ: (XMPPIQ*)iq {