Compare commits

...

1 Commits

Author SHA1 Message Date
Chris Ballinger 52d0d63968 Fixing KVO crash 2018-04-29 23:32:45 -07:00
15 changed files with 167 additions and 512 deletions

View File

@ -245,7 +245,6 @@
D93DDAF51BA79A2800CD8331 /* OTRGoolgeOAuthLoginHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 634680891B041F2F00D9A1C5 /* OTRGoolgeOAuthLoginHandler.m */; };
D93DDAF71BA79A2900CD8331 /* OTRXMPPCreateAccountHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6346808C1B04206400D9A1C5 /* OTRXMPPCreateAccountHandler.m */; };
D93DDAF81BA79A2900CD8331 /* OTRLoginHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 63BE425D1B320EE20017058C /* OTRLoginHandler.m */; };
D93DDAFB1BA79A2900CD8331 /* OTRBuddyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 633106171A16D1A300C17BAE /* OTRBuddyViewController.m */; };
D93DDAFC1BA79A2900CD8331 /* OTRCertificateDomainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 633106191A16D1A300C17BAE /* OTRCertificateDomainViewController.m */; };
D93DDAFD1BA79A2900CD8331 /* OTRCertificatesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6331061B1A16D1A300C17BAE /* OTRCertificatesViewController.m */; };
D93DDAFF1BA79A2900CD8331 /* OTRChooseAccountViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6331061F1A16D1A300C17BAE /* OTRChooseAccountViewController.m */; };
@ -374,7 +373,6 @@
D93DDBAB1BA79AAE00CD8331 /* OTRGoolgeOAuthLoginHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 634680881B041F2F00D9A1C5 /* OTRGoolgeOAuthLoginHandler.h */; settings = {ATTRIBUTES = (Private, ); }; };
D93DDBAD1BA79AB000CD8331 /* OTRXMPPCreateAccountHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6346808B1B04206400D9A1C5 /* OTRXMPPCreateAccountHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
D93DDBAE1BA79AB100CD8331 /* OTRLoginHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 63BE425C1B320EE20017058C /* OTRLoginHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
D93DDBB11BA79AB500CD8331 /* OTRBuddyViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 633106161A16D1A300C17BAE /* OTRBuddyViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
D93DDBB21BA79AB600CD8331 /* OTRCertificateDomainViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 633106181A16D1A300C17BAE /* OTRCertificateDomainViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
D93DDBB31BA79AB700CD8331 /* OTRCertificatesViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6331061A1A16D1A300C17BAE /* OTRCertificatesViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
D93DDBB51BA79ABA00CD8331 /* OTRChooseAccountViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6331061E1A16D1A300C17BAE /* OTRChooseAccountViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -796,8 +794,6 @@
633105FB1A16D1A300C17BAE /* OTRUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRUtilities.m; sourceTree = "<group>"; };
633105FC1A16D1A300C17BAE /* OTRXMPPError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRXMPPError.h; sourceTree = "<group>"; };
633105FD1A16D1A300C17BAE /* OTRXMPPError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRXMPPError.m; sourceTree = "<group>"; };
633106161A16D1A300C17BAE /* OTRBuddyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRBuddyViewController.h; sourceTree = "<group>"; };
633106171A16D1A300C17BAE /* OTRBuddyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRBuddyViewController.m; sourceTree = "<group>"; };
633106181A16D1A300C17BAE /* OTRCertificateDomainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRCertificateDomainViewController.h; sourceTree = "<group>"; };
633106191A16D1A300C17BAE /* OTRCertificateDomainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRCertificateDomainViewController.m; sourceTree = "<group>"; };
6331061A1A16D1A300C17BAE /* OTRCertificatesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRCertificatesViewController.h; sourceTree = "<group>"; };
@ -1619,8 +1615,6 @@
D92AC2081DB023D8007BD3E7 /* KeyManagementViewController.swift */,
638D2DFD1AFAD3AE00F3C50C /* Onboarding */,
633105FF1A16D1A300C17BAE /* Login View Controllers */,
633106161A16D1A300C17BAE /* OTRBuddyViewController.h */,
633106171A16D1A300C17BAE /* OTRBuddyViewController.m */,
633106181A16D1A300C17BAE /* OTRCertificateDomainViewController.h */,
633106191A16D1A300C17BAE /* OTRCertificateDomainViewController.m */,
6331061A1A16D1A300C17BAE /* OTRCertificatesViewController.h */,
@ -2300,7 +2294,6 @@
D93DDB951BA79A9600CD8331 /* OTRCertificatePinning.h in Headers */,
D93DDBB21BA79AB600CD8331 /* OTRCertificateDomainViewController.h in Headers */,
D93DDBD01BA79AE000CD8331 /* OTRButtonView.h in Headers */,
D93DDBB11BA79AB500CD8331 /* OTRBuddyViewController.h in Headers */,
D93DDB751BA79A8000CD8331 /* OTRBoolSetting.h in Headers */,
D93DDBDD1BA79AF700CD8331 /* OTRAudioTrashView.h in Headers */,
D93DDB411BA79A7100CD8331 /* OTRAudioSessionManager.h in Headers */,
@ -3191,7 +3184,6 @@
D9A2C4DD204B2D5B00C5DF8B /* OTRXMPPManager.m in Sources */,
D9F3B1AF1FD48DDA00DFC5DA /* Account.swift in Sources */,
631C79931E56846700B30CB4 /* NSData+ChatSecure.swift in Sources */,
D93DDAFB1BA79A2900CD8331 /* OTRBuddyViewController.m in Sources */,
D97097A21FC4DB3D008ED04B /* MessageStorage.swift in Sources */,
D93DDAFC1BA79A2900CD8331 /* OTRCertificateDomainViewController.m in Sources */,
D93DDAFD1BA79A2900CD8331 /* OTRCertificatesViewController.m in Sources */,

