Skip to content

Commit 60fa06c

Browse files
Merge PRs #998 #1001 #1002 #1003
2 parents 0ec4785 + baf95bf commit 60fa06c

File tree

19 files changed

+950
-21
lines changed

19 files changed

+950
-21
lines changed

Core/XMPPFramework.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#import "XMPPTimer.h"
3535
#import "XMPPCoreDataStorage.h"
3636
#import "XMPPCoreDataStorageProtected.h"
37+
#import "XMPPDelayedDelivery.h"
3738
#import "NSXMLElement+XEP_0203.h"
3839
#import "XMPPFileTransfer.h"
3940
#import "XMPPIncomingFileTransfer.h"
@@ -132,6 +133,7 @@
132133
#import "XMPPStreamManagementMemoryStorage.h"
133134
#import "XMPPStreamManagementStanzas.h"
134135
#import "XMPPStreamManagement.h"
136+
#import "XMPPManagedMessaging.h"
135137
#import "XMPPAutoPing.h"
136138
#import "XMPPPing.h"
137139
#import "XMPPAutoTime.h"
@@ -164,6 +166,7 @@
164166
#import "XMPPRoomLightCoreDataStorage.h"
165167
#import "XMPPRoomLightCoreDataStorageProtected.h"
166168
#import "XMPPRoomLightMessageCoreDataStorageObject.h"
169+
#import "XMPPOneToOneChat.h"
167170

168171

169172
FOUNDATION_EXPORT double XMPPFrameworkVersionNumber;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#import "XMPPModule.h"
2+
3+
NS_ASSUME_NONNULL_BEGIN
4+
5+
@class XMPPMessage;
6+
7+
/// @brief A module that handles one-to-one chat messaging.
8+
/// @discussion This module triggers delegate callbacks for all sent or received messages of type 'chat'.
9+
@interface XMPPOneToOneChat : XMPPModule
10+
11+
@end
12+
13+
/// A protocol defining @c XMPPOneToOneChat module delegate API.
14+
@protocol XMPPOneToOneChatDelegate <NSObject>
15+
16+
@optional
17+
/// Notifies the delegate that a chat message has been received in the stream.
18+
- (void)xmppOneToOneChat:(XMPPOneToOneChat *)xmppOneToOneChat didReceiveChatMessage:(XMPPMessage *)message
19+
NS_SWIFT_NAME(xmppOneToOneChat(_:didReceiveChatMessage:));
20+
21+
/// Notifies the delegate that a chat message has been sent in the stream.
22+
- (void)xmppOneToOneChat:(XMPPOneToOneChat *)xmppOneToOneChat didSendChatMessage:(XMPPMessage *)message
23+
NS_SWIFT_NAME(xmppOneToOneChat(_:didSendChatMessage:));
24+
25+
@end
26+
27+
NS_ASSUME_NONNULL_END
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#import "XMPPOneToOneChat.h"
2+
#import "XMPPMessage.h"
3+
#import "XMPPStream.h"
4+
#import "XMPPLogging.h"
5+
6+
// Log levels: off, error, warn, info, verbose
7+
// Log flags: trace
8+
#if DEBUG
9+
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN; // | XMPP_LOG_FLAG_TRACE;
10+
#else
11+
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
12+
#endif
13+
14+
@implementation XMPPOneToOneChat
15+
16+
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
17+
{
18+
XMPPLogTrace();
19+
20+
if (![message isChatMessage]) {
21+
return;
22+
}
23+
24+
XMPPLogInfo(@"Received chat message from %@", [message from]);
25+
[multicastDelegate xmppOneToOneChat:self didReceiveChatMessage:message];
26+
}
27+
28+
- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
29+
{
30+
XMPPLogTrace();
31+
32+
if (![message isChatMessage]) {
33+
return;
34+
}
35+
36+
XMPPLogInfo(@"Sent chat message to %@", [message to]);
37+
[multicastDelegate xmppOneToOneChat:self didSendChatMessage:message];
38+
}
39+
40+
@end

Extensions/XEP-0184/XMPPMessageDeliveryReceipts.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#define _XMPP_MESSAGE_DELIVERY_RECEIPTS_H
44

