IOS-1659 hardens parsing. There were no know issues, but its cleaner now and who knows.

IOS-2659
Andreas Buff 2 years ago
parent 01b0731646
commit 1ff40395a6

@ -28,6 +28,16 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "4329CB8622391DBD007D377E"
BuildableName = "PantomimeFrameworkTests.xctest"
BlueprintName = "PantomimeFrameworkTests"
ReferencedContainer = "container:PantomimeFramework.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction

@ -183,7 +183,7 @@ extern NSString * _Nonnull PantomimeMessageStoreFailed;
Note: In case there are no new messages, the server return the UID of the last existing message.
Possible server responses:
If there are new messages: list of UIDs of the new messages
Otherwize: the UID of the last message that exists on server (that is already fetched)
Otherwize: the UID of the last message that exists on server (that is already fetched)
*/
- (void)fetchUidsForNewMailsIgnoringMessagesWithHeaderDefined:(NSArray<NSString*> *_Nullable)headersToIgnore;

@ -253,13 +253,16 @@ static NSString *CRLF = @"\r\n";
- (void)test_uniqueIdentifiersFromFetchUidsResponseData
{
NSDictionary *testInputs = @{@"* 5 FETCH (UID 905)": @[@905],
@"* 7 FETCH (UID 3819)": @[@3819],
NSDictionary *testInputs = @{@"* 9 FETCH (UID 9 BODY[HEADER.FIELDS (pEp-auto-consume)] {0}": @[@(9)],
@"* 9 FETCH (UID 91 BODY[HEADER.FIELDS (pEp-auto-consume)] {0}": @[@(91)],
@"* 9 FETCH (UID 191 BODY[HEADER.FIELDS (pEp-auto-consume)] {0}": @[@(191)],
@"* 3 FETCH (UID 3819 BODY[HEADER.FIELDS (PEP-AUTO-CONSUME)] {2}": @[@(3819)],
@"": @[],
@"* 39 FETCH (FLAGS (\\Seen NonJunk))": @[],
@"* 39 FETCH (UID 666)": @[@(666)]
}
;
@"* 10 FETCH (UID 10 BODY[HEADER.FIELDS (pEp-auto-consume)] {23}": @[@(10)],
@"* 5 FETCH (UID 666 BODY[HEADER.FIELDS (PEP-AUTO-CONSUME)] {25}": @[@(666)],
@"* 5 FETCH (UID INVALID_BUT_SHOULD_PARSE_AS_WELL ANYWAY BODY[HEADER.FIELDS (PEP-AUTO-CONSUME)] {25}": @[],
@"* 5 FETCH (UID 1 AND UID 2 INVALID_BUT_SHOULD_PARSE_AS_WELL ANYWAY BODY[HEADER.FIELDS (PEP-AUTO-CONSUME)] {25}": @[@(1), @(2)]
};
CWIMAPStore *store = [CWIMAPStore new];
for (int i = 0; i < testInputs.count; ++i) {
NSString *testee = testInputs.allKeys[i];

@ -1403,18 +1403,20 @@ static inline int has_literal(char *buf, NSUInteger c)
}
//
// This method parses a SEARCH response in order to decode
// This method parses a IMAP_UID_FETCH_UIDS_IGNORING_HEADERS response in order to decode
// all UIDs in the result.
//
// Examples:
// "* 5 FETCH (UID 905)"
// "* 39 FETCH (FLAGS (\Seen NonJunk))"
// "* 9 FETCH (UID 9 BODY[HEADER.FIELDS (pEp-auto-consume)] {0}"
// "* 3 FETCH (UID 4808 BODY[HEADER.FIELDS (PEP-AUTO-CONSUME)] {2}"
//
- (NSArray<NSNumber*> *)_uniqueIdentifiersFromFetchUidsResponseData:(NSData *)response
{
NSString *searchResponsePrefix = @"* X FETCH";
NSString *searchResponsePostfix = @"{*}";
return [self _uniqueIdentifiersFromData: response
skippingFirstNumberOfChars: searchResponsePrefix.length];
skippingFirstNumberOfChars: searchResponsePrefix.length
skippingLastNumberOfChars: searchResponsePostfix.length];
}
//
@ -1430,23 +1432,34 @@ static inline int has_literal(char *buf, NSUInteger c)
{
NSString *searchResponsePrefix = @"* SEARCH";
return [self _uniqueIdentifiersFromData: response
skippingFirstNumberOfChars: searchResponsePrefix.length];
skippingFirstNumberOfChars: searchResponsePrefix.length
skippingLastNumberOfChars:0];
}
- (NSArray<NSNumber*> *)_uniqueIdentifiersFromData:(NSData *)theData
skippingFirstNumberOfChars:(NSUInteger)numSkip
skippingFirstNumberOfChars:(NSUInteger)numSkipPre
skippingLastNumberOfChars:(NSUInteger)numSkipPost
{
NSMutableArray<NSNumber*> *results = [NSMutableArray new];
if (numSkip >= theData.length) {
if (numSkipPre + numSkipPost >= theData.length) {
// Nothing to scan.
return results;
}
theData = [theData subdataFromIndex: numSkip];
theData = [theData subdataFromIndex: numSkipPre];
if (![theData length]) {
// Nothing to scan.
return results;
}
if (numSkipPost) {
theData = [theData subdataToIndex: theData.length - numSkipPost];
if (![theData length]) {
// Nothing to scan.
return results;
}
}
// We scan all our UIDs.
NSScanner *scanner = [[NSScanner alloc] initWithString: [theData asciiString]];
NSUInteger value = 0;
@ -1787,22 +1800,12 @@ static inline int has_literal(char *buf, NSUInteger c)
- The x is the lenght of the data of the fetched headers
- In case none of headersToIgnore is defined in the message, {0} is returned.
- Otherwize x > 0 is returned.
At least in theory. In practice (see example above "none of headersToIgnore" with x == 2)
*/
- (void) _parseFETCH_UIDS_IGNORING_HEADERS
{
NSArray<NSNumber*> *uidsFromResponse =
[self _uniqueIdentifiersFromFetchUidsResponseData:[_responsesFromServer lastObject]];
if (uidsFromResponse.count > 1 && uidsFromResponse[1].intValue >= 20) {
// A message with one ore more of the headers to ignore defined results in a server
// response with "{x}" where x > 0. This is then results in *two* ints parsed by
// _uniqueIdentifiersFromFetchUidsResponseData.
// Other servers return x > 0 for non-autoconsumable (normal) mails though.
//
// All tested servers return x < 20 for "normal" mails. thus we are testing for this.
// (this is a very ugly hack. We should actually ready the full response and make an educated decition).
// Ignore the message.
return;
}
NSArray *alreadyParsedUids = self.currentQueueObject.info[@"Uids"];
if (!alreadyParsedUids) {
@ -1811,7 +1814,7 @@ static inline int has_literal(char *buf, NSUInteger c)
alreadyParsedUids = [alreadyParsedUids arrayByAddingObjectsFromArray:uidsFromResponse];
}
// Store/update the results in our command queue.
[self.currentQueueObject.info setObject: alreadyParsedUids forKey: @"Uids"];
[self.currentQueueObject.info setObject:alreadyParsedUids forKey:@"Uids"];
}
//

Loading…
Cancel
Save