/// <summary>
 /// Sends a <seealso cref="QueryArchiveMessage"/> to the server and requests the MAM archive.
 /// </summary>
 /// <param name="filter">A filter for filtering the MAM results like filtering by JID.</param>
 /// <param name="rsm">Optional configuration for the result set.</param>
 /// <param name="to">The target of the request. null for request to your own server. Used for requesting MUC-MAMs.</param>
 /// <returns>The result of the request.</returns>
 public async Task<MessageResponseHelperResult<MamResult>> requestMamAsync(QueryFilter filter, Set rsm, string to)
 {
     QueryArchiveMessage msg = new QueryArchiveMessage(filter, rsm, CONNECTION.account.getFullJid(), to);
     List<QueryArchiveResultMessage> results = new List<QueryArchiveResultMessage>();
     Predicate<AbstractAddressableMessage> predicate = (x) =>
     {
         if (x is QueryArchiveResultMessage result && string.Equals(result.QUERY_ID, msg.QUERY_ID))
         {
             results.Insert(0, result);
             return false;
         }
         return x is QueryArchiveFinishMessage fin && string.Equals(fin.ID, msg.ID) && string.Equals(fin.QUERY_ID, msg.QUERY_ID);
     };
     AsyncMessageResponseHelper<AbstractAddressableMessage> helper = new AsyncMessageResponseHelper<AbstractAddressableMessage>(CONNECTION, predicate)
     {
         matchId = false
     };
     MessageResponseHelperResult<AbstractAddressableMessage> finResult = await helper.startAsync(msg);
     MamResult mamResult = null;
     if (finResult.STATE == MessageResponseHelperResultState.SUCCESS)
     {
         mamResult = new MamResult(finResult.RESULT as QueryArchiveFinishMessage, results);
     }
     return new MessageResponseHelperResult<MamResult>(finResult.STATE, mamResult);
 }
        private async Task <bool> DiscoAsync(string discoTarget, CheckDiscoResponseAsync action, DiscoType discoType)
        {
            MessageResponseHelperResult <IQMessage> result = await CONNECTION.GENERAL_COMMAND_HELPER.discoAsync(discoTarget, discoType);

            if (result.STATE != MessageResponseHelperResultState.SUCCESS)
            {
                Logger.Error($"Failed to perform server DISCO#{discoType} for '{CONNECTION.account.getBareJid()}' - {result.STATE}");
                return(false);
            }

            if (result.RESULT is IQErrorMessage errorMessage)
            {
                Logger.Error($"Failed to perform server DISCO#{discoType} for '{CONNECTION.account.getBareJid()}' - {errorMessage.ERROR_OBJ}");
                return(false);
            }

            // Success:
            if (result.RESULT is DiscoResponseMessage disco)
            {
                await OnDiscoResponseMessage(disco, action, discoTarget);

                return(true);
            }

            Logger.Error($"Failed to perform server DISCO#{discoType} for '{CONNECTION.account.getBareJid()}' - invalid response.");
            return(false);
        }
        private async Task DisablePushAsync()
        {
            PushAccountModel push = CLIENT.dbAccount.push;

            if (string.IsNullOrEmpty(push.bareJid))
            {
                Logger.Info("No need to disable push. Has never been activated on this device (push bare JID is null).");
                return;
            }

            MessageResponseHelperResult <IQMessage> result = await CLIENT.xmppClient.GENERAL_COMMAND_HELPER.disablePushNotificationsAsync(push.bareJid);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is IQErrorMessage errorMessage)
                {
                    Logger.Error($"Failed to disable push notifications for '{CLIENT.dbAccount.bareJid}' - " + errorMessage.ERROR_OBJ.ToString());
                }
                else if (result.RESULT.TYPE != IQMessage.RESULT)
                {
                    Logger.Error($"Failed to disable push notifications for '{CLIENT.dbAccount.bareJid}' - server responded with: " + result.RESULT.TYPE);
                }
                else
                {
                    push.state = PushState.DISABLED;
                    push.Update();
                    Logger.Info($"Successfully disabled push notifications for: '{CLIENT.dbAccount.bareJid}'");
                }
            }
            else
            {
                Logger.Error($"Failed to disable push notifications for '{CLIENT.dbAccount.bareJid}' - " + result.STATE);
            }
        }
        public async Task EnablePushNotificationsAsync()
        {
            MessageResponseHelperResult <IQMessage> result = await GENERAL_COMMAND_HELPER.enablePushNotificationsAsync(account.pushServerBareJid, account.pushNode, account.pushNodeSecret);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is IQErrorMessage errorMessage)
                {
                    account.CONNECTION_INFO.pushState = PushState.ERROR;
                    Logger.Error("Failed to enable push notifications for '" + account.getBareJid() + "' - " + errorMessage.ERROR_OBJ.ToString());
                }
                else if (result.RESULT.TYPE != IQMessage.RESULT)
                {
                    account.CONNECTION_INFO.pushState = PushState.ERROR;
                    Logger.Error("Failed to enable push notifications for '" + account.getBareJid() + "' - server responded with: " + result.RESULT.TYPE);
                }
                else
                {
                    account.pushNodePublished         = true;
                    account.CONNECTION_INFO.pushState = PushState.ENABLED;
                    Logger.Info("Successfully enabled push notifications for: '" + account.getBareJid() + '\'');
                }
            }
            else
            {
                account.CONNECTION_INFO.pushState = PushState.ERROR;
                Logger.Error("Failed to enable push notifications for '" + account.getBareJid() + "' - " + result.STATE);
            }
        }
        private async Task <List <ChatMessageDataTemplate> > LoadMoreMamMessagesAsync()
        {
            Logger.Info("Requesting MAM messages for \"" + MODEL.Chat.Chat.id + "\".");
            QueryFilter filter = GenerateMamQueryFilter();
            // For MUCs ask the MUC server and for everything else ask our own server for messages:
            string target = MODEL.Chat.Chat.chatType == ChatType.CHAT ? MODEL.Chat.Client.getXMPPAccount().getBareJid() : MODEL.Chat.Chat.chatJabberId;
            MessageResponseHelperResult <MamResult> result = await MODEL.Chat.Client.GENERAL_COMMAND_HELPER.requestMamAsync(filter, target);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                Logger.Info("Found " + result.RESULT.COUNT + " MAM messages for \"" + MODEL.Chat.Chat.id + "\".");
                Logger.Debug("MAM result: " + result.RESULT.ToString());

                mamRequested = result.RESULT.COMPLETE;

                List <ChatMessageDataTemplate> msgs = new List <ChatMessageDataTemplate>();
                foreach (QueryArchiveResultMessage msg in result.RESULT.RESULTS)
                {
                    ChatMessageDataTemplate tmp = new ChatMessageDataTemplate
                    {
                        Message = new ChatMessageTable(msg.MESSAGE, MODEL.Chat.Chat),
                        Chat    = MODEL.Chat.Chat,
                        MUC     = MODEL.Chat.MucInfo
                    };
                    msgs.Add(tmp);
                    await ChatDBManager.INSTANCE.setChatMessageAsync(tmp.Message, false, false);
                }
                return(msgs);
            }
            else
            {
                Logger.Error("Failed to load more MAM messages for \"" + MODEL.Chat.Chat.id + "\". Failed with: " + result.STATE);
                return(new List <ChatMessageDataTemplate>());
            }
        }
