@@ -19,10 +19,12 @@ * 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_CONNECTION_M + #include #include #include @@ -35,32 +37,14 @@ #import "XMPPJID.h" #import "XMPPIQ.h" #import "XMPPMessage.h" #import "XMPPPresence.h" #import "XMPPRoster.h" -#import "XMPPRoster_private.h" #import "XMPPRosterItem.h" #import "XMPPExceptions.h" -@interface XMPPConnection () -- (void)XMPP_startStream; -- (void)XMPP_handleStanza: (OFXMLElement*)elem; -- (void)XMPP_sendAuth: (OFString*)name; -- (void)XMPP_handleIQ: (XMPPIQ*)iq; -- (void)XMPP_handleMessage: (XMPPMessage*)msg; -- (void)XMPP_handlePresence: (XMPPPresence*)pres; -- (void)XMPP_handleFeatures: (OFXMLElement*)elem; -- (void)XMPP_sendResourceBind; -- (void)XMPP_handleResourceBind: (XMPPIQ*)iq; -- (void)XMPP_sendSession; -- (void)XMPP_handleSession: (XMPPIQ*)iq; -- (void)XMPP_handleRoster: (XMPPIQ*)iq; -@end - @implementation XMPPConnection -@synthesize JID, port, delegate, roster; - - init { self = [super init]; @try { @@ -68,12 +52,12 @@ parser = [[OFXMLParser alloc] init]; elementBuilder = [[OFXMLElementBuilder alloc] init]; port = 5222; - parser.delegate = self; - elementBuilder.delegate = self; + [parser setDelegate: self]; + [elementBuilder setDelegate: self]; roster = [[XMPPRoster alloc] initWithConnection: self]; } @catch (id e) { [self release]; @throw e; @@ -164,14 +148,14 @@ Idna_rc rc; if ((rc = idna_to_ascii_8z([server_ cString], &srv, IDNA_USE_STD3_ASCII_RULES)) != IDNA_SUCCESS) @throw [XMPPIDNATranslationFailedException - newWithClass: isa - connection: self - operation: @"ToASCII" - string: server_]; + newWithClass: isa + connection: self + operation: @"ToASCII" + string: server_]; @try { server = [[OFString alloc] initWithCString: srv]; } @finally { free(srv); @@ -256,36 +240,39 @@ withPrefix: (OFString*)prefix namespace: (OFString*)ns attributes: (OFArray*)attrs { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFEnumerator *enumerator; + OFXMLAttribute *attr; if (![name isEqual: @"stream"] || ![prefix isEqual: @"stream"] || ![ns isEqual: XMPP_NS_STREAM]) { of_log(@"Did not get expected stream start!"); assert(0); } - for (OFXMLAttribute *attr in attrs) { - if ([attr.name isEqual: @"from"] && - ![attr.stringValue isEqual: server]) { + enumerator = [attrs objectEnumerator]; + while ((attr = [enumerator nextObject]) != nil) { + if ([[attr name] isEqual: @"from"] && + ![[attr stringValue] isEqual: server]) { of_log(@"Got invalid from in stream start!"); assert(0); } } - parser.delegate = elementBuilder; + [parser setDelegate: elementBuilder]; [pool release]; } - (void)elementBuilder: (OFXMLElementBuilder*)b didBuildElement: (OFXMLElement*)elem { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - elem.defaultNamespace = XMPP_NS_CLIENT; + [elem setDefaultNamespace: XMPP_NS_CLIENT]; [elem setPrefix: @"stream" forNamespace: XMPP_NS_STREAM]; of_log(@"In: %@", elem); @@ -303,64 +290,64 @@ @"version='1.0'>", server]; } - (void)XMPP_handleStanza: (OFXMLElement*)elem { - if ([elem.namespace isEqual: XMPP_NS_CLIENT]) { - if ([elem.name isEqual: @"iq"]) { + if ([[elem namespace] isEqual: XMPP_NS_CLIENT]) { + if ([[elem name] isEqual: @"iq"]) { [self XMPP_handleIQ: [XMPPIQ stanzaWithElement: elem]]; return; } - if ([elem.name isEqual: @"message"]) { + if ([[elem name] isEqual: @"message"]) { [self XMPP_handleMessage: [XMPPMessage stanzaWithElement: elem]]; return; } - if ([elem.name isEqual: @"presence"]) { + if ([[elem name] isEqual: @"presence"]) { [self XMPP_handlePresence: [XMPPPresence stanzaWithElement: elem]]; return; } assert(0); } - if ([elem.namespace isEqual: XMPP_NS_STREAM]) { - if ([elem.name isEqual: @"features"]) { + if ([[elem namespace] isEqual: XMPP_NS_STREAM]) { + if ([[elem name] isEqual: @"features"]) { [self XMPP_handleFeatures: elem]; return; } assert(0); } - if ([elem.namespace isEqual: XMPP_NS_STARTTLS]) { - if ([elem.name isEqual: @"proceed"]) { + if ([[elem namespace] isEqual: XMPP_NS_STARTTLS]) { + if ([[elem name] isEqual: @"proceed"]) { /* FIXME: Catch errors here */ sock = [[SSLSocket alloc] initWithSocket: sock]; /* Stream restart */ - parser.delegate = self; + [parser setDelegate: self]; [self XMPP_startStream]; return; } - if ([elem.name isEqual: @"failure"]) + if ([[elem name] isEqual: @"failure"]) /* TODO: Find/create an exception to throw here */ @throw [OFException newWithClass: isa]; assert(0); } - if ([elem.namespace isEqual: XMPP_NS_SASL]) { - if ([elem.name isEqual: @"challenge"]) { + if ([[elem namespace] isEqual: XMPP_NS_SASL]) { + if ([[elem name] isEqual: @"challenge"]) { OFXMLElement *responseTag; OFDataArray *challenge = [OFDataArray dataArrayWithBase64EncodedString: - [elem.children.firstObject stringValue]]; + [[[elem children] firstObject] stringValue]]; OFDataArray *response = [authModule calculateResponseWithChallenge: challenge]; responseTag = [OFXMLElement elementWithName: @"response" @@ -371,32 +358,32 @@ [self sendStanza: responseTag]; return; } - if ([elem.name isEqual: @"success"]) { + if ([[elem name] isEqual: @"success"]) { [authModule parseServerFinalMessage: [OFDataArray dataArrayWithBase64EncodedString: - [elem.children.firstObject stringValue]]]; + [[[elem children] firstObject] stringValue]]]; if ([delegate respondsToSelector: @selector(connectionWasAuthenticated:)]) [delegate connectionWasAuthenticated: self]; /* Stream restart */ - parser.delegate = self; + [parser setDelegate: self]; [self XMPP_startStream]; return; } - if ([elem.name isEqual: @"failure"]) { + if ([[elem name] isEqual: @"failure"]) { of_log(@"Auth failed!"); // FIXME: Do more parsing/handling @throw [XMPPAuthFailedException newWithClass: isa connection: self - reason: elem.stringValue]; + reason: [elem stringValue]]; } assert(0); } @@ -405,38 +392,37 @@ - (void)XMPP_handleIQ: (XMPPIQ*)iq { BOOL handled = NO; - if ([iq.ID isEqual: bindID]) { + if ([[iq ID] isEqual: bindID]) { [self XMPP_handleResourceBind: iq]; return; } - if ([iq.ID isEqual: sessionID]) { + if ([[iq ID] isEqual: sessionID]) { [self XMPP_handleSession: iq]; return; } - if ([iq.ID isEqual: rosterID]) { + if ([[iq ID] isEqual: rosterID]) { [self XMPP_handleRoster: iq]; return; } if ([delegate respondsToSelector: @selector(connection:didReceiveIQ:)]) handled = [delegate connection: self didReceiveIQ: iq]; if (!handled) { - XMPPJID *from = iq.from; - XMPPJID *to = iq.to; + XMPPJID *from = [iq from]; + XMPPJID *to = [iq to]; OFXMLElement *error; [iq setType: @"error"]; - - iq.to = from; - iq.from = to; + [iq setTo: from]; + [iq setFrom: to]; error = [OFXMLElement elementWithName: @"error"]; [error addAttributeWithName: @"type" stringValue: @"cancel"]; [error addChild: @@ -465,17 +451,17 @@ } - (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; + [[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; + [[elem elementsForName: @"session" + namespace: XMPP_NS_SESSION] firstObject]; OFArray *mechs = [elem elementsForName: @"mechanisms" namespace: XMPP_NS_SASL]; OFMutableArray *mechanisms = [OFMutableArray array]; if (starttls != nil) { @@ -483,14 +469,18 @@ [OFXMLElement elementWithName: @"starttls" namespace: XMPP_NS_STARTTLS]]; return; } - if (mechs.count > 0) { - for (OFXMLElement *mech in [mechs.firstObject children]) + if ([mechs count] > 0) { + OFEnumerator *enumerator; + OFXMLElement *mech; + + enumerator = [[[mechs firstObject] children] objectEnumerator]; + while ((mech = [enumerator nextObject]) != nil) [mechanisms addObject: - [mech.children.firstObject stringValue]]; + [[[mech children] firstObject] stringValue]]; if ([mechanisms containsObject: @"SCRAM-SHA-1"]) { authModule = [[XMPPSCRAMAuth alloc] initWithAuthcid: username password: password @@ -559,22 +549,22 @@ - (void)XMPP_handleResourceBind: (XMPPIQ*)iq { OFXMLElement *bindElem; OFXMLElement *jidElem; - if (![iq.type isEqual: @"result"]) + if (![[iq type] isEqual: @"result"]) assert(0); - bindElem = iq.children.firstObject; + bindElem = [[iq children] firstObject]; - if (![bindElem.name isEqual: @"bind"] || - ![bindElem.namespace isEqual: XMPP_NS_BIND]) + if (![[bindElem name] isEqual: @"bind"] || + ![[bindElem namespace] isEqual: XMPP_NS_BIND]) assert(0); - jidElem = bindElem.children.firstObject; + jidElem = [[bindElem children] firstObject]; JID = [[XMPPJID alloc] initWithString: - [jidElem.children.firstObject stringValue]]; + [[[jidElem children] firstObject] stringValue]]; [bindID release]; bindID = nil; if (needsSession) { @@ -599,11 +589,11 @@ [self sendStanza: iq]; } - (void)XMPP_handleSession: (XMPPIQ*)iq { - if (![iq.type isEqual: @"result"]) + if (![[iq type] isEqual: @"result"]) assert(0); if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)]) [delegate connection: self wasBoundToJID: JID]; @@ -628,43 +618,50 @@ } - (void)XMPP_handleRoster: (XMPPIQ*)iq { OFXMLElement *rosterElem; - - if (![iq.type isEqual: @"result"]) - assert(0); - - rosterElem = iq.children.firstObject; - - if (![rosterElem.name isEqual: @"query"] || - ![rosterElem.namespace isEqual: XMPP_NS_ROSTER]) - assert(0); - - for (OFXMLElement *elem in rosterElem.children) { - XMPPRosterItem *rosterItem; - OFMutableArray *groups = [OFMutableArray array]; - - if (![elem.name isEqual: @"item"] || - ![elem.ns isEqual: XMPP_NS_ROSTER]) + 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; + + if (![[elem name] isEqual: @"item"] || + ![[elem namespace] isEqual: XMPP_NS_ROSTER]) continue; rosterItem = [XMPPRosterItem rosterItem]; - rosterItem.JID = [XMPPJID JIDWithString: - [elem attributeForName: @"jid"].stringValue]; - rosterItem.name = [elem attributeForName: @"name"].stringValue; - rosterItem.subscription = - [elem attributeForName: @"subscription"].stringValue; - - for (OFXMLElement *groupElem in - [elem elementsForName: @"group" - namespace: XMPP_NS_ROSTER]) + [rosterItem setJID: [XMPPJID JIDWithString: + [[elem attributeForName: @"jid"] stringValue]]]; + [rosterItem setName: + [[elem attributeForName: @"name"] stringValue]]; + [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]]; + [[[groupElem children] firstObject] stringValue]]; - if (groups.count > 0) - rosterItem.groups = groups; + if ([groups count] > 0) + [rosterItem setGroups: groups]; [roster XMPP_addRosterItem: rosterItem]; } if ([delegate respondsToSelector: @@ -672,6 +669,73 @@ [delegate connectionDidReceiveRoster: self]; [rosterID release]; rosterID = nil; } + +- (XMPPJID*)JID +{ + return [[JID copy] autorelease]; +} + +- (void)setPort: (uint16_t)port_ +{ + port = port_; +} + +- (uint16_t)port +{ + return port; +} + +- (void)setDelegate: (id )delegate_ +{ + id old = delegate; + delegate = [(id)delegate_ retain]; + [old release]; +} + +- (id )delegate +{ + return [[delegate retain] autorelease]; +} + +- (XMPPRoster*)roster +{ + return [[roster retain] autorelease]; +} +@end + +@implementation OFObject (XMPPConnectionDelegate) +- (void)connectionWasAuthenticated: (XMPPConnection*)conn +{ +} + +- (void)connection: (XMPPConnection*)conn + wasBoundToJID: (XMPPJID*)jid +{ +} + +- (void)connectionDidReceiveRoster: (XMPPConnection*)conn +{ +} + +- (BOOL)connection: (XMPPConnection*)conn + didReceiveIQ: (XMPPIQ*)iq +{ + return NO; +} + +- (void)connection: (XMPPConnection*)conn + didReceivePresence: (XMPPPresence*)pres +{ +} + +- (void)connection: (XMPPConnection*)conn + didReceiveMessage: (XMPPMessage*)msg +{ +} + +- (void)connectionWasClosed: (XMPPConnection*)conn +{ +} @end