PSZUC TAccountXmpp::Contact_RosterUpdateItem(const CXmlNode * pXmlNodeItemRoster) { Assert(pXmlNodeItemRoster != NULL); Assert(pXmlNodeItemRoster->FCompareTagName("item")); PSZUC pszJid = pXmlNodeItemRoster->PszFindAttributeValueJid_NZ(); PSZUC pszSubscription = pXmlNodeItemRoster->PszuFindAttributeValue_NZ("subscription"); /* // The attribute "subscription" is not present for a "<iq type='set'>" */ if (!FCompareStrings(pszSubscription, "remove")) { #ifdef DEBUG_DELETE_TEMP_ACCOUNTS if (PszrCompareStringBeginNoCase(pszJid, "temp") != NULL) { MessageLog_AppendTextFormatSev(eSeverityErrorAssert, "#$I Removing contact $s from roster...\n", ++g_cContactsRemoved, pszJid); if (m_paSocket != NULL) m_paSocket->Socket_WriteXmlFormatted("<iq type='set'><query xmlns='jabber:iq:roster'><item jid='^s' subscription='remove'></item></query></iq>", pszJid); return NULL; } #endif TContact * pContact = Contact_PFindByJID(pszJid, eFindContact_kfCreateNew); Endorse(pContact == NULL); // The attribute "jid" may not be valid (for example, missing the '@' character) if (pContact != NULL) pContact->XmppRosterSubscriptionUpdate(pszSubscription); } return pszJid; }
void TAccountXmpp::Contacts_RosterUpdate(const CXmlNode * pXmlNodeQuery) { Assert(pXmlNodeQuery != NULL); Assert(pXmlNodeQuery->FCompareTagName("query")); MessageLog_AppendTextFormatSev(eSeverityNoise, "TAccountXmpp::Contacts_RosterUpdate()\n"); // Loop through every <item> under the <query> element const CXmlNode * pXmlNodeItemRoster = pXmlNodeQuery->m_pElementsList; while (pXmlNodeItemRoster != NULL) { Contact_RosterUpdateItem(pXmlNodeItemRoster); pXmlNodeItemRoster = pXmlNodeItemRoster->m_pNextSibling; } // Make sure every contact is subscribed TContact * pContact; TContact ** ppContactStop; TContact ** ppContact = m_arraypaContacts.PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { pContact = *ppContact++; if (pContact->XmppRoster_PszGetSubscription() == NULL) Contact_RosterSubscribe(pContact); //pContact->XmppRosterSubscribed(); } } // Contacts_RosterUpdate()
// Append the 'chat state' to the cursor void WChatLog::ChatLog_ChatStateTextAppend(INOUT OCursor & oTextCursor) { TContact ** ppContactStop; TContact ** ppContact = m_arraypContactsComposing.PrgpGetContactsStop(OUT &ppContactStop); if (ppContact == ppContactStop) { oTextCursor.removeSelectedText(); } else { if (g_poImageComposing == NULL) g_poImageComposing = new QImage(":/ico/Pencil"); while (TRUE) { oTextCursor.insertImage(*g_poImageComposing); TContact * pContact = *ppContact++; Assert(pContact != NULL); Assert(pContact->EGetRuntimeClass() == RTI(TContact)); g_strScratchBufferStatusBar.Format(d_szu_nbsp " <b>^s</b> is typing...", pContact->ChatLog_PszGetNickname()); oTextCursor.insertHtml(g_strScratchBufferStatusBar); if (ppContact == ppContactStop) break; } // while } if (m_pContactOrGroup->EGetRuntimeClass() == RTI(TContact)) ((TContact *)m_pContactOrGroup)->ChatLogContact_AppendExtraTextToChatState(INOUT oTextCursor); Widget_ScrollToEnd(INOUT this); } // ChatLog_ChatStateTextAppend()
TContact * TAccountXmpp::TreeItemAccount_PContactAllocateNewToNavigationTreeInvited_NZ(PSZUC pszContactJID) { TContact * pContact = TreeItemAccount_PContactAllocateNewToNavigationTree_NZ(pszContactJID); pContact->SetFlagContactAsInvited(); return pContact; }
void TAccountXmpp::PresenceUpdateFromContextMenu(EMenuAction eMenuAction_Presence) { Assert(eMenuAction_Presence <= eMenuAction_PresenceLast); const UINT uFlagsAccountStatus = (m_uFlagsAccountStatus & ~FAS_kmStatusPresenceMask) | eMenuAction_Presence; if (uFlagsAccountStatus == m_uFlagsAccountStatus) return; m_uFlagsAccountStatus = uFlagsAccountStatus; // Update the presence if (m_paSocket != NULL && m_paSocket->Socket_FuIsReadyToSendMessages()) { switch (eMenuAction_Presence) { case eMenuAction_PresenceAccountOnline: case eMenuAction_PresenceAway: case eMenuAction_PresenceAwayExtended: case eMenuAction_PresenceBusy: m_paSocket->Socket_WriteXmlPresence(); break; default: m_paSocket->Socket_Disconnect(); TContact ** ppContactStop; TContact ** ppContact = m_arraypaContacts.PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { TContact * pContact = *ppContact++; Assert(pContact != NULL); Assert(pContact->EGetRuntimeClass() == RTI(TContact)); Assert(pContact->m_pAccount == this); pContact->TreeItemContact_UpdateIconOffline(); } } // switch } // if TreeItemAccount_UpdateIcon(); // Update the icon according to the new presence } // PresenceUpdateFromContextMenu()
void TAccountXmpp::RemoveAllReferencesToObjectsAboutBeingDeleted() { TContact ** ppContactStop; TContact ** ppContact = m_arraypaContacts.PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { TContact * pContact = *ppContact++; pContact->Vault_RemoveAllReferencesToObjectsAboutBeingDeleted(); } TGroup ** ppGroupStop; TGroup ** ppGroup = m_arraypaGroups.PrgpGetGroupsStop(OUT &ppGroupStop); while (ppGroup != ppGroupStop) { TGroup * pGroup = *ppGroup++; Assert(pGroup != NULL); Assert(pGroup->EGetRuntimeClass() == RTI(TGroup)); Assert(pGroup->m_pAccount == this); pGroup->Group_RemoveAllReferencesToContactsAboutBeingDeleted(); } // m_arraypaGroups.RemoveAllUnserializableTreeItems(); // m_arraypaContacts.RemoveAllUnserializableTreeItems(); m_arraypContactsComposing.RemoveAllUnserializableTreeItems(); m_arraypContactsMessagesUnread.RemoveAllUnserializableTreeItems(); }
void TAccountXmpp::ChatLog_DisplayStanza(const CXmlNode * pXmlNodeMessageStanza) { Assert(pXmlNodeMessageStanza != NULL); TContact * pContact = Contact_PFindByJID(IN pXmlNodeMessageStanza->PszFindAttributeValueFrom_NZ(), eFindContact_kmCreateAsUnsolicited); // Find the contact matching the the stanza if (pContact != NULL) pContact->ChatLogContact_DisplayStanzaToUI(pXmlNodeMessageStanza); else MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "Unable to deliver message from unknown peer:\n^N", pXmlNodeMessageStanza); // This happens when the stanza is incomplete and the JID is not adequate to create a contact }
QString OJapiBallot::originator() const { if (m_pEventBallot->EGetEventClass() == CEventBallotReceived::c_eEventClass) { TContact * pContactSender = m_pEventBallot->PGetContactForReply_YZ(); if (pContactSender != NULL) return pContactSender->TreeItem_SGetNameDisplay(); } return m_pEventBallot->PGetProfile()->m_strNameProfile; // At the moment, the originator is the profile/role who sent the ballot }
void TAccountXmpp::Contact_PresenceUpdate(const CXmlNode * pXmlNodeStanzaPresence) { Assert(pXmlNodeStanzaPresence != NULL); Assert(pXmlNodeStanzaPresence->FCompareTagName("presence")); // Find the contact to update the presence TContact * pContact = Contact_PFindByJID(pXmlNodeStanzaPresence->PszFindAttributeValueFrom_NZ(), eFindContact_kfCreateNew); Endorse(pContact == NULL); // The <presence> stanza sometimes is just a reply from the server, which means the attribute "from" is not a contact. if (pContact != NULL) pContact->XmppPresenceUpdateIcon(pXmlNodeStanzaPresence); }
TContact * TAccountXmpp::TreeItemAccount_PContactAllocateNewTemporary(int nContact) { TContact * pContact = new TContact(this); pContact->m_strJidBare.Format("Temp$i$i$i#[email protected]", qrand(), qrand(), qrand(), nContact); pContact->m_strNameDisplayTyped = pContact->m_strJidBare; pContact->m_uFlagsTreeItem |= FTI_kfTreeItem_Temporary; m_arraypaContacts.Add(PA_CHILD pContact); pContact->TreeItemW_DisplayWithinNavigationTree(this); return pContact; }
void CArrayPtrContacts::ForEach_ChatLogResetNickNameAndRepopulateAllEvents() { TContact ** ppContactStop; TContact ** ppContact = PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { TContact * pContact = *ppContact++; Assert(pContact->EGetRuntimeClass() == RTI(TContact)); pContact->m_uFlagsTreeItem |= TContact::FTI_kfChatLogEvents_RepopulateAll; pContact->ChatLog_ResetNickname(); } }
void TAccountXmpp::TreeItemAccount_UpdateIconOfAllContacts() { TContact ** ppContactStop; TContact ** ppContact = m_arraypaContacts.PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { TContact * pContact = *ppContact++; Assert(pContact != NULL); Assert(pContact->EGetRuntimeClass() == RTI(TContact)); Assert(pContact->m_pAccount == this); pContact->TreeItemContact_UpdateIcon(); } }
void TAccountXmpp::Contacts_RosterDisplayDebug(PSZAC pszName) { MessageLog_AppendTextFormatSev(eSeverityNoise, "Roster subscription for account $S: $s\n", &m_strJID, pszName); TContact * pContact; TContact ** ppContactStop; TContact ** ppContact = m_arraypaContacts.PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { pContact = *ppContact++; PSZUC pszSubscription = pContact->XmppRoster_PszGetSubscription(); if (pszSubscription != NULL) MessageLog_AppendTextFormatSev(eSeverityNoise, "\t $S: $s\n", &pContact->m_strJidBare, pszSubscription); } }
void DDialogSendBitcoin::SL_ButtonSendBitcoins() { TContact * pContact = NavigationTree_PGetSelectedTreeItemMatchingInterfaceTContact(); if (pContact == NULL) return; //IEventWalletTransaction * pEvent = TWallet::S_PAllocateEventTransaction(pContact); IEventWalletTransaction * pEvent = new CEventWalletTransactionSent(NULL); pEvent->m_amtQuantity = m_pwEditQuantity->text().toDouble() * -d_cSatoshisPerBitcoin; // Use a negative value to indicate a withdraw pEvent->m_strComment = *m_pwEditComment; pContact->Vault_AddEventToChatLogAndSendToContacts(PA_CHILD pEvent); TWallet::S_SaveAll(); // Save all wallets (in case of a crash) pContact->TreeItem_GotFocus(); // Refresh the layout close(); }
PSZUC CArrayPtrContacts::PszFormatDisplayNames(OUT CStr * pstrScratchBuffer) const { pstrScratchBuffer->Empty(); TContact ** ppContactStop; TContact ** ppContact = PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { TContact * pContact = *ppContact++; Assert(pContact->EGetRuntimeClass() == RTI(TContact)); if (!pstrScratchBuffer->FIsEmptyBinary()) pstrScratchBuffer->BinAppendText(", "); pstrScratchBuffer->BinAppendText((PSZAC)pContact->TreeItem_PszGetNameDisplay()); } return pstrScratchBuffer->BinAppendNullTerminatorSz(); }
// Core routine to add a new event to the vault and send it to the contact(s). // Optionally this method may also send an 'Updater' event void CVaultEvents::EventAddAndDispatchToContacts(PA_CHILD IEvent * paEvent, PA_CHILD CEventUpdaterSent * paEventUpdater) { Assert(paEvent != NULL); Assert(paEvent->m_tsOther == d_ts_zNA); Assert(paEvent->m_pVaultParent_NZ == NULL); Assert(paEvent->Event_FIsEventTypeSent()); //MessageLog_AppendTextFormatSev(eSeverityWarningToErrorLog, "EventAddAndDispatchToContacts() - tsEventID $t\n", paEvent->m_tsEventID); if (paEventUpdater != NULL) { // Always include the Updater before the updated event paEventUpdater->m_pVaultParent_NZ = this; m_arraypaEvents.Add(PA_CHILD paEventUpdater); } paEvent->m_pVaultParent_NZ = this; m_arraypaEvents.Add(PA_CHILD paEvent); SetModified(); // Make sure the events are saved to disk if (paEvent->EGetEventClass() & eEventClass_kfNeverSerializeToXCP) return; // The event is never serialized to XOSP, therefore there is nothing else to do CBinXcpStanza binXcpStanza; // All events are sent as XMPP 'messages' so they may be cached TGroup * pGroup = (TGroup *)m_pParent; TContact * pContact = (TContact *)m_pParent; if (pContact->EGetRuntimeClass() == RTI(TContact)) { // Send the message to a contact MessageLog_AppendTextFormatCo(d_coGrayDark, "\t Sending message to $S\n\t\t m_tsEventIdLastSentCached $t, m_tsOtherLastSynchronized $t\n", &pContact->m_strJidBare, pContact->m_tsEventIdLastSentCached, pContact->m_tsOtherLastSynchronized); binXcpStanza.BinXmlAppendXcpApiCall_SendEventToContact(pContact, paEvent, paEventUpdater); } else { // Broadcast the message to every [active] group member Assert(pGroup->EGetRuntimeClass() == RTI(TGroup)); TGroupMember ** ppMemberStop; TGroupMember ** ppMember = pGroup->m_arraypaMembers.PrgpGetMembersStop(OUT &ppMemberStop); while (ppMember != ppMemberStop) { TGroupMember * pMember = *ppMember++; Assert(pMember != NULL); Assert(pMember->EGetRuntimeClass() == RTI(TGroupMember)); binXcpStanza.BinXmlAppendXcpApiCall_SendEventToContact(pMember->m_pContact, paEvent, paEventUpdater); } // while } // if...else m_pParent->m_tsEventIdLastSentCached = paEvent->m_tsEventID; } // EventAddAndDispatchToContacts()
TContact * CArrayPtrContacts::PFindContactByNameDisplay(PSZUC pszContactNameDisplay, const TContact * pContactExclude) const { TContact ** ppContactStop; TContact ** ppContact = PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { TContact * pContact = *ppContact++; Assert(pContact->EGetRuntimeClass() == RTI(TContact)); if (pContact != pContactExclude) { if (pContact->m_strNameDisplayTyped.FCompareStringsNoCase(pszContactNameDisplay)) return pContact; } } // while return NULL; }
void CArrayPtrContacts::RemoveAllContactsComposingWhoAreIdle() { if (m_paArrayHdr == NULL) return; TContact ** ppContactStop; TContact ** ppContactStart = PrgpGetContactsStop(OUT &ppContactStop); TContact ** ppContactDst = ppContactStart; TContact ** ppContactSrc = ppContactStart; while (ppContactSrc != ppContactStop) { TContact * pContact = *ppContactSrc++; Assert(pContact->EGetRuntimeClass() == RTI(TContact)); MessageLog_AppendTextFormatSev(eSeverityNoise, "\t[$@] $S ($s) is still typing for $i minutes...\n", &pContact->m_strJidBare, pContact->ChatLog_PszGetNickname(), g_tsmMinutesSinceApplicationStarted - pContact->m_tsmLastStanzaReceived); if (g_tsmMinutesSinceApplicationStarted - pContact->m_tsmLastStanzaReceived >= 4) pContact->ChatLogContact_ChatStateIconUpdateComposingStopped(); // If the user has not typed anything during the past 4 minutes, then assume he stopped typing. else *ppContactDst++ = pContact; } m_paArrayHdr->cElements = ppContactDst - ppContactStart; } // RemoveAllContactsComposingWhoAreIdle()
TContact * TAccountXmpp::TreeItemAccount_PContactAllocateNewToNavigationTree_NZ(PSZUC pszContactJID, PSZUC pszContactNameDisplay) { Assert(pszContactJID != NULL); Endorse(pszContactNameDisplay == NULL); // Automatically generate a display name Assert(Contact_PFindByJID(pszContactJID, eFindContact_zDefault) == NULL && "The JID is already present!"); Assert(!m_strJID.FCompareStringsJIDs(pszContactJID) && "The contact JID is the same as the JID of the XMPP account!"); Assert(m_paTreeItemW_YZ != NULL && "No Tree Item to attach to"); // This line of code has to be revised TContact * pContact = new TContact(this); pContact->m_strRessource = pContact->m_strJidBare.AppendTextUntilCharacterPszr(pszContactJID, '/'); pContact->m_strNameDisplayTyped = pszContactNameDisplay; pContact->TreeItemContact_GenerateDisplayNameFromJid(); m_arraypaContacts.Add(PA_CHILD pContact); #ifdef WANT_TREE_NODE_NEW_CONTACT pContact->TreeItemW_DisplayWithinNavigationTreeBefore(m_pTreeItemContactNew); #else pContact->TreeItemW_DisplayWithinNavigationTree(this); #endif pContact->TreeItemContact_UpdateIcon(); pContact->TreeItemW_EnsureVisible(); // Make sure the new contact is visible in the Navigation Tree pContact->m_tsCreated = Timestamp_GetCurrentDateTime(); if (m_paSocket != NULL) Contact_RosterSubscribe(pContact); Configuration_Save(); // Save the configuration after adding a new contact (just in case the application crashes) TWallet::S_ContactAdded(pContact); // Notify the wallet(s) there is a new contact return pContact; }
void TAccountXmpp::TreeItemAccount_DisplayWithinNavigationTree() { Endorse(g_pTreeItemInbox == NULL); // Display the account at the root of the Navigation Tree TreeItemW_DisplayWithinNavigationTree(g_pTreeItemInbox); TContact ** ppContactStop; TContact ** ppContact = m_arraypaContacts.PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { TContact * pContact = *ppContact++; Assert(pContact != NULL); Assert(pContact->EGetRuntimeClass() == RTI(TContact)); Assert(pContact->m_pAccount == this); pContact->TreeItemContact_DisplayWithinNavigationTree(); } // while #ifdef WANT_TREE_NODE_NEW_CONTACT m_pTreeItemContactNew = new TContactNew(this); #endif TGroup ** ppGroupStop; TGroup ** ppGroup = m_arraypaGroups.PrgpGetGroupsStop(OUT &ppGroupStop); while (ppGroup != ppGroupStop) { TGroup * pGroup = *ppGroup++; Assert(pGroup != NULL); Assert(pGroup->EGetRuntimeClass() == RTI(TGroup)); Assert(pGroup->m_pAccount == this); if (pGroup->TreeItemGroup_FCanDisplayWithinNavigationTree()) pGroup->TreeItemGroup_DisplayWithinNavigationTree(); } TreeItemW_ExpandAccordingToSavedState(); TreeItemAccount_UpdateIcon(); #if FIX_THIS // Display the alias as well m_paAlias->TreeItem_DisplayWithinNavigationTree(m_pProfileParent, m_strJID, eMenuIconXmpp); #endif } // TreeItemAccount_DisplayWithinNavigationTree()
void CVaultEvents::ReadEventsFromDisk(const SHashSha1 * pHashFileName) { Assert(pHashFileName != NULL); CWaitCursor wait; CXmlTree oXmlTreeEvents; m_sPathFileName = m_pParent->PGetConfiguration()->SGetPathOfFileName(IN pHashFileName); if (oXmlTreeEvents.m_binXmlFileData.BinFileReadE(m_sPathFileName) == errSuccess) { if (oXmlTreeEvents.EParseFileDataToXmlNodes_ML() == errSuccess) { EventsUnserialize(IN &oXmlTreeEvents); // TODO: We need to check if this is the first vault in the chain. So far, there is always only one vault, however this code will have to be revised when chaining vaults. } } m_pParent->m_tsEventIdLastSentCached = m_arraypaEvents.TsEventIdLastEventSent(); // Update the timestamp so it is what is from the vault, rather than what was loaded from the configuration, as the Chat Log may have been deleted. MessageLog_AppendTextFormatSev(eSeverityNoise, "CVaultEvents::ReadEventsFromDisk(\"{h!}.dat\") for '$s': $I events, m_tsEventIdLastSentCached=$t\n", pHashFileName, m_pParent->TreeItem_PszGetNameDisplay(), m_arraypaEvents.GetSize(), m_pParent->m_tsEventIdLastSentCached); if (m_pParent->EGetRuntimeClass() == RTI(TContact)) { TContact * pContact = (TContact *)m_pParent; TIMESTAMP tsOtherLastReceived = m_arraypaEvents.TsEventOtherLastEventReceived(); if (tsOtherLastReceived > 0) pContact->SetFlagContactAsInvited(); // If there is one event received, then the contact does not need an invitation if (tsOtherLastReceived < pContact->m_tsOtherLastReceived) { MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "\t Adjusting m_tsOtherLastReceived by -$T from $t to $t for '$s'\n", pContact->m_tsOtherLastReceived - tsOtherLastReceived, pContact->m_tsOtherLastReceived, tsOtherLastReceived, m_pParent->TreeItem_PszGetNameDisplay()); pContact->m_tsOtherLastReceived = tsOtherLastReceived; pContact->ContactFlag_SynchronizeWhenPresenceOnline_Set(); // If the timestamp is adjusted, then trigger a synchronization } if (tsOtherLastReceived < pContact->m_tsOtherLastSynchronized || pContact->m_tsOtherLastSynchronized == d_ts_zNA) { if (pContact->m_tsOtherLastSynchronized != tsOtherLastReceived) MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "\t Adjusting m_tsOtherLastSynchronized by -$T from $t ({tL}) to $t ({tL}) for '$s'\n", pContact->m_tsOtherLastSynchronized - tsOtherLastReceived, pContact->m_tsOtherLastSynchronized, pContact->m_tsOtherLastSynchronized, tsOtherLastReceived, tsOtherLastReceived, m_pParent->TreeItem_PszGetNameDisplay()); pContact->m_tsOtherLastSynchronized = tsOtherLastReceived; pContact->ContactFlag_SynchronizeWhenPresenceOnline_Set(); // If the timestamp is adjusted, then trigger a synchronization } if (pContact->m_tsGuiLastActivity < tsOtherLastReceived) pContact->m_tsGuiLastActivity = tsOtherLastReceived; } else { Assert(m_pParent->EGetRuntimeClass() == RTI(TGroup)); if (m_arraypaEvents.FIsEmpty()) { // If there are no events, this means the Chat Log is new or was deleted. In any regards, make sure the timestamps are initialized to zero to make sure the Chat Log is properly reconstructed. TGroupMember ** ppMemberStop; TGroupMember ** ppMember = ((TGroup *)m_pParent)->m_arraypaMembers.PrgpGetMembersStop(OUT &ppMemberStop); while (ppMember != ppMemberStop) { TGroupMember * pMember = *ppMember++; Assert(pMember != NULL); Assert(pMember->EGetRuntimeClass() == RTI(TGroupMember)); if (pMember->m_tsOtherLastSynchronized != d_ts_zNULL) { MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "\t Clearing m_tsOtherLastSynchronized $t for group member ^j\n", pMember->m_tsOtherLastSynchronized, pMember->m_pContact); pMember->m_tsOtherLastSynchronized = d_ts_zNULL; } } // while } } // if...else } // ReadEventsFromDisk()
// Find the contact matching the JID and update the contact resource (if any). // If the JID is not in the contact list, the method will create a new contact to the list according to the value of eFindContact. // This method may return NULL if the JID is empty/invalid because a new contact cannot not be created. // // IMPLEMENTATION NOTES // This method should use a hash table to quickly find a contact from its JID and/or use a pointer to cache the last contact found. TContact * TAccountXmpp::Contact_PFindByJID(PSZUC pszContactJID, EFindContact eFindContact) { Assert(pszContactJID != NULL); if (pszContactJID != NULL) { // Find the resource PSZUC pszResource = pszContactJID; while (TRUE) { if (*pszResource == '/') break; if (*pszResource == '\0') break; pszResource++; } // while const int cchJID = pszResource - pszContactJID; if (cchJID > 0) { TContact * pContact; TContact ** ppContactStop; TContact ** ppContact = m_arraypaContacts.PrgpGetContactsStop(OUT &ppContactStop); while (ppContact != ppContactStop) { pContact = *ppContact++; // Assert(!m_strJID.FCompareStringsJIDs(pContact->m_strJidBare) && "Contact should not have the same JID as its parent XMPP account!"); //MessageLog_AppendTextFormatCo(d_coBlack, "Comparing $s with $S\n", pszContactJID, &pContact->m_strJidBare); if (pContact->m_strJidBare.FCompareStringsNoCaseCch(pszContactJID, cchJID)) { // We have found our contact if (pContact->TreeItemFlags_FuIsInvisible()) { Endorse(pContact->m_paTreeItemW_YZ != NULL); // Typically an invisible contact should not appear in the Navigation Tree, however there are situations where it is. For instance, if the contact was just deleted, or if displayed into the list of "Deleted Items" if (eFindContact & eFindContact_kfMakeVisible) pContact->TreeItemContact_DisplayWithinNavigationTreeAndClearInvisibleFlag(); } if (*pszResource != '\0') { // Update the contact resource if (!pContact->m_strRessource.FCompareStringsExactCase(pszResource)) { if (pContact->m_strRessource.FIsEmptyString()) MessageLog_AppendTextFormatCo(d_coBlack, "Contact $S: Assigning resource '$s' (m_uFlagsTreeItem = 0x$x)\n", &pContact->m_strJidBare, pszResource, m_uFlagsTreeItem); else MessageLog_AppendTextFormatCo(COX_MakeBold(d_coBlack), "Contact $S: Updating resource from '$S' to '$s'\n", &pContact->m_strJidBare, &pContact->m_strRessource, pszResource); //pContact->Xcp_ServiceDiscovery(); // The resource changed, therefore query the remote client for its capabilities pContact->SetFlagXcpComposingSendTimestampsOfLastKnownEvents(); // Each time the resource change, re-send the timestamps of the last known events so we give an opportunity to synchronize //pContact->m_cVersionXCP = 0; // Also, reset the XCP version, to make sure the device connects properly } pContact->m_strRessource.InitFromStringU(pszResource); } return pContact; } } // while // We could not find the contact, so create a new one if the JID meets the minimal conditions if ((eFindContact & eFindContact_kfCreateNew) && PcheValidateJID(pszContactJID) == NULL && // Make sure the JID is somewhat valid to create a new contact !m_strJID.FCompareStringsJIDs(pszContactJID)) // Make sure the JID is not the same as the account. It makes no sense to create a contact with the same JID as its parent account. This situation occurs rarely when the server sends a stanza where the 'from' contains the JID of the account. { MessageLog_AppendTextFormatSev(eSeverityInfoTextBlack, "Contact_PFindByJID('$s') - Creating contact for account $S\n", pszContactJID, &m_strJID); pContact = TreeItemAccount_PContactAllocateNewToNavigationTree_NZ(IN pszContactJID); if (eFindContact & eFindContact_kfCreateAsUnsolicited) pContact->SetFlagContactAsUnsolicited(); return pContact; } } // if } // if return NULL; } // Contact_PFindByJID()