Exemple #6
0
        private async Task <bool> UpdateNicknameAsync(ChatDataTemplate chat)
        {
            MessageResponseHelperResult <MUCMemberPresenceMessage> result = await chat.Client.MUC_COMMAND_HELPER.changeNicknameAsync(chat.Chat.chatJabberId, chat.MucInfo.nickname);

            if (!string.IsNullOrEmpty(result.RESULT.ERROR_TYPE))
            {
                Logger.Warn("Failed to change nickname for room \"" + chat.Chat.chatJabberId + "\" to \"" + chat.MucInfo.nickname + "\" with: " + result.RESULT.ERROR_MESSAGE);
                return(false);
            }
            // Nickname has been updated successfully:
            else if (result.RESULT.STATUS_CODES.Contains(MUCPresenceStatusCode.MEMBER_NICK_CHANGED))
            {
                return(true);
            }
            // The room has change the nickname:
            else if (result.RESULT.STATUS_CODES.Contains(MUCPresenceStatusCode.ROOM_NICK_CHANGED))
            {
                if (!Utils.isFullJid(result.RESULT.JID))
                {
                    Logger.Error("Expected a full JID as a MUC nickname changed message with status code 210, but received: " + result.RESULT.JID);
                    return(false);
                }
                chat.MucInfo.nickname = Utils.getJidResourcePart(result.RESULT.JID);
                return(true);
            }
            // Should not happen:
            Logger.Error("Unknown MUC member presence status code combination received. This should not happen!");
            return(false);
        }
        private async Task EnablePushAsync()
        {
            PushAccountModel push = CLIENT.dbAccount.push;

            if (string.IsNullOrEmpty(push.bareJid) || string.IsNullOrEmpty(push.node))
            {
                Logger.Info($"Skipping push initialization for '{CLIENT.dbAccount.bareJid}' - server JID or node is empty.");
                return;
            }

            MessageResponseHelperResult <IQMessage> result = await CLIENT.xmppClient.GENERAL_COMMAND_HELPER.enablePushNotificationsAsync(push.bareJid, push.node, push.secret);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is IQErrorMessage errorMessage)
                {
                    Logger.Error($"Failed to enable push notifications for '{CLIENT.dbAccount.bareJid}' - " + errorMessage.ERROR_OBJ.ToString());
                }
                else if (result.RESULT.TYPE != IQMessage.RESULT)
                {
                    Logger.Error($"Failed to enable push notifications for '{CLIENT.dbAccount.bareJid}' - server responded with: " + result.RESULT.TYPE);
                }
                else
                {
                    push.state = PushState.ENABLED;
                    push.Update();
                    Logger.Info($"Successfully enabled push notifications for: '{CLIENT.dbAccount.bareJid}'");
                }
            }
            else
            {
                Logger.Error($"Failed to enable push notifications for '{CLIENT.dbAccount.bareJid}' - " + result.STATE);
            }
        }