5+
@class XMPPMessage;
6+
57
/**
68
* XMPPMessageDeliveryReceipts can be configured to automatically send delivery receipts and requests in accordance to XEP-0184
79
**/
@@ -30,5 +32,19 @@ NS_ASSUME_NONNULL_BEGIN
3032

3133
@property (assign) BOOL autoSendMessageDeliveryReceipts;
3234

35+
@end
36+
37+
/**
38+
* A protocol defining @c XMPPManagedMessaging module delegate API.
39+
**/
40+
@protocol XMPPMessageDeliveryReceiptsDelegate <NSObject>
41+
42+
@optional
43+
44+
/**
45+
* Notifies the delegate of a receipt response message received in the stream.
46+
**/
47+
- (void)xmppMessageDeliveryReceipts:(XMPPMessageDeliveryReceipts *)xmppMessageDeliveryReceipts didReceiveReceiptResponseMessage:(XMPPMessage *)message;
48+
3349
@end
3450
NS_ASSUME_NONNULL_END

Extensions/XEP-0184/XMPPMessageDeliveryReceipts.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
129129
[sender sendElement:generatedReceiptResponse];
130130
}
131131
}
132+
133+
if ([message hasReceiptResponse])
134+
{
135+
[multicastDelegate xmppMessageDeliveryReceipts:self didReceiveReceiptResponseMessage:message];
136+
}
132137
}
133138

