Private
Public Access
1
0

new message: initial commit

This commit is contained in:
2026-04-01 15:29:37 -07:00
parent 45285892de
commit c2a697f2c1
23 changed files with 674 additions and 262 deletions

View File

@@ -10,6 +10,7 @@
#import "IMCore_ClassDump.h"
#import "IMMessageItem+Encoded.h"
#import "MBIMErrorResponse.h"
@implementation MBIMSendMessageOperation
@@ -20,40 +21,93 @@
return @"sendMessage";
}
- (IMMessage *)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID attachmentGUIDs:(NSArray<NSString *> *)guids
- (nullable IMChat *)_chatForHandleIDs:(NSArray<NSString *> *)handleIDs registry:(IMChatRegistry *)registry
{
__block IMMessage *result = nil;
dispatch_sync([[self class] sharedIMAccessQueue], ^{
IMChat *chat = [[IMChatRegistry sharedInstance] existingChatWithGUID:chatGUID];
// TODO: chat might not be an iMessage chat!
IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]];
IMHandle *senderHandle = [iMessageAccount loginIMHandle];
NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody];
NSAttributedString *attrStringWithFileTransfers = IMCreateSuperFormatStringWithAppendedFileTransfers(replyAttrString, guids);
IMMessage *reply = [IMMessage fromMeIMHandle:senderHandle
withText:attrStringWithFileTransfers
fileTransferGUIDs:guids
flags:(kIMMessageFinished | kIMMessageIsFromMe)];
for (NSString *guid in [reply fileTransferGUIDs]) {
[[IMFileTransferCenter sharedInstance] assignTransfer:guid toHandle:chat.recipient];
IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]];
if (!iMessageAccount) {
MBIMLogError(@"Unable to find an iMessage account for message send.");
return nil;
}
NSMutableArray<IMHandle *> *handles = [NSMutableArray arrayWithCapacity:[handleIDs count]];
for (NSString *handleID in handleIDs) {
IMHandle *handle = [iMessageAccount imHandleWithID:handleID];
if (!handle) {
MBIMLogError(@"Couldn't resolve IMHandle for id %@", handleID);
return nil;
}
[handles addObject:handle];
}
if ([handles count] == 1) {
IMHandle *handle = [handles firstObject];
IMChat *chat = [registry existingChatWithHandle:handle allowAlternativeService:NO];
if (!chat) {
MBIMLogInfo(@"Chat does not exist: %@", chatGUID);
} else {
result = reply;
dispatch_async(dispatch_get_main_queue(), ^{
[chat sendMessage:reply];
});
chat = [registry chatWithHandle:handle];
}
return chat;
}
IMChat *chat = [registry existingChatWithHandles:handles
allowAlternativeService:NO
groupID:nil
displayName:nil
joinedChatsOnly:YES];
if (!chat) {
chat = [registry chatWithHandles:handles displayName:nil joinedChatsOnly:YES];
}
return chat;
}
- (nullable NSDictionary *)_sendMessage:(NSString *)messageBody toChat:(IMChat *)chat attachmentGUIDs:(NSArray<NSString *> *)guids includeConversationGUID:(BOOL)includeConversationGUID
{
if (!chat) {
return nil;
}
IMAccount *sendingAccount = [chat account];
if (!sendingAccount) {
sendingAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]];
}
IMHandle *senderHandle = [sendingAccount loginIMHandle];
if (!senderHandle) {
MBIMLogError(@"Unable to determine sender handle for message send.");
return nil;
}
NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody];
NSAttributedString *attrStringWithFileTransfers = IMCreateSuperFormatStringWithAppendedFileTransfers(replyAttrString, guids);
IMMessage *reply = [IMMessage fromMeIMHandle:senderHandle
withText:attrStringWithFileTransfers
fileTransferGUIDs:guids
flags:(kIMMessageFinished | kIMMessageIsFromMe)];
for (NSString *guid in [reply fileTransferGUIDs]) {
[[IMFileTransferCenter sharedInstance] assignTransfer:guid toMessage:reply account:sendingAccount];
}
NSMutableDictionary *result = [[reply mbim_dictionaryRepresentation] mutableCopy];
if (includeConversationGUID) {
NSString *conversationGUID = [chat guid];
if (!conversationGUID) {
conversationGUID = [[[IMChatRegistry sharedInstance] allGUIDsForChat:chat] firstObject];
}
if (conversationGUID) {
result[@"conversationGUID"] = conversationGUID;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[chat sendMessage:reply];
});
return result;
}
@@ -79,7 +133,7 @@
- (void)main
{
NSObject<HTTPResponse> *response = [[HTTPErrorResponse alloc] initWithErrorCode:500];
__block NSObject<HTTPResponse> *response = [[HTTPErrorResponse alloc] initWithErrorCode:500];
NSError *error = nil;
NSDictionary *args = [NSJSONSerialization JSONObjectWithData:self.requestBodyData options:0 error:&error];
@@ -90,31 +144,70 @@
NSString *guid = [args objectForKey:@"guid"];
NSString *messageBody = [args objectForKey:@"body"];
if (!guid || !messageBody) {
NSArray *rawHandleIDs = [args objectForKey:@"handleIDs"];
BOOL hasGUID = [guid isKindOfClass:[NSString class]] && [guid length] > 0;
BOOL hasHandleIDs = [rawHandleIDs isKindOfClass:[NSArray class]] && [rawHandleIDs count] > 0;
if (![messageBody isKindOfClass:[NSString class]] || (!hasGUID && !hasHandleIDs) || (hasGUID && hasHandleIDs)) {
response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"sendMessage requires body and exactly one of guid or handleIDs."];
self.serverCompletionBlock(response);
return;
}
// tapbacks
#if 0
IMMessage *acknowledgment = [IMMessage instantMessageWithAssociatedMessageContent: /* [NSString stringWithFormat:@"%@ \"%%@\"", tapbackAction] */
flags:0
associatedMessageGUID:guid
associatedMessageType:IMAssociatedMessageTypeAcknowledgmentHeart
associatedMessageRange:[imMessage messagePartRange]
messageSummaryInfo:[self adjustMessageSummaryInfoForSending:message]
threadIdentifier:[imMessage threadIdentifier]];
#endif
NSArray *transferGUIDs = [args objectForKey:@"fileTransferGUIDs"];
if (!transferGUIDs) {
transferGUIDs = @[];
NSMutableArray<NSString *> *handleIDs = [NSMutableArray array];
if (hasHandleIDs) {
for (id handleID in rawHandleIDs) {
if ([handleID isKindOfClass:[NSString class]] && [handleID length] > 0) {
[handleIDs addObject:handleID];
}
}
handleIDs = [[[NSOrderedSet orderedSetWithArray:handleIDs] array] mutableCopy];
if ([handleIDs count] == 0) {
response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"No valid handle IDs provided."];
self.serverCompletionBlock(response);
return;
}
}
IMMessage *result = [self _sendMessage:messageBody toChatWithGUID:guid attachmentGUIDs:transferGUIDs];
if (result) {
response = [MBIMJSONDataResponse responseWithJSONObject:[result mbim_dictionaryRepresentation]];
NSArray *rawTransferGUIDs = [args objectForKey:@"fileTransferGUIDs"];
NSMutableArray<NSString *> *transferGUIDs = [NSMutableArray array];
if ([rawTransferGUIDs isKindOfClass:[NSArray class]]) {
for (id transferGUID in rawTransferGUIDs) {
if ([transferGUID isKindOfClass:[NSString class]] && [transferGUID length] > 0) {
[transferGUIDs addObject:transferGUID];
}
}
}
dispatch_sync([[self class] sharedIMAccessQueue], ^{
IMChatRegistry *registry = [IMChatRegistry sharedInstance];
IMChat *chat = nil;
BOOL includeConversationGUID = NO;
if (hasGUID) {
chat = [registry existingChatWithGUID:guid];
if (!chat) {
response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"Chat does not exist for the provided guid."];
return;
}
} else {
chat = [self _chatForHandleIDs:handleIDs registry:registry];
includeConversationGUID = YES;
if (!chat) {
response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"Unable to create or locate a chat for the provided handles."];
return;
}
}
NSDictionary *result = [self _sendMessage:messageBody
toChat:chat
attachmentGUIDs:transferGUIDs
includeConversationGUID:includeConversationGUID];
if (result) {
response = [MBIMJSONDataResponse responseWithJSONObject:result];
}
});
self.serverCompletionBlock(response);
}