Exemple #8
0
        public async Task RefreshOmemoDevicesAsync(XMPPClient client)
        {
            MODEL.RefreshingDevices = true;
            MessageResponseHelperResult <IQMessage> result = await client.OMEMO_COMMAND_HELPER.requestDeviceListAsync(client.getXMPPAccount().getBareJid());

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is OmemoDeviceListResultMessage deviceListResultMessage)
                {
                    MODEL.DEVICES.Clear();
                    MODEL.DEVICES.AddRange(deviceListResultMessage.DEVICES.IDS.Select(x => new UintDataTemplate {
                        Value = x
                    }));
                }
                else
                {
                    Logger.Warn("Failed to request device list (" + result.RESULT.ToString() + ").");
                }
            }
            else
            {
                Logger.Warn("Failed to request device list (" + result.STATE.ToString() + ").");
            }
            MODEL.RefreshingDevices = false;
        }
        private async Task DiscoAsync(string discoTarget, CheckDiscoFeaturesAsync action)
        {
            MessageResponseHelperResult <IQMessage> result = await CONNECTION.GENERAL_COMMAND_HELPER.discoAsync(discoTarget, DiscoType.INFO);

            if (result.STATE != MessageResponseHelperResultState.SUCCESS)
            {
                Logger.Error("Failed to perform server DISCO for '" + CONNECTION.account.getBareJid() + "' - " + result.STATE);
            }
            else if (result.RESULT is IQErrorMessage errorMessage)
            {
                Logger.Error("Failed to perform server DISCO for '" + CONNECTION.account.getBareJid() + "' - " + errorMessage.ERROR_OBJ.ToString());
            }
            // Success:
            else if (result.RESULT is DiscoResponseMessage disco)
            {
                await OnDiscoResponseMessage(disco, action, discoTarget);

                return;
            }
            else
            {
                Logger.Error("Failed to perform server DISCO for '" + CONNECTION.account.getBareJid() + "' - invalid response.");
            }

            CONNECTION.account.CONNECTION_INFO.msgCarbonsState = MessageCarbonsState.ERROR;
            CONNECTION.account.CONNECTION_INFO.pushState       = PushState.ERROR;
        }
        //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
        #region --Constructors--


        #endregion
        //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
        #region --Set-, Get- Methods--


        #endregion
        //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
        #region --Misc Methods (Public)--
        public async Task LoadAsync()
        {
            MODEL.IsLoading = true;
            // Unsubscribe while we are loading:
            MODEL.Chat.Client.NewPubSubEvent -= Client_NewPubSubEvent;

            // Request nodes:
            string targetBareJid = MODEL.Chat.Chat.chatJabberId;
            MessageResponseHelperResult <IQMessage> result = await MODEL.Chat.Client.PUB_SUB_COMMAND_HELPER.discoNodesAsync(targetBareJid);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS && result.RESULT is DiscoResponseMessage discoResponse)
            {
                await SubscribeToIoTNodesAsync(discoResponse.ITEMS, MODEL.Chat.Client, targetBareJid);
                await RequestUiNodeAsync(MODEL.Chat.Client, targetBareJid);
                await RequestSensorsNodeAsync(MODEL.Chat.Client, targetBareJid);
                await RequestActuatorsNodeAsync(MODEL.Chat.Client, targetBareJid);
            }
            else
            {
                // Workaround since prosody does not allow us to query all nodes:
                await SubscribeToNodeAsync(IoTConsts.NODE_NAME_UI, MODEL.Chat.Client, targetBareJid);
                await SubscribeToNodeAsync(IoTConsts.NODE_NAME_SENSORS, MODEL.Chat.Client, targetBareJid);
                await SubscribeToNodeAsync(IoTConsts.NODE_NAME_ACTUATORS, MODEL.Chat.Client, targetBareJid);

                // Request Nodes:
                await RequestUiNodeAsync(MODEL.Chat.Client, targetBareJid);
                await RequestSensorsNodeAsync(MODEL.Chat.Client, targetBareJid);
                await RequestActuatorsNodeAsync(MODEL.Chat.Client, targetBareJid);

                Logger.Warn("Failed to request PubSub nodes from: " + targetBareJid);
            }
            // Subscribe again:
            MODEL.Chat.Client.NewPubSubEvent += Client_NewPubSubEvent;
            MODEL.IsLoading = false;
        }
        public async Task EnableMessageCarbonsAsync()
        {
            account.CONNECTION_INFO.msgCarbonsState = MessageCarbonsState.REQUESTED;
            MessageResponseHelperResult <IQMessage> result = await GENERAL_COMMAND_HELPER.enableMessageCarbonsAsync();

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is IQErrorMessage errorMessage)
                {
                    account.CONNECTION_INFO.msgCarbonsState = MessageCarbonsState.ERROR;
                    Logger.Error("Failed to enable push message carbons for '" + account.getBareJid() + "' - " + errorMessage.ERROR_OBJ.ToString());
                }
                else if (result.RESULT.TYPE != IQMessage.RESULT)
                {
                    account.CONNECTION_INFO.msgCarbonsState = MessageCarbonsState.ERROR;
                    Logger.Error("Failed to enable push message carbons for '" + account.getBareJid() + "' - server responded with: " + result.RESULT.TYPE);
                }
                else
                {
                    account.CONNECTION_INFO.msgCarbonsState = MessageCarbonsState.ENABLED;
                    Logger.Info("Successfully enable push message carbons for: '" + account.getBareJid() + '\'');
                }
            }
            else
            {
                account.CONNECTION_INFO.msgCarbonsState = MessageCarbonsState.ERROR;
                Logger.Error("Failed to enable push message carbons for '" + account.getBareJid() + "' - " + result.STATE);
            }
        }
        private async Task requestDeviceListAsync()
        {
            setState(OmemoHelperState.REQUESTING_DEVICE_LIST);

            Logger.Info("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Requesting device list.");
            MessageResponseHelperResult <IQMessage> result = await CONNECTION.OMEMO_COMMAND_HELPER.requestDeviceListAsync(CONNECTION.account.getBareJid());

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is OmemoDeviceListResultMessage devMsg)
                {
                    await updateDevicesIfNeededAsync(devMsg.DEVICES);
                }
                else if (result.RESULT is IQErrorMessage errMsg)
                {
                    if (errMsg.ERROR_OBJ.ERROR_NAME == ErrorName.ITEM_NOT_FOUND)
                    {
                        Logger.Warn("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Failed to request OMEMO device list - node does not exist. Creating node.");
                        await updateDevicesIfNeededAsync(null);
                    }
                    else
                    {
                        Logger.Error("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Failed to request OMEMO device list form: " + CONNECTION.account.user.domainPart + "\n" + errMsg.ERROR_OBJ.ToString());
                        setState(OmemoHelperState.ERROR);
                    }
                }
            }
            else
            {
                onRequestError(result);
            }
        }
