summaryrefslogtreecommitdiff
path: root/indra/newview/llimpanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llimpanel.cpp')
-rw-r--r--indra/newview/llimpanel.cpp895
1 files changed, 2 insertions, 893 deletions
diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp
index 163984f740..77ee90f681 100644
--- a/indra/newview/llimpanel.cpp
+++ b/indra/newview/llimpanel.cpp
@@ -54,6 +54,7 @@
#include "llconsole.h"
#include "llgroupactions.h"
#include "llfloater.h"
+#include "llfloateractivespeakers.h"
#include "llfloatercall.h"
#include "llavataractions.h"
#include "llimview.h"
@@ -77,6 +78,7 @@
#include "llviewercontrol.h"
#include "lluictrlfactory.h"
#include "llviewerwindow.h"
+#include "llvoicechannel.h"
#include "lllogchat.h"
#include "llweb.h"
#include "llhttpclient.h"
@@ -90,7 +92,6 @@
const S32 LINE_HEIGHT = 16;
const S32 MIN_WIDTH = 200;
const S32 MIN_HEIGHT = 130;
-const U32 DEFAULT_RETRIES_COUNT = 3;
//
// Statics
@@ -100,831 +101,6 @@ static std::string sTitleString = "Instant Message with [NAME]";
static std::string sTypingStartString = "[NAME]: ...";
static std::string sSessionStartString = "Starting session with [NAME] please wait.";
-LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap;
-LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap;
-LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL;
-LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL;
-
-BOOL LLVoiceChannel::sSuspended = FALSE;
-
-
-
-class LLVoiceCallCapResponder : public LLHTTPClient::Responder
-{
-public:
- LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {};
-
- virtual void error(U32 status, const std::string& reason); // called with bad status codes
- virtual void result(const LLSD& content);
-
-private:
- LLUUID mSessionID;
-};
-
-
-void LLVoiceCallCapResponder::error(U32 status, const std::string& reason)
-{
- llwarns << "LLVoiceCallCapResponder::error("
- << status << ": " << reason << ")"
- << llendl;
- LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
- if ( channelp )
- {
- if ( 403 == status )
- {
- //403 == no ability
- LLNotifications::instance().add(
- "VoiceNotAllowed",
- channelp->getNotifyArgs());
- }
- else
- {
- LLNotifications::instance().add(
- "VoiceCallGenericError",
- channelp->getNotifyArgs());
- }
- channelp->deactivate();
- }
-}
-
-void LLVoiceCallCapResponder::result(const LLSD& content)
-{
- LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID);
- if (channelp)
- {
- //*TODO: DEBUG SPAM
- LLSD::map_const_iterator iter;
- for(iter = content.beginMap(); iter != content.endMap(); ++iter)
- {
- llinfos << "LLVoiceCallCapResponder::result got "
- << iter->first << llendl;
- }
-
- channelp->setChannelInfo(
- content["voice_credentials"]["channel_uri"].asString(),
- content["voice_credentials"]["channel_credentials"].asString());
- }
-}
-
-//
-// LLVoiceChannel
-//
-LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :
- mSessionID(session_id),
- mState(STATE_NO_CHANNEL_INFO),
- mSessionName(session_name),
- mIgnoreNextSessionLeave(FALSE)
-{
- mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName;
-
- if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second)
- {
- // a voice channel already exists for this session id, so this instance will be orphaned
- // the end result should simply be the failure to make voice calls
- llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl;
- }
-
- LLVoiceClient::getInstance()->addObserver(this);
-}
-
-LLVoiceChannel::~LLVoiceChannel()
-{
- // Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed.
- if(gVoiceClient)
- {
- gVoiceClient->removeObserver(this);
- }
-
- sVoiceChannelMap.erase(mSessionID);
- sVoiceChannelURIMap.erase(mURI);
-}
-
-void LLVoiceChannel::setChannelInfo(
- const std::string& uri,
- const std::string& credentials)
-{
- setURI(uri);
-
- mCredentials = credentials;
-
- if (mState == STATE_NO_CHANNEL_INFO)
- {
- if (mURI.empty())
- {
- LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs);
- llwarns << "Received empty URI for channel " << mSessionName << llendl;
- deactivate();
- }
- else if (mCredentials.empty())
- {
- LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs);
- llwarns << "Received empty credentials for channel " << mSessionName << llendl;
- deactivate();
- }
- else
- {
- setState(STATE_READY);
-
- // if we are supposed to be active, reconnect
- // this will happen on initial connect, as we request credentials on first use
- if (sCurrentVoiceChannel == this)
- {
- // just in case we got new channel info while active
- // should move over to new channel
- activate();
- }
- }
- }
-}
-
-void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal)
-{
- if (channelURI != mURI)
- {
- return;
- }
-
- if (type < BEGIN_ERROR_STATUS)
- {
- handleStatusChange(type);
- }
- else
- {
- handleError(type);
- }
-}
-
-void LLVoiceChannel::handleStatusChange(EStatusType type)
-{
- // status updates
- switch(type)
- {
- case STATUS_LOGIN_RETRY:
- //mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle();
- LLNotifications::instance().add("VoiceLoginRetry");
- break;
- case STATUS_LOGGED_IN:
- //if (!mLoginNotificationHandle.isDead())
- //{
- // LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get();
- // if (notifyp)
- // {
- // notifyp->close();
- // }
- // mLoginNotificationHandle.markDead();
- //}
- break;
- case STATUS_LEFT_CHANNEL:
- if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
- {
- // if forceably removed from channel
- // update the UI and revert to default channel
- LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs);
- deactivate();
- }
- mIgnoreNextSessionLeave = FALSE;
- break;
- case STATUS_JOINING:
- if (callStarted())
- {
- setState(STATE_RINGING);
- }
- break;
- case STATUS_JOINED:
- if (callStarted())
- {
- setState(STATE_CONNECTED);
- }
- default:
- break;
- }
-}
-
-// default behavior is to just deactivate channel
-// derived classes provide specific error messages
-void LLVoiceChannel::handleError(EStatusType type)
-{
- deactivate();
- setState(STATE_ERROR);
-}
-
-BOOL LLVoiceChannel::isActive()
-{
- // only considered active when currently bound channel matches what our channel
- return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;
-}
-
-BOOL LLVoiceChannel::callStarted()
-{
- return mState >= STATE_CALL_STARTED;
-}
-
-void LLVoiceChannel::deactivate()
-{
- if (mState >= STATE_RINGING)
- {
- // ignore session leave event
- mIgnoreNextSessionLeave = TRUE;
- }
-
- if (callStarted())
- {
- setState(STATE_HUNG_UP);
- // mute the microphone if required when returning to the proximal channel
- if (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this)
- {
- gSavedSettings.setBOOL("PTTCurrentlyEnabled", true);
- }
- }
-
- if (sCurrentVoiceChannel == this)
- {
- // default channel is proximal channel
- sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
- sCurrentVoiceChannel->activate();
- }
-}
-
-void LLVoiceChannel::activate()
-{
- if (callStarted())
- {
- return;
- }
-
- // deactivate old channel and mark ourselves as the active one
- if (sCurrentVoiceChannel != this)
- {
- // mark as current before deactivating the old channel to prevent
- // activating the proximal channel between IM calls
- LLVoiceChannel* old_channel = sCurrentVoiceChannel;
- sCurrentVoiceChannel = this;
- if (old_channel)
- {
- old_channel->deactivate();
- }
- }
-
- if (mState == STATE_NO_CHANNEL_INFO)
- {
- // responsible for setting status to active
- getChannelInfo();
- }
- else
- {
- setState(STATE_CALL_STARTED);
- }
-}
-
-void LLVoiceChannel::getChannelInfo()
-{
- // pretend we have everything we need
- if (sCurrentVoiceChannel == this)
- {
- setState(STATE_CALL_STARTED);
- }
-}
-
-//static
-LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id)
-{
- voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id);
- if (found_it == sVoiceChannelMap.end())
- {
- return NULL;
- }
- else
- {
- return found_it->second;
- }
-}
-
-//static
-LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri)
-{
- voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri);
- if (found_it == sVoiceChannelURIMap.end())
- {
- return NULL;
- }
- else
- {
- return found_it->second;
- }
-}
-
-void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id)
-{
- sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID));
- mSessionID = new_session_id;
- sVoiceChannelMap.insert(std::make_pair(mSessionID, this));
-}
-
-void LLVoiceChannel::setURI(std::string uri)
-{
- sVoiceChannelURIMap.erase(mURI);
- mURI = uri;
- sVoiceChannelURIMap.insert(std::make_pair(mURI, this));
-}
-
-void LLVoiceChannel::setState(EState state)
-{
- switch(state)
- {
- case STATE_RINGING:
- gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
- break;
- case STATE_CONNECTED:
- gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs);
- break;
- case STATE_HUNG_UP:
- gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs);
- break;
- default:
- break;
- }
-
- mState = state;
-}
-
-void LLVoiceChannel::toggleCallWindowIfNeeded(EState state)
-{
- if (state == STATE_CONNECTED)
- {
- LLFloaterReg::showInstance("voice_call", mSessionID);
- }
- // By checking that current state is CONNECTED we make sure that the call window
- // has been shown, hence there's something to hide. This helps when user presses
- // the "End call" button right after initiating the call.
- // *TODO: move this check to LLFloaterCall?
- else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED)
- {
- LLFloaterReg::hideInstance("voice_call", mSessionID);
- }
-}
-
-//static
-void LLVoiceChannel::initClass()
-{
- sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance();
-}
-
-
-//static
-void LLVoiceChannel::suspend()
-{
- if (!sSuspended)
- {
- sSuspendedVoiceChannel = sCurrentVoiceChannel;
- sSuspended = TRUE;
- }
-}
-
-//static
-void LLVoiceChannel::resume()
-{
- if (sSuspended)
- {
- if (gVoiceClient->voiceEnabled())
- {
- if (sSuspendedVoiceChannel)
- {
- sSuspendedVoiceChannel->activate();
- }
- else
- {
- LLVoiceChannelProximal::getInstance()->activate();
- }
- }
- sSuspended = FALSE;
- }
-}
-
-
-//
-// LLVoiceChannelGroup
-//
-
-LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :
- LLVoiceChannel(session_id, session_name)
-{
- mRetries = DEFAULT_RETRIES_COUNT;
- mIsRetrying = FALSE;
-}
-
-void LLVoiceChannelGroup::deactivate()
-{
- if (callStarted())
- {
- LLVoiceClient::getInstance()->leaveNonSpatialChannel();
- }
- LLVoiceChannel::deactivate();
-}
-
-void LLVoiceChannelGroup::activate()
-{
- if (callStarted()) return;
-
- LLVoiceChannel::activate();
-
- if (callStarted())
- {
- // we have the channel info, just need to use it now
- LLVoiceClient::getInstance()->setNonSpatialChannel(
- mURI,
- mCredentials);
-
-#if 0 // *TODO
- if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel
- {
- // Add the party to the list of people with which we've recently interacted.
- for (/*people in the chat*/)
- LLRecentPeople::instance().add(buddy_id);
- }
-#endif
- }
-}
-
-void LLVoiceChannelGroup::getChannelInfo()
-{
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- std::string url = region->getCapability("ChatSessionRequest");
- LLSD data;
- data["method"] = "call";
- data["session-id"] = mSessionID;
- LLHTTPClient::post(url,
- data,
- new LLVoiceCallCapResponder(mSessionID));
- }
-}
-
-void LLVoiceChannelGroup::setChannelInfo(
- const std::string& uri,
- const std::string& credentials)
-{
- setURI(uri);
-
- mCredentials = credentials;
-
- if (mState == STATE_NO_CHANNEL_INFO)
- {
- if(!mURI.empty() && !mCredentials.empty())
- {
- setState(STATE_READY);
-
- // if we are supposed to be active, reconnect
- // this will happen on initial connect, as we request credentials on first use
- if (sCurrentVoiceChannel == this)
- {
- // just in case we got new channel info while active
- // should move over to new channel
- activate();
- }
- }
- else
- {
- //*TODO: notify user
- llwarns << "Received invalid credentials for channel " << mSessionName << llendl;
- deactivate();
- }
- }
- else if ( mIsRetrying )
- {
- // we have the channel info, just need to use it now
- LLVoiceClient::getInstance()->setNonSpatialChannel(
- mURI,
- mCredentials);
- }
-}
-
-void LLVoiceChannelGroup::handleStatusChange(EStatusType type)
-{
- // status updates
- switch(type)
- {
- case STATUS_JOINED:
- mRetries = 3;
- mIsRetrying = FALSE;
- default:
- break;
- }
-
- LLVoiceChannel::handleStatusChange(type);
-}
-
-void LLVoiceChannelGroup::handleError(EStatusType status)
-{
- std::string notify;
- switch(status)
- {
- case ERROR_CHANNEL_LOCKED:
- case ERROR_CHANNEL_FULL:
- notify = "VoiceChannelFull";
- break;
- case ERROR_NOT_AVAILABLE:
- //clear URI and credentials
- //set the state to be no info
- //and activate
- if ( mRetries > 0 )
- {
- mRetries--;
- mIsRetrying = TRUE;
- mIgnoreNextSessionLeave = TRUE;
-
- getChannelInfo();
- return;
- }
- else
- {
- notify = "VoiceChannelJoinFailed";
- mRetries = DEFAULT_RETRIES_COUNT;
- mIsRetrying = FALSE;
- }
-
- break;
-
- case ERROR_UNKNOWN:
- default:
- break;
- }
-
- // notification
- if (!notify.empty())
- {
- LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs);
- // echo to im window
- gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage());
- }
-
- LLVoiceChannel::handleError(status);
-}
-
-void LLVoiceChannelGroup::setState(EState state)
-{
- // HACK: Open/close the call window if needed.
- toggleCallWindowIfNeeded(state);
-
- switch(state)
- {
- case STATE_RINGING:
- if ( !mIsRetrying )
- {
- gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs);
- }
-
- mState = state;
- break;
- default:
- LLVoiceChannel::setState(state);
- }
-}
-
-//
-// LLVoiceChannelProximal
-//
-LLVoiceChannelProximal::LLVoiceChannelProximal() :
- LLVoiceChannel(LLUUID::null, LLStringUtil::null)
-{
- activate();
-}
-
-BOOL LLVoiceChannelProximal::isActive()
-{
- return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();
-}
-
-void LLVoiceChannelProximal::activate()
-{
- if (callStarted()) return;
-
- LLVoiceChannel::activate();
-
- if (callStarted())
- {
- // this implicitly puts you back in the spatial channel
- LLVoiceClient::getInstance()->leaveNonSpatialChannel();
- }
-}
-
-void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal)
-{
- if (!proximal)
- {
- return;
- }
-
- if (type < BEGIN_ERROR_STATUS)
- {
- handleStatusChange(type);
- }
- else
- {
- handleError(type);
- }
-}
-
-void LLVoiceChannelProximal::handleStatusChange(EStatusType status)
-{
- // status updates
- switch(status)
- {
- case STATUS_LEFT_CHANNEL:
- // do not notify user when leaving proximal channel
- return;
- case STATUS_VOICE_DISABLED:
- gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs);
- return;
- default:
- break;
- }
- LLVoiceChannel::handleStatusChange(status);
-}
-
-
-void LLVoiceChannelProximal::handleError(EStatusType status)
-{
- std::string notify;
- switch(status)
- {
- case ERROR_CHANNEL_LOCKED:
- case ERROR_CHANNEL_FULL:
- notify = "ProximalVoiceChannelFull";
- break;
- default:
- break;
- }
-
- // notification
- if (!notify.empty())
- {
- LLNotifications::instance().add(notify, mNotifyArgs);
- }
-
- LLVoiceChannel::handleError(status);
-}
-
-void LLVoiceChannelProximal::deactivate()
-{
- if (callStarted())
- {
- setState(STATE_HUNG_UP);
- }
-}
-
-
-//
-// LLVoiceChannelP2P
-//
-LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :
- LLVoiceChannelGroup(session_id, session_name),
- mOtherUserID(other_user_id),
- mReceivedCall(FALSE)
-{
- // make sure URI reflects encoded version of other user's agent id
- setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id));
-}
-
-void LLVoiceChannelP2P::handleStatusChange(EStatusType type)
-{
- // status updates
- switch(type)
- {
- case STATUS_LEFT_CHANNEL:
- if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended)
- {
- if (mState == STATE_RINGING)
- {
- // other user declined call
- LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs);
- }
- else
- {
- // other user hung up
- LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs);
- }
- deactivate();
- }
- mIgnoreNextSessionLeave = FALSE;
- return;
- default:
- break;
- }
-
- LLVoiceChannel::handleStatusChange(type);
-}
-
-void LLVoiceChannelP2P::handleError(EStatusType type)
-{
- switch(type)
- {
- case ERROR_NOT_AVAILABLE:
- LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs);
- break;
- default:
- break;
- }
-
- LLVoiceChannel::handleError(type);
-}
-
-void LLVoiceChannelP2P::activate()
-{
- if (callStarted()) return;
-
- LLVoiceChannel::activate();
-
- if (callStarted())
- {
- // no session handle yet, we're starting the call
- if (mSessionHandle.empty())
- {
- mReceivedCall = FALSE;
- LLVoiceClient::getInstance()->callUser(mOtherUserID);
- }
- // otherwise answering the call
- else
- {
- LLVoiceClient::getInstance()->answerInvite(mSessionHandle);
-
- // using the session handle invalidates it. Clear it out here so we can't reuse it by accident.
- mSessionHandle.clear();
- }
-
- // Add the party to the list of people with which we've recently interacted.
- LLRecentPeople::instance().add(mOtherUserID);
- }
-}
-
-void LLVoiceChannelP2P::getChannelInfo()
-{
- // pretend we have everything we need, since P2P doesn't use channel info
- if (sCurrentVoiceChannel == this)
- {
- setState(STATE_CALL_STARTED);
- }
-}
-
-// receiving session from other user who initiated call
-void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI)
-{
- BOOL needs_activate = FALSE;
- if (callStarted())
- {
- // defer to lower agent id when already active
- if (mOtherUserID < gAgent.getID())
- {
- // pretend we haven't started the call yet, so we can connect to this session instead
- deactivate();
- needs_activate = TRUE;
- }
- else
- {
- // we are active and have priority, invite the other user again
- // under the assumption they will join this new session
- mSessionHandle.clear();
- LLVoiceClient::getInstance()->callUser(mOtherUserID);
- return;
- }
- }
-
- mSessionHandle = handle;
-
- // The URI of a p2p session should always be the other end's SIP URI.
- if(!inURI.empty())
- {
- setURI(inURI);
- }
- else
- {
- setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID));
- }
-
- mReceivedCall = TRUE;
-
- if (needs_activate)
- {
- activate();
- }
-}
-
-void LLVoiceChannelP2P::setState(EState state)
-{
- // HACK: Open/close the call window if needed.
- toggleCallWindowIfNeeded(state);
-
- // you only "answer" voice invites in p2p mode
- // so provide a special purpose message here
- if (mReceivedCall && state == STATE_RINGING)
- {
- gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs);
- mState = state;
- return;
- }
- LLVoiceChannel::setState(state);
-}
-
//
// LLFloaterIMPanel
@@ -1836,75 +1012,8 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string
self->mHistoryEditor->blockUndo();
}
-void LLFloaterIMPanel::showSessionStartError(
- const std::string& error_string)
-{
- LLSD args;
- args["REASON"] = LLTrans::getString(error_string);
- args["RECIPIENT"] = getTitle();
-
- LLSD payload;
- payload["session_id"] = mSessionUUID;
-
- LLNotifications::instance().add(
- "ChatterBoxSessionStartError",
- args,
- payload,
- onConfirmForceCloseError);
-}
-
-void LLFloaterIMPanel::showSessionEventError(
- const std::string& event_string,
- const std::string& error_string)
-{
- LLSD args;
- args["REASON"] =
- LLTrans::getString(error_string);
- args["EVENT"] =
- LLTrans::getString(event_string);
- args["RECIPIENT"] = getTitle();
-
- LLNotifications::instance().add(
- "ChatterBoxSessionEventError",
- args);
-}
-
-void LLFloaterIMPanel::showSessionForceClose(
- const std::string& reason_string)
-{
- LLSD args;
-
- args["NAME"] = getTitle();
- args["REASON"] = LLTrans::getString(reason_string);
-
- LLSD payload;
- payload["session_id"] = mSessionUUID;
-
- LLNotifications::instance().add(
- "ForceCloseChatterBoxSession",
- args,
- payload,
- LLFloaterIMPanel::onConfirmForceCloseError);
-
-}
-
//static
void LLFloaterIMPanel::onKickSpeaker(void* user_data)
{
}
-
-bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const LLSD& response)
-{
- //only 1 option really
- LLUUID session_id = notification["payload"]["session_id"];
-
- if ( gIMMgr )
- {
- LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(
- session_id);
-
- if ( floaterp ) floaterp->closeFloater(FALSE);
- }
- return false;
-}