988 lines
24 KiB
C++
988 lines
24 KiB
C++
/**
|
|
* @file llimview.cpp
|
|
* @brief Container for Instant Messaging
|
|
*
|
|
* Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
|
|
* $License$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include "llimview.h"
|
|
|
|
#include "llfontgl.h"
|
|
#include "llrect.h"
|
|
#include "llerror.h"
|
|
#include "llbutton.h"
|
|
#include "llstring.h"
|
|
#include "linked_lists.h"
|
|
#include "llvieweruictrlfactory.h"
|
|
|
|
#include "llagent.h"
|
|
#include "llcallingcard.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llresmgr.h"
|
|
#include "llfloaternewim.h"
|
|
#include "llhttpnode.h"
|
|
#include "llimpanel.h"
|
|
#include "llresizebar.h"
|
|
#include "lltabcontainer.h"
|
|
#include "viewer.h"
|
|
#include "llfloater.h"
|
|
#include "llresizehandle.h"
|
|
#include "llkeyboard.h"
|
|
#include "llui.h"
|
|
#include "llviewermenu.h"
|
|
#include "llcallingcard.h"
|
|
#include "lltoolbar.h"
|
|
|
|
const EInstantMessage GROUP_DIALOG = IM_SESSION_GROUP_START;
|
|
const EInstantMessage DEFAULT_DIALOG = IM_NOTHING_SPECIAL;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
LLIMView* gIMView = NULL;
|
|
|
|
//
|
|
// Statics
|
|
//
|
|
static LLString sOnlyUserMessage;
|
|
static LLString sOfflineMessage;
|
|
|
|
static std::map<std::string,LLString> sEventStringsMap;
|
|
static std::map<std::string,LLString> sErrorStringsMap;
|
|
static std::map<std::string,LLString> sForceCloseSessionMap;
|
|
//
|
|
// Helper Functions
|
|
//
|
|
|
|
// returns true if a should appear before b
|
|
static BOOL group_dictionary_sort( LLGroupData* a, LLGroupData* b )
|
|
{
|
|
return (LLString::compareDict( a->mName, b->mName ) < 0);
|
|
}
|
|
|
|
|
|
// the other_participant_id is either an agent_id, a group_id, or an inventory
|
|
// folder item_id (collection of calling cards)
|
|
static LLUUID compute_session_id(EInstantMessage dialog,
|
|
const LLUUID& other_participant_id)
|
|
{
|
|
LLUUID session_id;
|
|
if (IM_SESSION_GROUP_START == dialog)
|
|
{
|
|
// slam group session_id to the group_id (other_participant_id)
|
|
session_id = other_participant_id;
|
|
}
|
|
else if (IM_SESSION_CONFERENCE_START == dialog)
|
|
{
|
|
session_id.generate();
|
|
}
|
|
else
|
|
{
|
|
LLUUID agent_id = gAgent.getID();
|
|
if (other_participant_id == agent_id)
|
|
{
|
|
// if we try to send an IM to ourselves then the XOR would be null
|
|
// so we just make the session_id the same as the agent_id
|
|
session_id = agent_id;
|
|
}
|
|
else
|
|
{
|
|
// peer-to-peer or peer-to-asset session_id is the XOR
|
|
session_id = other_participant_id ^ agent_id;
|
|
}
|
|
}
|
|
return session_id;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// LLFloaterIM
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
LLFloaterIM::LLFloaterIM()
|
|
{
|
|
gUICtrlFactory->buildFloater(this, "floater_im.xml");
|
|
}
|
|
|
|
BOOL LLFloaterIM::postBuild()
|
|
{
|
|
requires("only_user_message", WIDGET_TYPE_TEXT_BOX);
|
|
requires("offline_message", WIDGET_TYPE_TEXT_BOX);
|
|
requires("generic_request_error", WIDGET_TYPE_TEXT_BOX);
|
|
requires("insufficient_perms_error", WIDGET_TYPE_TEXT_BOX);
|
|
requires("generic_request_error", WIDGET_TYPE_TEXT_BOX);
|
|
requires("add_session_event", WIDGET_TYPE_TEXT_BOX);
|
|
requires("message_session_event", WIDGET_TYPE_TEXT_BOX);
|
|
requires("removed_from_group", WIDGET_TYPE_TEXT_BOX);
|
|
|
|
if (checkRequirements())
|
|
{
|
|
sOnlyUserMessage = childGetText("only_user_message");
|
|
sOfflineMessage = childGetText("offline_message");
|
|
|
|
sErrorStringsMap["generic"] =
|
|
childGetText("generic_request_error");
|
|
sErrorStringsMap["unverified"] =
|
|
childGetText("insufficient_perms_error");
|
|
sErrorStringsMap["no_user_911"] =
|
|
childGetText("user_no_help");
|
|
|
|
sEventStringsMap["add"] = childGetText("add_session_event");;
|
|
sEventStringsMap["message"] =
|
|
childGetText("message_session_event");;
|
|
sEventStringsMap["teleport"] =
|
|
childGetText("teleport_session_event");;
|
|
|
|
sForceCloseSessionMap["removed"] =
|
|
childGetText("removed_from_group");
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//// virtual
|
|
//BOOL LLFloaterIM::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
|
|
//{
|
|
// BOOL handled = FALSE;
|
|
// if (getEnabled()
|
|
// && mask == (MASK_CONTROL|MASK_SHIFT))
|
|
// {
|
|
// if (key == 'W')
|
|
// {
|
|
// LLFloater* floater = getActiveFloater();
|
|
// if (floater)
|
|
// {
|
|
// if (mTabContainer->getTabCount() == 1)
|
|
// {
|
|
// // trying to close last tab, close
|
|
// // entire window.
|
|
// close();
|
|
// handled = TRUE;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// return handled || LLMultiFloater::handleKeyHere(key, mask, called_from_parent);
|
|
//}
|
|
|
|
void LLFloaterIM::onClose(bool app_quitting)
|
|
{
|
|
if (!app_quitting)
|
|
{
|
|
gSavedSettings.setBOOL("ShowIM", FALSE);
|
|
}
|
|
setVisible(FALSE);
|
|
}
|
|
|
|
//virtual
|
|
void LLFloaterIM::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point)
|
|
{
|
|
// this code is needed to fix the bug where new IMs received will resize the IM floater.
|
|
// SL-29075, SL-24556, and others
|
|
LLRect parent_rect = getRect();
|
|
S32 dheight = LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT;
|
|
LLRect rect(0, parent_rect.getHeight()-dheight, parent_rect.getWidth(), 0);
|
|
floaterp->reshape(rect.getWidth(), rect.getHeight(), TRUE);
|
|
LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Class LLIMViewFriendObserver
|
|
//
|
|
// Bridge to suport knowing when the inventory has changed.
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
class LLIMViewFriendObserver : public LLFriendObserver
|
|
{
|
|
public:
|
|
LLIMViewFriendObserver(LLIMView* tv) : mTV(tv) {}
|
|
virtual ~LLIMViewFriendObserver() {}
|
|
virtual void changed(U32 mask)
|
|
{
|
|
if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE))
|
|
{
|
|
mTV->refresh();
|
|
}
|
|
}
|
|
protected:
|
|
LLIMView* mTV;
|
|
};
|
|
|
|
|
|
//
|
|
// Public Static Member Functions
|
|
//
|
|
|
|
// This is a helper function to determine what kind of im session
|
|
// should be used for the given agent.
|
|
// static
|
|
EInstantMessage LLIMView::defaultIMTypeForAgent(const LLUUID& agent_id)
|
|
{
|
|
EInstantMessage type = IM_NOTHING_SPECIAL;
|
|
if(is_agent_friend(agent_id))
|
|
{
|
|
if(LLAvatarTracker::instance().isBuddyOnline(agent_id))
|
|
{
|
|
type = IM_SESSION_CONFERENCE_START;
|
|
}
|
|
}
|
|
return type;
|
|
}
|
|
|
|
// static
|
|
//void LLIMView::onPinButton(void*)
|
|
//{
|
|
// BOOL state = gSavedSettings.getBOOL( "PinTalkViewOpen" );
|
|
// gSavedSettings.setBOOL( "PinTalkViewOpen", !state );
|
|
//}
|
|
|
|
// static
|
|
void LLIMView::toggle(void*)
|
|
{
|
|
static BOOL return_to_mouselook = FALSE;
|
|
|
|
// Hide the button and show the floater or vice versa.
|
|
llassert( gIMView );
|
|
BOOL old_state = gIMView->getFloaterOpen();
|
|
|
|
// If we're in mouselook and we triggered the Talk View, we want to talk.
|
|
if( gAgent.cameraMouselook() && old_state )
|
|
{
|
|
return_to_mouselook = TRUE;
|
|
gAgent.changeCameraToDefault();
|
|
return;
|
|
}
|
|
|
|
BOOL new_state = !old_state;
|
|
|
|
if (new_state)
|
|
{
|
|
// ...making visible
|
|
if ( gAgent.cameraMouselook() )
|
|
{
|
|
return_to_mouselook = TRUE;
|
|
gAgent.changeCameraToDefault();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ...hiding
|
|
if ( gAgent.cameraThirdPerson() && return_to_mouselook )
|
|
{
|
|
gAgent.changeCameraToMouselook();
|
|
}
|
|
return_to_mouselook = FALSE;
|
|
}
|
|
|
|
gIMView->setFloaterOpen( new_state );
|
|
}
|
|
|
|
//
|
|
// Member Functions
|
|
//
|
|
|
|
LLIMView::LLIMView(const std::string& name, const LLRect& rect) :
|
|
LLView(name, rect, FALSE),
|
|
mFriendObserver(NULL),
|
|
mIMReceived(FALSE)
|
|
{
|
|
gIMView = this;
|
|
mFriendObserver = new LLIMViewFriendObserver(this);
|
|
LLAvatarTracker::instance().addObserver(mFriendObserver);
|
|
|
|
mTalkFloater = new LLFloaterIM();
|
|
|
|
// New IM Panel
|
|
mNewIMFloater = new LLFloaterNewIM();
|
|
mTalkFloater->addFloater(mNewIMFloater, TRUE);
|
|
|
|
// Tabs sometimes overlap resize handle
|
|
mTalkFloater->moveResizeHandleToFront();
|
|
}
|
|
|
|
LLIMView::~LLIMView()
|
|
{
|
|
LLAvatarTracker::instance().removeObserver(mFriendObserver);
|
|
delete mFriendObserver;
|
|
// Children all cleaned up by default view destructor.
|
|
}
|
|
|
|
EWidgetType LLIMView::getWidgetType() const
|
|
{
|
|
return WIDGET_TYPE_TALK_VIEW;
|
|
}
|
|
|
|
LLString LLIMView::getWidgetTag() const
|
|
{
|
|
return LL_TALK_VIEW_TAG;
|
|
}
|
|
|
|
// Add a message to a session.
|
|
void LLIMView::addMessage(
|
|
const LLUUID& session_id,
|
|
const LLUUID& other_participant_id,
|
|
const char* from,
|
|
const char* msg,
|
|
const char* session_name,
|
|
EInstantMessage dialog,
|
|
U32 parent_estate_id,
|
|
const LLUUID& region_id,
|
|
const LLVector3& position)
|
|
{
|
|
LLFloaterIMPanel* floater;
|
|
LLUUID new_session_id = session_id;
|
|
if (new_session_id.isNull())
|
|
{
|
|
new_session_id = compute_session_id(dialog, other_participant_id);
|
|
}
|
|
floater = findFloaterBySession(new_session_id);
|
|
if (!floater)
|
|
{
|
|
floater = findFloaterBySession(other_participant_id);
|
|
if (floater)
|
|
{
|
|
llinfos << "found the IM session " << session_id
|
|
<< " by participant " << other_participant_id << llendl;
|
|
}
|
|
}
|
|
if(floater)
|
|
{
|
|
floater->addHistoryLine(msg);
|
|
}
|
|
else
|
|
{
|
|
//if we have recently requsted to be dropped from a session
|
|
//but are still receiving messages from the session, don't make
|
|
//a new floater
|
|
// if ( mSessionsDropRequested.has(session_id.asString()) )
|
|
// {
|
|
// return ;
|
|
// }
|
|
|
|
const char* name = from;
|
|
if(session_name && (strlen(session_name)>1))
|
|
{
|
|
name = session_name;
|
|
}
|
|
|
|
|
|
floater = createFloater(new_session_id, other_participant_id, name, dialog, FALSE);
|
|
|
|
// When we get a new IM, and if you are a god, display a bit
|
|
// of information about the source. This is to help liaisons
|
|
// when answering questions.
|
|
if(gAgent.isGodlike())
|
|
{
|
|
// XUI:translate
|
|
std::ostringstream bonus_info;
|
|
bonus_info << "*** parent estate: "
|
|
<< parent_estate_id
|
|
<< ((parent_estate_id == 1) ? ", mainland" : "")
|
|
<< ((parent_estate_id == 5) ? ", teen" : "");
|
|
|
|
// once we have web-services (or something) which returns
|
|
// information about a region id, we can print this out
|
|
// and even have it link to map-teleport or something.
|
|
//<< "*** region_id: " << region_id << std::endl
|
|
//<< "*** position: " << position << std::endl;
|
|
|
|
floater->addHistoryLine(bonus_info.str());
|
|
}
|
|
|
|
floater->addHistoryLine(msg);
|
|
make_ui_sound("UISndNewIncomingIMSession");
|
|
}
|
|
|
|
if( !mTalkFloater->getVisible() && !floater->getVisible())
|
|
{
|
|
//if the IM window is not open and the floater is not visible (i.e. not torn off)
|
|
LLFloater* previouslyActiveFloater = mTalkFloater->getActiveFloater();
|
|
|
|
// select the newly added floater (or the floater with the new line added to it).
|
|
// it should be there.
|
|
mTalkFloater->selectFloater(floater);
|
|
|
|
//there was a previously unseen IM, make that old tab flashing
|
|
//it is assumed that the most recently unseen IM tab is the one current selected/active
|
|
if ( previouslyActiveFloater && getIMReceived() )
|
|
{
|
|
mTalkFloater->setFloaterFlashing(previouslyActiveFloater, TRUE);
|
|
}
|
|
|
|
//notify of a new IM
|
|
notifyNewIM();
|
|
}
|
|
}
|
|
|
|
void LLIMView::notifyNewIM()
|
|
{
|
|
if(!gIMView->getFloaterOpen())
|
|
{
|
|
mIMReceived = TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL LLIMView::getIMReceived() const
|
|
{
|
|
return mIMReceived;
|
|
}
|
|
|
|
// This method returns TRUE if the local viewer has a session
|
|
// currently open keyed to the uuid.
|
|
BOOL LLIMView::isIMSessionOpen(const LLUUID& uuid)
|
|
{
|
|
LLFloaterIMPanel* floater = findFloaterBySession(uuid);
|
|
if(floater) return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
// This adds a session to the talk view. The name is the local name of
|
|
// the session, dialog specifies the type of session. If the session
|
|
// exists, it is brought forward. Specifying id = NULL results in an
|
|
// im session to everyone. Returns the uuid of the session.
|
|
LLUUID LLIMView::addSession(const std::string& name,
|
|
EInstantMessage dialog,
|
|
const LLUUID& other_participant_id)
|
|
{
|
|
LLUUID session_id = compute_session_id(dialog, other_participant_id);
|
|
|
|
LLFloaterIMPanel* floater = findFloaterBySession(session_id);
|
|
if(!floater)
|
|
{
|
|
LLDynamicArray<LLUUID> ids;
|
|
ids.put(other_participant_id);
|
|
|
|
floater = createFloater(session_id,
|
|
other_participant_id,
|
|
name,
|
|
ids,
|
|
dialog,
|
|
TRUE);
|
|
|
|
noteOfflineUsers(floater, ids);
|
|
mTalkFloater->showFloater(floater);
|
|
}
|
|
else
|
|
{
|
|
floater->open();
|
|
}
|
|
//mTabContainer->selectTabPanel(panel);
|
|
floater->setInputFocus(TRUE);
|
|
return floater->getSessionID();
|
|
}
|
|
|
|
// Adds a session using the given session_id. If the session already exists
|
|
// the dialog type is assumed correct. Returns the uuid of the session.
|
|
LLUUID LLIMView::addSession(const std::string& name,
|
|
EInstantMessage dialog,
|
|
const LLUUID& other_participant_id,
|
|
const LLDynamicArray<LLUUID>& ids)
|
|
{
|
|
if (0 == ids.getLength())
|
|
{
|
|
return LLUUID::null;
|
|
}
|
|
|
|
LLUUID session_id = compute_session_id(dialog,
|
|
other_participant_id);
|
|
|
|
LLFloaterIMPanel* floater = findFloaterBySession(session_id);
|
|
if(!floater)
|
|
{
|
|
// On creation, use the first element of ids as the
|
|
// "other_participant_id"
|
|
floater = createFloater(session_id,
|
|
other_participant_id,
|
|
name,
|
|
ids,
|
|
dialog,
|
|
TRUE);
|
|
|
|
if ( !floater ) return LLUUID::null;
|
|
|
|
noteOfflineUsers(floater, ids);
|
|
}
|
|
mTalkFloater->showFloater(floater);
|
|
//mTabContainer->selectTabPanel(panel);
|
|
floater->setInputFocus(TRUE);
|
|
return floater->getSessionID();
|
|
}
|
|
|
|
// This removes the panel referenced by the uuid, and then restores
|
|
// internal consistency. The internal pointer is not deleted.
|
|
void LLIMView::removeSession(const LLUUID& session_id)
|
|
{
|
|
LLFloaterIMPanel* floater = findFloaterBySession(session_id);
|
|
if(floater)
|
|
{
|
|
mFloaters.erase(floater->getHandle());
|
|
mTalkFloater->removeFloater(floater);
|
|
//mTabContainer->removeTabPanel(floater);
|
|
}
|
|
|
|
// if ( session_id.notNull() )
|
|
// {
|
|
// mSessionsDropRequested[session_id.asString()] = LLSD();
|
|
// }
|
|
}
|
|
|
|
void LLIMView::refresh()
|
|
{
|
|
S32 old_scroll_pos = mNewIMFloater->getScrollPos();
|
|
mNewIMFloater->clearAllTargets();
|
|
|
|
// build a list of groups.
|
|
LLLinkedList<LLGroupData> group_list( group_dictionary_sort );
|
|
|
|
LLGroupData* group;
|
|
S32 count = gAgent.mGroups.count();
|
|
S32 i;
|
|
// read/sort groups on the first pass.
|
|
for(i = 0; i < count; ++i)
|
|
{
|
|
group = &(gAgent.mGroups.get(i));
|
|
group_list.addDataSorted( group );
|
|
}
|
|
|
|
// add groups to the floater on the second pass.
|
|
for(group = group_list.getFirstData();
|
|
group;
|
|
group = group_list.getNextData())
|
|
{
|
|
mNewIMFloater->addGroup(group->mID, (void*)(&GROUP_DIALOG), TRUE, FALSE);
|
|
}
|
|
|
|
// build a set of buddies in the current buddy list.
|
|
LLCollectAllBuddies collector;
|
|
LLAvatarTracker::instance().applyFunctor(collector);
|
|
LLCollectAllBuddies::buddy_map_t::iterator it;
|
|
LLCollectAllBuddies::buddy_map_t::iterator end;
|
|
it = collector.mOnline.begin();
|
|
end = collector.mOnline.end();
|
|
for( ; it != end; ++it)
|
|
{
|
|
mNewIMFloater->addAgent((*it).second, (void*)(&DEFAULT_DIALOG), TRUE);
|
|
}
|
|
it = collector.mOffline.begin();
|
|
end = collector.mOffline.end();
|
|
for( ; it != end; ++it)
|
|
{
|
|
mNewIMFloater->addAgent((*it).second, (void*)(&DEFAULT_DIALOG), FALSE);
|
|
}
|
|
|
|
mNewIMFloater->setScrollPos( old_scroll_pos );
|
|
}
|
|
|
|
// JC - This used to set console visibility. It doesn't any more.
|
|
void LLIMView::setFloaterOpen(BOOL set_open)
|
|
{
|
|
gSavedSettings.setBOOL("ShowIM", set_open);
|
|
|
|
//RN "visible" and "open" are considered synonomous for now
|
|
if (set_open)
|
|
{
|
|
mTalkFloater->open(); /*Flawfinder: ignore*/
|
|
}
|
|
else
|
|
{
|
|
mTalkFloater->close();
|
|
}
|
|
|
|
if( set_open )
|
|
{
|
|
// notifyNewIM();
|
|
|
|
// We're showing the IM, so mark view as non-pending
|
|
mIMReceived = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL LLIMView::getFloaterOpen()
|
|
{
|
|
return mTalkFloater->getVisible();
|
|
}
|
|
|
|
void LLIMView::pruneSessions()
|
|
{
|
|
if(mNewIMFloater)
|
|
{
|
|
BOOL removed = TRUE;
|
|
LLFloaterIMPanel* floater = NULL;
|
|
while(removed)
|
|
{
|
|
removed = FALSE;
|
|
std::set<LLViewHandle>::iterator handle_it;
|
|
for(handle_it = mFloaters.begin();
|
|
handle_it != mFloaters.end();
|
|
++handle_it)
|
|
{
|
|
floater = (LLFloaterIMPanel*)LLFloater::getFloaterByHandle(*handle_it);
|
|
if(floater && !mNewIMFloater->isUUIDAvailable(floater->getOtherParticipantID()))
|
|
{
|
|
// remove this floater
|
|
removed = TRUE;
|
|
mFloaters.erase(handle_it++);
|
|
floater->close();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void LLIMView::disconnectAllSessions()
|
|
{
|
|
if(mNewIMFloater)
|
|
{
|
|
mNewIMFloater->setEnabled(FALSE);
|
|
}
|
|
LLFloaterIMPanel* floater = NULL;
|
|
std::set<LLViewHandle>::iterator handle_it;
|
|
for(handle_it = mFloaters.begin();
|
|
handle_it != mFloaters.end();
|
|
)
|
|
{
|
|
floater = (LLFloaterIMPanel*)LLFloater::getFloaterByHandle(*handle_it);
|
|
|
|
// MUST do this BEFORE calling floater->onClose() because that may remove the item from the set, causing the subsequent increment to crash.
|
|
++handle_it;
|
|
|
|
if (floater)
|
|
{
|
|
floater->setEnabled(FALSE);
|
|
floater->onClose(TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// This method returns the im panel corresponding to the uuid
|
|
// provided. The uuid can either be a session id or an agent
|
|
// id. Returns NULL if there is no matching panel.
|
|
LLFloaterIMPanel* LLIMView::findFloaterBySession(const LLUUID& session_id)
|
|
{
|
|
LLFloaterIMPanel* rv = NULL;
|
|
std::set<LLViewHandle>::iterator handle_it;
|
|
for(handle_it = mFloaters.begin();
|
|
handle_it != mFloaters.end();
|
|
++handle_it)
|
|
{
|
|
rv = (LLFloaterIMPanel*)LLFloater::getFloaterByHandle(*handle_it);
|
|
if(rv && session_id == rv->getSessionID())
|
|
{
|
|
break;
|
|
}
|
|
rv = NULL;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
BOOL LLIMView::hasSession(const LLUUID& session_id)
|
|
{
|
|
return (findFloaterBySession(session_id) != NULL);
|
|
}
|
|
|
|
|
|
// create a floater and update internal representation for
|
|
// consistency. Returns the pointer, caller (the class instance since
|
|
// it is a private method) is not responsible for deleting the
|
|
// pointer. Add the floater to this but do not select it.
|
|
LLFloaterIMPanel* LLIMView::createFloater(
|
|
const LLUUID& session_id,
|
|
const LLUUID& other_participant_id,
|
|
const std::string& session_label,
|
|
EInstantMessage dialog,
|
|
BOOL user_initiated)
|
|
{
|
|
if (session_id.isNull())
|
|
{
|
|
llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl;
|
|
}
|
|
|
|
llinfos << "LLIMView::createFloater: from " << other_participant_id
|
|
<< " in session " << session_id << llendl;
|
|
LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label,
|
|
LLRect(),
|
|
session_label,
|
|
session_id,
|
|
other_participant_id,
|
|
dialog);
|
|
LLTabContainerCommon::eInsertionPoint i_pt = user_initiated ? LLTabContainerCommon::RIGHT_OF_CURRENT : LLTabContainerCommon::END;
|
|
mTalkFloater->addFloater(floater, FALSE, i_pt);
|
|
mFloaters.insert(floater->getHandle());
|
|
return floater;
|
|
}
|
|
|
|
LLFloaterIMPanel* LLIMView::createFloater(
|
|
const LLUUID& session_id,
|
|
const LLUUID& other_participant_id,
|
|
const std::string& session_label,
|
|
const LLDynamicArray<LLUUID>& ids,
|
|
EInstantMessage dialog,
|
|
BOOL user_initiated)
|
|
{
|
|
if (session_id.isNull())
|
|
{
|
|
llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl;
|
|
}
|
|
|
|
llinfos << "LLIMView::createFloater: from " << other_participant_id
|
|
<< " in session " << session_id << llendl;
|
|
LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label,
|
|
LLRect(),
|
|
session_label,
|
|
session_id,
|
|
other_participant_id,
|
|
ids,
|
|
dialog);
|
|
LLTabContainerCommon::eInsertionPoint i_pt = user_initiated ? LLTabContainerCommon::RIGHT_OF_CURRENT : LLTabContainerCommon::END;
|
|
mTalkFloater->addFloater(floater, FALSE, i_pt);
|
|
mFloaters.insert(floater->getHandle());
|
|
return floater;
|
|
}
|
|
|
|
void LLIMView::noteOfflineUsers(LLFloaterIMPanel* floater,
|
|
const LLDynamicArray<LLUUID>& ids)
|
|
{
|
|
S32 count = ids.count();
|
|
if(count == 0)
|
|
{
|
|
floater->addHistoryLine(sOnlyUserMessage);
|
|
}
|
|
else
|
|
{
|
|
const LLRelationship* info = NULL;
|
|
LLAvatarTracker& at = LLAvatarTracker::instance();
|
|
for(S32 i = 0; i < count; ++i)
|
|
{
|
|
info = at.getBuddyInfo(ids.get(i));
|
|
char first[DB_FIRST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/
|
|
char last[DB_LAST_NAME_BUF_SIZE]; /*Flawfinder: ignore*/
|
|
if(info && !info->isOnline()
|
|
&& gCacheName->getName(ids.get(i), first, last))
|
|
{
|
|
LLUIString offline = sOfflineMessage;
|
|
offline.setArg("[FIRST]", first);
|
|
offline.setArg("[LAST]", last);
|
|
floater->addHistoryLine(offline);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLIMView::processIMTypingStart(const LLIMInfo* im_info)
|
|
{
|
|
processIMTypingCore(im_info, TRUE);
|
|
}
|
|
|
|
void LLIMView::processIMTypingStop(const LLIMInfo* im_info)
|
|
{
|
|
processIMTypingCore(im_info, FALSE);
|
|
}
|
|
|
|
void LLIMView::processIMTypingCore(const LLIMInfo* im_info, BOOL typing)
|
|
{
|
|
LLUUID session_id = compute_session_id(im_info->mIMType, im_info->mFromID);
|
|
LLFloaterIMPanel* floater = findFloaterBySession(session_id);
|
|
if (floater)
|
|
{
|
|
floater->processIMTyping(im_info, typing);
|
|
}
|
|
}
|
|
|
|
void LLIMView::updateFloaterSessionID(const LLUUID& old_session_id,
|
|
const LLUUID& new_session_id)
|
|
{
|
|
LLFloaterIMPanel* floater = findFloaterBySession(old_session_id);
|
|
if (floater)
|
|
{
|
|
floater->sessionInitReplyReceived(new_session_id);
|
|
}
|
|
}
|
|
|
|
void LLIMView::onDropRequestReplyReceived(const LLUUID& session_id)
|
|
{
|
|
mSessionsDropRequested.erase(session_id.asString());
|
|
}
|
|
|
|
void onConfirmForceCloseError(S32 option, void* data)
|
|
{
|
|
//only 1 option really
|
|
LLFloaterIMPanel* floater = ((LLFloaterIMPanel*) data);
|
|
|
|
if ( floater ) floater->onClose(FALSE);
|
|
}
|
|
|
|
class LLViewerIMSessionStartReply : public LLHTTPNode
|
|
{
|
|
public:
|
|
virtual void describe(Description& desc) const
|
|
{
|
|
desc.shortInfo("Used for receiving a reply to a request to initialize an IM session");
|
|
desc.postAPI();
|
|
desc.input(
|
|
"{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string");
|
|
desc.source(__FILE__, __LINE__);
|
|
}
|
|
|
|
virtual void post(ResponsePtr response,
|
|
const LLSD& context,
|
|
const LLSD& input) const
|
|
{
|
|
LLSD body;
|
|
LLUUID temp_session_id;
|
|
LLUUID session_id;
|
|
bool success;
|
|
|
|
body = input["body"];
|
|
success = body["success"].asBoolean();
|
|
temp_session_id = body["temp_session_id"].asUUID();
|
|
|
|
if ( success )
|
|
{
|
|
session_id = body["session_id"].asUUID();
|
|
gIMView->updateFloaterSessionID(temp_session_id,
|
|
session_id);
|
|
}
|
|
else
|
|
{
|
|
//throw an error dialog and close the temp session's
|
|
//floater
|
|
LLFloaterIMPanel* floater =
|
|
gIMView->findFloaterBySession(temp_session_id);
|
|
if (floater)
|
|
{
|
|
LLString::format_map_t args;
|
|
args["[REASON]"] =
|
|
sErrorStringsMap[body["error"].asString()];
|
|
args["[RECIPIENT]"] = floater->getTitle();
|
|
|
|
gViewerWindow->alertXml("IMSessionStartError",
|
|
args,
|
|
onConfirmForceCloseError,
|
|
floater);
|
|
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
class LLViewerIMSessionEventReply : public LLHTTPNode
|
|
{
|
|
public:
|
|
virtual void describe(Description& desc) const
|
|
{
|
|
desc.shortInfo("Used for receiving a reply to a IM session event");
|
|
desc.postAPI();
|
|
desc.input(
|
|
"{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID");
|
|
desc.source(__FILE__, __LINE__);
|
|
}
|
|
|
|
virtual void post(ResponsePtr response,
|
|
const LLSD& context,
|
|
const LLSD& input) const
|
|
{
|
|
LLUUID session_id;
|
|
bool success;
|
|
|
|
LLSD body = input["body"];
|
|
success = body["success"].asBoolean();
|
|
session_id = body["session_id"].asUUID();
|
|
|
|
if ( !success )
|
|
{
|
|
//throw an error dialog
|
|
LLFloaterIMPanel* floater =
|
|
gIMView->findFloaterBySession(session_id);
|
|
if (floater)
|
|
{
|
|
LLString::format_map_t args;
|
|
args["[REASON]"] =
|
|
sErrorStringsMap[body["error"].asString()];
|
|
args["[EVENT]"] =
|
|
sEventStringsMap[body["event"].asString()];
|
|
args["[RECIPIENT]"] = floater->getTitle();
|
|
|
|
gViewerWindow->alertXml("IMSessionEventError",
|
|
args);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
class LLViewerForceCloseIMSession: public LLHTTPNode
|
|
{
|
|
public:
|
|
virtual void post(ResponsePtr response,
|
|
const LLSD& context,
|
|
const LLSD& input) const
|
|
{
|
|
LLUUID session_id;
|
|
LLString reason;
|
|
|
|
session_id = input["body"]["session_id"].asUUID();
|
|
reason = input["body"]["reason"].asString();
|
|
|
|
LLFloaterIMPanel* floater =
|
|
gIMView ->findFloaterBySession(session_id);
|
|
|
|
if ( floater )
|
|
{
|
|
LLString::format_map_t args;
|
|
|
|
args["[NAME]"] = floater->getTitle();
|
|
args["[REASON]"] = sForceCloseSessionMap[reason];
|
|
|
|
gViewerWindow->alertXml("ForceCloseIMSession",
|
|
args,
|
|
onConfirmForceCloseError,
|
|
floater);
|
|
}
|
|
}
|
|
};
|
|
|
|
class LLViewerIMSessionDropReply : public LLHTTPNode
|
|
{
|
|
public:
|
|
virtual void post(ResponsePtr response,
|
|
const LLSD& context,
|
|
const LLSD& input) const
|
|
{
|
|
LLUUID session_id;
|
|
bool success;
|
|
|
|
success = input["body"]["success"].asBoolean();
|
|
session_id = input["body"]["session_id"].asUUID();
|
|
|
|
if ( !success )
|
|
{
|
|
//throw an error alert?
|
|
}
|
|
|
|
gIMView->onDropRequestReplyReceived(session_id);
|
|
}
|
|
};
|
|
|
|
LLHTTPRegistration<LLViewerIMSessionStartReply>
|
|
gHTTPRegistrationMessageImsessionstartreply(
|
|
"/message/IMSessionStartReply");
|
|
|
|
LLHTTPRegistration<LLViewerIMSessionEventReply>
|
|
gHTTPRegistrationMessageImsessioneventreply(
|
|
"/message/IMSessionEventReply");
|
|
|
|
LLHTTPRegistration<LLViewerForceCloseIMSession>
|
|
gHTTPRegistrationMessageForceCloseImSession(
|
|
"/message/ForceCloseIMSession");
|
|
|
|
LLHTTPRegistration<LLViewerIMSessionDropReply>
|
|
gHTTPRegistrationMessageImSessionDropReply(
|
|
"/message/IMSessionDropReply");
|