Exemple #13
0
 public void Save(ChatDataTemplate chat)
 {
     Task.Run(async() =>
     {
         MODEL.IsLoading      = true;
         MODEL.Form.Form.type = DataFormType.SUBMIT;
         MessageResponseHelperResult <IQMessage> result = await chat.Client.MUC_COMMAND_HELPER.saveRoomConfigurationAsync(chat.Chat.chatJabberId, MODEL.Form.Form);
         if (result.STATE != MessageResponseHelperResultState.SUCCESS)
         {
             SetError("Failed to save room configuration:\n**" + result.STATE + "**");
             Logger.Warn("Failed to save the room configuration for '" + chat.Chat.chatJabberId + "': " + result.STATE);
         }
         else if (result.RESULT is IQErrorMessage errorMessage)
         {
             SetError("Failed to save room configuration:\n**" + errorMessage + "**");
             Logger.Warn("Failed to save the room configuration for '" + chat.Chat.chatJabberId + "': " + errorMessage);
         }
         else
         {
             SetError("");
             Logger.Info("Successfully saved the room configuration for '" + chat.Chat.chatJabberId + '\'');
         }
         MODEL.IsLoading = false;
     });
 }
        private async Task announceBundleInfoAsync()
        {
            setState(OmemoHelperState.ANNOUNCING_BUNDLE_INFO);

            Logger.Info("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Announcing bundle information for: " + CONNECTION.account.omemoDeviceId);
            MessageResponseHelperResult <IQMessage> result = await CONNECTION.OMEMO_COMMAND_HELPER.setBundleInfoAsync(CONNECTION.account.getOmemoBundleInformation(), CONNECTION.account.omemoDeviceId);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is IQMessage)
                {
                    Logger.Info("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Bundle info announced.");
                    setState(OmemoHelperState.ENABLED);
                    CONNECTION.account.omemoBundleInfoAnnounced = true;
                }
                else if (result.RESULT is IQErrorMessage errMsg)
                {
                    Logger.Error("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Failed to announce OMEMO bundle info to: " + CONNECTION.account.user.domainPart + "\n" + errMsg.ERROR_OBJ.ToString());
                    setState(OmemoHelperState.ERROR);
                }
            }
            else
            {
                onRequestError(result);
            }
        }
        private async Task RequestSensorsNodeAsync(XMPPClient client, string pubSubServer)
        {
            MessageResponseHelperResult <IQMessage> result = await client.PUB_SUB_COMMAND_HELPER.requestNodeAsync(pubSubServer, IoTConsts.NODE_NAME_SENSORS, 0);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS && result.RESULT is SensorsNodeItemsResponseMessage sensorsResponse)
            {
                UpdateFields(sensorsResponse.VALUES);
            }
        }
        private async Task RequestUiNodeAsync(XMPPClient client, string pubSubServer)
        {
            MessageResponseHelperResult <IQMessage> result = await client.PUB_SUB_COMMAND_HELPER.requestNodeAsync(pubSubServer, IoTConsts.NODE_NAME_UI, 0);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS && result.RESULT is UiNodeItemsResponseMessage uiResponse)
            {
                UpdateForm(uiResponse.form);
            }
        }
        private async Task <MessageResponseHelperResult <MamResult> > RequestMamWithRetry(QueryFilter filter, int numOfTries)
        {
            MessageResponseHelperResult <MamResult> result = await ccHandler.client.GENERAL_COMMAND_HELPER.requestMamAsync(filter);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS || numOfTries <= 0 || state != SetupState.REQUESTING_MAM)
            {
                return(result);
            }
            return(await RequestMamWithRetry(filter, --numOfTries));
        }
