Skip to content

Commit

Permalink
1.13.0 (#1260)
Browse files Browse the repository at this point in the history
- Fix several bugs and crashes
  • Loading branch information
tmolitor-stud-tu authored Oct 13, 2024
2 parents 58bb0d4 + ebf86fb commit e411efb
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 38 deletions.
3 changes: 2 additions & 1 deletion Monal/Classes/HelperTools.m
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,8 @@ -(void) swizzled_setObject:(id) value forKey:(NSString*) defaultName
[value isKindOfClass:[NSDictionary class]] ||
[value isKindOfClass:[NSMutableDictionary class]] ||
[value isKindOfClass:[NSArray class]] ||
[value isKindOfClass:[NSMutableArray class]]
[value isKindOfClass:[NSMutableArray class]] ||
value == nil
)
; //do nothing, already handled by original NSUserDefaults method
//every NSData should be double serialized (see swizzled_objectForKey: above for a detailed explanation)
Expand Down
20 changes: 16 additions & 4 deletions Monal/Classes/MLCall.m
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,10 @@ -(void) internalUpdateCallKitState
[self.voipProcessor.cxProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonFailed];
}
else
unreachable(@"Unexpected finish reason!", (@{@"call": self}));
{
DDLogError(@"Unexpected finish reason: %@", (@{@"call": self, @"finishReason": @(self.finishReason)}));
[self.voipProcessor.cxProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonFailed];
}
}
else
{
Expand All @@ -668,7 +671,10 @@ -(void) internalUpdateCallKitState
[self.voipProcessor.cxProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonFailed];
}
else
unreachable(@"Unexpected finish reason!", (@{@"call": self}));
{
DDLogError(@"Unexpected finish reason: %@", (@{@"call": self, @"finishReason": @(self.finishReason)}));
[self.voipProcessor.cxProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonFailed];
}
}
}
else
Expand All @@ -694,7 +700,10 @@ -(void) internalUpdateCallKitState
[self.voipProcessor.cxProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonFailed];
}
else
unreachable(@"Unexpected finish reason!", (@{@"call": self}));
{
DDLogError(@"Unexpected finish reason: %@", (@{@"call": self, @"finishReason": @(self.finishReason)}));
[self.voipProcessor.cxProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonFailed];
}
}
else
{
Expand All @@ -720,7 +729,10 @@ -(void) internalUpdateCallKitState
[self.voipProcessor.cxProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonFailed];
}
else
unreachable(@"Unexpected finish reason!", (@{@"call": self}));
{
DDLogError(@"Unexpected finish reason: %@", (@{@"call": self, @"finishReason": @(self.finishReason)}));
[self.voipProcessor.cxProvider reportCallWithUUID:self.uuid endedAtDate:nil reason:CXCallEndedReasonFailed];
}
}
}
else
Expand Down
13 changes: 12 additions & 1 deletion Monal/Classes/MLDelayableTimer.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,15 @@ -(void) pause
DDLogWarn(@"Tried to pause already fired timer: %@", self);
return;
}
NSTimeInterval remaining = _wrappedTimer.fireDate.timeIntervalSinceNow;
if(remaining == 0)
{
DDLogWarn(@"Tried to pause timer the exact second its firing: %@", self);
return;
}
DDLogDebug(@"Pausing timer: %@", self);
_remainingTime = _wrappedTimer.fireDate.timeIntervalSinceNow;
_wrappedTimer.fireDate = NSDate.distantFuture; //postpone timer virtually indefinitely
_remainingTime = remaining;
}
}

