Commits

richard  committed c1b1d04

fix for UI scale != 1.0 breaking edit tools, web browser, world view rect, etc.

  • Participants
  • Parent commits e582ec8

Comments (0)

Files changed (20)

File indra/newview/llchannelmanager.cpp

 	gViewerWindow->getRootView()->addChild(mStartUpChannel);
 
 	// init channel's position and size
-	S32 channel_right_bound = gViewerWindow->getWorldViewRectRaw().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); 
+	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); 
 	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
 	mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
 	mStartUpChannel->setMouseDownCallback(boost::bind(&LLSysWellWindow::onStartUpToastClick, LLFloaterReg::getTypedInstance<LLSysWellWindow>("syswell_window"), _2, _3, _4));

File indra/newview/llimfloater.cpp

 
 void LLIMFloater::getAllowedRect(LLRect& rect)
 {
-	rect = gViewerWindow->getWorldViewRectRaw();
+	rect = gViewerWindow->getWorldViewRectScaled();
 }
 
 void LLIMFloater::setDocked(bool docked, bool pop_on_undock)

File indra/newview/llimhandler.cpp

 //--------------------------------------------------------------------------
 void LLIMHandler::initChannel()
 {
-	S32 channel_right_bound = gViewerWindow->getWorldViewRectRaw().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); 
+	S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); 
 	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
 	mChannel->init(channel_right_bound - channel_width, channel_right_bound);
 }

File indra/newview/llimview.cpp