Exemple #18
0
        private async Task AddMucAsync(Client client, string roomBareJid, string nickname, string password, bool bookmark, bool autoJoin)
        {
            ChatModel chat = new ChatModel(roomBareJid, client.dbAccount)
            {
                chatType     = ChatType.MUC,
                inRoster     = bookmark,
                subscription = "none",
                isChatActive = true
            };
            MucInfoModel muc = new MucInfoModel()
            {
                chat          = chat,
                subject       = null,
                autoEnterRoom = autoJoin,
                name          = null,
                nickname      = nickname,
                password      = string.IsNullOrEmpty(password) ? null : password,
                state         = MucState.DISCONNECTED
            };

            chat.muc = muc;
            SemaLock semaLock = DataCache.INSTANCE.NewChatSemaLock();

            semaLock.Wait();
            DataCache.INSTANCE.AddChatUnsafe(chat, client);
            semaLock.Dispose();

            if (muc.autoEnterRoom)
            {
                await MucHandler.INSTANCE.EnterMucAsync(client.xmppClient, muc);
            }

            if (bookmark)
            {
                List <ConferenceItem> conferenceItems;
                using (MainDbContext ctx = new MainDbContext())
                {
                    conferenceItems = ctx.GetXEP0048ConferenceItemsForAccount(client.dbAccount.bareJid);
                }
                MessageResponseHelperResult <IQMessage> result = await client.xmppClient.PUB_SUB_COMMAND_HELPER.setBookmars_xep_0048Async(conferenceItems);

                if (result.STATE == MessageResponseHelperResultState.SUCCESS)
                {
                    if (result.RESULT is IQErrorMessage errMsg)
                    {
                        Logger.Warn("Failed to set bookmarks: " + errMsg.ToString());
                    }
                }
                else
                {
                    Logger.Warn("Failed to set bookmarks: " + result.STATE);
                }
            }
        }
        private async Task <MessageResponseHelperResult <MamResult> > RequestMamWithRetry(QueryFilter filter, Set rsm, int numOfTries)
        {
            MessageResponseHelperResult <MamResult> result = await ccHandler.client.xmppClient.GENERAL_COMMAND_HELPER.requestMamAsync(filter, rsm);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS || numOfTries <= 0 || state != SetupState.REQUESTING_MAM)
            {
                return(result);
            }
            Logger.Warn($"MAM request failed for '{ccHandler.client.dbAccount.bareJid}' failed with {result.STATE}. Retrying...");
            return(await RequestMamWithRetry(filter, rsm, --numOfTries));
        }
 private void onRequestError(MessageResponseHelperResult <IQMessage> result)
 {
     switch (STATE)
     {
     case OmemoHelperState.REQUESTING_DEVICE_LIST:
     case OmemoHelperState.UPDATING_DEVICE_LIST:
     case OmemoHelperState.ANNOUNCING_BUNDLE_INFO:
         Logger.Error("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Failed in state " + STATE + " - timeout!");
         setState(OmemoHelperState.ERROR);
         break;
     }
 }
        private async Task AddMucAsync(XMPPClient client, string roomBareJid, string nickname, string password, bool bookmark, bool autoJoin)
        {
            ChatTable muc = new ChatTable(roomBareJid, client.getXMPPAccount().getBareJid())
            {
                chatType     = ChatType.MUC,
                inRoster     = bookmark,
                subscription = "none",
                isChatActive = true
            };

            MUCChatInfoTable info = new MUCChatInfoTable()
            {
                chatId        = muc.id,
                subject       = null,
                state         = MUCState.DISCONNECTED,
                name          = null,
                password      = string.IsNullOrEmpty(password) ? null : password,
                nickname      = nickname,
                autoEnterRoom = autoJoin,
            };

            await Task.Run(() =>
            {
                ChatDBManager.INSTANCE.setChat(muc, false, true);
                MUCDBManager.INSTANCE.setMUCChatInfo(info, false, true);
            });

            if (info.autoEnterRoom)
            {
                await MUCHandler.INSTANCE.enterMUCAsync(client, muc, info);
            }

            if (bookmark)
            {
                List <ConferenceItem> conferenceItems          = MUCDBManager.INSTANCE.getXEP0048ConferenceItemsForAccount(client.getXMPPAccount().getBareJid());
                MessageResponseHelperResult <IQMessage> result = await client.PUB_SUB_COMMAND_HELPER.setBookmars_xep_0048Async(conferenceItems);

                if (result.STATE == MessageResponseHelperResultState.SUCCESS)
                {
                    if (result.RESULT is IQErrorMessage errMsg)
                    {
                        Logger.Warn("Failed to set bookmarks: " + errMsg.ToString());
                    }
                }
                else
                {
                    Logger.Warn("Failed to set bookmarks: " + result.STATE);
                }
            }
        }
Exemple #22
0
        private async Task <bool> PublishAvatarAsync(AvatarDataPubSubItem avatar)
        {
            MessageResponseHelperResult <IQMessage> result = await MODEL.Client.xmppClient.PUB_SUB_COMMAND_HELPER.publishAvatarAsync(avatar);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is IQErrorMessage errorMsg)
                {
                    Logger.Error($"Failed to publish avatar: {errorMsg.ERROR_OBJ}");
                    return(false);
                }
                Logger.Info("Successfully published avatar.");
                return(true);
            }
            Logger.Error($"Failed to publish avatar: {result.STATE}");
            return(false);
        }