View File

@ -61,7 +61,7 @@
[connection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
account = [OTRAccount fetchObjectWithUniqueID:accountKey transaction:transaction];
}];
OTRXMPPManager *xmppManager = (OTRXMPPManager *)[[OTRProtocolManager sharedInstance] protocolForAccount:account];
OTRXMPPManager *xmppManager = (OTRXMPPManager *)[OTRProtocolManager.shared protocolForAccount:account];
if (room.roomJID) {
[xmppManager.roomManager leaveRoom:room.roomJID];
}

View File

@ -217,7 +217,7 @@ public class MessageQueueHandler:NSObject {
switch message.messageSecurity {
case .plaintext:
self.waitingForMessage(message.uniqueId, messageCollection: message.messageCollection, messageSecurity:message.messageSecurity, completion: completion)
OTRProtocolManager.sharedInstance().send(message)
OTRProtocolManager.shared.send(message)
break
case .plaintextWithOTR:
self.sendOTRMessage(message: message, buddyKey: buddy.uniqueId, buddyUsername: buddy.username, accountUsername: account.username, accountProtocolStrintg: account.protocolTypeString(), requiresActiveSession: false, completion: completion)
@ -296,7 +296,7 @@ public class MessageQueueHandler:NSObject {
}
//Get the XMPP procol manager associated with this message and therefore account
guard let accountProtocol = OTRProtocolManager.sharedInstance().protocol(for: account) as? XMPPManager else {
guard let accountProtocol = OTRProtocolManager.shared.protocol(for: account) as? XMPPManager else {
completion(true, 0.0)
return
}
@ -350,7 +350,7 @@ public class MessageQueueHandler:NSObject {
}
//Get the XMPP procol manager associated with this message and therefore account
guard let accountProtocol = OTRProtocolManager.sharedInstance().protocol(for: account) as? XMPPManager else {
guard let accountProtocol = OTRProtocolManager.shared.protocol(for: account) as? XMPPManager else {
completion(true, 0.0)
return
}
@ -385,7 +385,7 @@ public class MessageQueueHandler:NSObject {
}
//Get the XMPP procol manager associated with this message and therefore account
guard let accountProtocol = OTRProtocolManager.sharedInstance().protocol(for: account) as? XMPPManager else {
guard let accountProtocol = OTRProtocolManager.shared.protocol(for: account) as? XMPPManager else {
completion(true, 0.0)
return
}

View File

@ -248,7 +248,7 @@ NSString *const OTRMessageStateKey = @"OTREncryptionManagerMessageStateKey";
} completionBlock:^{
if (!buddy) { return; }
message.buddyUniqueId = buddy.uniqueId;
[[OTRProtocolManager sharedInstance] sendMessage:message];
[OTRProtocolManager.shared sendMessage:message];
}];
}

View File

@ -30,16 +30,16 @@
@class OTRAccount, OTRXMPPAccount, OTRBuddy, OTROutgoingMessage, PushController, OTRXMPPManager;
NS_ASSUME_NONNULL_BEGIN
@interface OTRProtocolManager : NSObject
@interface _OTRProtocolManager : NSObject
@property (atomic, readonly) NSUInteger numberOfConnectedProtocols;
@property (atomic, readonly) NSUInteger numberOfConnectingProtocols;
@property (atomic, strong, readonly, nonnull) NSMutableDictionary<NSString*,id<OTRProtocol>> *protocolManagers;
@property (atomic, readonly) NSArray<id<OTRProtocol>> *allProtocols;
- (BOOL)existsProtocolForAccount:(OTRAccount *)account;
- (nullable id <OTRProtocol>)protocolForAccount:(OTRAccount *)account;
- (nullable OTRXMPPManager*)xmppManagerForAccount:(OTRAccount *)account;
- (void)removeProtocolForAccount:(OTRAccount *)account;
- (void)setProtocol:(id <OTRProtocol>)protocol forAccount:(OTRAccount *)account;
- (BOOL)isAccountConnected:(OTRAccount *)account;
@ -47,8 +47,6 @@ NS_ASSUME_NONNULL_BEGIN
- (void)loginAccount:(OTRAccount *)account userInitiated:(BOOL)userInitiated;
- (void)loginAccounts:(NSArray<OTRAccount*> *)accounts;
- (void)goAwayForAllAccounts;
- (void)disconnectAllAccounts;
- (void)disconnectAllAccountsSocketOnly:(BOOL)socketOnly timeout:(NSTimeInterval)timeout completionBlock:(nullable void (^)())completionBlock;
- (void)sendMessage:(OTROutgoingMessage *)message;
@ -58,7 +56,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)sharedInstance; // Singleton method
/** Convenience for sharedInstance */
@property (class, nonatomic, readonly) OTRProtocolManager *shared;
//@property (class, nonatomic, readonly) OTRProtocolManager *shared;
@end
NS_ASSUME_NONNULL_END

View File

@ -39,13 +39,11 @@
#import <ChatSecureCore/ChatSecureCore-Swift.h>
#import "OTRXMPPPresenceSubscriptionRequest.h"
@interface OTRProtocolManager ()
@property (atomic, readwrite) NSUInteger numberOfConnectedProtocols;
@property (atomic, readwrite) NSUInteger numberOfConnectingProtocols;
@property (nonatomic, strong, readonly, nonnull) NSMutableDictionary<NSString*,id<OTRProtocol>> *protocolManagers;
@interface _OTRProtocolManager ()
//@property (atomic, strong, readonly, nonnull) NSMutableDictionary<NSString*,id<OTRProtocol>> *protocolManagers;
@end
@implementation OTRProtocolManager
@implementation _OTRProtocolManager
-(instancetype)init
{
@ -53,53 +51,36 @@
if(self)
{
_protocolManagers = [[NSMutableDictionary alloc] init];
_numberOfConnectedProtocols = 0;
_numberOfConnectingProtocols = 0;
}
return self;
}
- (NSArray<id<OTRProtocol>> *)allProtocols {
return self.protocolManagers.allValues;
}
- (void)removeProtocolForAccount:(OTRAccount *)account
{
NSParameterAssert(account);
if (!account) { return; }
id<OTRProtocol> protocol = nil;
@synchronized (self) {
protocol = [self.protocolManagers objectForKey:account.uniqueId];
}
protocol = [self.protocolManagers objectForKey:account.uniqueId];
if (protocol && [protocol respondsToSelector:@selector(disconnect)]) {
[protocol disconnect];
}
[self.KVOController unobserve:protocol];
@synchronized (self) {
[self.protocolManagers removeObjectForKey:account.uniqueId];
}
[self.protocolManagers removeObjectForKey:account.uniqueId];
}
- (void)addProtocol:(id<OTRProtocol>)protocol forAccount:(OTRAccount *)account
{
@synchronized (self) {
[self.protocolManagers setObject:protocol forKey:account.uniqueId];
}
[self.KVOController observe:protocol keyPath:NSStringFromSelector(@selector(loginStatus)) options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld action:@selector(protocolDidChange:)];
[self.protocolManagers setObject:protocol forKey:account.uniqueId];
}
- (BOOL)existsProtocolForAccount:(OTRAccount *)account
{
NSParameterAssert(account.uniqueId);
if (!account.uniqueId) { return NO; }
@synchronized (self) {
return [self.protocolManagers objectForKey:account.uniqueId] != nil;
}
}
- (void)setProtocol:(id <OTRProtocol>)protocol forAccount:(OTRAccount *)account
{
NSParameterAssert(protocol);
NSParameterAssert(account.uniqueId);
if (!protocol || !account.uniqueId) { return; }
[self addProtocol:protocol forAccount:account];
return [self.protocolManagers objectForKey:account.uniqueId] != nil;
}
- (id <OTRProtocol>)protocolForAccount:(OTRAccount *)account
@ -107,14 +88,12 @@
NSParameterAssert(account);
if (!account.uniqueId) { return nil; }
id <OTRProtocol> protocol = nil;
@synchronized (self) {
protocol = [self.protocolManagers objectForKey:account.uniqueId];
if(!protocol)
{
protocol = [[[account protocolClass] alloc] initWithAccount:account];
if (protocol && account.uniqueId) {
[self addProtocol:protocol forAccount:account];
}
protocol = [self.protocolManagers objectForKey:account.uniqueId];
if(!protocol)
{
protocol = [[[account protocolClass] alloc] initWithAccount:account];
if (protocol && account.uniqueId) {
[self addProtocol:protocol forAccount:account];
}
}
return protocol;
@ -167,89 +146,19 @@
}
- (void)goAwayForAllAccounts {
@synchronized (self) {
[self.protocolManagers enumerateKeysAndObjectsUsingBlock:^(id key, id <OTRProtocol> protocol, BOOL *stop) {
if ([protocol isKindOfClass:[OTRXMPPManager class]]) {
OTRXMPPManager *xmpp = (OTRXMPPManager*)protocol;
[xmpp goAway];
}
}];
}
}
- (void)disconnectAllAccountsSocketOnly:(BOOL)socketOnly timeout:(NSTimeInterval)timeout completionBlock:(nullable void (^)())completionBlock
{
@synchronized (self) {
dispatch_group_t group = dispatch_group_create();
NSMutableDictionary<NSString*, NSObject<OTRProtocol>*> *observingManagersForTokens = [NSMutableDictionary new];
for (NSObject<OTRProtocol> *manager in self.protocolManagers.allValues) {
OTRXMPPManager *xmpp = (OTRXMPPManager*)manager;
NSParameterAssert([xmpp isKindOfClass:OTRXMPPManager.class]);
if (![xmpp isKindOfClass:OTRXMPPManager.class]) {
DDLogError(@"Wrong protocol class for manager %@", manager);
continue;
}
if (xmpp.loginStatus != OTRLoginStatusDisconnected) {
dispatch_group_enter(group);
NSString *token = [xmpp addObserverForKeyPath:NSStringFromSelector(@selector(loginStatus))
options:0
block:^(NSString *keyPath, OTRXMPPManager *mgr, NSDictionary *change) {
if (mgr.loginStatus == OTRLoginStatusDisconnected) {
dispatch_group_leave(group);
}
}];
observingManagersForTokens[token] = manager;
[manager disconnectSocketOnly:socketOnly];
}
[self.protocolManagers enumerateKeysAndObjectsUsingBlock:^(id key, id <OTRProtocol> protocol, BOOL *stop) {
if ([protocol isKindOfClass:[OTRXMPPManager class]]) {
OTRXMPPManager *xmpp = (OTRXMPPManager*)protocol;
[xmpp goAway];
}
if (timeout > 0) {
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t) (timeout * NSEC_PER_SEC)));
}
for (NSString *token in observingManagersForTokens.allKeys) {
[observingManagersForTokens[token] removeObserverForToken:token];
}
if (completionBlock != nil) {
completionBlock();
}
}
}
- (void)disconnectAllAccounts
{
[self disconnectAllAccountsSocketOnly:NO timeout:0 completionBlock:nil];
}
- (void)protocolDidChange:(NSDictionary *)change
{
__block NSUInteger connected = 0;
__block NSUInteger connecting = 0;
@synchronized (self) {
[self.protocolManagers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id<OTRProtocol> _Nonnull obj, BOOL * _Nonnull stop) {
OTRXMPPManager *xmpp = (OTRXMPPManager*)obj;
NSParameterAssert([xmpp isKindOfClass:OTRXMPPManager.class]);
if (![xmpp isKindOfClass:OTRXMPPManager.class]) {
DDLogError(@"Wrong protocol class for account %@", obj);
return;
}
if (xmpp.loginStatus == OTRLoginStatusAuthenticated) {
connected++;
} else if (xmpp.loginStatus == OTRLoginStatusConnecting) {
connecting++;
}
}];
}
self.numberOfConnectedProtocols = connected;
self.numberOfConnectingProtocols = connecting;
}];
}
-(BOOL)isAccountConnected:(OTRAccount *)account;
{
BOOL connected = NO;
id <OTRProtocol> protocol = nil;
@synchronized (self) {
protocol = [self.protocolManagers objectForKey:account.uniqueId];
}
protocol = [self.protocolManagers objectForKey:account.uniqueId];
OTRXMPPManager *xmpp = (OTRXMPPManager*)protocol;
NSParameterAssert([xmpp isKindOfClass:OTRXMPPManager.class]);
if (![xmpp isKindOfClass:OTRXMPPManager.class]) {
@ -268,7 +177,7 @@
OTRBuddy *buddy = [OTRBuddy fetchObjectWithUniqueID:message.buddyUniqueId transaction:transaction];
account = [OTRAccount fetchObjectWithUniqueID:buddy.accountUniqueId transaction:transaction];
} completionBlock:^{
OTRProtocolManager * protocolManager = [OTRProtocolManager sharedInstance];
OTRProtocolManager * protocolManager = [OTRProtocolManager shared];
id<OTRProtocol> protocol = [protocolManager protocolForAccount:account];
[protocol sendMessage:message];
}];
@ -307,7 +216,7 @@
title = account.username;
}
UIAlertAction *action = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
OTRXMPPManager *manager = (OTRXMPPManager *)[[OTRProtocolManager sharedInstance] protocolForAccount:account];
OTRXMPPManager *manager = (OTRXMPPManager *)[[OTRProtocolManager shared] protocolForAccount:account];
OTRXMPPBuddy *buddy = [manager addToRosterWithJID:jid displayName:nil];