-/** 
- * @file LLIMMgr.cpp
- * @brief Container for Instant Messaging
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- * 
- * Copyright (c) 2001-2009, Linden Research, Inc.
- * 
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- * 
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- * 
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- * 
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llimview.h"
-
-#include "llfloaterreg.h"
-#include "llfontgl.h"
-#include "llrect.h"
-#include "llerror.h"
-#include "llbutton.h"
-#include "llhttpclient.h"
-#include "llsdutil_math.h"
-#include "llstring.h"
-#include "lluictrlfactory.h"
-
-#include "llagent.h"
-#include "llavatariconctrl.h"
-#include "llbottomtray.h"
-#include "llcallingcard.h"
-#include "llchat.h"
-#include "llresmgr.h"
-#include "llfloaterchat.h"
-#include "llfloaterchatterbox.h"
-#include "llavataractions.h"
-#include "llhttpnode.h"
-#include "llimfloater.h"
-#include "llimpanel.h"
-#include "llresizebar.h"
-#include "lltabcontainer.h"
-#include "llviewercontrol.h"
-#include "llfloater.h"
-#include "llmutelist.h"
-#include "llresizehandle.h"
-#include "llkeyboard.h"
-#include "llui.h"
-#include "llviewermenu.h"
-#include "llcallingcard.h"
-#include "lltoolbar.h"
-#include "llviewermessage.h"
-#include "llviewerwindow.h"
-#include "llnotify.h"
-#include "llviewerregion.h"
-#include "llvoicechannel.h"
-#include "lltrans.h"
-#include "llrecentpeople.h"
-#include "llsyswellwindow.h"
-
-#include "llfirstuse.h"
-#include "llagentui.h"
-
-//
-// Globals
-//
-LLIMMgr* gIMMgr = NULL;
-
-//
-// Statics
-//
-// *FIXME: make these all either UIStrings or Strings
-
-const static std::string IM_SEPARATOR(": ");
-
-
-void toast_callback(const LLSD& msg){
-	// do not show toast in busy mode or it goes from agent
-	if (gAgent.getBusy() || gAgent.getID() == msg["from_id"])
-	{
-		return;
-	}
-
-	// check whether incoming IM belongs to an active session or not
-	if (LLIMModel::getInstance()->getActiveSessionID() == msg["session_id"])
-	{
-		return;
-	}
-
-	// Skip toasting for system messages
-	if (msg["from_id"].asUUID() == LLUUID::null)
-	{
-		return;
-	}
-
-	LLSD args;
-	args["MESSAGE"] = msg["message"];
-	args["TIME"] = msg["time"];
-	args["FROM"] = msg["from"];
-	args["FROM_ID"] = msg["from_id"];
-	args["SESSION_ID"] = msg["session_id"];
-
-	LLNotifications::instance().add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID()));
-}
-
-void LLIMModel::setActiveSessionID(const LLUUID& session_id)
-{
-	// check if such an ID really exists
-	if (!findIMSession(session_id))
-	{
-		llwarns << "Trying to set as active a non-existent session!" << llendl;
-		return;
-	}
-
-	mActiveSessionID = session_id;
-}
-
-LLIMModel::LLIMModel() 
-{
-	addNewMsgCallback(LLIMFloater::newIMCallback);
-	addNewMsgCallback(toast_callback);
-}
-
-LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const std::vector<LLUUID>& ids)
-:	mSessionID(session_id),
-	mName(name),
-	mType(type),
-	mNumUnread(0),
-	mOtherParticipantID(other_participant_id),
-	mInitialTargetIDs(ids),
-	mVoiceChannel(NULL),
-	mSpeakers(NULL),
-	mSessionInitialized(false),
-	mCallBackEnabled(true),
-	mTextIMPossible(true),
-	mOtherParticipantIsAvatar(true)
-{
-	if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type)
-	{
-		mVoiceChannel  = new LLVoiceChannelP2P(session_id, name, other_participant_id);
-	}
-	else
-	{
-		mVoiceChannel = new LLVoiceChannelGroup(session_id, name);
-	}
-	mSpeakers = new LLIMSpeakerMgr(mVoiceChannel);
-
-	// All participants will be added to the list of people we've recently interacted with.
-	mSpeakers->addListener(&LLRecentPeople::instance(), "add");
-
-	//we need to wait for session initialization for outgoing ad-hoc and group chat session
-	//correct session id for initiated ad-hoc chat will be received from the server
-	if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID, 
-		mInitialTargetIDs, mType))
-	{
-		//we don't need to wait for any responses
-		//so we're already initialized
-		mSessionInitialized = true;
-	}
-
-	if (IM_NOTHING_SPECIAL == type)
-	{
-		mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID);
-		mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID);
-		mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID);
-	}
-
-	if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") )
-		LLLogChat::loadHistory(mName, &chatFromLogFile, (void *)this);
-}
-
-LLIMModel::LLIMSession::~LLIMSession()
-{
-	delete mSpeakers;
-	mSpeakers = NULL;
-
-	// End the text IM session if necessary
-	if(gVoiceClient && mOtherParticipantID.notNull())
-	{
-		switch(mType)
-		{
-		case IM_NOTHING_SPECIAL:
-		case IM_SESSION_P2P_INVITE:
-			gVoiceClient->endUserIMSession(mOtherParticipantID);
-			break;
-
-		default:
-			// Appease the linux compiler
-			break;
-		}
-	}
-
-	// HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point).
-	mVoiceChannel->deactivate();
-	
-	delete mVoiceChannel;
-	mVoiceChannel = NULL;
-}
-
-void LLIMModel::LLIMSession::sessionInitReplyReceived(const LLUUID& new_session_id)
-{
-	mSessionInitialized = true;
-
-	if (new_session_id != mSessionID)
-	{
-		mSessionID = new_session_id;
-		mVoiceChannel->updateSessionID(new_session_id);
-	}
-}
-
-void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time)
-{
-	LLSD message;
-	message["from"] = from;
-	message["from_id"] = from_id;
-	message["message"] = utf8_text;
-	message["time"] = time; 
-	message["index"] = (LLSD::Integer)mMsgs.size(); 
-
-	mMsgs.push_front(message); 
-
-	if (mSpeakers && from_id.notNull())
-	{
-		mSpeakers->speakerChatted(from_id);
-		mSpeakers->setSpeakerTyping(from_id, FALSE);
-	}
-}
-
-void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata)
-{
-	if (!userdata) return;
-
-	LLIMSession* self = (LLIMSession*) userdata;
-
-	if (type == LLLogChat::LOG_LINE)
-	{
-		self->addMessage("", LLSD(), msg["message"].asString(), "");
-	}
-	else if (type == LLLogChat::LOG_LLSD)
-	{
-		self->addMessage(msg["from"].asString(), msg["from_id"].asUUID(), msg["message"].asString(), msg["time"].asString());
-	}
-}
-
-LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const
-{
-	return get_if_there(mId2SessionMap, session_id,
-		(LLIMModel::LLIMSession*) NULL);
-}
-
-void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id)
-{
-	LLIMSession* session = findIMSession(old_session_id);
-	if (session)
-	{
-		session->sessionInitReplyReceived(new_session_id);
-
-		if (old_session_id != new_session_id)
-		{
-			mId2SessionMap.erase(old_session_id);
-			mId2SessionMap[new_session_id] = session;
-
-			gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id);
-		}
-
-		LLIMFloater* im_floater = LLIMFloater::findInstance(old_session_id);
-		if (im_floater)
-		{
-			im_floater->sessionInitReplyReceived(new_session_id);
-		}
-	}
-
-	//*TODO remove this "floater" stuff when Communicate Floater is gone
-	LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(old_session_id);
-	if (floater)
-	{
-		floater->sessionInitReplyReceived(new_session_id);
-	}
-}
-
-void LLIMModel::testMessages()
-{
-	LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9");
-	LLUUID bot1_session_id;
-	std::string from = "IM Tester";
-
-	bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id);
-	newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id);
-	addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!");
-
-	LLUUID bot2_id;
-	std::string firstname[] = {"Roflcopter", "Joe"};
-	std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"};
-
-	S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]);
-	S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]);
-	
-	from = firstname[rand1] + " " + lastname[rand2];
-	bot2_id.generate(from);
-	LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id);
-	newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id);
-	addMessage(bot2_session_id, from, bot2_id, "Test Message: Hello there, I have a question. Can I bother you for a second? ");
-	addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ.");
-}
-
-
-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 (findIMSession(session_id))
-	{
-		llwarns << "IM Session " << session_id << " already exists" << llendl;
-		return false;
-	}
-
-	LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids);
-	mId2SessionMap[session_id] = session;
-
-	LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, name, other_participant_id);
-
-	return true;
-
-}
-
-bool LLIMModel::clearSession(const LLUUID& session_id)
-{
-	if (mId2SessionMap.find(session_id) == mId2SessionMap.end()) return false;
-	delete (mId2SessionMap[session_id]);
-	mId2SessionMap.erase(session_id);
-	return true;
-}
-
-void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
-{
-	LLIMSession* session = findIMSession(session_id);
-	if (!session) 
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return;
-	}
-
-	int i = session->mMsgs.size() - start_index;
-
-	for (std::list<LLSD>::iterator iter = session->mMsgs.begin(); 
-		iter != session->mMsgs.end() && i > 0;
-		iter++)
-	{
-		LLSD msg;
-		msg = *iter;
-		messages.push_back(*iter);
-		i--;
-	}
-
-	session->mNumUnread = 0;
-	
-	LLSD arg;
-	arg["session_id"] = session_id;
-	arg["num_unread"] = 0;
-	mNoUnreadMsgsSignal(arg);
-}
-
-bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) {
-	
-	LLIMSession* session = findIMSession(session_id);
-
-	if (!session) 
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return false;
-	}
-
-	session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp(false)); //might want to add date separately
-
-	return true;
-}
-
-bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
-{
-	S32 im_log_option =  gSavedPerAccountSettings.getS32("IMLogOptions");
-	if (im_log_option != LOG_CHAT)
-	{
-		if(im_log_option == LOG_BOTH_TOGETHER)
-		{
-			LLLogChat::saveHistory(std::string("chat"), from, from_id, utf8_text);
-			return true;
-		}
-		else
-		{
-			LLLogChat::saveHistory(LLIMModel::getInstance()->getName(session_id), from, from_id, utf8_text);
-			return true;
-		}
-	}
-	return false;
-}
-
-bool LLIMModel::proccessOnlineOfflineNotification(
-	const LLUUID& session_id, 
-	const std::string& utf8_text)
-{
-	// Add message to old one floater
-	LLFloaterIMPanel *floater = gIMMgr->findFloaterBySession(session_id);
-	if ( floater )
-	{
-		if ( !utf8_text.empty() )
-		{
-			floater->addHistoryLine(utf8_text, LLUIColorTable::instance().getColor("SystemChatColor"));
-		}
-	}
-	// Add system message to history
-	return addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text);
-}
-
-bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, 
-						   const std::string& utf8_text, bool log2file /* = true */) { 
-	LLIMSession* session = findIMSession(session_id);
-
-	if (!session) 
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return false;
-	}
-
-	addToHistory(session_id, from, from_id, utf8_text);
-	if (log2file) logToFile(session_id, from, from_id, utf8_text);
-
-	session->mNumUnread++;
-
-	// notify listeners
-	LLSD arg;
-	arg["session_id"] = session_id;
-	arg["num_unread"] = session->mNumUnread;
-	arg["message"] = utf8_text;
-	arg["from"] = from;
-	arg["from_id"] = from_id;
-	arg["time"] = LLLogChat::timestamp(false);
-	mNewMsgSignal(arg);
-
-	return true;
-}
-
-
-const std::string& LLIMModel::getName(const LLUUID& session_id) const
-{
-	LLIMSession* session = findIMSession(session_id);
-
-	if (!session) 
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return LLStringUtil::null;
-	}
-
-	return session->mName;
-}
-
-const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const
-{
-	LLIMSession* session = findIMSession(session_id);
-	if (!session)
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return -1;
-	}
-
-	return session->mNumUnread;
-}
-
-const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const
-{
-	LLIMSession* session = findIMSession(session_id);
-	if (!session)
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return LLUUID::null;
-	}
-
-	return session->mOtherParticipantID;
-}
-
-EInstantMessage LLIMModel::getType(const LLUUID& session_id) const
-{
-	LLIMSession* session = findIMSession(session_id);
-	if (!session)
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return IM_COUNT;
-	}
-
-	return session->mType;
-}
-
-LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const
-{
-	LLIMSession* session = findIMSession(session_id);
-	if (!session)
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return NULL;
-	}
-
-	return session->mVoiceChannel;
-}
-
-LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const
-{
-	LLIMSession* session = findIMSession(session_id);
-	if (!session)
-	{
-		llwarns << "session " << session_id << "does not exist " << llendl;
-		return NULL;
-	}
-
-	return session->mSpeakers;
-}
-
-
-// TODO get rid of other participant ID
-void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) 
-{
-	std::string name;
-	LLAgentUI::buildFullname(name);
-
-	pack_instant_message(
-		gMessageSystem,
-		gAgent.getID(),
-		FALSE,
-		gAgent.getSessionID(),
-		other_participant_id,
-		name,
-		std::string("typing"),
-		IM_ONLINE,
-		(typing ? IM_TYPING_START : IM_TYPING_STOP),
-		session_id);
-	gAgent.sendReliableMessage();
-}
-
-void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id)
-{
-	if(session_id.notNull())
-	{
-		std::string name;
-		LLAgentUI::buildFullname(name);
-		pack_instant_message(
-			gMessageSystem,
-			gAgent.getID(),
-			FALSE,
-			gAgent.getSessionID(),
-			other_participant_id,
-			name, 
-			LLStringUtil::null,
-			IM_ONLINE,
-			IM_SESSION_LEAVE,
-			session_id);
-		gAgent.sendReliableMessage();
-	}
-}
-
-//*TODO this method is better be moved to the LLIMMgr
-void LLIMModel::sendMessage(const std::string& utf8_text,
-					 const LLUUID& im_session_id,
-					 const LLUUID& other_participant_id,
-					 EInstantMessage dialog)
-{
-	std::string name;
-	bool sent = false;
-	LLAgentUI::buildFullname(name);
-
-	const LLRelationship* info = NULL;
-	info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id);
-	
-	U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE;
-	
-	if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id)))
-	{
-		// User is online through the OOW connector, but not with a regular viewer.  Try to send the message via SLVoice.
-		sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text);
-	}
-	
-	if(!sent)
-	{
-		// Send message normally.
-
-		// default to IM_SESSION_SEND unless it's nothing special - in
-		// which case it's probably an IM to everyone.
-		U8 new_dialog = dialog;
-
-		if ( dialog != IM_NOTHING_SPECIAL )
-		{
-			new_dialog = IM_SESSION_SEND;
-		}
-		pack_instant_message(
-			gMessageSystem,
-			gAgent.getID(),
-			FALSE,
-			gAgent.getSessionID(),
-			other_participant_id,
-			name.c_str(),
-			utf8_text.c_str(),
-			offline,
-			(EInstantMessage)new_dialog,
-			im_session_id);
-		gAgent.sendReliableMessage();
-	}
-
-	// If there is a mute list and this is not a group chat...
-	if ( LLMuteList::getInstance() )
-	{
-		// ... the target should not be in our mute list for some message types.
-		// Auto-remove them if present.
-		switch( dialog )
-		{
-		case IM_NOTHING_SPECIAL:
-		case IM_GROUP_INVITATION:
-		case IM_INVENTORY_OFFERED:
-		case IM_SESSION_INVITE:
-		case IM_SESSION_P2P_INVITE:
-		case IM_SESSION_CONFERENCE_START:
-		case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing.
-		case IM_LURE_USER:
-		case IM_GODLIKE_LURE_USER:
-		case IM_FRIENDSHIP_OFFERED:
-			LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM);
-			break;
-		default: ; // do nothing
-		}
-	}
-
-	if((dialog == IM_NOTHING_SPECIAL) && 
-	   (other_participant_id.notNull()))
-	{
-		// Do we have to replace the /me's here?
-		std::string from;
-		LLAgentUI::buildFullname(from);
-		LLIMModel::getInstance()->addMessage(im_session_id, from, gAgentID, utf8_text);
-
-		//local echo for the legacy communicate panel
-		std::string history_echo;
-		LLAgentUI::buildFullname(history_echo);
-
-		history_echo += ": " + utf8_text;
-
-		LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(im_session_id);
-		if (floater) floater->addHistoryLine(history_echo, LLUIColorTable::instance().getColor("IMChatColor"), true, gAgent.getID());
-
-		LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id);
-		if (speaker_mgr)
-		{
-			speaker_mgr->speakerChatted(gAgentID);
-			speaker_mgr->setSpeakerTyping(gAgentID, FALSE);
-		}
-	}
-
-	// Add the recipient to the recent people list.
-	LLRecentPeople::instance().add(other_participant_id);
-}
-
-void session_starter_helper(
-	const LLUUID& temp_session_id,
-	const LLUUID& other_participant_id,
-	EInstantMessage im_type)
-{
-	LLMessageSystem *msg = gMessageSystem;
-
-	msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
-	msg->nextBlockFast(_PREHASH_AgentData);
-	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-
-	msg->nextBlockFast(_PREHASH_MessageBlock);
-	msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
-	msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id);
-	msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
-	msg->addU8Fast(_PREHASH_Dialog, im_type);
-	msg->addUUIDFast(_PREHASH_ID, temp_session_id);
-	msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
-
-	std::string name;
-	LLAgentUI::buildFullname(name);
-
-	msg->addStringFast(_PREHASH_FromAgentName, name);
-	msg->addStringFast(_PREHASH_Message, LLStringUtil::null);
-	msg->addU32Fast(_PREHASH_ParentEstateID, 0);
-	msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
-	msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
-}
-
-void start_deprecated_conference_chat(
-	const LLUUID& temp_session_id,
-	const LLUUID& creator_id,
-	const LLUUID& other_participant_id,
-	const LLSD& agents_to_invite)
-{
-	U8* bucket;
-	U8* pos;
-	S32 count;
-	S32 bucket_size;
-
-	// *FIX: this could suffer from endian issues
-	count = agents_to_invite.size();
-	bucket_size = UUID_BYTES * count;
-	bucket = new U8[bucket_size];
-	pos = bucket;
-
-	for(S32 i = 0; i < count; ++i)
-	{
-		LLUUID agent_id = agents_to_invite[i].asUUID();
-		
-		memcpy(pos, &agent_id, UUID_BYTES);
-		pos += UUID_BYTES;
-	}
-
-	session_starter_helper(
-		temp_session_id,
-		other_participant_id,
-		IM_SESSION_CONFERENCE_START);
-
-	gMessageSystem->addBinaryDataFast(
-		_PREHASH_BinaryBucket,
-		bucket,
-		bucket_size);
-
-	gAgent.sendReliableMessage();
- 
-	delete[] bucket;
-}
-
-class LLStartConferenceChatResponder : public LLHTTPClient::Responder
-{
-public:
-	LLStartConferenceChatResponder(
-		const LLUUID& temp_session_id,
-		const LLUUID& creator_id,
-		const LLUUID& other_participant_id,
-		const LLSD& agents_to_invite)
-	{
-		mTempSessionID = temp_session_id;
-		mCreatorID = creator_id;
-		mOtherParticipantID = other_participant_id;
-		mAgents = agents_to_invite;
-	}
-
-	virtual void error(U32 statusNum, const std::string& reason)
-	{
-		//try an "old school" way.
-		if ( statusNum == 400 )
-		{
-			start_deprecated_conference_chat(
-				mTempSessionID,
-				mCreatorID,
-				mOtherParticipantID,
-				mAgents);
-		}
-
-		//else throw an error back to the client?
-		//in theory we should have just have these error strings
-		//etc. set up in this file as opposed to the IMMgr,
-		//but the error string were unneeded here previously
-		//and it is not worth the effort switching over all
-		//the possible different language translations
-	}
-
-private:
-	LLUUID mTempSessionID;
-	LLUUID mCreatorID;
-	LLUUID mOtherParticipantID;
-
-	LLSD mAgents;
-};
-
-// Returns true if any messages were sent, false otherwise.
-// Is sort of equivalent to "does the server need to do anything?"
-bool LLIMModel::sendStartSession(
-	const LLUUID& temp_session_id,
-	const LLUUID& other_participant_id,
-	const std::vector<LLUUID>& ids,
-	EInstantMessage dialog)
-{
-	if ( dialog == IM_SESSION_GROUP_START )
-	{
-		session_starter_helper(
-			temp_session_id,
-			other_participant_id,
-			dialog);
-		gMessageSystem->addBinaryDataFast(
-				_PREHASH_BinaryBucket,
-				EMPTY_BINARY_BUCKET,
-				EMPTY_BINARY_BUCKET_SIZE);
-		gAgent.sendReliableMessage();
-
-		return true;
-	}
-	else if ( dialog == IM_SESSION_CONFERENCE_START )
-	{
-		LLSD agents;
-		for (int i = 0; i < (S32) ids.size(); i++)
-		{
-			agents.append(ids[i]);
-		}
-
-		//we have a new way of starting conference calls now
-		LLViewerRegion* region = gAgent.getRegion();
-		if (region)
-		{
-			std::string url = region->getCapability(
-				"ChatSessionRequest");
-			LLSD data;
-			data["method"] = "start conference";
-			data["session-id"] = temp_session_id;
-
-			data["params"] = agents;
-
-			LLHTTPClient::post(
-				url,
-				data,
-				new LLStartConferenceChatResponder(
-					temp_session_id,
-					gAgent.getID(),
-					other_participant_id,
-					data["params"]));
-		}
-		else
-		{
-			start_deprecated_conference_chat(
-				temp_session_id,
-				gAgent.getID(),
-				other_participant_id,
-				agents);
-		}
-
-		//we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id)
-		return true;
-	}
-
-	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
-//
-
-class LLViewerChatterBoxInvitationAcceptResponder :
-	public LLHTTPClient::Responder
-{
-public:
-	LLViewerChatterBoxInvitationAcceptResponder(
-		const LLUUID& session_id,
-		LLIMMgr::EInvitationType invitation_type)
-	{
-		mSessionID = session_id;
-		mInvitiationType = invitation_type;
-	}
-
-	void result(const LLSD& content)
-	{
-		if ( gIMMgr)
-		{
-			LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
-			if (speaker_mgr)
-			{
-				//we've accepted our invitation
-				//and received a list of agents that were
-				//currently in the session when the reply was sent
-				//to us.  Now, it is possible that there were some agents
-				//to slip in/out between when that message was sent to us
-				//and now.
-
-				//the agent list updates we've received have been
-				//accurate from the time we were added to the session
-				//but unfortunately, our base that we are receiving here
-				//may not be the most up to date.  It was accurate at
-				//some point in time though.
-				speaker_mgr->setSpeakers(content);
-
-				//we now have our base of users in the session
-				//that was accurate at some point, but maybe not now
-				//so now we apply all of the udpates we've received
-				//in case of race conditions
-				speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(mSessionID));
-			}
-
-			if (LLIMMgr::INVITATION_TYPE_VOICE == mInvitiationType)
-			{
-				gIMMgr->startCall(mSessionID);
-			}
-
-			if ((mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE 
-				|| mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE)
-				&& LLIMModel::getInstance()->findIMSession(mSessionID))
-			{
-				// always open IM window when connecting to voice
-				LLIMFloater::show(mSessionID);
-			}
-
-			gIMMgr->clearPendingAgentListUpdates(mSessionID);
-			gIMMgr->clearPendingInvitation(mSessionID);
-		}
-	}
-
-	void error(U32 statusNum, const std::string& reason)
-	{		
-		//throw something back to the viewer here?
-		if ( gIMMgr )
-		{
-			gIMMgr->clearPendingAgentListUpdates(mSessionID);
-			gIMMgr->clearPendingInvitation(mSessionID);
-			if ( 404 == statusNum )
-			{
-				std::string error_string;
-				error_string = "does not exist";
-				gIMMgr->showSessionStartError(error_string, mSessionID);
-			}
-		}
-	}
-
-private:
-	LLUUID mSessionID;
-	LLIMMgr::EInvitationType mInvitiationType;
-};
-
-
-// the other_participant_id is either an agent_id, a group_id, or an inventory
-// folder item_id (collection of calling cards)
-
-// static
-LLUUID LLIMMgr::computeSessionID(
-	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 if (IM_SESSION_INVITE == dialog)
-	{
-		// use provided session id for invites
-		session_id = other_participant_id;
-	}
-	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;
-}
-
-inline LLFloater* getFloaterBySessionID(const LLUUID session_id)
-{
-	LLFloater* floater = NULL;
-	if ( gIMMgr )
-	{
-		floater = dynamic_cast < LLFloater* >
-			( gIMMgr->findFloaterBySession(session_id) );
-	}
-	if ( !floater )
-	{
-		floater = dynamic_cast < LLFloater* >
-			( LLIMFloater::findInstance(session_id) );
-	}
-	return floater;
-}
-
-void
-LLIMMgr::showSessionStartError(
-	const std::string& error_string,
-	const LLUUID session_id)
-{
-	const LLFloater* floater = getFloaterBySessionID (session_id);
-	if (!floater) return;
-
-	LLSD args;
-	args["REASON"] = LLTrans::getString(error_string);
-	args["RECIPIENT"] = floater->getTitle();
-
-	LLSD payload;
-	payload["session_id"] = session_id;
-
-	LLNotifications::instance().add(
-		"ChatterBoxSessionStartError",
-		args,
-		payload,
-		LLIMMgr::onConfirmForceCloseError);
-}
-
-void
-LLIMMgr::showSessionEventError(
-	const std::string& event_string,
-	const std::string& error_string,
-	const LLUUID session_id)
-{
-	const LLFloater* floater = getFloaterBySessionID (session_id);
-	if (!floater) return;
-
-	LLSD args;
-	args["REASON"] =
-		LLTrans::getString(error_string);
-	args["EVENT"] =
-		LLTrans::getString(event_string);
-	args["RECIPIENT"] = floater->getTitle();
-
-	LLNotifications::instance().add(
-		"ChatterBoxSessionEventError",
-		args);
-}
-
-void
-LLIMMgr::showSessionForceClose(
-	const std::string& reason_string,
-	const LLUUID session_id)
-{
-	const LLFloater* floater = getFloaterBySessionID (session_id);
-	if (!floater) return;
-
-	LLSD args;
-
-	args["NAME"] = floater->getTitle();
-	args["REASON"] = LLTrans::getString(reason_string);
-
-	LLSD payload;
-	payload["session_id"] = session_id;
-
-	LLNotifications::instance().add(
-		"ForceCloseChatterBoxSession",
-		args,
-		payload,
-		LLIMMgr::onConfirmForceCloseError);
-}
-
-//static
-bool
-LLIMMgr::onConfirmForceCloseError(
-	const LLSD& notification,
-	const LLSD& response)
-{
-	//only 1 option really
-	LLUUID session_id = notification["payload"]["session_id"];
-
-	LLFloater* floater = getFloaterBySessionID (session_id);
-	if ( floater )
-	{
-		floater->closeFloater(FALSE);
-	}
-	return false;
-}
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Class LLOutgoingCallDialog
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) :
-	LLDockableFloater(NULL, false, payload),
-	mPayload(payload)
-{
-}
-
-void LLOutgoingCallDialog::getAllowedRect(LLRect& rect)
-{
-	rect = gViewerWindow->getWorldViewRectRaw();
-}
-
-void LLOutgoingCallDialog::onOpen(const LLSD& key)
-{
-	// tell the user which voice channel they are leaving
-	if (!mPayload["old_channel_name"].asString().empty())
-	{
-		childSetTextArg("leaving", "[CURRENT_CHAT]", mPayload["old_channel_name"].asString());
-	}
-	else
-	{
-		childSetTextArg("leaving", "[CURRENT_CHAT]", getString("localchat"));
-	}
-
-	std::string callee_name = mPayload["session_name"].asString();
-	if (callee_name == "anonymous")
-	{
-		callee_name = getString("anonymous");
-	}
-	
-	setTitle(callee_name);
-
-	LLSD callee_id = mPayload["other_user_id"];
-	childSetTextArg("calling", "[CALLEE_NAME]", callee_name);
-	childSetTextArg("connecting", "[CALLEE_NAME]", callee_name);
-	LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon");
-	icon->setValue(callee_id);
-}
-
-
-//static
-void LLOutgoingCallDialog::onCancel(void* user_data)
-{
-	LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data;
-
-	if (!gIMMgr)
-		return;
-
-	LLUUID session_id = self->mPayload["session_id"].asUUID();
-	gIMMgr->endCall(session_id);
-	
-	self->closeFloater();
-}
-
-
-BOOL LLOutgoingCallDialog::postBuild()
-{
-	BOOL success = LLDockableFloater::postBuild();
-
-	childSetAction("Cancel", onCancel, this);
-
-	// dock the dialog to the sys well, where other sys messages appear
-	setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(),
-					 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)
-{
-}
-
-BOOL LLIncomingCallDialog::postBuild()
-{
-	LLDockableFloater::postBuild();
-
-	LLSD caller_id = mPayload["caller_id"];
-	EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger();
-
-	std::string call_type = getString("VoiceInviteP2P");
-	std::string caller_name = mPayload["caller_name"].asString();
-	if (caller_name == "anonymous")
-	{
-		caller_name = getString("anonymous");
-	}
-	
-	setTitle(caller_name + " " + call_type);
-	
-	// If it is not a P2P invite, then it's an AdHoc invite
-	if ( type != IM_SESSION_P2P_INVITE )
-	{
-		call_type = getString("VoiceInviteAdHoc");
-	}
-
-	// check to see if this is an Avaline call
-	LLUUID session_id = mPayload["session_id"].asUUID();
+/** 
+ * @file LLIMMgr.cpp
+ * @brief Container for Instant Messaging
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llimview.h"
+
+#include "llfloaterreg.h"
+#include "llfontgl.h"
+#include "llrect.h"
+#include "llerror.h"
+#include "llbutton.h"
+#include "llhttpclient.h"
+#include "llsdutil_math.h"
+#include "llstring.h"
+#include "lluictrlfactory.h"
+
+#include "llagent.h"
+#include "llavatariconctrl.h"
+#include "llbottomtray.h"
+#include "llcallingcard.h"
+#include "llchat.h"
+#include "llresmgr.h"
+#include "llfloaterchat.h"
+#include "llfloaterchatterbox.h"
+#include "llavataractions.h"
+#include "llhttpnode.h"
+#include "llimfloater.h"
+#include "llimpanel.h"
+#include "llresizebar.h"
+#include "lltabcontainer.h"
+#include "llviewercontrol.h"
+#include "llfloater.h"
+#include "llmutelist.h"
+#include "llresizehandle.h"
+#include "llkeyboard.h"
+#include "llui.h"
+#include "llviewermenu.h"
+#include "llcallingcard.h"
+#include "lltoolbar.h"
+#include "llviewermessage.h"
+#include "llviewerwindow.h"
+#include "llnotify.h"
+#include "llviewerregion.h"
+#include "llvoicechannel.h"
+#include "lltrans.h"
+#include "llrecentpeople.h"
+#include "llsyswellwindow.h"
+
+#include "llfirstuse.h"
+#include "llagentui.h"
+
+//
+// Globals
+//
+LLIMMgr* gIMMgr = NULL;
+
+//
+// Statics
+//
+// *FIXME: make these all either UIStrings or Strings
+
+const static std::string IM_SEPARATOR(": ");
+
+
+void toast_callback(const LLSD& msg){
+	// do not show toast in busy mode or it goes from agent
+	if (gAgent.getBusy() || gAgent.getID() == msg["from_id"])
+	{
+		return;
+	}
+
+	// check whether incoming IM belongs to an active session or not
+	if (LLIMModel::getInstance()->getActiveSessionID() == msg["session_id"])
+	{
+		return;
+	}
+
+	// Skip toasting for system messages
+	if (msg["from_id"].asUUID() == LLUUID::null)
+	{
+		return;
+	}
+
+	LLSD args;
+	args["MESSAGE"] = msg["message"];
+	args["TIME"] = msg["time"];
+	args["FROM"] = msg["from"];
+	args["FROM_ID"] = msg["from_id"];
+	args["SESSION_ID"] = msg["session_id"];
+
+	LLNotifications::instance().add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID()));
+}
+
+void LLIMModel::setActiveSessionID(const LLUUID& session_id)
+{
+	// check if such an ID really exists
+	if (!findIMSession(session_id))
+	{
+		llwarns << "Trying to set as active a non-existent session!" << llendl;
+		return;
+	}
+
+	mActiveSessionID = session_id;
+}
+
+LLIMModel::LLIMModel() 
+{
+	addNewMsgCallback(LLIMFloater::newIMCallback);
+	addNewMsgCallback(toast_callback);
+}
+
+LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const std::vector<LLUUID>& ids)
+:	mSessionID(session_id),
+	mName(name),
+	mType(type),
+	mNumUnread(0),
+	mOtherParticipantID(other_participant_id),
+	mInitialTargetIDs(ids),
+	mVoiceChannel(NULL),
+	mSpeakers(NULL),
+	mSessionInitialized(false),
+	mCallBackEnabled(true),
+	mTextIMPossible(true),
+	mOtherParticipantIsAvatar(true)
+{
+	if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type)
+	{
+		mVoiceChannel  = new LLVoiceChannelP2P(session_id, name, other_participant_id);
+	}
+	else
+	{
+		mVoiceChannel = new LLVoiceChannelGroup(session_id, name);
+	}
+	mSpeakers = new LLIMSpeakerMgr(mVoiceChannel);
+
+	// All participants will be added to the list of people we've recently interacted with.
+	mSpeakers->addListener(&LLRecentPeople::instance(), "add");
+
+	//we need to wait for session initialization for outgoing ad-hoc and group chat session
+	//correct session id for initiated ad-hoc chat will be received from the server
+	if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID, 
+		mInitialTargetIDs, mType))
+	{
+		//we don't need to wait for any responses
+		//so we're already initialized
+		mSessionInitialized = true;
+	}
+
+	if (IM_NOTHING_SPECIAL == type)
+	{
+		mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID);
+		mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID);
+		mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID);
+	}
+
+	if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") )
+		LLLogChat::loadHistory(mName, &chatFromLogFile, (void *)this);
+}
+
+LLIMModel::LLIMSession::~LLIMSession()
+{
+	delete mSpeakers;
+	mSpeakers = NULL;
+
+	// End the text IM session if necessary
+	if(gVoiceClient && mOtherParticipantID.notNull())
+	{
+		switch(mType)
+		{
+		case IM_NOTHING_SPECIAL:
+		case IM_SESSION_P2P_INVITE:
+			gVoiceClient->endUserIMSession(mOtherParticipantID);
+			break;
+
+		default:
+			// Appease the linux compiler
+			break;
+		}
+	}
+
+	// HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point).
+	mVoiceChannel->deactivate();
+	
+	delete mVoiceChannel;
+	mVoiceChannel = NULL;
+}
+
+void LLIMModel::LLIMSession::sessionInitReplyReceived(const LLUUID& new_session_id)
+{
+	mSessionInitialized = true;
+
+	if (new_session_id != mSessionID)
+	{
+		mSessionID = new_session_id;
+		mVoiceChannel->updateSessionID(new_session_id);
+	}
+}
+
+void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time)
+{
+	LLSD message;
+	message["from"] = from;
+	message["from_id"] = from_id;
+	message["message"] = utf8_text;
+	message["time"] = time; 
+	message["index"] = (LLSD::Integer)mMsgs.size(); 
+
+	mMsgs.push_front(message); 
+
+	if (mSpeakers && from_id.notNull())
+	{
+		mSpeakers->speakerChatted(from_id);
+		mSpeakers->setSpeakerTyping(from_id, FALSE);
+	}
+}
+
+void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata)
+{
+	if (!userdata) return;
+
+	LLIMSession* self = (LLIMSession*) userdata;
+
+	if (type == LLLogChat::LOG_LINE)
+	{
+		self->addMessage("", LLSD(), msg["message"].asString(), "");
+	}
+	else if (type == LLLogChat::LOG_LLSD)
+	{
+		self->addMessage(msg["from"].asString(), msg["from_id"].asUUID(), msg["message"].asString(), msg["time"].asString());
+	}
+}
+
+LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const
+{
+	return get_if_there(mId2SessionMap, session_id,
+		(LLIMModel::LLIMSession*) NULL);
+}
+
+void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id)
+{
+	LLIMSession* session = findIMSession(old_session_id);
+	if (session)
+	{
+		session->sessionInitReplyReceived(new_session_id);
+
+		if (old_session_id != new_session_id)
+		{
+			mId2SessionMap.erase(old_session_id);
+			mId2SessionMap[new_session_id] = session;
+
+			gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id);
+		}
+
+		LLIMFloater* im_floater = LLIMFloater::findInstance(old_session_id);
+		if (im_floater)
+		{
+			im_floater->sessionInitReplyReceived(new_session_id);
+		}
+	}
+
+	//*TODO remove this "floater" stuff when Communicate Floater is gone
+	LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(old_session_id);
+	if (floater)
+	{
+		floater->sessionInitReplyReceived(new_session_id);
+	}
+}
+
+void LLIMModel::testMessages()
+{
+	LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9");
+	LLUUID bot1_session_id;
+	std::string from = "IM Tester";
+
+	bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id);
+	newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id);
+	addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!");
+
+	LLUUID bot2_id;
+	std::string firstname[] = {"Roflcopter", "Joe"};
+	std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"};
+
+	S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]);
+	S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]);
+	
+	from = firstname[rand1] + " " + lastname[rand2];
+	bot2_id.generate(from);
+	LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id);
+	newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id);
+	addMessage(bot2_session_id, from, bot2_id, "Test Message: Hello there, I have a question. Can I bother you for a second? ");
+	addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ.");
+}
+
+
+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 (findIMSession(session_id))
+	{
+		llwarns << "IM Session " << session_id << " already exists" << llendl;
+		return false;
+	}
+
+	LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids);
+	mId2SessionMap[session_id] = session;
+
+	LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, name, other_participant_id);
+
+	return true;
+
+}
+
+bool LLIMModel::clearSession(const LLUUID& session_id)
+{
+	if (mId2SessionMap.find(session_id) == mId2SessionMap.end()) return false;
+	delete (mId2SessionMap[session_id]);
+	mId2SessionMap.erase(session_id);
+	return true;
+}
+
+void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)
+{
+	LLIMSession* session = findIMSession(session_id);
+	if (!session) 
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return;
+	}
+
+	int i = session->mMsgs.size() - start_index;
+
+	for (std::list<LLSD>::iterator iter = session->mMsgs.begin(); 
+		iter != session->mMsgs.end() && i > 0;
+		iter++)
+	{
+		LLSD msg;
+		msg = *iter;
+		messages.push_back(*iter);
+		i--;
+	}
+
+	session->mNumUnread = 0;
+	
+	LLSD arg;
+	arg["session_id"] = session_id;
+	arg["num_unread"] = 0;
+	mNoUnreadMsgsSignal(arg);
+}
+
+bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) {
+	
+	LLIMSession* session = findIMSession(session_id);
+
+	if (!session) 
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return false;
+	}
+
+	session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp(false)); //might want to add date separately
+
+	return true;
+}
+
+bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
+{
+	S32 im_log_option =  gSavedPerAccountSettings.getS32("IMLogOptions");
+	if (im_log_option != LOG_CHAT)
+	{
+		if(im_log_option == LOG_BOTH_TOGETHER)
+		{
+			LLLogChat::saveHistory(std::string("chat"), from, from_id, utf8_text);
+			return true;
+		}
+		else
+		{
+			LLLogChat::saveHistory(LLIMModel::getInstance()->getName(session_id), from, from_id, utf8_text);
+			return true;
+		}
+	}
+	return false;
+}
+
+bool LLIMModel::proccessOnlineOfflineNotification(
+	const LLUUID& session_id, 
+	const std::string& utf8_text)
+{
+	// Add message to old one floater
+	LLFloaterIMPanel *floater = gIMMgr->findFloaterBySession(session_id);
+	if ( floater )
+	{
+		if ( !utf8_text.empty() )
+		{
+			floater->addHistoryLine(utf8_text, LLUIColorTable::instance().getColor("SystemChatColor"));
+		}
+	}
+	// Add system message to history
+	return addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text);
+}
+
+bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, 
+						   const std::string& utf8_text, bool log2file /* = true */) { 
+	LLIMSession* session = findIMSession(session_id);
+
+	if (!session) 
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return false;
+	}
+
+	addToHistory(session_id, from, from_id, utf8_text);
+	if (log2file) logToFile(session_id, from, from_id, utf8_text);
+
+	session->mNumUnread++;
+
+	// notify listeners
+	LLSD arg;
+	arg["session_id"] = session_id;
+	arg["num_unread"] = session->mNumUnread;
+	arg["message"] = utf8_text;
+	arg["from"] = from;
+	arg["from_id"] = from_id;
+	arg["time"] = LLLogChat::timestamp(false);
+	mNewMsgSignal(arg);
+
+	return true;
+}
+
+
+const std::string& LLIMModel::getName(const LLUUID& session_id) const
+{
+	LLIMSession* session = findIMSession(session_id);
+
+	if (!session) 
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return LLStringUtil::null;
+	}
+
+	return session->mName;
+}
+
+const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const
+{
+	LLIMSession* session = findIMSession(session_id);
+	if (!session)
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return -1;
+	}
+
+	return session->mNumUnread;
+}
+
+const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const
+{
+	LLIMSession* session = findIMSession(session_id);
+	if (!session)
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return LLUUID::null;
+	}
+
+	return session->mOtherParticipantID;
+}
+
+EInstantMessage LLIMModel::getType(const LLUUID& session_id) const
+{
+	LLIMSession* session = findIMSession(session_id);
+	if (!session)
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return IM_COUNT;
+	}
+
+	return session->mType;
+}
+
+LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const
+{
+	LLIMSession* session = findIMSession(session_id);
+	if (!session)
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return NULL;
+	}
+
+	return session->mVoiceChannel;
+}
+
+LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const
+{
+	LLIMSession* session = findIMSession(session_id);
+	if (!session)
+	{
+		llwarns << "session " << session_id << "does not exist " << llendl;
+		return NULL;
+	}
+
+	return session->mSpeakers;
+}
+
+
+// TODO get rid of other participant ID
+void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) 
+{
+	std::string name;
+	LLAgentUI::buildFullname(name);
+
+	pack_instant_message(
+		gMessageSystem,
+		gAgent.getID(),
+		FALSE,
+		gAgent.getSessionID(),
+		other_participant_id,
+		name,
+		std::string("typing"),
+		IM_ONLINE,
+		(typing ? IM_TYPING_START : IM_TYPING_STOP),
+		session_id);
+	gAgent.sendReliableMessage();
+}
+
+void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id)
+{
+	if(session_id.notNull())
+	{
+		std::string name;
+		LLAgentUI::buildFullname(name);
+		pack_instant_message(
+			gMessageSystem,
+			gAgent.getID(),
+			FALSE,
+			gAgent.getSessionID(),
+			other_participant_id,
+			name, 
+			LLStringUtil::null,
+			IM_ONLINE,
+			IM_SESSION_LEAVE,
+			session_id);
+		gAgent.sendReliableMessage();
+	}
+}
+
+//*TODO this method is better be moved to the LLIMMgr
+void LLIMModel::sendMessage(const std::string& utf8_text,
+					 const LLUUID& im_session_id,
+					 const LLUUID& other_participant_id,
+					 EInstantMessage dialog)
+{
+	std::string name;
+	bool sent = false;
+	LLAgentUI::buildFullname(name);
+
+	const LLRelationship* info = NULL;
+	info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id);
+	
+	U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE;
+	
+	if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id)))
+	{
+		// User is online through the OOW connector, but not with a regular viewer.  Try to send the message via SLVoice.
+		sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text);
+	}
+	
+	if(!sent)
+	{
+		// Send message normally.
+
+		// default to IM_SESSION_SEND unless it's nothing special - in
+		// which case it's probably an IM to everyone.
+		U8 new_dialog = dialog;
+
+		if ( dialog != IM_NOTHING_SPECIAL )
+		{
+			new_dialog = IM_SESSION_SEND;
+		}
+		pack_instant_message(
+			gMessageSystem,
+			gAgent.getID(),
+			FALSE,
+			gAgent.getSessionID(),
+			other_participant_id,
+			name.c_str(),
+			utf8_text.c_str(),
+			offline,
+			(EInstantMessage)new_dialog,
+			im_session_id);
+		gAgent.sendReliableMessage();
+	}
+
+	// If there is a mute list and this is not a group chat...
+	if ( LLMuteList::getInstance() )
+	{
+		// ... the target should not be in our mute list for some message types.
+		// Auto-remove them if present.
+		switch( dialog )
+		{
+		case IM_NOTHING_SPECIAL:
+		case IM_GROUP_INVITATION:
+		case IM_INVENTORY_OFFERED:
+		case IM_SESSION_INVITE:
+		case IM_SESSION_P2P_INVITE:
+		case IM_SESSION_CONFERENCE_START:
+		case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing.
+		case IM_LURE_USER:
+		case IM_GODLIKE_LURE_USER:
+		case IM_FRIENDSHIP_OFFERED:
+			LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM);
+			break;
+		default: ; // do nothing
+		}
+	}
+
+	if((dialog == IM_NOTHING_SPECIAL) && 
+	   (other_participant_id.notNull()))
+	{
+		// Do we have to replace the /me's here?
+		std::string from;
+		LLAgentUI::buildFullname(from);
+		LLIMModel::getInstance()->addMessage(im_session_id, from, gAgentID, utf8_text);
+
+		//local echo for the legacy communicate panel
+		std::string history_echo;
+		LLAgentUI::buildFullname(history_echo);
+
+		history_echo += ": " + utf8_text;
+
+		LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(im_session_id);
+		if (floater) floater->addHistoryLine(history_echo, LLUIColorTable::instance().getColor("IMChatColor"), true, gAgent.getID());
+
+		LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id);
+		if (speaker_mgr)
+		{
+			speaker_mgr->speakerChatted(gAgentID);
+			speaker_mgr->setSpeakerTyping(gAgentID, FALSE);
+		}
+	}
+
+	// Add the recipient to the recent people list.
+	LLRecentPeople::instance().add(other_participant_id);
+}
+
+void session_starter_helper(
+	const LLUUID& temp_session_id,
+	const LLUUID& other_participant_id,
+	EInstantMessage im_type)
+{
+	LLMessageSystem *msg = gMessageSystem;
+
+	msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+	msg->nextBlockFast(_PREHASH_MessageBlock);
+	msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
+	msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id);
+	msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
+	msg->addU8Fast(_PREHASH_Dialog, im_type);
+	msg->addUUIDFast(_PREHASH_ID, temp_session_id);
+	msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
+
+	std::string name;
+	LLAgentUI::buildFullname(name);
+
+	msg->addStringFast(_PREHASH_FromAgentName, name);
+	msg->addStringFast(_PREHASH_Message, LLStringUtil::null);
+	msg->addU32Fast(_PREHASH_ParentEstateID, 0);
+	msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
+	msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
+}
+
+void start_deprecated_conference_chat(
+	const LLUUID& temp_session_id,
+	const LLUUID& creator_id,
+	const LLUUID& other_participant_id,
+	const LLSD& agents_to_invite)
+{
+	U8* bucket;
+	U8* pos;
+	S32 count;
+	S32 bucket_size;
+
+	// *FIX: this could suffer from endian issues
+	count = agents_to_invite.size();
+	bucket_size = UUID_BYTES * count;
+	bucket = new U8[bucket_size];
+	pos = bucket;
+
+	for(S32 i = 0; i < count; ++i)
+	{
+		LLUUID agent_id = agents_to_invite[i].asUUID();
+		
+		memcpy(pos, &agent_id, UUID_BYTES);
+		pos += UUID_BYTES;
+	}
+
+	session_starter_helper(
+		temp_session_id,
+		other_participant_id,
+		IM_SESSION_CONFERENCE_START);
+
+	gMessageSystem->addBinaryDataFast(
+		_PREHASH_BinaryBucket,
+		bucket,
+		bucket_size);
+
+	gAgent.sendReliableMessage();
+ 
+	delete[] bucket;
+}
+
+class LLStartConferenceChatResponder : public LLHTTPClient::Responder
+{
+public:
+	LLStartConferenceChatResponder(
+		const LLUUID& temp_session_id,
+		const LLUUID& creator_id,
+		const LLUUID& other_participant_id,
+		const LLSD& agents_to_invite)
+	{
+		mTempSessionID = temp_session_id;
+		mCreatorID = creator_id;
+		mOtherParticipantID = other_participant_id;
+		mAgents = agents_to_invite;
+	}
+
+	virtual void error(U32 statusNum, const std::string& reason)
+	{
+		//try an "old school" way.
+		if ( statusNum == 400 )
+		{
+			start_deprecated_conference_chat(
+				mTempSessionID,
+				mCreatorID,
+				mOtherParticipantID,
+				mAgents);
+		}
+
+		//else throw an error back to the client?
+		//in theory we should have just have these error strings
+		//etc. set up in this file as opposed to the IMMgr,
+		//but the error string were unneeded here previously
+		//and it is not worth the effort switching over all
+		//the possible different language translations
+	}
+
+private:
+	LLUUID mTempSessionID;
+	LLUUID mCreatorID;
+	LLUUID mOtherParticipantID;
+
+	LLSD mAgents;
+};
+
+// Returns true if any messages were sent, false otherwise.
+// Is sort of equivalent to "does the server need to do anything?"
+bool LLIMModel::sendStartSession(
+	const LLUUID& temp_session_id,
+	const LLUUID& other_participant_id,
+	const std::vector<LLUUID>& ids,
+	EInstantMessage dialog)
+{
+	if ( dialog == IM_SESSION_GROUP_START )
+	{
+		session_starter_helper(
+			temp_session_id,
+			other_participant_id,
+			dialog);
+		gMessageSystem->addBinaryDataFast(
+				_PREHASH_BinaryBucket,
+				EMPTY_BINARY_BUCKET,
+				EMPTY_BINARY_BUCKET_SIZE);
+		gAgent.sendReliableMessage();
+
+		return true;
+	}
+	else if ( dialog == IM_SESSION_CONFERENCE_START )
+	{
+		LLSD agents;
+		for (int i = 0; i < (S32) ids.size(); i++)
+		{
+			agents.append(ids[i]);
+		}
+
+		//we have a new way of starting conference calls now
+		LLViewerRegion* region = gAgent.getRegion();
+		if (region)
+		{
+			std::string url = region->getCapability(
+				"ChatSessionRequest");
+			LLSD data;
+			data["method"] = "start conference";
+			data["session-id"] = temp_session_id;
+
+			data["params"] = agents;
+
+			LLHTTPClient::post(
+				url,
+				data,
+				new LLStartConferenceChatResponder(
+					temp_session_id,
+					gAgent.getID(),
+					other_participant_id,
+					data["params"]));
+		}
+		else
+		{
+			start_deprecated_conference_chat(
+				temp_session_id,
+				gAgent.getID(),
+				other_participant_id,
+				agents);
+		}
+
+		//we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id)
+		return true;
+	}
+
+	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
+//
+
+class LLViewerChatterBoxInvitationAcceptResponder :
+	public LLHTTPClient::Responder
+{
+public:
+	LLViewerChatterBoxInvitationAcceptResponder(
+		const LLUUID& session_id,
+		LLIMMgr::EInvitationType invitation_type)