Expand All @@ -91,6 +97,11 @@ -(void) resume
DDLogWarn(@"Tried to resume already fired timer: %@", self);
return;
}
if(_remainingTime == 0)
{
DDLogWarn(@"Tried to resume non-paused timer: %@", self);
return;
}
DDLogDebug(@"Resuming timer: %@", self);
_wrappedTimer.fireDate = [NSDate dateWithTimeIntervalSinceNow:_remainingTime];
_remainingTime = 0;
Expand Down
43 changes: 24 additions & 19 deletions Monal/Classes/MLStream.m
Original file line number Diff line number Diff line change
Expand Up @@ -686,25 +686,30 @@ -(void) generateEvent:(NSStreamEvent) event
//don't schedule delegate calls if no runloop was specified
if(self.shared_state.runLoop == nil)
return;
//schedule the delegate calls in the runloop that was registered
CFRunLoopPerformBlock([self.shared_state.runLoop getCFRunLoop], (__bridge CFStringRef)self.shared_state.runLoopMode, ^{
@synchronized(self.shared_state) {
if(event == NSStreamEventOpenCompleted && self.open_called && self.shared_state.open)
[self->_delegate stream:self handleEvent:event];
else if(event == NSStreamEventHasBytesAvailable && self.open_called && self.shared_state.open)
[self->_delegate stream:self handleEvent:event];
else if(event == NSStreamEventHasSpaceAvailable && self.open_called && self.shared_state.open)
[self->_delegate stream:self handleEvent:event];
else if(event == NSStreamEventErrorOccurred)
[self->_delegate stream:self handleEvent:event];
else if(event == NSStreamEventEndEncountered && self.open_called && self.shared_state.open)
[self->_delegate stream:self handleEvent:event];
else
DDLogVerbose(@"Ignored event %ld", (long)event);
}
});
//trigger wakeup of runloop to execute the block as soon as possible
CFRunLoopWakeUp([self.shared_state.runLoop getCFRunLoop]);
//make sure to NOT hold the @synchronized lock when calling the delegate to not introduce deadlocks
BOOL handleEvent = NO;
if(event == NSStreamEventOpenCompleted && self.open_called && self.shared_state.open)
handleEvent = YES;
else if(event == NSStreamEventHasBytesAvailable && self.open_called && self.shared_state.open)
handleEvent = YES;
else if(event == NSStreamEventHasSpaceAvailable && self.open_called && self.shared_state.open)
handleEvent = YES;
else if(event == NSStreamEventErrorOccurred)
handleEvent = YES;
else if(event == NSStreamEventEndEncountered && self.open_called && self.shared_state.open)
handleEvent = YES;
//check if the event should be handled
if(!handleEvent)
DDLogVerbose(@"Ignoring event %ld", (long)event);
else
{
//schedule the delegate calls in the runloop that was registered
CFRunLoopPerformBlock([self.shared_state.runLoop getCFRunLoop], (__bridge CFStringRef)self.shared_state.runLoopMode, ^{
[self->_delegate stream:self handleEvent:event];
});
//trigger wakeup of runloop to execute the block as soon as possible
CFRunLoopWakeUp([self.shared_state.runLoop getCFRunLoop]);
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions Monal/Classes/MLXMLNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ +(BOOL) supportsSecureCoding

-(id) copyWithZone:(NSZone*) zone
{
MLXMLNode* copy = [[[self class] alloc] initWithElement:_element];
MLXMLNode* copy = [[[self class] alloc] initWithElement:[_element copy]];
copy.attributes = [[NSMutableDictionary alloc] initWithDictionary:_attributes copyItems:YES];
for(MLXMLNode* child in _children)
[copy addChildNode:child];
Expand All @@ -219,7 +219,7 @@ -(id) shallowCopy

-(id) shallowCopyWithData:(BOOL) copyData
{
MLXMLNode* copy = [[[self class] alloc] initWithElement:_element];
MLXMLNode* copy = [[[self class] alloc] initWithElement:[_element copy]];
copy.attributes = [[NSMutableDictionary alloc] initWithDictionary:_attributes copyItems:YES];
if(copyData)
copy.data = _data ? [_data copy] : nil;
Expand Down Expand Up @@ -256,7 +256,7 @@ -(MLXMLNode*) addChildNodeWithoutCopy:(MLXMLNode*) child
//namespace inheritance (will be stripped by XMLString later on)
//we do this here to make sure manual created nodes always have a namespace like the nodes created by the xml parser do
if(!insertedChild.attributes[@"xmlns"])
insertedChild.attributes[@"xmlns"] = _attributes[@"xmlns"];
insertedChild.attributes[@"xmlns"] = [_attributes[@"xmlns"] copy];
[_children addObject:insertedChild];
[self invalidateUpstreamCache];
//this one can be removed if the query path component ".." is removed from our language
Expand Down
5 changes: 5 additions & 0 deletions Monal/Classes/Quicksy_Country.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ -(NSString*) id
return [NSString stringWithFormat:@"%@|%@", nilDefault(self.name, @""), nilDefault(self.alpha2, @"")];
}

-(NSString*) description
{
return [NSString stringWithFormat:@"%@ (%@) --> %@", nilDefault(self.name, nilDefault(self.alpha2, @"")), self.code, self.pattern];
}

+(BOOL) supportsSecureCoding
{
return YES;
Expand Down
12 changes: 10 additions & 2 deletions Monal/Classes/Quicksy_RegisterAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ struct Quicksy_RegisterAccount: View {

if state.phoneNumber == nil || state.country == nil {
VStack(alignment: .leading) {
Text("")

Text("Verify your phone number")
.font(.title)
.fontWeight(.bold)
Expand Down Expand Up @@ -295,29 +297,35 @@ struct Quicksy_RegisterAccount: View {
DDLogInfo("Localization: using regionCode: \(String(describing:regionCode))")
DDLogInfo("Localization: current locale localized string for regionCode: \(String(describing:Locale.current.localizedString(forRegionCode:regionCode)))")
DDLogInfo("Localization: en_US localized string for regionCode: \(String(describing:Locale(identifier: "en_US").localizedString(forRegionCode:regionCode)))")
DDLogInfo("Previous country: \(String(describing:state.country))")
for country in countries {
if let previousCountry = state.country {
//check alpha2 code and country name explicitly to still match even when changing other properties
if previousCountry.alpha2 == country.alpha2 || previousCountry.name == country.name {
if (previousCountry.alpha2 != nil && previousCountry.alpha2 == country.alpha2) || (previousCountry.name != nil && previousCountry.name == country.name) {
DDLogInfo("Selecting country from previous: \(String(describing:country))")
selectedCountry = country
break
}
} else if country.alpha2 == regionCode || country.name == Locale.current.localizedString(forRegionCode:regionCode) || country.name == Locale(identifier: "en_US").localizedString(forRegionCode:regionCode) {
DDLogInfo("Selecting country from locale: \(String(describing:country))")
selectedCountry = country
break
}
}
DDLogInfo("Finally preselected country: \(String(describing:selectedCountry))")
phoneNumberFocused = true
}
} else if let number = state.phoneNumber, let _ = state.country {
VStack(alignment: .leading) {
Text("")

Text("Verify your phone number")
.font(.title)
.fontWeight(.bold)
.foregroundColor(.primary)
.padding(.bottom, 8)

Text("We sent you an SMS to \(number)")
Text("We sent you an SMS to **\(number)**")
Text("Please enter the six-digit pin below")
HStack {
TextField("Pin", text: $pin)
Expand Down
2 changes: 1 addition & 1 deletion Monal/Classes/SwiftHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ extension Optional : OptionalProtocol {
func unwrap() -> Any {
switch self {
// If a nil is unwrapped it will crash!
case .none: preconditionFailure("nil unwrap!")
case .none: unreachable("nil unwrap!")
case .some(let unwrapped): return unwrapped
}
}
Expand Down
4 changes: 2 additions & 2 deletions Monal/Classes/XMPPDataForm.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ @implementation XMPPDataForm

+(void) initialize
{
dataFormQueryRegex = [NSRegularExpression regularExpressionWithPattern:@"^(\\{(\\*|[^}]+)\\})?([!a-zA-Z0-9_:-]+|\\*)?(\\[([0-9]+)\\])?(@[a-zA-Z0-9_:#-]+|%[a-zA-Z0-9_:#-]+)?" options:0 error:nil];
dataFormQueryRegex = [NSRegularExpression regularExpressionWithPattern:@"^(\\{(\\*|[^}]+)\\})?([!a-zA-Z0-9_:-]+|\\*)?(\\[([0-9]+)\\])?(@[a-zA-Z0-9_:#-]+|&[a-zA-Z0-9_:#-]+)?" options:0 error:nil];
}

//this simple init is not public api because type and form type are mandatory in xep-0004
Expand Down Expand Up @@ -275,7 +275,7 @@ -(id _Nullable) processDataFormQuery:(NSString*) query
return self[[parsedQuery[@"index"] unsignedIntegerValue]][parsedQuery[@"var"]];
return self[parsedQuery[@"var"]];
}
if([parsedQuery[@"extractionCommand"] isEqualToString:@"%"])
if([parsedQuery[@"extractionCommand"] isEqualToString:@"&"])
{
if(parsedQuery[@"index"] != nil)
return [self getField:parsedQuery[@"var"] atIndex:parsedQuery[@"index"]];
Expand Down
20 changes: 18 additions & 2 deletions Monal/Classes/XMPPEdit.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#import "MLSwitchCell.h"
#import "MLOMEMO.h"
#import "MLNotificationQueue.h"
#import "MonalAppDelegate.h"
#import "ActiveChatsViewController.h"
#import "Monal-Swift.h"

@import MobileCoreServices;
Expand Down Expand Up @@ -467,7 +469,14 @@ - (IBAction) removeAccountClicked: (id) sender
[hud hideAnimated:YES afterDelay:1.0f];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:^{
//we want to start fresh instead of doing a "password migration"-restore directly triggering an sms
[[HelperTools defaultsDB] removeObjectForKey:@"Quicksy_phoneNumber"];
[[HelperTools defaultsDB] removeObjectForKey:@"Quicksy_country"];
//make sure we show account creation view etc. after removing the last account
MonalAppDelegate* appDelegate = (MonalAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.activeChats segueToIntroScreensIfNeeded];
}];
});
}];
[questionAlert addAction:noAction];
Expand Down Expand Up @@ -523,7 +532,14 @@ -(IBAction) deleteAccountClicked:(id) sender
[hud hideAnimated:YES afterDelay:1.0f];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:^{
//we want to start fresh instead of doing a "password migration"-restore directly triggering an sms
[[HelperTools defaultsDB] removeObjectForKey:@"Quicksy_phoneNumber"];
[[HelperTools defaultsDB] removeObjectForKey:@"Quicksy_country"];
//make sure we show account creation view etc. after removing the last account
MonalAppDelegate* appDelegate = (MonalAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.activeChats segueToIntroScreensIfNeeded];
}];
});
}
});
Expand Down
7 changes: 4 additions & 3 deletions Monal/Classes/ZoomableContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,12 @@ struct ZoomableContainer<Content: View>: View {
uiView.setZoomScale(currentScale, animated: true)
} else if tapLocation != .zero { // Scale in to a specific point
uiView.zoom(to: zoomRect(for: uiView, scale: uiView.maximumZoomScale, center: tapLocation), animated: true)
// Reset the location to prevent scaling to it in case of a negative scale (manual pinch)
// Use the main thread to prevent unexpected behavior
DispatchQueue.main.async { tapLocation = .zero }
}

// Reset the location to prevent scaling to it in case of a negative scale (manual pinch)
// Use the main thread to prevent unexpected behavior
DispatchQueue.main.async { tapLocation = .zero }

assert(context.coordinator.hostingController.view.superview == uiView)
}

Expand Down

0 comments on commit e411efb

Please sign in to comment.