View File

@ -9,6 +9,123 @@
import Foundation
import OTRAssets
@objc
public class OTRProtocolManager: NSObject {
private var protocols: [String:OTRProtocol] = [:]
private var xmppManagers: [XMPPManager] {
return protocols.values.compactMap { $0 as? XMPPManager }
}
@objc
public func existsProtocolForAccount(_ account: OTRAccount) -> Bool {
return existsProtocol(for: account)
}
public func existsProtocol(for account: OTRAccount) -> Bool {
return protocols[account.uniqueId] != nil
}
@objc
public func protocolForAccount(_ account: OTRAccount) -> OTRProtocol? {
return protocols[account.uniqueId]
}
public func `protocol`(for account: OTRAccount) -> OTRProtocol? {
return protocolForAccount(account)
}
@objc
public func xmppManagerForAccount(_ account: OTRAccount) -> XMPPManager? {
return xmppManager(for: account)
}
public func xmppManager(for account: OTRAccount) -> XMPPManager? {
return protocolForAccount(account) as? XMPPManager
}
@objc
public func removeProtocolForAccount(_ account: OTRAccount) {
removeProtocolForAccount(account)
}
public func removeProtocol(for account: OTRAccount) {
protocols[account.uniqueId] = nil
}
@objc
public func isAccountConnected(_ account: OTRAccount) -> Bool {
return xmppManager(for: account)?.loginStatus == .authenticated
}
@objc
public func loginAccount(_ account: OTRAccount) {
loginAccount(account, userInitiated: false)
}
@objc
public func loginAccount(_ account: OTRAccount, userInitiated: Bool) {
xmppManager(for: account)?.connectUserInitiated(userInitiated)
}
@objc
public func loginAccounts(_ accounts: [OTRAccount]) {
accounts.forEach {
self.loginAccount($0)
}
}
@objc
public func goAwayForAllAccounts() {
xmppManagers.forEach {
$0.goAway()
}
}
@objc
public func sendMessage(_ message: OTROutgoingMessage) {
send(message)
}
/// This should probably be moved elsewhere
public func send(_ message: OTROutgoingMessage) {
let _account = OTRDatabaseManager.shared.connections?.read.fetch {
message.buddy(with: $0)?.account(with: $0)
}
guard let account = _account else { return }
xmppManager(for: account)?.send(message)
}
@objc
public func disconnectAllAccounts() {
disconnectAllAccountsSocketOnly(false, timeout: 0, completionBlock: nil)
}
@objc
public func disconnectAllAccountsSocketOnly(_ socketOnly: Bool,
timeout: TimeInterval,
completionBlock: (()->Void)?) {
let group = DispatchGroup()
var observers: [NSKeyValueObservation] = []
xmppManagers.forEach { (xmpp) in
guard xmpp.loginStatus != .disconnected else {
return
}
group.enter()
let observer = xmpp.observe(\.loginStatus, changeHandler: { (xmpp, change) in
if xmpp.loginStatus == .disconnected {
group.leave()
}
})
observers.append(observer)
xmpp.disconnectSocketOnly(socketOnly)
}
group.notify(queue: .main) {
observers.removeAll()
completionBlock?()
}
}
}
public extension OTRProtocolManager {
#if DEBUG
/// when OTRBranding.pushStagingAPIURL is nil (during tests) a valid value must be supplied for the integration tests to pass
@ -18,6 +135,10 @@ public extension OTRProtocolManager {
#endif
@objc public static let encryptionManager = OTREncryptionManager()
@objc public static let shared = OTRProtocolManager()
@objc public static func sharedInstance() -> OTRProtocolManager {
return OTRProtocolManager.shared
}
@objc public static let pushController = PushController(baseURL: OTRProtocolManager.pushApiEndpoint, sessionConfiguration: URLSessionConfiguration.ephemeral)
}

View File

@ -54,7 +54,7 @@ open class BuddyAction: OTRYapDatabaseObject, YapActionable {
return
}
guard let proto = OTRProtocolManager.sharedInstance().protocol(for: acct) as? XMPPManager else {
guard let proto = OTRProtocolManager.shared.protocol(for: acct) as? XMPPManager else {
connection.readWrite({ (transaction) -> Void in
transaction.removeObject(forKey: key, inCollection: collection)
})

View File

@ -429,7 +429,7 @@
}];
}];
if (jid) {
[OTRProtocolManager handleInviteForJID:jid otrFingerprint:fingerprint buddyAddedCallback:nil];
[_OTRProtocolManager handleInviteForJID:jid otrFingerprint:fingerprint buddyAddedCallback:nil];
}
return YES;
}
@ -450,7 +450,7 @@
NSString *otrFingerprint = xmppURI.queryParameters[@"otr-fingerprint"];
// NSString *action = xmppURI.queryAction; // && [action isEqualToString:@"subscribe"]
if (jid) {
[OTRProtocolManager handleInviteForJID:jid otrFingerprint:otrFingerprint buddyAddedCallback:^ (OTRBuddy *buddy) {
[_OTRProtocolManager handleInviteForJID:jid otrFingerprint:otrFingerprint buddyAddedCallback:^ (OTRBuddy *buddy) {
OTRXMPPBuddy *xmppBuddy = (OTRXMPPBuddy *)buddy;
if (xmppBuddy != nil) {
[self enterThreadWithKey:xmppBuddy.threadIdentifier collection:xmppBuddy.threadCollection];

View File

@ -153,7 +153,7 @@ open class AccountDetailViewController: UIViewController, UITableViewDelegate, U
let alert = UIAlertController(title: "\(DELETE_ACCOUNT_MESSAGE_STRING()) \(account.username)?", message: nil, preferredStyle: .actionSheet)
let cancel = UIAlertAction(title: CANCEL_STRING(), style: .cancel)
let delete = UIAlertAction(title: DELETE_ACCOUNT_BUTTON_STRING(), style: .destructive) { (action) in
let protocols = OTRProtocolManager.sharedInstance()
let protocols = OTRProtocolManager.shared
if let xmpp = protocols.protocol(for: account) as? XMPPManager,
xmpp.loginStatus != .disconnected {
xmpp.disconnect()
@ -175,7 +175,7 @@ open class AccountDetailViewController: UIViewController, UITableViewDelegate, U
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let cancel = UIAlertAction(title: CANCEL_STRING(), style: .cancel)
let logout = UIAlertAction(title: LOGOUT_STRING(), style: .destructive) { (action) in
let protocols = OTRProtocolManager.sharedInstance()
let protocols = OTRProtocolManager.shared
if let xmpp = protocols.protocol(for: account) as? XMPPManager,
xmpp.loginStatus != .disconnected {
xmpp.disconnect()
@ -214,7 +214,7 @@ open class AccountDetailViewController: UIViewController, UITableViewDelegate, U
}
private func attemptLogin(_ sender: Any) {
let protocols = OTRProtocolManager.sharedInstance()
let protocols = OTRProtocolManager.shared
if let _ = self.account.password,
self.account.accountType != .xmppTor {
protocols.loginAccount(self.account)

View File

@ -73,10 +73,10 @@ typedef NS_ENUM(NSInteger, MigrationStatus) {
- (void)loginButtonPressed:(id)sender {
// If account isn't logged in, login so we can spam old contacts & update your old vCard.jid with new details
BOOL isConnected = [[OTRProtocolManager sharedInstance] isAccountConnected:self.oldAccount];
BOOL isConnected = [OTRProtocolManager.shared isAccountConnected:self.oldAccount];
if (!isConnected) {
// TODO: Fix Tor connection issues
[[OTRProtocolManager sharedInstance] loginAccount:self.oldAccount];
[OTRProtocolManager.shared loginAccount:self.oldAccount];
}
self.migrationStatus = MigrationStatusCreating;
[super loginButtonPressed:sender];

View File

@ -1,27 +0,0 @@
//
// OTRBuddyViewController.h
// Off the Record
//
// Created by David on 3/6/13.
// Copyright (c) 2013 Chris Ballinger. All rights reserved.
//
@import UIKit;
@import TTTAttributedLabel;
@class OTRBuddy;
@interface OTRBuddyViewController : UIViewController <TTTAttributedLabelDelegate, UITableViewDataSource, UITableViewDelegate,UITextFieldDelegate>
{
UITextField * displayNameTextField;
UIButton * removeBuddyButton;
UIButton * blockBuddyButton;
BOOL isXMPPAccount;
}
@property (nonatomic, strong) OTRBuddy *buddy;
-(id)initWithBuddyID:(NSString *)buddyID;
@end

View File

@ -1,338 +0,0 @@
//
// OTRBuddyViewController.m
// Off the Record
//
// Created by David on 3/6/13.
// Copyright (c) 2013 Chris Ballinger. All rights reserved.
//
#import "OTRBuddyViewController.h"
@import QuartzCore;
#import "OTRInLineTextEditTableViewCell.h"
#import "OTRProtocolManager.h"
#import "OTRConstants.h"
#import "OTRUtilities.h"
#import "OTRXMPPManager.h"
#import "UIActivityViewController+ChatSecure.h"
#import "OTRAccount.h"
#import "OTRBuddy.h"
#import "OTRDatabaseManager.h"
#import "OTRUtilities.h"
@import OTRAssets;
@import XLForm;
@interface OTRBuddyViewController ()
@property (nonatomic, strong) OTRAccount *account;
@end
@implementation OTRBuddyViewController
-(id)initWithBuddyID:(NSString *)buddyID
{
if(self = [self init])
{
[[OTRDatabaseManager sharedInstance].uiConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
self.buddy = [OTRBuddy fetchObjectWithUniqueID:buddyID transaction:transaction];
self.account = [self.buddy accountWithTransaction:transaction];
isXMPPAccount = [[self.account protocolClass] isSubclassOfClass:[OTRXMPPManager class]];
}];
self.title = BUDDY_INFO_STRING();
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneButtonPressed:)];
UITableView * tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
tableView.delegate = self;
tableView.dataSource = self;
tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:tableView];
displayNameTextField = [[UITextField alloc]init];
displayNameTextField.placeholder = OPTIONAL_STRING();
displayNameTextField.font = [UIFont systemFontOfSize:15];
displayNameTextField.delegate = self;
if ([self.buddy.displayName length] && ![self.buddy.displayName isEqualToString:self.buddy.username]) {
displayNameTextField.text = self.buddy.displayName;
}
removeBuddyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[removeBuddyButton setTitle:REMOVE_STRING() forState:UIControlStateNormal];
[removeBuddyButton addTarget:self action:@selector(removeBuddyButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
blockBuddyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[blockBuddyButton setTitle:BLOCK_STRING() forState:UIControlStateNormal];
if (!isXMPPAccount) {
[blockBuddyButton setTitle:BLOCK_AND_REMOVE_STRING() forState:UIControlStateNormal];
}
/*FIXMEif (!self.account.isConnected) {
removeBuddyButton.enabled = NO;
blockBuddyButton.enabled = NO;
displayNameTextField.enabled = NO;
}*/
[blockBuddyButton addTarget:self action:@selector(blockBuddyButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
removeBuddyButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin ;
blockBuddyButton.autoresizingMask =UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin ;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if ((section == 1 && isXMPPAccount) || section == 2) {
return 2;
}
return 1;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 4;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
return 80.0f;
}
return 44.0f;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cellIdentifier = @"cell";
static NSString * cellIdentifierText = @"cellText";
static NSString * cellIdentifierLabel = @"cellLabel";
static NSString * cellIdentifierGroups = @"cellgroups";
static NSString * cellIdentifierButtons = @"cellgroups";
UITableViewCell * cell = nil;
if (indexPath.section == 0) {
// Image and Status
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
[self setupPhotoCell:cell];
}
else if (indexPath.section == 1 && indexPath.row == 0)
{
//Account Name
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierLabel];
if(!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:cellIdentifierLabel];
cell.textLabel.text = EMAIL_STRING();
cell.detailTextLabel.text = self.buddy.username;
}
}
else if(indexPath.section == 1 && indexPath.row == 1){
//Display Name
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierText];
if (!cell) {
cell =[[OTRInLineTextEditTableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:cellIdentifierText];
}
cell.textLabel.text = NAME_STRING();
[cell layoutIfNeeded];
((OTRInLineTextEditTableViewCell *)cell).textField = displayNameTextField;
}
else if(indexPath.section == 2)
{
//Groups
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierGroups];
if(!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifierGroups];
}
if (indexPath.row == 0) {
cell.textLabel.text = ACCOUNT_STRING();
cell.detailTextLabel.text = self.account.username;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
//cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
else if(indexPath.section == 3 && indexPath.row == 0)
{
//remove and block
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierButtons];
if(!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
[self setupButtonsCell:cell];
}
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 2 && indexPath.row == 0) {
//go to edit groups view
}
}
-(void)setupButtonsCell:(UITableViewCell *)cell
{
cell.backgroundView = cell.backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
CGSize cellSize = cell.contentView.frame.size;
CGFloat buttonWidth = 150;
removeBuddyButton.frame = CGRectMake(0, 0, buttonWidth, cellSize.height);
blockBuddyButton.frame = CGRectMake(cellSize.width-buttonWidth, 0, buttonWidth, cellSize.height);
[cell.contentView addSubview:removeBuddyButton];
[cell.contentView addSubview:blockBuddyButton];
}
-(void)setupPhotoCell:(UITableViewCell *)cell
{
cell.backgroundView = cell.backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
UIImageView * buddyImageView = [[UIImageView alloc] initWithFrame:CGRectMake(5.0, 5.0, 70.0, 70.0)];
buddyImageView.backgroundColor = [UIColor lightGrayColor];
/*FIXMEif (self.buddy.photo) {
//FIXMEbuddyImageView.image = self.buddy.photo;
}
else
{
buddyImageView.image = [UIImage imageNamed:@"person"];
}
[buddyImageView.layer setCornerRadius:10.0];
buddyImageView.layer.masksToBounds = YES;
[cell.contentView addSubview:buddyImageView];*/
UILabel * nameLabel = [[UILabel alloc] initWithFrame:CGRectZero];
nameLabel.font = [UIFont boldSystemFontOfSize:18];
nameLabel.numberOfLines = 0;
//nameLabel.lineBreakMode = UILineBreakModeWordWrap;
nameLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
nameLabel.backgroundColor = [UIColor clearColor];
nameLabel.shadowOffset = CGSizeMake(1, 1);
nameLabel.textColor = [UIColor blackColor];
[cell.contentView addSubview:nameLabel];
if([self.buddy.displayName length])
{
nameLabel.text = self.buddy.displayName;
}
else{
nameLabel.text = self.buddy.username;
}
[nameLabel sizeToFit];
CGFloat xPos = buddyImageView.frame.size.width + buddyImageView.frame.origin.x + 10;
CGRect tempFrame = nameLabel.frame;
tempFrame.size.width = cell.contentView.frame.size.width -xPos;
tempFrame.origin = CGPointMake(xPos, 5.0);
nameLabel.frame = tempFrame;
TTTAttributedLabel * statusMessageLabel = [[TTTAttributedLabel alloc] initWithFrame:CGRectZero];
NSMutableDictionary *mutableLinkAttributes = [NSMutableDictionary dictionary];
[mutableLinkAttributes setObject:(id)[statusMessageLabel.textColor CGColor] forKey:(NSString*)kCTForegroundColorAttributeName];
[mutableLinkAttributes setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCTUnderlineStyleAttributeName];
statusMessageLabel.linkAttributes = mutableLinkAttributes;
statusMessageLabel.delegate = self;
statusMessageLabel.enabledTextCheckingTypes = UIDataDetectorTypeLink;
statusMessageLabel.numberOfLines = 0;
statusMessageLabel.lineBreakMode = NSLineBreakByTruncatingTail;
statusMessageLabel.adjustsFontSizeToFitWidth = YES;
statusMessageLabel.backgroundColor = [UIColor clearColor];
statusMessageLabel.shadowOffset = CGSizeMake(1, 1);
statusMessageLabel.textColor = [UIColor blackColor];
statusMessageLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[cell.contentView addSubview:statusMessageLabel];
statusMessageLabel.text = self.buddy.statusMessage;
tempFrame = statusMessageLabel.frame;
tempFrame.size.width = cell.contentView.frame.size.width -xPos - 5.0;
double yPos = nameLabel.frame.origin.y+nameLabel.frame.size.height+5.0;
tempFrame.size.height = (buddyImageView.frame.origin.y+buddyImageView.frame.size.height)-yPos;
tempFrame.origin = CGPointMake(xPos, yPos);
statusMessageLabel.frame = tempFrame;
}
-(void)doneButtonPressed:(id)sender
{
/*FIXMEif (self.account.isConnected) {
NSString * newDisplayName = [displayNameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([newDisplayName length] && ![newDisplayName isEqualToString:self.buddy.displayName]) {
self.buddy.displayName = newDisplayName;
id<OTRXMPPProtocol> protocol = (id<OTRXMPPProtocol>)[[OTRProtocolManager sharedInstance] protocolForAccount:self.buddy.account];
[protocol setDisplayName:newDisplayName forBuddy:self.buddy];
}
}*/
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
-(void)removeBuddyButtonPressed:(id)sender
{
[[[OTRProtocolManager sharedInstance] protocolForAccount:self.account] removeBuddies:@[self.buddy]];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
-(void)blockBuddyButtonPressed:(id)sender
{
[[[OTRProtocolManager sharedInstance] protocolForAccount:self.account] blockBuddies:@[self.buddy]];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[displayNameTextField resignFirstResponder];
return NO;
}
-(void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url
{
UIActivityViewController *activityViewController = [UIActivityViewController otr_linkActivityViewControllerWithURLs:@[url]];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
activityViewController.popoverPresentationController.sourceView = label;
activityViewController.popoverPresentationController.sourceRect = label.bounds;
}
[self presentViewController:activityViewController animated:YES completion:nil];
}
@end

View File

@ -42,7 +42,7 @@
}];
}];
if (jid) {
[OTRProtocolManager handleInviteForJID:jid otrFingerprint:fingerprint buddyAddedCallback:nil];
[_OTRProtocolManager handleInviteForJID:jid otrFingerprint:fingerprint buddyAddedCallback:nil];
}
//send subscription request to JID

@ -1 +1 @@
Subproject commit dba4bda8843db3818b94fa0762103324a52e2a09
Subproject commit 865b763e73c5f8030b2fc6a1633ad3f74e39eb87