private async void C_NewChatMessage(XMPPClient client, XMPP_API.Classes.Network.Events.NewChatMessageEventArgs args)
        {
            MessageMessage msg = args.getMessage();

            // Handel MUC room subject messages:
            if (msg is MUCRoomSubjectMessage)
            {
                MUCHandler.INSTANCE.onMUCRoomSubjectMessage(msg as MUCRoomSubjectMessage);
                return;
            }

            string from = Utils.getBareJidFromFullJid(msg.getFrom());
            string to   = Utils.getBareJidFromFullJid(msg.getTo());
            string id;

            if (msg.CC_TYPE == CarbonCopyType.SENT)
            {
                id = ChatTable.generateId(to, from);
            }
            else
            {
                id = ChatTable.generateId(from, to);
            }

            // Check if device id is valid and if, decrypt the OMEMO messages:
            if (msg is OmemoMessageMessage omemoMessage)
            {
                OmemoHelper helper = client.getOmemoHelper();
                if (helper is null)
                {
                    C_OmemoSessionBuildError(client, new OmemoSessionBuildErrorEventArgs(id, OmemoSessionBuildError.KEY_ERROR, new List <OmemoMessageMessage> {
                        omemoMessage
                    }));
                    Logger.Error("Failed to decrypt OMEMO message - OmemoHelper is null");
                    return;
                }
                else if (!client.getXMPPAccount().checkOmemoKeys())
                {
                    C_OmemoSessionBuildError(client, new OmemoSessionBuildErrorEventArgs(id, OmemoSessionBuildError.KEY_ERROR, new List <OmemoMessageMessage> {
                        omemoMessage
                    }));
                    Logger.Error("Failed to decrypt OMEMO message - keys are corrupted");
                    return;
                }
                else if (!await omemoMessage.decryptAsync(client.getOmemoHelper(), client.getXMPPAccount().omemoDeviceId))
                {
                    return;
                }
            }

            ChatTable chat        = ChatDBManager.INSTANCE.getChat(id);
            bool      chatChanged = false;

            // Spam detection:
            if (Settings.getSettingBoolean(SettingsConsts.SPAM_DETECTION_ENABLED))
            {
                if (Settings.getSettingBoolean(SettingsConsts.SPAM_DETECTION_FOR_ALL_CHAT_MESSAGES) || chat is null)
                {
                    if (SpamDBManager.INSTANCE.isSpam(msg.MESSAGE))
                    {
                        Logger.Warn("Received spam message from " + from);
                        return;
                    }
                }
            }

            if (chat is null)
            {
                chatChanged = true;
                chat        = new ChatTable(from, to)
                {
                    lastActive = msg.getDelay(),
                    chatType   = string.Equals(msg.TYPE, MessageMessage.TYPE_GROUPCHAT) ? ChatType.MUC : ChatType.CHAT
                };
            }

            ChatMessageTable message = new ChatMessageTable(msg, chat);

            // Handle MUC invite messages:
            if (msg is DirectMUCInvitationMessage)
            {
                DirectMUCInvitationMessage inviteMessage = msg as DirectMUCInvitationMessage;
                bool doesRoomExist = ChatDBManager.INSTANCE.doesMUCExist(ChatTable.generateId(inviteMessage.ROOM_JID, msg.getTo()));
                bool doesOutstandingInviteExist = ChatDBManager.INSTANCE.doesOutstandingMUCInviteExist(id, inviteMessage.ROOM_JID);

                if (doesRoomExist && doesOutstandingInviteExist)
                {
                    return;
                }

                MUCDirectInvitationTable inviteTable = new MUCDirectInvitationTable(inviteMessage, message.id);
                ChatDBManager.INSTANCE.setMUCDirectInvitation(inviteTable);
            }

            bool             isMUCMessage     = string.Equals(MessageMessage.TYPE_GROUPCHAT, message.type);
            ChatMessageTable existingMessage  = ChatDBManager.INSTANCE.getChatMessageById(message.id);
            bool             doesMessageExist = existingMessage != null;

            if (isMUCMessage)
            {
                MUCChatInfoTable mucInfo = MUCDBManager.INSTANCE.getMUCInfo(chat.id);
                if (mucInfo != null)
                {
                    if (Equals(message.fromUser, mucInfo.nickname))
                    {
                        // Filter MUC messages that already exist:
                        // ToDo: Allow MUC messages being edited and detect it
                        if (doesMessageExist)
                        {
                            return;
                        }
                        else
                        {
                            message.state = MessageState.SEND;
                        }
                    }
                    else
                    {
                        if (doesMessageExist)
                        {
                            message.state = existingMessage.state;
                        }
                    }
                }
            }

            if (chat.lastActive.CompareTo(msg.getDelay()) < 0)
            {
                chatChanged     = true;
                chat.lastActive = msg.getDelay();
            }

            if (chatChanged)
            {
                ChatDBManager.INSTANCE.setChat(chat, false, true);
            }

            // Send XEP-0184 (Message Delivery Receipts) reply:
            if (msg.RECIPT_REQUESTED && id != null && !Settings.getSettingBoolean(SettingsConsts.DONT_SEND_CHAT_MESSAGE_RECEIVED_MARKERS))
            {
                await Task.Run(async() =>
                {
                    DeliveryReceiptMessage receiptMessage = new DeliveryReceiptMessage(client.getXMPPAccount().getFullJid(), from, msg.ID);
                    await client.sendAsync(receiptMessage);
                });
            }

            ChatDBManager.INSTANCE.setChatMessage(message, !doesMessageExist, doesMessageExist && !isMUCMessage);

            // Show toast:
            if (!doesMessageExist && !chat.muted)
            {
                await Task.Run(() =>
                {
                    try
                    {
                        switch (msg.TYPE)
                        {
                        case MessageMessage.TYPE_GROUPCHAT:
                        case MessageMessage.TYPE_CHAT:
                            if (!message.isCC)
                            {
                                if (message.isImage)
                                {
                                    ToastHelper.showChatTextImageToast(message, chat);
                                }
                                else
                                {
                                    ToastHelper.showChatTextToast(message, chat);
                                }
                            }
                            break;

                        default:
                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Failed to send toast notification!", e);
                    }
                });
            }
        }
        private void C_NewChatMessage(XMPPClient client, XMPP_API.Classes.Network.Events.NewChatMessageEventArgs args)
        {
            MessageMessage msg = args.getMessage();

            // Handel MUC room subject messages:
            if (msg is MUCRoomSubjectMessage)
            {
                MUCHandler.INSTANCE.onMUCRoomSubjectMessage(msg as MUCRoomSubjectMessage);
                return;
            }

            string from = Utils.getBareJidFromFullJid(msg.getFrom());

            // Check if device id is valid and if, decrypt the OMEMO messages:
            if (msg is OmemoMessageMessage omemoMessage)
            {
                // Decryption failed:
                if (!omemoMessage.decrypt(client.getOmemoHelper(), client.getXMPPAccount().omemoDeviceId))
                {
                    return;
                }
            }

            string to = Utils.getBareJidFromFullJid(msg.getTo());
            string id;

            if (msg.CC_TYPE == CarbonCopyType.SENT)
            {
                id = ChatTable.generateId(to, from);
            }
            else
            {
                id = ChatTable.generateId(from, to);
            }


            ChatTable chat        = ChatDBManager.INSTANCE.getChat(id);
            bool      chatChanged = false;

            if (chat == null)
            {
                chatChanged = true;
                chat        = new ChatTable()
                {
                    id            = id,
                    chatJabberId  = from,
                    userAccountId = to,
                    ask           = null,
                    inRoster      = false,
                    lastActive    = msg.getDelay(),
                    muted         = false,
                    presence      = Presence.Unavailable,
                    status        = null,
                    subscription  = null,
                    chatType      = Equals(msg.TYPE, MessageMessage.TYPE_GROUPCHAT) ? ChatType.MUC : ChatType.CHAT,
                };
            }

            ChatMessageTable message = new ChatMessageTable(msg, chat);

            // Handle MUC invite messages:
            if (msg is DirectMUCInvitationMessage)
            {
                DirectMUCInvitationMessage inviteMessage = msg as DirectMUCInvitationMessage;
                bool doesRoomExist = ChatDBManager.INSTANCE.doesMUCExist(ChatTable.generateId(inviteMessage.ROOM_JID, msg.getTo()));
                bool doesOutstandingInviteExist = ChatDBManager.INSTANCE.doesOutstandingMUCInviteExist(id, inviteMessage.ROOM_JID);

                if (doesRoomExist && doesOutstandingInviteExist)
                {
                    return;
                }

                MUCDirectInvitationTable inviteTable = new MUCDirectInvitationTable(inviteMessage, message.id);
                ChatDBManager.INSTANCE.setMUCDirectInvitation(inviteTable);
            }

            bool             isMUCMessage     = string.Equals(MessageMessage.TYPE_GROUPCHAT, message.type);
            ChatMessageTable existingMessage  = ChatDBManager.INSTANCE.getChatMessageById(message.id);
            bool             doesMessageExist = existingMessage != null;

            if (isMUCMessage)
            {
                MUCChatInfoTable mucInfo = MUCDBManager.INSTANCE.getMUCInfo(chat.id);
                if (mucInfo != null)
                {
                    if (Equals(message.fromUser, mucInfo.nickname))
                    {
                        // Filter MUC messages that already exist:
                        // ToDo: Allow MUC messages being edited and detect it
                        if (doesMessageExist)
                        {
                            return;
                        }
                        else
                        {
                            message.state = MessageState.SEND;
                        }
                    }
                    else
                    {
                        if (doesMessageExist)
                        {
                            message.state = existingMessage.state;
                        }
                    }
                }
            }

            if (chat.lastActive.CompareTo(msg.getDelay()) < 0)
            {
                chatChanged     = true;
                chat.lastActive = msg.getDelay();
            }

            if (chatChanged)
            {
                ChatDBManager.INSTANCE.setChat(chat, false, true);
            }

            // Send XEP-0184 (Message Delivery Receipts) reply:
            if (msg.RECIPT_REQUESTED && id != null && !Settings.getSettingBoolean(SettingsConsts.DONT_SEND_CHAT_MESSAGE_RECEIVED_MARKERS))
            {
                Task.Run(async() =>
                {
                    DeliveryReceiptMessage receiptMessage = new DeliveryReceiptMessage(client.getXMPPAccount().getIdDomainAndResource(), from, msg.ID);
                    await client.sendAsync(receiptMessage, true);
                });
            }

            ChatDBManager.INSTANCE.setChatMessage(message, !doesMessageExist, doesMessageExist && !isMUCMessage);

            // Show toast:
            if (!doesMessageExist && !chat.muted)
            {
                Task.Run(() =>
                {
                    try
                    {
                        if (!msg.toasted)
                        {
                            switch (msg.TYPE)
                            {
                            case MessageMessage.TYPE_GROUPCHAT:
                            case MessageMessage.TYPE_CHAT:
                                if (!message.isCC)
                                {
                                    if (message.isEncrypted)
                                    {
                                        ToastHelper.showChatTextEncryptedToast(message, chat);
                                    }
                                    else if (message.isImage)
                                    {
                                        ToastHelper.showChatTextImageToast(message, chat);
                                    }
                                    else
                                    {
                                        ToastHelper.showChatTextToast(message, chat);
                                    }
                                }
                                break;

                            default:
                                break;
                            }
                            msg.setToasted();
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Failed to send toast notification!", e);
                    }
                });
            }
        }
Beispiel #3
0
 //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
 #region --Constructors--
 /// <summary>
 /// Basic Constructor
 /// </summary>
 /// <history>
 /// 31/07/2018 Created [Fabian Sauter]
 /// </history>
 public NewDeliveryReceiptEventArgs(DeliveryReceiptMessage msg)
 {
     MSG = msg;
 }
Beispiel #4
0
        public async Task HandleNewChatMessageAsync(MessageMessage msg)
        {
            // Handel MUC room subject messages:
            if (msg is MUCRoomSubjectMessage)
            {
                MucHandler.INSTANCE.OnMUCRoomSubjectMessage(msg as MUCRoomSubjectMessage);
                return;
            }

            string from        = Utils.getBareJidFromFullJid(msg.getFrom());
            string to          = Utils.getBareJidFromFullJid(msg.getTo());
            string chatBareJid = string.Equals(from, client.dbAccount.bareJid) ? to : from;

            SemaLock  semaLock    = DataCache.INSTANCE.NewChatSemaLock();
            ChatModel chat        = DataCache.INSTANCE.GetChat(client.dbAccount.bareJid, chatBareJid, semaLock);
            bool      newChat     = chat is null;
            bool      chatChanged = false;

            // Spam detection:
            if (Settings.GetSettingBoolean(SettingsConsts.SPAM_DETECTION_ENABLED))
            {
                if (Settings.GetSettingBoolean(SettingsConsts.SPAM_DETECTION_FOR_ALL_CHAT_MESSAGES) || newChat)
                {
                    if (SpamHelper.INSTANCE.IsSpam(msg.MESSAGE))
                    {
                        Logger.Warn("Received spam message from " + chatBareJid);
                        return;
                    }
                }
            }

            // Detect invalid chat messages:
            if (!string.Equals(msg.TYPE, MessageMessage.TYPE_CHAT) && !string.Equals(msg.TYPE, MessageMessage.TYPE_ERROR) && !string.Equals(msg.TYPE, MessageMessage.TYPE_GROUPCHAT))
            {
                Logger.Warn($"Received an unknown message type ('{msg.TYPE}') form '{chatBareJid}'. Dropping it.");
                return;
            }

            // Add the new chat to the DB since it's expected to be there by for example our OMEMO encryption:
            if (newChat)
            {
                chat = new ChatModel(chatBareJid, client.dbAccount)
                {
                    lastActive   = msg.delay,
                    chatType     = string.Equals(msg.TYPE, MessageMessage.TYPE_GROUPCHAT) ? ChatType.MUC : ChatType.CHAT,
                    isChatActive = false // Mark chat as inactive until we can be sure, it's a valid message
                };
                DataCache.INSTANCE.AddChatUnsafe(chat, client);
            }
            else
            {
                // Mark chat as active:
                chat.isChatActive = true;
                chatChanged       = true;
            }
            semaLock.Dispose();

            // Check if device id is valid and if, decrypt the OMEMO messages:
            if (msg is OmemoEncryptedMessage omemoMessage)
            {
                OmemoHelper helper = client.xmppClient.getOmemoHelper();
                if (helper is null)
                {
                    OnOmemoSessionBuildError(client.xmppClient, new OmemoSessionBuildErrorEventArgs(chatBareJid, OmemoSessionBuildError.KEY_ERROR, new List <OmemoEncryptedMessage> {
                        omemoMessage
                    }));
                    Logger.Error("Failed to decrypt OMEMO message - OmemoHelper is null");
                    return;
                }
                else if (!await DecryptOmemoEncryptedMessageAsync(omemoMessage, !newChat && chat.omemoInfo.trustedKeysOnly))
                {
                    if (newChat)
                    {
                        // We failed to decrypt, so this chat could be spam. Delete it again...
                        DataCache.INSTANCE.DeleteChat(chat, false, false);
                        Logger.Debug($"Deleting chat '{chat.bareJid}' again, since decrypting the initial OMEMO message failed.");
                    }
                    return;
                }
                else if (omemoMessage.IS_PURE_KEY_EXCHANGE_MESSAGE)
                {
                    return;
                }
            }

            // Valid new chat, so we can change it to active now:
            chat.isChatActive = true;
            chatChanged       = true;

            ChatMessageModel message = null;

            if (!newChat)
            {
                message = DataCache.INSTANCE.GetChatMessage(chat.id, msg.ID);
            }

            // Filter messages that already exist:
            // ToDo: Allow MUC messages being edited and detect it
            if (!(message is null))
            {
                Logger.Debug("Duplicate message received from '" + chatBareJid + "'. Dropping it...");
                return;
            }
            message = new ChatMessageModel(msg, chat);
            // Set the image path and file name:
            if (message.isImage)
            {
                await DataCache.PrepareImageModelPathAndNameAsync(message.image);
            }
            DataCache.INSTANCE.AddChatMessage(message, chat);

            // Handle MUC invite messages:
            if (msg is DirectMUCInvitationMessage inviteMessage)
            {
                if (!newChat)
                {
                    Logger.Info("Ignoring received MUC direct invitation form '" + chatBareJid + "' since we already joined this MUC (" + inviteMessage.ROOM_JID + ").");
                    return;
                }
                // Ensure we add the message to the DB before we add the invite since the invite has the message as a foreign key:
                using (MainDbContext ctx = new MainDbContext())
                {
                    ctx.Add(new MucDirectInvitationModel(inviteMessage, message));
                }
            }

            bool isMUCMessage = string.Equals(MessageMessage.TYPE_GROUPCHAT, message.type);

            if (chat.lastActive.CompareTo(msg.delay) < 0)
            {
                chatChanged     = true;
                chat.lastActive = msg.delay;
            }

            // Send XEP-0184 (Message Delivery Receipts) reply:
            if (msg.RECIPT_REQUESTED && !Settings.GetSettingBoolean(SettingsConsts.DONT_SEND_CHAT_MESSAGE_RECEIVED_MARKERS))
            {
                await Task.Run(async() =>
                {
                    DeliveryReceiptMessage receiptMessage = new DeliveryReceiptMessage(client.dbAccount.fullJid.FullJid(), from, msg.ID);
                    await client.xmppClient.SendAsync(receiptMessage);
                });
            }

            if (chatChanged)
            {
                chat.Update();
                chatChanged = false;
            }

            // Show toast:
            if (!chat.muted)
            {
                await Task.Run(() =>
                {
                    try
                    {
                        switch (msg.TYPE)
                        {
                        case MessageMessage.TYPE_GROUPCHAT:
                        case MessageMessage.TYPE_CHAT:
                            if (!message.isCC)
                            {
                                // Create toast:
                                if (message.isImage)
                                {
                                    ToastHelper.ShowChatTextImageToast(message, chat);
                                }
                                else
                                {
                                    ToastHelper.ShowChatTextToast(message, chat);
                                }

                                // Update badge notification count:
                                ToastHelper.UpdateBadgeNumber();
                            }
                            break;

                        default:
                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Failed to send toast notification!", e);
                    }
                });
            }
        }