Exemple #23
0
        private async Task updateDeviceListAsync(OmemoXmlDevices devices)
        {
            setState(OmemoHelperState.UPDATING_DEVICE_LIST);

            // Make sure we set the item ID to "current":
            devices.setId();

            Logger.Info("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Updating device list.");
            MessageResponseHelperResult <IQMessage> result = await CONNECTION.OMEMO_COMMAND_HELPER.setDeviceListAsync(devices);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is IQErrorMessage errMsg)
                {
                    Logger.Error("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Failed to set OMEMO device list to: " + CONNECTION.account.user.domainPart + "\n" + errMsg.ERROR_OBJ.ToString());
                    setState(OmemoHelperState.ERROR);
                }
                else
                {
                    Logger.Info("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Device list updated.");
                    if (tmpDeviceId != 0)
                    {
                        if (CONNECTION.account.omemoDeviceId != tmpDeviceId)
                        {
                            CONNECTION.account.omemoDeviceId            = tmpDeviceId;
                            CONNECTION.account.omemoBundleInfoAnnounced = false;
                        }
                    }
                    if (!CONNECTION.account.omemoBundleInfoAnnounced)
                    {
                        await announceBundleInfoAsync();
                    }
                    else
                    {
                        setState(OmemoHelperState.ENABLED);
                    }
                }
            }
            else
            {
                onRequestError(result);
            }
        }
Exemple #24
0
        private async Task <bool> UpdateBookmarksAsync(ChatDataTemplate chat)
        {
            List <ConferenceItem> conferences = MUCDBManager.INSTANCE.getXEP0048ConferenceItemsForAccount(chat.Client.getXMPPAccount().getBareJid());
            MessageResponseHelperResult <IQMessage> result = await chat.Client.PUB_SUB_COMMAND_HELPER.setBookmars_xep_0048Async(conferences);

            if (string.Equals(result.RESULT.TYPE, IQMessage.RESULT))
            {
                return(true);
            }
            if (result.RESULT is IQErrorMessage errorMessage)
            {
                Logger.Warn("Failed to update XEP-0048 Bookmarks: " + errorMessage.ERROR_OBJ.ToString());
            }
            else
            {
                Logger.Warn("Failed to update XEP-0048 Bookmarks: " + result.RESULT.TYPE);
            }
            return(false);
        }
        /// <summary>
        /// Sends a <seealso cref="QueryArchiveMessage"/> to the server and requests the MAM archive.
        /// </summary>
        /// <param name="filter">A filter for filtering the MAM results like filtering by JID.</param>
        /// <param name="rsm">Optional configuration for the result set.</param>
        /// <param name="to">The target of the request. null for request to your own server. Used for requesting MUC-MAMs.</param>
        /// <returns>The result of the request.</returns>
        public async Task <MessageResponseHelperResult <MamResult> > requestMamAsync(QueryFilter filter, Set rsm, string to)
        {
            QueryArchiveMessage msg = new QueryArchiveMessage(filter, rsm, CONNECTION.account.getFullJid(), to);
            List <QueryArchiveResultMessage>       results   = new List <QueryArchiveResultMessage>();
            Predicate <AbstractAddressableMessage> predicate = (x) =>
            {
                if (x is QueryArchiveResultMessage result && string.Equals(result.QUERY_ID, msg.QUERY_ID))
                {
                    results.Insert(0, result);
                    return(false);
                }
                if (x is IQErrorMessage && string.Equals(msg.ID, x.ID))
                {
                    return(true);
                }
                return(x is QueryArchiveFinishMessage fin && string.Equals(fin.ID, msg.ID));
            };
            AsyncMessageResponseHelper <AbstractAddressableMessage> helper = new AsyncMessageResponseHelper <AbstractAddressableMessage>(CONNECTION, predicate)
            {
                matchId = false
            };
            MessageResponseHelperResult <AbstractAddressableMessage> finResult = await helper.startAsync(msg);

            MamResult mamResult = null;

            if (finResult.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (finResult.RESULT is QueryArchiveFinishMessage archiveFinishMessage)
                {
                    mamResult = new MamResult(finResult.RESULT as QueryArchiveFinishMessage, results);
                }
                else
                {
                    if (finResult.RESULT is IQErrorMessage errorMessage)
                    {
                        Logger.Warn($"Failed to request MAM from {to} with: {errorMessage.ERROR_OBJ}");
                    }
                    return(new MessageResponseHelperResult <MamResult>(MessageResponseHelperResultState.ERROR, null));
                }
            }
            return(new MessageResponseHelperResult <MamResult>(finResult.STATE, mamResult));
        }
