Initial commit.
Work done by me and Florian Zeitz.
This commit is contained in:
commit
dde9ac7d85
3 changed files with 276 additions and 0 deletions
43
XMPPConnection.h
Normal file
43
XMPPConnection.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#import <ObjFW/ObjFW.h>
|
||||
|
||||
@class XMPPConnection;
|
||||
@class XMPPIQ;
|
||||
@class XMPPMessage;
|
||||
@class XMPPPresence;
|
||||
|
||||
@protocol XMPPConnectionDelegate
|
||||
- (void)connectionWasClosed: (XMPPConnection*)conn;
|
||||
- (void)connection: (XMPPConnection*)conn
|
||||
didReceiveIQ: (XMPPIQ*)iq;
|
||||
- (void)connection: (XMPPConnection*)conn
|
||||
didReceivePresence: (XMPPPresence*)pres;
|
||||
- (void)connection: (XMPPConnection*)conn
|
||||
didReceiveMessage: (XMPPMessage*)msg;
|
||||
@end
|
||||
|
||||
@interface XMPPConnection: OFObject <OFXMLElementBuilderDelegate>
|
||||
{
|
||||
OFTCPSocket *sock;
|
||||
OFXMLParser *parser;
|
||||
OFXMLElementBuilder *elementBuilder;
|
||||
OFString *username;
|
||||
OFString *password;
|
||||
OFString *server;
|
||||
OFString *resource;
|
||||
short port;
|
||||
BOOL useTLS;
|
||||
id <XMPPConnectionDelegate> delegate;
|
||||
OFMutableArray *mechanisms;
|
||||
}
|
||||
|
||||
@property (copy) OFString *username;
|
||||
@property (copy) OFString *password;
|
||||
@property (copy) OFString *server;
|
||||
@property (copy) OFString *resource;
|
||||
@property (assign) short port;
|
||||
@property (assign) BOOL useTLS;
|
||||
@property (retain) id <XMPPConnectionDelegate> delegate;
|
||||
|
||||
- (void)connect;
|
||||
- (void)handleConnection;
|
||||
@end
|
200
XMPPConnection.m
Normal file
200
XMPPConnection.m
Normal file
|
@ -0,0 +1,200 @@
|
|||
#import "XMPPConnection.h"
|
||||
|
||||
#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_STREAM @"http://etherx.jabber.org/streams"
|
||||
|
||||
@implementation XMPPConnection
|
||||
@synthesize username;
|
||||
@synthesize password;
|
||||
@synthesize server;
|
||||
@synthesize resource;
|
||||
@synthesize port;
|
||||
@synthesize useTLS;
|
||||
@synthesize delegate;
|
||||
|
||||
- init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
sock = [[OFTCPSocket alloc] init];
|
||||
parser = [[OFXMLParser alloc] init];
|
||||
elementBuilder = [[OFXMLElementBuilder alloc] init];
|
||||
|
||||
port = 5222;
|
||||
useTLS = YES;
|
||||
|
||||
mechanisms = [[OFMutableArray alloc] init];
|
||||
|
||||
parser.delegate = self;
|
||||
elementBuilder.delegate = self;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[sock release];
|
||||
[parser release];
|
||||
[elementBuilder release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)_startStream
|
||||
{
|
||||
[sock writeFormat: @"<?xml version='1.0'?>\n"
|
||||
@"<stream:stream to='%@' xmlns='" NS_CLIENT @"' "
|
||||
@"xmlns:stream='" NS_STREAM @"' "
|
||||
@"version='1.0'>", server];
|
||||
}
|
||||
|
||||
- (void)connect
|
||||
{
|
||||
OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
|
||||
|
||||
[sock connectToService: [OFString stringWithFormat: @"%u", port]
|
||||
onNode: server];
|
||||
[self _startStream];
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
- (void)handleConnection
|
||||
{
|
||||
char buf[512];
|
||||
|
||||
for (;;) {
|
||||
size_t len = [sock readNBytes: 512
|
||||
intoBuffer: buf];
|
||||
|
||||
if (len < 1)
|
||||
[delegate connectionWasClosed: self];
|
||||
|
||||
[of_stdout writeNBytes: len
|
||||
fromBuffer: buf];
|
||||
[parser parseBuffer: buf
|
||||
withSize: len];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)parser: (OFXMLParser*)p
|
||||
didStartElement: (OFString*)name
|
||||
withPrefix: (OFString*)prefix
|
||||
namespace: (OFString*)ns
|
||||
attributes: (OFArray*)attrs
|
||||
{
|
||||
if (![name isEqual: @"stream"] || ![prefix isEqual: @"stream"] ||
|
||||
![ns isEqual: NS_STREAM])
|
||||
of_log(@"Did not get expected stream start!");
|
||||
|
||||
for (OFXMLAttribute *attr in attrs)
|
||||
if ([attr.name isEqual: @"from"] &&
|
||||
![attr.stringValue isEqual: server])
|
||||
of_log(@"Got invalid from in stream start!");
|
||||
|
||||
parser.delegate = elementBuilder;
|
||||
}
|
||||
|
||||
- (void)_addAuthMechanisms: (OFXMLElement*)mechanisms_
|
||||
{
|
||||
for (OFXMLElement *mechanism in mechanisms_.children)
|
||||
[mechanisms addObject:
|
||||
[mechanism.children.firstObject stringValue]];
|
||||
}
|
||||
|
||||
- (void)_sendPLAINAuth
|
||||
{
|
||||
OFXMLElement *authTag;
|
||||
OFDataArray *message;
|
||||
|
||||
message = [OFDataArray dataArrayWithItemSize: 1];
|
||||
/* XXX: authzid would go here */
|
||||
//[message addItem: authzid];
|
||||
/* separator */
|
||||
[message addItem: ""];
|
||||
/* authcid */
|
||||
[message addNItems: [username cStringLength]
|
||||
fromCArray: [username cString]];
|
||||
/* separator */
|
||||
[message addItem: ""];
|
||||
/* passwd */
|
||||
[message addNItems: [password cStringLength]
|
||||
fromCArray: [password cString]];
|
||||
|
||||
authTag = [OFXMLElement elementWithName: @"auth"
|
||||
namespace: NS_SASL];
|
||||
[authTag addAttributeWithName: @"mechanism"
|
||||
stringValue: @"PLAIN"];
|
||||
[authTag addChild: [OFXMLElement elementWithCharacters:
|
||||
[message stringByBase64Encoding]]];
|
||||
|
||||
[sock writeString: [authTag stringValue]];
|
||||
}
|
||||
|
||||
- (void)_sendResourceBind
|
||||
{
|
||||
OFXMLElement *iq = [OFXMLElement elementWithName: @"iq"];
|
||||
[iq addAttributeWithName: @"type" stringValue: @"set"];
|
||||
[iq addChild: [OFXMLElement elementWithName: @"bind"
|
||||
namespace: NS_BIND]];
|
||||
|
||||
[sock writeString: [iq stringValue]];
|
||||
}
|
||||
|
||||
- (void)_handleFeatures: (OFXMLElement*)elem
|
||||
{
|
||||
for (OFXMLElement *child in elem.children) {
|
||||
if ([[child name] isEqual: @"mechanisms"] &&
|
||||
[[child namespace] isEqual: NS_SASL])
|
||||
[self _addAuthMechanisms: child];
|
||||
else if ([[child name] isEqual: @"bind"] &&
|
||||
[[child namespace] isEqual: NS_BIND])
|
||||
[self _sendResourceBind];
|
||||
}
|
||||
|
||||
if ([mechanisms containsObject: @"PLAIN"])
|
||||
[self _sendPLAINAuth];
|
||||
}
|
||||
|
||||
- (void)elementBuilder: (OFXMLElementBuilder*)b
|
||||
didBuildElement: (OFXMLElement*)elem
|
||||
{
|
||||
elem.defaultNamespace = NS_CLIENT;
|
||||
[elem setPrefix: @"stream"
|
||||
forNamespace: NS_STREAM];
|
||||
|
||||
if ([elem.name isEqual: @"features"] &&
|
||||
[elem.namespace isEqual: NS_STREAM]) {
|
||||
[self _handleFeatures: elem];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([elem.namespace isEqual: NS_SASL]) {
|
||||
if ([elem.name isEqual: @"success"]) {
|
||||
of_log(@"Auth successful");
|
||||
|
||||
/* Stream restart */
|
||||
[mechanisms release];
|
||||
mechanisms = [[OFMutableArray alloc] init];
|
||||
parser.delegate = self;
|
||||
|
||||
[self _startStream];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([elem.name isEqual: @"failure"])
|
||||
of_log(@"Auth failed!");
|
||||
// FIXME: Handle!
|
||||
}
|
||||
}
|
||||
|
||||
- (void)elementBuilder: (OFXMLElementBuilder*)b
|
||||
didNotExpectCloseTag: (OFString*)name
|
||||
withPrefix: (OFString*)prefix
|
||||
namespace: (OFString*)ns
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
@end
|
33
test.m
Normal file
33
test.m
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <ObjFW/ObjFW.h>
|
||||
#import "XMPPConnection.h"
|
||||
|
||||
@interface AppDelegate: OFObject
|
||||
{
|
||||
XMPPConnection *conn;
|
||||
}
|
||||
@end
|
||||
|
||||
OF_APPLICATION_DELEGATE(AppDelegate)
|
||||
|
||||
@implementation AppDelegate
|
||||
- (void)applicationDidFinishLaunching
|
||||
{
|
||||
OFArray *arguments = [OFApplication arguments];
|
||||
|
||||
conn = [[XMPPConnection alloc] init];
|
||||
|
||||
if (arguments.count != 3) {
|
||||
of_log(@"Invalid count of command line arguments!");
|
||||
[OFApplication terminateWithStatus: 1];
|
||||
}
|
||||
|
||||
[conn setServer: [arguments objectAtIndex: 0]];
|
||||
[conn setUsername: [arguments objectAtIndex: 1]];
|
||||
[conn setPassword: [arguments objectAtIndex: 2]];
|
||||
[conn setResource: @"ObjXMPP"];
|
||||
[conn setUseTLS: NO];
|
||||
|
||||
[conn connect];
|
||||
[conn handleConnection];
|
||||
}
|
||||
@end
|
Loading…
Add table
Add a link
Reference in a new issue