Skip to content

Commit

Permalink
XEP-0184
Browse files Browse the repository at this point in the history
  • Loading branch information
ObjColumnist committed May 5, 2013
1 parent 9bbef60 commit 349232e
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 2 deletions.
4 changes: 3 additions & 1 deletion Extensions/XEP-0184/XMPPMessage+XEP_0184.h
Expand Up @@ -6,7 +6,9 @@

- (BOOL)hasReceiptRequest;
- (BOOL)hasReceiptResponse;
- (NSString *)extractReceiptResponseID;
- (NSString *)receiptResponseID;
- (XMPPMessage *)generateReceiptResponse;

- (void)addReceiptRequest;

@end
9 changes: 8 additions & 1 deletion Extensions/XEP-0184/XMPPMessage+XEP_0184.m
Expand Up @@ -18,7 +18,7 @@ - (BOOL)hasReceiptResponse
return (receiptResponse != nil);
}

- (NSString *)extractReceiptResponseID
- (NSString *)receiptResponseID
{
NSXMLElement *receiptResponse = [self elementForName:@"received" xmlns:@"urn:xmpp:receipts"];

Expand Down Expand Up @@ -54,4 +54,11 @@ - (XMPPMessage *)generateReceiptResponse
return [[self class] messageFromElement:message];
}


- (void)addReceiptRequest
{
NSXMLElement *receiptRequest = [NSXMLElement elementWithName:@"request" xmlns:@"urn:xmpp:receipts"];
[self addChild:receiptRequest];
}

@end
32 changes: 32 additions & 0 deletions Extensions/XEP-0184/XMPPMessageDeliveryReceipts.h
@@ -0,0 +1,32 @@
#import "XMPPModule.h"

#define _XMPP_MESSAGE_DELIVERY_RECEIPTS_H

/**
* XMPPMessageDeliveryReceipts can be configured to automatically send delivery receipts and requests in accordance to XEP-0184
**/

@interface XMPPMessageDeliveryReceipts : XMPPModule

/**
* Automatically add message delivery requests to outgoing messages, in all situations that are permitted in XEP-0184
*
* - Message MUST NOT be of type 'error' or 'groupchat'
* - Message MUST have an id
* - Message MUST NOT have a delivery receipt or request
* - To must either be a bare JID or a full JID that advertises the urn:xmpp:receipts capability
*
* Default NO
**/

@property (assign) BOOL autoSendMessageDeliveryRequests;

/**
* Automatically send message delivery receipts when a message with a delivery request is recieved
*
* Default NO
**/

@property (assign) BOOL autoSendMessageDeliveryReceipts;

@end
210 changes: 210 additions & 0 deletions Extensions/XEP-0184/XMPPMessageDeliveryReceipts.m
@@ -0,0 +1,210 @@
#import "XMPPMessageDeliveryReceipts.h"
#import "XMPPMessage+XEP_0184.h"
#import "XMPPFramework.h"

#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif

#define XMLNS_URN_XMPP_RECEIPTS @"urn:xmpp:receipts"

@implementation XMPPMessageDeliveryReceipts