Exemple #26
0
        public async Task refreshDevicesAsync()
        {
            MessageResponseHelperResult <IQMessage> result = await CONNECTION.OMEMO_COMMAND_HELPER.requestDeviceListAsync(CONNECTION.account.getBareJid());

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is OmemoDeviceListResultMessage devMsg)
                {
                    DEVICES = devMsg.DEVICES;
                    // Store the new list in the DB:
                    OMEMO_STORAGE.StoreDevices(DEVICES.toOmemoProtocolAddress(CONNECTION.account.getBareJid()), CONNECTION.account.getBareJid());
                }
                else if (result.RESULT is IQErrorMessage errMsg)
                {
                    Logger.Error("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Failed to request OMEMO device list form: " + CONNECTION.account.user.domainPart + "\n" + errMsg.ERROR_OBJ.ToString());
                }
            }
            else
            {
                Logger.Error("[OMEMO HELPER](" + CONNECTION.account.getBareJid() + ") Failed to request OMEMO device list form: " + CONNECTION.account.user.domainPart + " with: " + result.STATE);
            }
        }
        private async Task <bool> SubscribeToNodeAsync(string nodeName, XMPPClient client, string pubSubServer)
        {
            MessageResponseHelperResult <IQMessage> result = await client.PUB_SUB_COMMAND_HELPER.requestNodeSubscriptionAsync(pubSubServer, nodeName);

            if (result.STATE == MessageResponseHelperResultState.SUCCESS)
            {
                if (result.RESULT is PubSubSubscriptionsResultMessage pubSubResult)
                {
                    Logger.Debug("Subscribed to node: " + nodeName);
                    return(true);
                }
                else if (result.RESULT is IQErrorMessage errorMessage)
                {
                    Logger.Warn("Subscribing to node failed with: " + errorMessage.ERROR_OBJ.ToString());
                }
            }
            else
            {
                Logger.Warn("Subscribing to node failed with: " + result.RESULT);
            }

            return(false);
        }