134139
- (XMPPMessage *)xmppStream:(XMPPStream *)sender willSendMessage:(XMPPMessage *)message
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#import "XMPPModule.h"
2+
3+
NS_ASSUME_NONNULL_BEGIN
4+
5+
@class XMPPMessage;
6+
7+
/**
8+
A module working in tandem with @c XMPPStreamManagement to trace outgoing message stream acknowledgements.
9+
10+
This module only monitors messages with @c elementID assigned. The rationale behind this is that any potential retransmissions
11+
of messages without IDs will cause deduplication issues on the receiving end.
12+
*/
13+
@interface XMPPManagedMessaging : XMPPModule
14+
15+
@end
16+
17+
/// A protocol defining @c XMPPManagedMessaging module delegate API.
18+
@protocol XMPPManagedMessagingDelegate <NSObject>
19+
20+
@optional
21+
22+
/// Notifies the delegate that a message subject to monitoring has been sent in the stream.
23+
- (void)xmppManagedMessaging:(XMPPManagedMessaging *)sender didBeginMonitoringOutgoingMessage:(XMPPMessage *)message;
24+
25+
/// Notifies the delegate that @c XMPPStreamManagement module has received server acknowledgement for sent messages with given IDs.
26+
- (void)xmppManagedMessaging:(XMPPManagedMessaging *)sender didConfirmSentMessagesWithIDs:(NSArray<NSString *> *)messageIDs;
27+
28+
/// @brief Notifies the delegate that post-reauthentication message acknowledgement processing is finished.
29+
/// At this point, no more acknowledgements for currently monitored messages are to be expected.
30+
- (void)xmppManagedMessagingDidFinishProcessingPreviousStreamConfirmations:(XMPPManagedMessaging *)sender;
31+
32+
@end
33+
34+
NS_ASSUME_NONNULL_END
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#import "XMPPManagedMessaging.h"
2+
#import "XMPPStreamManagement.h"
3+
#import "XMPPLogging.h"
4+
5+
// Log levels: off, error, warn, info, verbose
6+
// Log flags: trace
7+
#if DEBUG
8+
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN; // | XMPP_LOG_FLAG_TRACE;
9+
#else
10+
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
11+
#endif
12+
13+
static NSString * const XMPPManagedMessagingURLScheme = @"xmppmanagedmessage";
14+
15+
@implementation XMPPManagedMessaging
16+
17+
- (void)didActivate
18+
{
19+
XMPPLogTrace();
20+
[self.xmppStream autoAddDelegate:self delegateQueue:self.moduleQueue toModulesOfClass:[XMPPStreamManagement class]];
21+
}
22+
23+
- (void)willDeactivate
24+
{
25+
XMPPLogTrace();
26+
[self.xmppStream removeAutoDelegate:self delegateQueue:self.moduleQueue fromModulesOfClass:[XMPPStreamManagement class]];
27+
}
28+
29+
- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
30+
{
31+
XMPPLogTrace();
32+
33+
if (![message elementID]) {
34+
XMPPLogWarn(@"Sent message without an ID excluded from managed messaging");
35+
return;
36+
}
37+
38+
XMPPLogInfo(@"Registering message with ID=%@ for managed messaging", [message elementID]);
39+
[multicastDelegate xmppManagedMessaging:self didBeginMonitoringOutgoingMessage:message];
40+
}
41+
42+
- (id)xmppStreamManagement:(XMPPStreamManagement *)sender stanzaIdForSentElement:(XMPPElement *)element
43+
{
44+
if (![element isKindOfClass:[XMPPMessage class]] || ![element elementID]) {
45+
return nil;
46+
}
47+
48+
NSURLComponents *managedMessageURLComponents = [[NSURLComponents alloc] init];
49+
managedMessageURLComponents.scheme = XMPPManagedMessagingURLScheme;
50+
managedMessageURLComponents.path = [element elementID];
51+
52+
return managedMessageURLComponents.URL;
53+
}
54+
55+
- (void)xmppStreamManagement:(XMPPStreamManagement *)sender didReceiveAckForStanzaIds:(NSArray *)stanzaIds
56+
{
57+
XMPPLogTrace();
58+
59+
NSArray *resumeStanzaIDs;
60+
[sender didResumeWithAckedStanzaIds:&resumeStanzaIDs serverResponse:nil];
61+
if ([resumeStanzaIDs isEqualToArray:stanzaIds]) {
62+
// Handled in -xmppStreamDidAuthenticate:
63+
return;
64+
}
65+
66+
[self processStreamManagementAcknowledgementForStanzaIDs:stanzaIds];
67+
}
68+
69+
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
70+
{
71+
XMPPLogTrace();
72+
73+
dispatch_group_t stanzaAcknowledgementGroup = dispatch_group_create();
74+
75+
[sender enumerateModulesOfClass:[XMPPStreamManagement class] withBlock:^(XMPPModule *module, NSUInteger idx, BOOL *stop) {
76+
NSArray *acknowledgedStanzaIDs;
77+
[(XMPPStreamManagement *)module didResumeWithAckedStanzaIds:&acknowledgedStanzaIDs serverResponse:nil];
78+
if (acknowledgedStanzaIDs.count == 0) {
79+
return;
80+
}
81+
82+
dispatch_group_async(stanzaAcknowledgementGroup, self.moduleQueue, ^{
83+
[self processStreamManagementAcknowledgementForStanzaIDs:acknowledgedStanzaIDs];
84+
});
85+
}];
86+
87+
dispatch_group_notify(stanzaAcknowledgementGroup, self.moduleQueue, ^{
88+
[multicastDelegate xmppManagedMessagingDidFinishProcessingPreviousStreamConfirmations:self];
89+
});
90+
}
91+
92+
- (void)processStreamManagementAcknowledgementForStanzaIDs:(NSArray *)stanzaIDs
93+
{
94+
NSMutableArray *managedMessageIDs = [NSMutableArray array];
95+
for (id stanzaID in stanzaIDs) {
96+
if (![stanzaID isKindOfClass:[NSURL class]] || ![((NSURL *)stanzaID).scheme isEqualToString:XMPPManagedMessagingURLScheme]) {
97+
continue;
98+
}
99+
// Extracting path directly from NSURL does not work if it doesn't start with "/"
100+
NSURLComponents *managedMessageURLComponents = [[NSURLComponents alloc] initWithURL:stanzaID resolvingAgainstBaseURL:NO];
101+
[managedMessageIDs addObject:managedMessageURLComponents.path];
102+
}
103+
104+
if (managedMessageIDs.count == 0) {
105+
return;
106+
}
107+
108+
XMPPLogInfo(@"Confirming managed messages with IDs={%@}", [managedMessageIDs componentsJoinedByString:@","]);
109+
[multicastDelegate xmppManagedMessaging:self didConfirmSentMessagesWithIDs:managedMessageIDs];
110+
}
111+
112+
@end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
#import <Foundation/Foundation.h>
22
@import KissXML;
33

