// Return TRUE if the contact never received any message (which means the contact may need an invitation) // Return FALSE if there is at least one message received (which means both parties have communicated successfully) BOOL TContact::Contact_FIsInvitationRecommended() { if ((m_uFlagsContact & FC_kfContactNeedsInvitation) == 0) return FALSE; if (m_paVaultEvents != NULL) { // Search the entire Chat Log to find any message received. Of course this is not the most optimal code, however the Chat Log should be rather short if there has been no communication between the two parties. IEvent ** ppEventStop; IEvent ** ppEvent = m_paVaultEvents->m_arraypaEvents.PrgpGetEventsStop(OUT &ppEventStop); while (ppEvent != ppEventStop) { IEvent * pEvent = *--ppEventStop; AssertValidEvent(pEvent); EEventClass eEventClass = pEvent->EGetEventClass(); if ((eEventClass == eEventClass_eMessageTextSent && pEvent->Event_FHasCompleted()) || // If the message was sent successfully (with a confirmation receipt), then there is no need to send an invitation because the remote contact has the JID of the account (eEventClass & eEventClass_kfReceivedByRemoteClient)) // Anything received by the remote client means there has been a communication between the two contacts, and therefore there is no need to send an invitaiton { m_uFlagsContact &= ~FC_kfContactNeedsInvitation; // Remove the invitation flag return FALSE; } } // while } // if return TRUE; }
void CBinXcpStanza::BinXmlAppendAttributeOfContactIdentifierOfGroupSenderForEvent(const IEvent * pEvent) { AssertValidEvent(pEvent); Endorse(m_pContact == NULL); // Saving to disk /* TContact * pContact = pEvent->m_pContactGroupSender_YZ; if (pContact != NULL && pContact != m_pContact) { Assert(pContact->EGetRuntimeClass() == RTI(TContact)); pContact->BinAppendXmlAttributeOfContactIdentifier(INOUT this, d_chXCPa_pContactGroupSender); } */ if (pEvent->m_pContactGroupSender_YZ != m_pContact) { Endorse(pEvent->m_pContactGroupSender_YZ == NULL); // The event was sent, or was received on a 1-to-1 conversation. If this pointer is NULL, then the method BinAppendXmlAttributeOfContactIdentifier() will ignore it BinAppendXmlAttributeOfContactIdentifier(d_chXCPa_pContactGroupSender, pEvent->m_pContactGroupSender_YZ); } }
void WChatLog::ChatLog_EventsDisplay(const CArrayPtrEvents & arraypEvents, int iEventStart) { Assert(iEventStart >= 0); Assert(m_oTextBlockComposing.isValid()); // CSocketXmpp * pSocket = m_pContactOrGroup->Xmpp_PGetSocketOnlyIfReady(); OCursorSelectBlock oCursor(m_oTextBlockComposing); QTextBlock oTextBlockEvent; // Text block for each event to insert IEvent ** ppEventStop; IEvent ** ppEventFirst = arraypEvents.PrgpGetEventsStop(OUT &ppEventStop) + iEventStart; IEvent ** ppEvent = ppEventFirst; if (!m_fDisplayAllMessages) { // For performance, limit the display to the last 100 events if (ppEventStop != NULL) { IEvent ** ppEventStart = ppEventStop - 100; if (ppEventStart > ppEvent) { ppEvent = ppEventStart; QTextBlockFormat oFormat; oFormat.setAlignment(Qt::AlignHCenter); oFormat.setBackground(c_brushSilver); // Use a silver color oCursor.setBlockFormat(oFormat); g_strScratchBufferStatusBar.Format("<a href='" d_SzMakeCambrianAction(d_szCambrianAction_DisplayAllHistory) "'>Display complete history ($I messages)</a>", arraypEvents.GetSize()); oCursor.insertHtml(g_strScratchBufferStatusBar); oCursor.AppendBlockBlank(); } } } while (ppEvent < ppEventStop) { IEvent * pEvent = *ppEvent++; AssertValidEvent(pEvent); if (pEvent->m_tsEventID >= m_tsMidnightNext) { QDateTime dtl = QDateTime::fromMSecsSinceEpoch(pEvent->m_tsEventID).toLocalTime(); QDate date = dtl.date(); // Strip the time of the day m_tsMidnightNext = QDateTime(date).toMSecsSinceEpoch() + d_ts_cDays; // I am sure there is a more elegant way to strip the time from a date, however at the moment I don't have time to investigate a better solution (and this code works) QTextBlockFormat oFormatBlock; oFormatBlock.setAlignment(Qt::AlignHCenter); oFormatBlock.setBackground(c_brushSilver); oCursor.setBlockFormat(oFormatBlock); QTextCharFormat oFormatChar; // = oCursor.charFormat(); oFormatChar.setFontWeight(QFont::Bold); //oFormatChar.setFontItalic(true); //oCursor.setCharFormat(oFormatChar); oCursor.insertText(date.toString("dddd MMMM d, yyyy"), oFormatChar); oCursor.AppendBlockBlank(); } oTextBlockEvent = oCursor.block(); // Get the current block under the cursor Endorse(oTextBlockEvent.userData() == NULL); if (pEvent->m_uFlagsEvent & IEvent::FE_kfReplacing) { MessageLog_AppendTextFormatSev(eSeverityComment, "Attempting to replace Event ID $t\n", pEvent->m_tsEventID); QTextBlock oTextBlockUpdate; QTextBlock oTextBlockTemp = document()->lastBlock(); IEvent * pEventOld = pEvent; const EEventClass eEventClassUpdater = pEvent->Event_FIsEventTypeSent() ? CEventUpdaterSent::c_eEventClass : CEventUpdaterReceived::c_eEventClass; // Which updater to search for // The event is replacing an older event. This code is a bit complex because the Chat Log may not display all events and therefore we need to find the most recent block displaying the most recent event. IEvent ** ppEventStop; IEvent ** ppEventFirst = pEvent->m_pVaultParent_NZ->m_arraypaEvents.PrgpGetEventsStop(OUT &ppEventStop); IEvent ** ppEventCompare = ppEventStop; // Search the array from the end, as the event to search is likely to be a recent one while (ppEventFirst < ppEventCompare) { // Find the updater which should be right before the replacing event IEvent * pEventTemp = *--ppEventCompare; TryAgain: if (pEventTemp == pEventOld && ppEventFirst < ppEventCompare) { CEventUpdaterSent * pEventUpdater = (CEventUpdaterSent *)*--ppEventCompare; // Get the updater which is just before the event if (pEventUpdater->EGetEventClass() != eEventClassUpdater) { MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "\t Missing Updater for Event ID $t ({tL}); instead found class '$U' with Event ID $t.\n", pEventTemp->m_tsEventID, pEventTemp->m_tsEventID, pEventUpdater->EGetEventClass(), pEventUpdater->m_tsEventID); pEvent->m_uFlagsEvent &= ~IEvent::FE_kfReplacing; // Remove the bit to avoid displaying the error again and again pEvent->m_pVaultParent_NZ->SetModified(); // Save the change continue; } const TIMESTAMP tsEventIdOld = pEventUpdater->m_tsEventIdOld; MessageLog_AppendTextFormatSev(eSeverityNoise, "\t [$i] Found updater: $t -> $t\n", ppEventCompare - ppEventFirst, pEventUpdater->m_tsEventIdNew, tsEventIdOld); // Now, search for the block containing the replacement event while (oTextBlockTemp.isValid()) { OTextBlockUserDataEvent * pUserData = (OTextBlockUserDataEvent *)oTextBlockTemp.userData(); if (pUserData != NULL) { TIMESTAMP_DELTA dtsEvent = (pUserData->m_pEvent->m_tsEventID - tsEventIdOld); MessageLog_AppendTextFormatCo(d_coPurple, "Comparing block Event ID $t with $t: dtsEvent = $T\n", pUserData->m_pEvent->m_tsEventID, tsEventIdOld, dtsEvent); if (dtsEvent <= 0) { if (dtsEvent == 0) { MessageLog_AppendTextFormatSev(eSeverityNoise, "\t Found matching textblock for replacement: Event ID $t -> $t\n", pEventOld->m_tsEventID, tsEventIdOld); oTextBlockUpdate = oTextBlockTemp; } break; } } oTextBlockTemp = oTextBlockTemp.previous(); } // while // Keep searching in case there are chained updated events while (ppEventFirst < ppEventCompare) { pEventTemp = *--ppEventCompare; if (pEventTemp->m_tsEventID == tsEventIdOld) { MessageLog_AppendTextFormatSev(eSeverityNoise, "\t [$i] Found chained replacement: Event ID $t -> $t\n", ppEventCompare - ppEventFirst, pEvent->m_tsEventID, tsEventIdOld); pEventTemp->m_uFlagsEvent |= IEvent::FE_kfReplaced; pEventOld = pEventTemp; goto TryAgain; } } // while } // if } // while if (oTextBlockUpdate.isValid()) { MessageLog_AppendTextFormatSev(eSeverityNoise, "\t Event ID $t is updating its old Event ID $t\n", pEvent->m_tsEventID, pEventOld->m_tsEventID); OCursorSelectBlock oCursorEventOld(oTextBlockUpdate); pEvent->ChatLogUpdateTextBlock(INOUT &oCursorEventOld); continue; } MessageLog_AppendTextFormatSev(eSeverityErrorWarning, "Event ID $t is replacing another event which cannot be found\n", pEvent->m_tsEventID); } // if (replacing) oTextBlockEvent.setUserData(PA_CHILD new OTextBlockUserDataEvent(pEvent)); // Assign an event for each text block pEvent->ChatLogUpdateTextBlock(INOUT &oCursor); if ((pEvent->m_uFlagsEvent & IEvent::FE_kfEventHidden) == 0) oCursor.AppendBlockBlank(); // If the event is visible, then add a new text block (otherwise it will reuse the same old block) else oTextBlockEvent.setUserData(NULL); // Since we are reusing the same block, delete its userdata so we may assing another OTextBlockUserDataEvent } // while m_oTextBlockComposing = oCursor.block(); ChatLog_ChatStateTextAppend(INOUT oCursor); Widget_ScrollToEnd(INOUT this); } // ChatLog_EventsDisplay()