Exemple #28
0
        private void RequestConfiguartion(ChatDataTemplate chat)
        {
            Task.Run(async() =>
            {
                MODEL.IsLoading = true;
                MessageResponseHelperResult <IQMessage> result = await chat.Client.MUC_COMMAND_HELPER.requestRoomConfigurationAsync(chat.Chat.chatJabberId);

                if (result.STATE == MessageResponseHelperResultState.SUCCESS)
                {
                    if (result.RESULT is RoomConfigMessage configMessage)
                    {
                        MODEL.Form      = new DataFormDataTemplate(configMessage.ROOM_CONFIG);
                        MODEL.IsLoading = false;
                        MODEL.Success   = true;
                        SetError("");
                        return;
                    }
                    else if (result.RESULT is IQErrorMessage errorMessage)
                    {
                        SetError("Failed to request room configuration:\n**" + errorMessage + "**");
                        Logger.Warn("Failed to request the room configuration for '" + chat.Chat.chatJabberId + "': " + errorMessage);
                    }
                    else
                    {
                        SetError("Failed to request room configuration:\n**Unexpected response - " + result.RESULT?.GetType().ToString() + "**");
                        Logger.Warn("Failed to request the room configuration for '" + chat.Chat.chatJabberId + "': Unexpected response - " + result.RESULT?.GetType().ToString());
                    }
                }
                else
                {
                    SetError("Failed to request room configuration:\n**" + result.STATE + "**");
                    Logger.Warn("Failed to request the room configuration for '" + chat.Chat.chatJabberId + "': " + result.STATE);
                }
                MODEL.IsLoading = false;
                MODEL.Success   = false;
            });
        }
        public void SaveDeviceLabel(string deviceLabel, Client client)
        {
            OmemoAccountInformationModel omemoInfo = client.dbAccount.omemoInfo;

            deviceLabel = deviceLabel.Trim();

            string newLabel;

            if (string.IsNullOrEmpty(deviceLabel) || string.Equals(deviceLabel, omemoInfo.deviceId.ToString()))
            {
                newLabel = null;
            }
            else
            {
                newLabel = deviceLabel;
            }

            // Prevent unnecessary updates in case for example the control loaded:
            if (string.Equals(newLabel, omemoInfo.deviceLabel))
            {
                return;
            }

            MODEL.Saving = true;
            Task.Run(async() =>
            {
                try
                {
                    if (client.xmppClient.isConnected())
                    {
                        MessageResponseHelperResult <IQMessage> result = await client.xmppClient.OMEMO_COMMAND_HELPER.requestDeviceListAsync(client.dbAccount.bareJid);
                        if (result.STATE == MessageResponseHelperResultState.SUCCESS)
                        {
                            if (result.RESULT is OmemoDeviceListResultMessage deviceListResultMessage)
                            {
                                OmemoXmlDevice device = deviceListResultMessage.DEVICES.DEVICES.Where(d => d.ID == omemoInfo.deviceId).FirstOrDefault();
                                if (device is null)
                                {
                                    device = new OmemoXmlDevice(omemoInfo.deviceId, deviceLabel);
                                    deviceListResultMessage.DEVICES.DEVICES.Add(device);
                                }
                                else if (string.Equals(device.label, deviceLabel))
                                {
                                    MODEL.ErrorSaving = false;
                                    MODEL.Saving      = false;
                                    Logger.Info("No need to update devices. Label already the same.");
                                    return;
                                }
                                else
                                {
                                    device.label = newLabel;
                                    result       = await client.xmppClient.OMEMO_COMMAND_HELPER.setDeviceListAsync(deviceListResultMessage.DEVICES);
                                    if (result.STATE != MessageResponseHelperResultState.SUCCESS)
                                    {
                                        Logger.Error("Failed to set device list (" + result.STATE + ").");
                                    }
                                    else if (result.RESULT is IQErrorMessage errorMessage)
                                    {
                                        Logger.Error("Failed to set device list (" + errorMessage.ERROR_OBJ.ToString() + ").");
                                    }
                                    else
                                    {
                                        MODEL.ErrorSaving     = false;
                                        omemoInfo.deviceLabel = newLabel;
                                        omemoInfo.Update();
                                        MODEL.Saving = false;
                                        Logger.Info($"Device label for device {omemoInfo.deviceId} successfully updated to: '{newLabel}'.");
                                        return;
                                    }
                                }
                            }
                            else
                            {
                                Logger.Error("Failed to request device list (" + result.RESULT.ToString() + ").");
                            }
                        }
                        else
                        {
                            Logger.Error("Failed to request device list (" + result.STATE.ToString() + ").");
                        }
                    }
                    else
                    {
                        Logger.Error("Failed to update device label. Client not connected");
                    }
                }
                catch (Exception e)
                {
                    Logger.Error("Failed to update device label.", e);
                }
                MODEL.Saving      = false;
                MODEL.ErrorSaving = true;
            });
        }
        private async Task RequestMamAsync()
        {
            state = SetupState.REQUESTING_MAM;

            if (!ccHandler.client.connection.DISCO_HELPER.HasFeature(Consts.XML_XEP_0313_NAMESPACE, ccHandler.client.getXMPPAccount().getBareJid()))
            {
                Logger.Info("No need to request MAM for " + ccHandler.client.getXMPPAccount().getBareJid() + " - not supported.");
                Continue();
                return;
            }

            bool extendedMamSupport = ccHandler.client.connection.DISCO_HELPER.HasFeature(Consts.XML_XEP_0313_EXTENDED_NAMESPACE, ccHandler.client.getXMPPAccount().getBareJid());

            Logger.Info("Extended MAM support for " + ccHandler.client.getXMPPAccount().getBareJid() + ": " + extendedMamSupport);

            MamRequestTable mamRequest  = MamDBManager.INSTANCE.getLastRequest(ccHandler.client.getXMPPAccount().getBareJid());
            string          lastMsgId   = null;
            DateTime        lastMsgDate = DateTime.MinValue;

            if (!(mamRequest is null))
            {
                lastMsgId   = mamRequest.lastMsgId;
                lastMsgDate = mamRequest.lastUpdate;
            }

            // Request all MAM messages:
            bool done      = false;
            int  iteration = 1;

            while (!done)
            {
                QueryFilter filter = new QueryFilter();
                if (extendedMamSupport)
                {
                    // Only extended MAM supports setting the 'after-id' property.
                    // Reference: https://xmpp.org/extensions/xep-0313.html#support
                    if (!(lastMsgId is null))
                    {
                        filter.AfterId(lastMsgId);
                    }
                }
                else
                {
                    // Fallback for servers not supporting 'urn:xmpp:mam:2#extended'.
                    if (lastMsgDate != DateTime.MinValue)
                    {
                        filter.Start(lastMsgDate);
                    }
                }

                MessageResponseHelperResult <MamResult> result = await RequestMamWithRetry(filter, 2);

                if (result.STATE == MessageResponseHelperResultState.SUCCESS)
                {
                    mamRequest = new MamRequestTable
                    {
                        accountId  = ccHandler.client.getXMPPAccount().getBareJid(),
                        lastUpdate = DateTime.Now
                    };
                    if (result.RESULT.RESULTS.Count > 0)
                    {
                        mamRequest.lastMsgId = result.RESULT.LAST;
                        lastMsgId            = result.RESULT.LAST;
                        HandleMamMessages(result.RESULT);
                        Logger.Info("MAM request for " + ccHandler.client.getXMPPAccount().getBareJid() + " received " + result.RESULT.RESULTS.Count + " messages in iteration " + iteration + '.');
                        Logger.Debug("First: " + result.RESULT.RESULTS[result.RESULT.RESULTS.Count - 1].QUERY_ID + " Last: " + result.RESULT.RESULTS[0].QUERY_ID);
                    }
                    if (result.RESULT.COMPLETE || result.RESULT.RESULTS.Count <= 0)
                    {
                        done = true;
                        Logger.Info("MAM request for " + ccHandler.client.getXMPPAccount().getBareJid());
                    }

                    DateTime newDate = GetLastMessageDate(result.RESULT);
                    if (newDate == mamRequest.lastUpdate)
                    {
                        done = true;
                        Logger.Info("MAM request for " + ccHandler.client.getXMPPAccount().getBareJid());
                    }
                    else
                    {
                        lastMsgDate = newDate;
                    }
                    MamDBManager.INSTANCE.setLastRequest(mamRequest);
                }
                else if (state == SetupState.REQUESTING_MAM)
                {
                    done = true;
                    Logger.Warn("Failed to request MAM archive for " + ccHandler.client.getXMPPAccount().getBareJid() + " with: " + result.STATE);
                }
                ++iteration;
            }
            Continue();
        }