diff options
Diffstat (limited to 'indra/newview/llimview.cpp')
-rw-r--r-- | indra/newview/llimview.cpp | 376 |
1 files changed, 306 insertions, 70 deletions
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index d3058e67af..4d2ba16a4c 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -88,6 +88,13 @@ const static std::string IM_TEXT("message"); const static std::string IM_FROM("from"); const static std::string IM_FROM_ID("from_id"); +const static std::string NO_SESSION("(IM Session Doesn't Exist)"); +const static std::string ADHOC_NAME_SUFFIX(" Conference"); + +std::string LLCallDialogManager::sPreviousSessionlName = ""; +std::string LLCallDialogManager::sCurrentSessionlName = ""; +LLIMModel::LLIMSession* LLCallDialogManager::sSession = NULL; + // // Globals // @@ -112,6 +119,13 @@ void toast_callback(const LLSD& msg){ return; } + // Skip toasting if we have open window of IM with this session id + LLIMFloater* open_im_floater = LLIMFloater::findInstance(msg["session_id"]); + if (open_im_floater && open_im_floater->getVisible()) + { + return; + } + LLSD args; args["MESSAGE"] = msg["message"]; args["TIME"] = msg["time"]; @@ -144,6 +158,7 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& : mSessionID(session_id), mName(name), mType(type), + mParticipantUnreadMessageCount(0), mNumUnread(0), mOtherParticipantID(other_participant_id), mInitialTargetIDs(ids), @@ -152,7 +167,8 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& mSessionInitialized(false), mCallBackEnabled(true), mTextIMPossible(true), - mOtherParticipantIsAvatar(true) + mOtherParticipantIsAvatar(true), + mStartCallOnInitialize(false) { if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type) { @@ -167,6 +183,9 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& { mVoiceChannelStateChangeConnection = mVoiceChannel->setStateChangedCallback(boost::bind(&LLIMSession::onVoiceChannelStateChanged, this, _1, _2)); } + // define what type of session was opened + setSessionType(); + mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); // All participants will be added to the list of people we've recently interacted with. @@ -199,8 +218,35 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& } } +void LLIMModel::LLIMSession::setSessionType() +{ + // set P2P type by default + mSessionType = P2P_SESSION; + + if (dynamic_cast<LLVoiceChannelP2P*>(mVoiceChannel) && !mOtherParticipantIsAvatar) // P2P AVALINE channel was opened + { + mSessionType = AVALINE_SESSION; + return; + } + else if(dynamic_cast<LLVoiceChannelGroup*>(mVoiceChannel)) // GROUP channel was opened + { + if (mType == IM_SESSION_CONFERENCE_START) + { + mSessionType = ADHOC_SESSION; + return; + } + else if(mType == IM_SESSION_GROUP_START) + { + mSessionType = GROUP_SESSION; + return; + } + } +} + void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state) { + // *TODO: remove hardcoded string!!!!!!!!!!! + bool is_p2p_session = dynamic_cast<LLVoiceChannelP2P*>(mVoiceChannel); bool is_incoming_call = false; std::string other_avatar_name; @@ -374,6 +420,12 @@ void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, con { im_floater->sessionInitReplyReceived(new_session_id); } + + // auto-start the call on session initialization? + if (session->mStartCallOnInitialize) + { + gIMMgr->startCall(new_session_id); + } } //*TODO remove this "floater" stuff when Communicate Floater is gone @@ -409,10 +461,16 @@ void LLIMModel::testMessages() addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ."); } - +//session name should not be empty bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const std::vector<LLUUID>& ids) { + if (name.empty()) + { + llwarns << "Attempt to create a new session with empty name; id = " << session_id << llendl; + return false; + } + if (findIMSession(session_id)) { llwarns << "IM Session " << session_id << " already exists" << llendl; @@ -458,10 +516,12 @@ void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, } session->mNumUnread = 0; + session->mParticipantUnreadMessageCount = 0; LLSD arg; arg["session_id"] = session_id; arg["num_unread"] = 0; + arg["participant_unread"] = session->mParticipantUnreadMessageCount; mNoUnreadMsgsSignal(arg); } @@ -538,10 +598,18 @@ bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, co session->mNumUnread++; + //update count of unread messages from real participant + if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from)) + { + ++(session->mParticipantUnreadMessageCount); + } + + // notify listeners LLSD arg; arg["session_id"] = session_id; arg["num_unread"] = session->mNumUnread; + arg["participant_unread"] = session->mParticipantUnreadMessageCount; arg["message"] = utf8_text; arg["from"] = from; arg["from_id"] = from_id; @@ -559,7 +627,7 @@ const std::string& LLIMModel::getName(const LLUUID& session_id) const if (!session) { llwarns << "session " << session_id << "does not exist " << llendl; - return LLStringUtil::null; + return NO_SESSION; } return session->mName; @@ -946,18 +1014,6 @@ bool LLIMModel::sendStartSession( return false; } -// static -void LLIMModel::sendSessionInitialized(const LLUUID &session_id) -{ - LLIMSession* session = getInstance()->findIMSession(session_id); - if (session) - { - LLSD arg; - arg["session_id"] = session_id; - getInstance()->mSessionInitializedSignal(arg); - } -} - // // Helper Functions // @@ -1030,7 +1086,7 @@ public: if ( 404 == statusNum ) { std::string error_string; - error_string = "does not exist"; + error_string = "session_does_not_exist_error"; gIMMgr->showSessionStartError(error_string, mSessionID); } } @@ -1184,21 +1240,175 @@ LLIMMgr::onConfirmForceCloseError( //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLCallDialogManager +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LLCallDialogManager::LLCallDialogManager() +{ +} + +LLCallDialogManager::~LLCallDialogManager() +{ +} + +void LLCallDialogManager::initClass() +{ + LLVoiceChannel::setCurrentVoiceChannelChangedCallback(LLCallDialogManager::onVoiceChannelChanged); +} + +void LLCallDialogManager::onVoiceChannelChanged(const LLUUID &session_id) +{ + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if(!session) + { + sPreviousSessionlName = sCurrentSessionlName; + sCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution + return; + } + sSession = session; + sSession->mVoiceChannel->setStateChangedCallback(LLCallDialogManager::onVoiceChannelStateChanged); + sPreviousSessionlName = sCurrentSessionlName; + sCurrentSessionlName = session->mName; +} + +void LLCallDialogManager::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state) +{ + LLSD mCallDialogPayload; + LLOutgoingCallDialog* ocd; + bool is_incoming; + + mCallDialogPayload["session_id"] = sSession->mSessionID; + mCallDialogPayload["session_name"] = sSession->mName; + mCallDialogPayload["other_user_id"] = sSession->mOtherParticipantID; + mCallDialogPayload["old_channel_name"] = sPreviousSessionlName; + + switch(new_state) + { + case LLVoiceChannel::STATE_CALL_STARTED : + // do not show "Calling to..." if it is incoming call + is_incoming = LLVoiceClient::getInstance()->isSessionIncoming(sSession->mSessionID); + // *TODO: implement for AdHoc and Group voice chats + if(is_incoming) + { + return; + } + + ocd = dynamic_cast<LLOutgoingCallDialog*>(LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE)); + if (ocd) + { + ocd->getChild<LLTextBox>("calling")->setVisible(true); + ocd->getChild<LLTextBox>("leaving")->setVisible(true); + ocd->getChild<LLTextBox>("connecting")->setVisible(false); + ocd->getChild<LLTextBox>("noanswer")->setVisible(false); + ocd->getChild<LLButton>("Cancel")->setVisible(true); + } + return; + + case LLVoiceChannel::STATE_RINGING : + ocd = dynamic_cast<LLOutgoingCallDialog*>(LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE)); + if (ocd) + { + ocd->getChild<LLTextBox>("calling")->setVisible(false); + ocd->getChild<LLTextBox>("leaving")->setVisible(true); + ocd->getChild<LLTextBox>("connecting")->setVisible(true); + ocd->getChild<LLTextBox>("noanswer")->setVisible(false); + ocd->getChild<LLButton>("Cancel")->setVisible(true); + } + return; + + case LLVoiceChannel::STATE_ERROR : + mCallDialogPayload["start_timer"] = true; + ocd = dynamic_cast<LLOutgoingCallDialog*>(LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE)); + if (ocd) + { + ocd->getChild<LLTextBox>("calling")->setVisible(false); + ocd->getChild<LLTextBox>("leaving")->setVisible(false); + ocd->getChild<LLTextBox>("connecting")->setVisible(false); + ocd->getChild<LLTextBox>("noanswer")->setVisible(true); + ocd->getChild<LLButton>("Cancel")->setVisible(false); + } + return; + + case LLVoiceChannel::STATE_CONNECTED : + case LLVoiceChannel::STATE_HUNG_UP : + ocd = dynamic_cast<LLOutgoingCallDialog*>(LLFloaterReg::showInstance("outgoing_call", mCallDialogPayload, TRUE)); + if (ocd) + { + ocd->closeFloater(); + } + return; + + default: + break; + } + +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLCallDialog +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LLCallDialog::LLCallDialog(const LLSD& payload) : +LLDockableFloater(NULL, false, payload), +mPayload(payload) +{ +} + +void LLCallDialog::getAllowedRect(LLRect& rect) +{ + rect = gViewerWindow->getWorldViewRectScaled(); +} + +void LLCallDialog::onOpen(const LLSD& key) +{ + // dock the dialog to the Speak Button, where other sys messages appear + setDockControl(new LLDockControl(LLBottomTray::getInstance()->getChild<LLPanel>("speak_panel"), + this, getDockTongue(), LLDockControl::TOP, boost::bind(&LLCallDialog::getAllowedRect, this, _1))); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLOutgoingCallDialog //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) : - LLDockableFloater(NULL, false, payload), - mPayload(payload) +LLCallDialog(payload) +{ + LLOutgoingCallDialog* instance = LLFloaterReg::findTypedInstance<LLOutgoingCallDialog>("outgoing_call", payload); + if(instance && instance->getVisible()) + { + instance->onCancel(instance); + } +} +void LLOutgoingCallDialog::draw() +{ + if (lifetimeHasExpired()) + { + onLifetimeExpired(); + } + LLDockableFloater::draw(); +} + +bool LLOutgoingCallDialog::lifetimeHasExpired() { + if (mLifetimeTimer.getStarted()) + { + F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32(); + if (elapsed_time > LIFETIME) + { + return true; + } + } + return false; } -void LLOutgoingCallDialog::getAllowedRect(LLRect& rect) +void LLOutgoingCallDialog::onLifetimeExpired() { - rect = gViewerWindow->getWorldViewRectScaled(); + mLifetimeTimer.stop(); + closeFloater(); } void LLOutgoingCallDialog::onOpen(const LLSD& key) { + LLCallDialog::onOpen(key); + // tell the user which voice channel they are leaving if (!mPayload["old_channel_name"].asString().empty()) { @@ -1222,6 +1432,13 @@ void LLOutgoingCallDialog::onOpen(const LLSD& key) childSetTextArg("connecting", "[CALLEE_NAME]", callee_name); LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); icon->setValue(callee_id); + + // stop timer by default + mLifetimeTimer.stop(); + if(mPayload.has("start_timer")) + { + mLifetimeTimer.reset(); + } } @@ -1246,22 +1463,15 @@ BOOL LLOutgoingCallDialog::postBuild() childSetAction("Cancel", onCancel, this); - // dock the dialog to the sys well, where other sys messages appear - setDockControl(new LLDockControl(LLBottomTray::getInstance()->getChild<LLPanel>("speak_panel"), - this, getDockTongue(), LLDockControl::TOP, - boost::bind(&LLOutgoingCallDialog::getAllowedRect, this, _1))); - return success; } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLIncomingCallDialog //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) : - LLDockableFloater(NULL, false, payload), - mPayload(payload) +LLCallDialog(payload) { } @@ -1305,13 +1515,11 @@ BOOL LLIncomingCallDialog::postBuild() return TRUE; } -void LLIncomingCallDialog::getAllowedRect(LLRect& rect) -{ - rect = gViewerWindow->getWorldViewRectScaled(); -} void LLIncomingCallDialog::onOpen(const LLSD& key) { + LLCallDialog::onOpen(key); + // tell the user which voice channel they would be leaving LLVoiceChannel *voice = LLVoiceChannel::getCurrentVoiceChannel(); if (voice && !voice->getSessionName().empty()) @@ -1322,11 +1530,6 @@ void LLIncomingCallDialog::onOpen(const LLSD& key) { childSetTextArg("question", "[CURRENT_CHAT]", getString("localchat")); } - - // dock the dialog to the sys well, where other sys messages appear - setDockControl(new LLDockControl(LLBottomTray::getInstance()->getChild<LLPanel>("speak_panel"), - this, getDockTongue(), LLDockControl::TOP, - boost::bind(&LLIncomingCallDialog::getAllowedRect, this, _1))); } //static @@ -1359,6 +1562,8 @@ void LLIncomingCallDialog::processCallResponse(S32 response) return; LLUUID session_id = mPayload["session_id"].asUUID(); + LLUUID caller_id = mPayload["caller_id"].asUUID(); + std::string session_name = mPayload["session_name"].asString(); EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)mPayload["inv_type"].asInteger(); bool voice = true; @@ -1375,8 +1580,8 @@ void LLIncomingCallDialog::processCallResponse(S32 response) { // create a normal IM session session_id = gIMMgr->addP2PSession( - mPayload["session_name"].asString(), - mPayload["caller_id"].asUUID(), + session_name, + caller_id, mPayload["session_handle"].asString(), mPayload["session_uri"].asString()); @@ -1394,10 +1599,38 @@ void LLIncomingCallDialog::processCallResponse(S32 response) } else { - LLUUID new_session_id = gIMMgr->addSession( - mPayload["session_name"].asString(), - type, - session_id); + //session name should not be empty, but it can contain spaces so we don't trim + std::string correct_session_name = session_name; + if (session_name.empty()) + { + llwarns << "Received an empty session name from a server" << llendl; + + switch(type){ + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_GROUP_START: + case IM_SESSION_INVITE: + if (gAgent.isInGroup(session_id)) + { + LLGroupData data; + if (!gAgent.getGroupData(session_id, data)) break; + correct_session_name = data.mName; + } + else + { + if (gCacheName->getFullName(caller_id, correct_session_name)) + { + correct_session_name.append(ADHOC_NAME_SUFFIX); + } + } + llinfos << "Corrected session name is " << correct_session_name << llendl; + break; + default: + llwarning("Received an empty session name from a server and failed to generate a new proper session name", 0); + break; + } + } + + LLUUID new_session_id = gIMMgr->addSession(correct_session_name, type, session_id); if (new_session_id != LLUUID::null) { LLIMFloater::show(new_session_id); @@ -1751,6 +1984,19 @@ S32 LLIMMgr::getNumberOfUnreadIM() return num; } +S32 LLIMMgr::getNumberOfUnreadParticipantMessages() +{ + std::map<LLUUID, LLIMModel::LLIMSession*>::iterator it; + + S32 num = 0; + for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + num += (*it).second->mParticipantUnreadMessageCount; + } + + return num; +} + void LLIMMgr::clearNewIMNotification() { mIMReceived = FALSE; @@ -1761,6 +2007,15 @@ BOOL LLIMMgr::getIMReceived() const return mIMReceived; } +void LLIMMgr::autoStartCallOnStartup(const LLUUID& session_id) +{ + LLIMModel::LLIMSession *session = LLIMModel::getInstance()->findIMSession(session_id); + if (session) + { + session->mStartCallOnInitialize = true; + } +} + LLUUID LLIMMgr::addP2PSession(const std::string& name, const LLUUID& other_participant_id, const std::string& voice_session_handle, @@ -1811,6 +2066,12 @@ LLUUID LLIMMgr::addSession( return LLUUID::null; } + if (name.empty()) + { + llwarning("Session name cannot be null!", 0); + return LLUUID::null; + } + LLUUID session_id = computeSessionID(dialog,other_participant_id); bool new_session = !LLIMModel::getInstance()->findIMSession(session_id); @@ -1966,18 +2227,7 @@ void LLIMMgr::inviteToSession( } else { - if (notify_box_type == "VoiceInviteP2P" || notify_box_type == "VoiceInviteAdHoc") - { - LLFloaterReg::showInstance("incoming_call", payload, TRUE); - } - else - { - LLSD args; - args["NAME"] = caller_name; - args["GROUP"] = session_name; - - LLNotificationsUtil::add(notify_box_type, args, payload, &inviteUserResponse); - } + LLFloaterReg::showInstance("incoming_call", payload, TRUE); } mPendingInvitations[session_id.asString()] = LLSD(); } @@ -1990,21 +2240,7 @@ void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::stri std::string notify_box_type = payload["notify_box_type"].asString(); - if (notify_box_type == "VoiceInviteP2P" || notify_box_type == "VoiceInviteAdHoc") - { - LLFloaterReg::showInstance("incoming_call", payload, TRUE); - } - else - { - LLSD args; - args["NAME"] = payload["caller_name"].asString(); - - LLNotificationsUtil::add( - payload["notify_box_type"].asString(), - args, - payload, - &inviteUserResponse); - } + LLFloaterReg::showInstance("incoming_call", payload, TRUE); } void LLIMMgr::disconnectAllSessions() |