@synthesize autoSendMessageDeliveryRequests;
@synthesize autoSendMessageDeliveryReceipts;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Init/Dealloc
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (id)initWithDispatchQueue:(dispatch_queue_t)queue
{
if((self = [super initWithDispatchQueue:queue]))
{
autoSendMessageDeliveryRequests = NO;
autoSendMessageDeliveryReceipts = NO;
}

return self;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark XMPPModule
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (BOOL)activate:(XMPPStream *)aXmppStream
{
if ([super activate:aXmppStream])
{
#ifdef _XMPP_CAPABILITIES_H
[xmppStream autoAddDelegate:self delegateQueue:moduleQueue toModulesOfClass:[XMPPCapabilities class]];
#endif
return YES;
}

return NO;
}

- (void)deactivate
{
#ifdef _XMPP_CAPABILITIES_H
[xmppStream removeAutoDelegate:self delegateQueue:moduleQueue fromModulesOfClass:[XMPPCapabilities class]];
#endif

[super deactivate];
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Properties
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (BOOL)autoSendMessageDeliveryRequests
{
__block BOOL result = NO;

dispatch_block_t block = ^{
result = autoSendMessageDeliveryRequests;
};

if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_sync(moduleQueue, block);

return result;
}

- (void)setAutoSendMessageDeliveryRequests:(BOOL)flag
{
dispatch_block_t block = ^{
autoSendMessageDeliveryRequests = flag;
};

if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_async(moduleQueue, block);
}

- (BOOL)autoSendMessageDeliveryReceipts
{
__block BOOL result = NO;

dispatch_block_t block = ^{
result = autoSendMessageDeliveryReceipts;
};

if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_sync(moduleQueue, block);

return result;
}

- (void)setAutoSendMessageDeliveryReceipts:(BOOL)flag
{
dispatch_block_t block = ^{
autoSendMessageDeliveryReceipts = flag;
};

if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_async(moduleQueue, block);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark XMPPStream Delegate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
if([message hasReceiptRequest])
{
if(self.autoSendMessageDeliveryReceipts)
{
XMPPMessage *generatedReceiptResponse = [message generateReceiptResponse];
[sender sendElement:generatedReceiptResponse];
}
}
}

- (XMPPMessage *)xmppStream:(XMPPStream *)sender willSendMessage:(XMPPMessage *)message
{
if(self.autoSendMessageDeliveryRequests
&& [message to]
&& ![message isErrorMessage] && ![[[message attributeForName:@"type"] stringValue] isEqualToString:@"groupchat"]
&& [[message elementID] length]
&& ![message hasReceiptRequest] && ![message hasReceiptResponse])
{

#ifdef _XMPP_CAPABILITIES_H
BOOL addReadReceipt = NO;

__block XMPPCapabilities *xmppCapabilities = nil;

[xmppStream enumerateModulesOfClass:[XMPPCapabilities class] withBlock:^(XMPPModule *module, NSUInteger idx, BOOL *stop) {
xmppCapabilities = (XMPPCapabilities *)module;
}];

if([[message to] isFull] && [xmppCapabilities.xmppCapabilitiesStorage areCapabilitiesKnownForJID:[message to] xmppStream:sender])
{
NSXMLElement *capabilities = [xmppCapabilities.xmppCapabilitiesStorage capabilitiesForJID:[message to] xmppStream:xmppStream];

for(NSXMLElement *feature in [capabilities children])
{
if([[feature name] isEqualToString:@"feature"]
&& [[feature attributeStringValueForName:@"var"] isEqualToString:XMLNS_URN_XMPP_RECEIPTS])
{
addReadReceipt = YES;
break;
}

}

}
else
{
addReadReceipt = YES;
}
#else
BOOL addReadReceipt = YES;
#endif

if(addReadReceipt)
{
[message addReceiptRequest];
}
}

return message;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark XMPPCapabilities delegate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _XMPP_CAPABILITIES_H
/**
* If an XMPPCapabilites instance is used we want to advertise our support for XEP-0184.
**/
- (void)xmppCapabilities:(XMPPCapabilities *)sender collectingMyCapabilities:(NSXMLElement *)query
{
// This method is invoked on the moduleQueue.

// <query xmlns="http://jabber.org/protocol/disco#info">
// ...
// <feature var='urn:xmpp:receipts'/>
// ...
// </query>

NSXMLElement *messageDeliveryReceiptsFeatureElement = [NSXMLElement elementWithName:@"feature"];
[messageDeliveryReceiptsFeatureElement addAttributeWithName:@"var" stringValue:XMLNS_URN_XMPP_RECEIPTS];

[query addChild:messageDeliveryReceiptsFeatureElement];
}
#endif

@end

0 comments on commit 349232e

Please sign in to comment.