4+
@class XMPPJID;
45

56
@interface NSXMLElement (XEP_0203)
67

78
@property (nonatomic, readonly) BOOL wasDelayed;
89
@property (nonatomic, readonly, nullable) NSDate *delayedDeliveryDate;
10+
@property (nonatomic, readonly, nullable) XMPPJID *delayedDeliveryFrom;
11+
@property (nonatomic, readonly, nullable) NSString *delayedDeliveryReasonDescription;
912

1013
@end

Extensions/XEP-0203/NSXMLElement+XEP_0203.m

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#import "NSXMLElement+XEP_0203.h"
22
#import "XMPPDateTimeProfiles.h"
33
#import "NSXMLElement+XMPP.h"
4+
#import "XMPPJID.h"
45

56
#if ! __has_feature(objc_arc)
67
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
@@ -10,27 +11,11 @@ @implementation NSXMLElement (XEP_0203)
1011

1112
- (BOOL)wasDelayed
1213
{
13-
NSXMLElement *delay;
14-
15-
delay = [self elementForName:@"delay" xmlns:@"urn:xmpp:delay"];
16-
if (delay)
17-
{
18-
return YES;
19-
}
20-
21-
delay = [self elementForName:@"x" xmlns:@"jabber:x:delay"];
22-
if (delay)
23-
{
24-
return YES;
25-
}
26-
27-
return NO;
14+
return [self anyDelayedDeliveryChildElement] != nil;
2815
}
2916

3017
- (NSDate *)delayedDeliveryDate
3118
{
32-
NSXMLElement *delay;
33-
3419
// From XEP-0203 (Delayed Delivery)
3520
//
3621
// <delay xmlns='urn:xmpp:delay'
@@ -40,7 +25,7 @@ - (NSDate *)delayedDeliveryDate
4025
// The format [of the stamp attribute] MUST adhere to the dateTime format
4126
// specified in XEP-0082 and MUST be expressed in UTC.
4227

43-
delay = [self elementForName:@"delay" xmlns:@"urn:xmpp:delay"];
28+
NSXMLElement *delay = [self delayedDeliveryChildElement];
4429
if (delay)
4530
{
4631
NSString *stampValue = [delay attributeStringValueForName:@"stamp"];
@@ -60,12 +45,12 @@ - (NSDate *)delayedDeliveryDate
6045
// from='capulet.com'
6146
// stamp='20020910T23:08:25'>
6247

63-
delay = [self elementForName:@"x" xmlns:@"jabber:x:delay"];
64-
if (delay)
48+
NSXMLElement *legacyDelay = [self legacyDelayedDeliveryChildElement];
49+
if (legacyDelay)
6550
{
6651
NSDate *stamp;
6752

68-
NSString *stampValue = [delay attributeStringValueForName:@"stamp"];
53+
NSString *stampValue = [legacyDelay attributeStringValueForName:@"stamp"];
6954

7055
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
7156
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
@@ -81,4 +66,30 @@ - (NSDate *)delayedDeliveryDate
8166
return nil;
8267
}
8368

69+
- (XMPPJID *)delayedDeliveryFrom
70+
{
71+
NSString *delayedDeliveryFromString = [[self anyDelayedDeliveryChildElement] attributeStringValueForName:@"from"];
72+
return delayedDeliveryFromString ? [XMPPJID jidWithString:delayedDeliveryFromString] : nil;
73+
}
74+
75+
- (NSString *)delayedDeliveryReasonDescription
76+
{
77+
return [self anyDelayedDeliveryChildElement].stringValue;
78+
}
79+
80+
- (NSXMLElement *)delayedDeliveryChildElement
81+
{
82+
return [self elementForName:@"delay" xmlns:@"urn:xmpp:delay"];
83+
}
84+
85+
- (NSXMLElement *)legacyDelayedDeliveryChildElement
86+
{
87+
return [self elementForName:@"x" xmlns:@"jabber:x:delay"];
88+
}
89+
90+
- (NSXMLElement *)anyDelayedDeliveryChildElement
91+
{
92+
return [self delayedDeliveryChildElement] ?: [self legacyDelayedDeliveryChildElement];
93+
}
94+
8495
@end

0 commit comments

Comments
 (0)