summaryrefslogtreecommitdiff
path: root/indra/newview/llimview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llimview.cpp')
-rw-r--r--indra/newview/llimview.cpp376
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()