// // MBIMResolveHandleOperation.m // kordophoned // // Created by James Magahern on 10/1/24. // Copyright © 2024 James Magahern. All rights reserved. // #import "MBIMResolveHandleOperation.h" #import "IMCore_ClassDump.h" #import "IMMessageItem+Encoded.h" /* # Response: Dictionary { "resolvedHandle": "status": valid | invalid | unknown, "existingChat": chatGUID | null } # IMHandle: Dictionary { "id" : resolvedID "name" : fullName | null } */ @interface NSNumber (IDSStatusUtility) - (NSString *)_idsStatusDescription; @end @implementation NSNumber (IDSStatusUtility) - (NSString *)_idsStatusDescription { switch ([self unsignedIntegerValue]) { case 1: return @"valid"; case 2: return @"invalid"; default: return @"unknown"; } } @end @interface IMHandle (Encoded) - (NSDictionary *)mbim_dictionaryRepresentation; @end @implementation IMHandle (Encoded) - (NSDictionary *)mbim_dictionaryRepresentation { return @{ @"id" : [self ID], @"name" : [self name] ?: [NSNull null], }; } @end @implementation MBIMResolveHandleOperation + (void)load { [super load]; } + (NSString *)endpointName { return @"resolveHandle"; } - (void)main { NSString *specifiedIdentifier = [[self valueForQueryItemWithName:@"id"] _stripFZIDPrefix]; if (!specifiedIdentifier) { MBIMLogError(@"No handle ID provided."); HTTPErrorResponse *response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; self.serverCompletionBlock(response); return; } if (IMStringIsPhoneNumber(specifiedIdentifier)) { // Phone numbers will require a country code guess here. // Passing nil, I presume, will make some kind of guess for the country code (useNetworkCountryCode). specifiedIdentifier = IMCopyIDForPhoneNumber(specifiedIdentifier, nil, YES); } NSString *canonicalAddress = [specifiedIdentifier _bestGuessURI]; IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; IMHandle *loginHandle = [iMessageAccount loginIMHandle]; NSString *lastAddressedHandle = [[[loginHandle ID] _stripFZIDPrefix] _bestGuessURI]; IMChatCalculateServiceForSendingNewComposeMaybeForce(@[ canonicalAddress ], lastAddressedHandle, nil, NO, IMStringIsEmail(canonicalAddress), NO, NO, NO, [iMessageAccount service], ^(BOOL allAddressesiMessageCapable, NSDictionary * _Nullable perRecipientAvailability, BOOL checkedServer, IMChatServiceForSendingAvailabilityError error) { NSError *encodingError = nil; NSObject *response = nil; do { // Assume we have returned just one key here. NSString *resolvedHandleID = [[perRecipientAvailability allKeys] firstObject]; if (!resolvedHandleID) { MBIMLogError(@"Unexpected missing handle id"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } IMHandle *resolvedHandle = [iMessageAccount imHandleWithID:resolvedHandleID]; if (!resolvedHandle) { MBIMLogError(@"Couldn't resolve handle"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } NSString *handleStatus = [[perRecipientAvailability objectForKey:resolvedHandleID] _idsStatusDescription]; IMChat *existingChat = [[IMChatRegistry sharedInstance] existingChatForIMHandle:resolvedHandle]; NSDictionary *responseDict = @{ @"resolvedHandle" : [resolvedHandle mbim_dictionaryRepresentation], @"status" : handleStatus, @"existingChat" : [existingChat guid] ?: [NSNull null], }; NSData *data = [NSJSONSerialization dataWithJSONObject:responseDict options:0 error:&encodingError]; if (encodingError) { response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; } else { response = [[MBIMDataResponse alloc] initWithData:data contentType:@"application/json"]; } } while (0); self.serverCompletionBlock(response); }); } @end