diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 40c9bb6afabeedd4fcccbca94f16c8f1f350df78..bb14c41cec821d93c712a6bfd39898532f52c22d 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -263,18 +263,9 @@ bool LLAvatarActions::isCalling(const LLUUID &id)
 }
 
 //static
-bool LLAvatarActions::canCall(const LLUUID &id)
+bool LLAvatarActions::canCall()
 {
-	// For now we do not need to check whether passed UUID is ID of agent's friend.
-	// Use common check of Voice Client state.
-	{
-		// don't need to check online/offline status because "usual resident" (resident that is not a friend)
-		// can be only ONLINE. There is no way to see "usual resident" in OFFLINE status. If we see "usual
-		// resident" it automatically means that the resident is ONLINE. So to make a call to the "usual resident"
-		// we need to check only that "our" voice is enabled.
-		return LLVoiceClient::voiceEnabled();
-	}
-
+		return LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();
 }
 
 // static
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index a4504ae679b946b513670d19731b7c9e35e0c88c..ebfd40b796fb7c3399287eb50dc316b402792e4d 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -129,10 +129,10 @@ class LLAvatarActions
 	static bool isCalling(const LLUUID &id);
 
 	/**
-	 * @return true if call to the resident can be made (resident is online and voice is enabled)
+	 * @return true if call to the resident can be made
 	 */
 
-	static bool canCall(const LLUUID &id);
+	static bool canCall();
 	/**
 	 * Invite avatar to a group.
 	 */	
diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp
index 66ab32f3e88bd599ac39c3d232bc75a0ffc3fecc..2bcd097717539f3bacdb033f78d2b90878474f4f 100644
--- a/indra/newview/llavatarlistitem.cpp
+++ b/indra/newview/llavatarlistitem.cpp
@@ -440,17 +440,17 @@ LLAvatarListItem::icon_color_map_t& LLAvatarListItem::getItemIconColorMap()
 // static
 void LLAvatarListItem::initChildrenWidths(LLAvatarListItem* avatar_item)
 {
+	//speaking indicator width + padding
+	S32 speaking_indicator_width = avatar_item->getRect().getWidth() - avatar_item->mSpeakingIndicator->getRect().mLeft;
+
 	//profile btn width + padding
-	S32 profile_btn_width = avatar_item->getRect().getWidth() - avatar_item->mProfileBtn->getRect().mLeft;
+	S32 profile_btn_width = avatar_item->mSpeakingIndicator->getRect().mLeft - avatar_item->mProfileBtn->getRect().mLeft;
 
 	//info btn width + padding
 	S32 info_btn_width = avatar_item->mProfileBtn->getRect().mLeft - avatar_item->mInfoBtn->getRect().mLeft;
 
-	//speaking indicator width + padding
-	S32 speaking_indicator_width = avatar_item->mInfoBtn->getRect().mLeft - avatar_item->mSpeakingIndicator->getRect().mLeft;
-
 	// last interaction time textbox width + padding
-	S32 last_interaction_time_width = avatar_item->mSpeakingIndicator->getRect().mLeft - avatar_item->mLastInteractionTime->getRect().mLeft;
+	S32 last_interaction_time_width = avatar_item->mInfoBtn->getRect().mLeft - avatar_item->mLastInteractionTime->getRect().mLeft;
 
 	// icon width + padding
 	S32 icon_width = avatar_item->mAvatarName->getRect().mLeft - avatar_item->mAvatarIcon->getRect().mLeft;
@@ -462,9 +462,9 @@ void LLAvatarListItem::initChildrenWidths(LLAvatarListItem* avatar_item)
 	sChildrenWidths[--index] = icon_width;
 	sChildrenWidths[--index] = 0; // for avatar name we don't need its width, it will be calculated as "left available space"
 	sChildrenWidths[--index] = last_interaction_time_width;
-	sChildrenWidths[--index] = speaking_indicator_width;
 	sChildrenWidths[--index] = info_btn_width;
 	sChildrenWidths[--index] = profile_btn_width;
+	sChildrenWidths[--index] = speaking_indicator_width;
 }
 
 void LLAvatarListItem::updateChildren()
diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h
index 479a4833cb94bb8bcfec844a9c866dbb3ccde582..61c0a8660e3f5e0fe9325c1e7739230bc49b6232 100644
--- a/indra/newview/llavatarlistitem.h
+++ b/indra/newview/llavatarlistitem.h
@@ -129,9 +129,9 @@ class LLAvatarListItem : public LLPanel, public LLFriendObserver
 	 * @see updateChildren()
 	 */
 	typedef enum e_avatar_item_child {
+		ALIC_SPEAKER_INDICATOR,
 		ALIC_PROFILE_BUTTON,
 		ALIC_INFO_BUTTON,
-		ALIC_SPEAKER_INDICATOR,
 		ALIC_INTERACTION_TIME,
 		ALIC_NAME,
 		ALIC_ICON,
diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp
index d9767bc5730d1b3fa2ab8fda59ea7f645526c983..d9df537e032057a823835bc82b3b394a7e49e5e8 100644
--- a/indra/newview/llcallfloater.cpp
+++ b/indra/newview/llcallfloater.cpp
@@ -94,22 +94,6 @@ static void* create_non_avatar_caller(void*)
 	return new LLNonAvatarCaller;
 }
 
-LLCallFloater::LLAvatarListItemRemoveTimer::LLAvatarListItemRemoveTimer(callback_t remove_cb, F32 period, const LLUUID& speaker_id)
-: LLEventTimer(period)
-, mRemoveCallback(remove_cb)
-, mSpeakerId(speaker_id)
-{
-}
-
-BOOL LLCallFloater::LLAvatarListItemRemoveTimer::tick()
-{
-	if (mRemoveCallback)
-	{
-		mRemoveCallback(mSpeakerId);
-	}
-	return TRUE;
-}
-
 LLVoiceChannel* LLCallFloater::sCurrentVoiceCanel = NULL;
 
 LLCallFloater::LLCallFloater(const LLSD& key)
@@ -123,10 +107,9 @@ LLCallFloater::LLCallFloater(const LLSD& key)
 , mSpeakingIndicator(NULL)
 , mIsModeratorMutedVoice(false)
 , mInitParticipantsVoiceState(false)
-, mVoiceLeftRemoveDelay(10)
 {
 	static LLUICachedControl<S32> voice_left_remove_delay ("VoiceParticipantLeftRemoveDelay", 10);
-	mVoiceLeftRemoveDelay = voice_left_remove_delay;
+	mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), voice_left_remove_delay);
 
 	mFactoryMap["non_avatar_caller"] = LLCallbackMap(create_non_avatar_caller, NULL);
 	LLVoiceClient::getInstance()->addObserver(this);
@@ -136,6 +119,7 @@ LLCallFloater::LLCallFloater(const LLSD& key)
 LLCallFloater::~LLCallFloater()
 {
 	resetVoiceRemoveTimers();
+	delete mSpeakerDelayRemover;
 
 	delete mParticipants;
 	mParticipants = NULL;
@@ -654,33 +638,11 @@ void LLCallFloater::setState(LLAvatarListItem* item, ESpeakerState state)
 
 void LLCallFloater::setVoiceRemoveTimer(const LLUUID& voice_speaker_id)
 {
-
-	// If there is already a started timer for the current panel don't do anything.
-	bool no_timer_for_current_panel = true;
-	if (mVoiceLeftTimersMap.size() > 0)
-	{
-		timers_map::iterator found_it = mVoiceLeftTimersMap.find(voice_speaker_id);
-		if (found_it != mVoiceLeftTimersMap.end())
-		{
-			no_timer_for_current_panel = false;
-		}
-	}
-
-	if (no_timer_for_current_panel)
-	{
-		// Starting a timer to remove an avatar row panel after timeout
-		mVoiceLeftTimersMap.insert(timer_pair(voice_speaker_id,
-			new LLAvatarListItemRemoveTimer(boost::bind(&LLCallFloater::removeVoiceLeftParticipant, this, _1), mVoiceLeftRemoveDelay, voice_speaker_id)));
-	}
+	mSpeakerDelayRemover->setActionTimer(voice_speaker_id);
 }
 
-void LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id)
+bool LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id)
 {
-	if (mVoiceLeftTimersMap.size() > 0)
-	{
-		mVoiceLeftTimersMap.erase(mVoiceLeftTimersMap.find(voice_speaker_id));
-	}
-
 	LLAvatarList::uuid_vector_t& speaker_uuids = mAvatarList->getIDs();
 	LLAvatarList::uuid_vector_t::iterator pos = std::find(speaker_uuids.begin(), speaker_uuids.end(), voice_speaker_id);
 	if(pos != speaker_uuids.end())
@@ -688,34 +650,19 @@ void LLCallFloater::removeVoiceLeftParticipant(const LLUUID& voice_speaker_id)
 		speaker_uuids.erase(pos);
 		mAvatarList->setDirty();
 	}
+
+	return false;
 }
 
 
 void LLCallFloater::resetVoiceRemoveTimers()
 {
-	if (mVoiceLeftTimersMap.size() > 0)
-	{
-		for (timers_map::iterator iter = mVoiceLeftTimersMap.begin();
-			iter != mVoiceLeftTimersMap.end(); ++iter)
-		{
-			delete iter->second;
-		}
-	}
-	mVoiceLeftTimersMap.clear();
+	mSpeakerDelayRemover->removeAllTimers();
 }
 
 void LLCallFloater::removeVoiceRemoveTimer(const LLUUID& voice_speaker_id)
 {
-	// Remove the timer if it has been already started
-	if (mVoiceLeftTimersMap.size() > 0)
-	{
-		timers_map::iterator found_it = mVoiceLeftTimersMap.find(voice_speaker_id);
-		if (found_it != mVoiceLeftTimersMap.end())
-		{
-			delete found_it->second;
-			mVoiceLeftTimersMap.erase(found_it);
-		}
-	}
+	mSpeakerDelayRemover->unsetActionTimer(voice_speaker_id);
 }
 
 bool LLCallFloater::validateSpeaker(const LLUUID& speaker_id)
diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h
index 096594aaa2019e1a1bcea0270f2bd7749307220c..eded3a426b8fbc8c34ad9756af78025b9987fe3f 100644
--- a/indra/newview/llcallfloater.h
+++ b/indra/newview/llcallfloater.h
@@ -44,6 +44,8 @@ class LLNonAvatarCaller;
 class LLOutputMonitorCtrl;
 class LLParticipantList;
 class LLSpeakerMgr;
+class LLSpeakersDelayActionsStorage;
+
 /**
  * The Voice Control Panel is an ambient window summoned by clicking the flyout chevron on the Speak button.
  * It can be torn-off and freely positioned onscreen.
@@ -169,7 +171,7 @@ class LLCallFloater : public LLTransientDockableFloater, LLVoiceClientParticipan
 	 *
 	 * @param voice_speaker_id LLUUID of Avatar List item to be removed from the list.
 	 */
-	void removeVoiceLeftParticipant(const LLUUID& voice_speaker_id);
+	bool removeVoiceLeftParticipant(const LLUUID& voice_speaker_id);
 
 	/**
 	 * Deletes all timers from the list to prevent started timers from ticking after destruction
@@ -240,32 +242,11 @@ class LLCallFloater : public LLTransientDockableFloater, LLVoiceClientParticipan
 
 	boost::signals2::connection mAvatarListRefreshConnection;
 
+
 	/**
-	 * class LLAvatarListItemRemoveTimer
-	 * 
-	 * Implements a timer that removes avatar list item of a participant
-	 * who has left the call.
+	 * time out speakers when they are not part of current session
 	 */
-	class LLAvatarListItemRemoveTimer : public LLEventTimer
-	{
-	public:
-		typedef boost::function<void(const LLUUID&)> callback_t;
-
-		LLAvatarListItemRemoveTimer(callback_t remove_cb, F32 period, const LLUUID& speaker_id);
-		virtual ~LLAvatarListItemRemoveTimer() {};
-
-		virtual BOOL tick();
-
-	private:
-		callback_t		mRemoveCallback;
-		LLUUID			mSpeakerId;
-	};
-
-	typedef std::pair<LLUUID, LLAvatarListItemRemoveTimer*> timer_pair;
-	typedef std::map<LLUUID, LLAvatarListItemRemoveTimer*> timers_map;
-
-	timers_map		mVoiceLeftTimersMap;
-	S32				mVoiceLeftRemoveDelay;
+	LLSpeakersDelayActionsStorage* mSpeakerDelayRemover;
 
 	/**
 	 * Stores reference to current voice channel.
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index fb94657278e4e558b6ebf0e6c04802e410903d1e..0e42ff09d8c69e4de3a3efdb0b29118ce129466d 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -51,6 +51,7 @@
 #include "llinventorymodel.h"
 #include "llfloaterworldmap.h"
 #include "lllandmarkactions.h"
+#include "llnotificationsutil.h"
 #include "llsidetray.h"
 #include "lltoggleablemenu.h"
 #include "llviewerinventory.h"
@@ -975,6 +976,10 @@ BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
 void copy_slurl_to_clipboard_cb(std::string& slurl)
 {
 	gClipboard.copyFromString(utf8str_to_wstring(slurl));
+
+	LLSD args;
+	args["SLURL"] = slurl;
+	LLNotificationsUtil::add("CopySLURL", args);
 }
 
 
diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp
index 29f415bd43904b5288ab32731908e34d4ea080e3..c71764c2e54d086464f82ad29815bde54f845c2d 100644
--- a/indra/newview/llfloatergroups.cpp
+++ b/indra/newview/llfloatergroups.cpp
@@ -75,7 +75,7 @@ LLFloaterGroupPicker::~LLFloaterGroupPicker()
 void LLFloaterGroupPicker::setPowersMask(U64 powers_mask)
 {
 	mPowersMask = powers_mask;
-	postBuild();
+	init_group_list(getChild<LLScrollListCtrl>("group list"), gAgent.getGroupID(), mPowersMask);
 }
 
 
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index e0f2fca5809134496db350481ba078b6a7c9aa68..4a1eb51dbe9db149c91e08d2f268ffdd529796f0 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -277,13 +277,8 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
 				{
 					object_owner.append("Unknown");
 				}
-				childSetText("object_name", object_owner);
-				std::string owner_link =
-					LLSLURL::buildCommand("agent", mObjectID, "inspect");
-				childSetText("owner_name", owner_link);
-				childSetText("abuser_name_edit", object_owner);
-				mAbuserID = object_id;
-				mOwnerName = object_owner;
+
+				setFromAvatar(object_id, object_owner);
 			}
 			else
 			{
@@ -305,7 +300,6 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
 	}
 }
 
-
 void LLFloaterReporter::onClickSelectAbuser()
 {
 	gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterReporter::callbackAvatarID, this, _1, _2), FALSE, TRUE ));
@@ -323,6 +317,17 @@ void LLFloaterReporter::callbackAvatarID(const std::vector<std::string>& names,
 
 }
 
+void LLFloaterReporter::setFromAvatar(const LLUUID& avatar_id, const std::string& avatar_name)
+{
+	mAbuserID = mObjectID = avatar_id;
+	mOwnerName = avatar_name;
+
+	std::string avatar_link = LLSLURL::buildCommand("agent", mObjectID, "inspect");
+	childSetText("owner_name", avatar_link);
+	childSetText("object_name", avatar_name);
+	childSetText("abuser_name_edit", avatar_name);
+}
+
 // static
 void LLFloaterReporter::onClickSend(void *userdata)
 {
@@ -458,9 +463,8 @@ void LLFloaterReporter::showFromMenu(EReportType report_type)
 	}
 }
 
-
 // static
-void LLFloaterReporter::showFromObject(const LLUUID& object_id)
+void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name)
 {
 	LLFloaterReporter* f = LLFloaterReg::showTypedInstance<LLFloaterReporter>("reporter");
 
@@ -469,8 +473,11 @@ void LLFloaterReporter::showFromObject(const LLUUID& object_id)
 	LLAgentUI::buildFullname(fullname);
 	f->childSetText("reporter_field", fullname);
 
-	// Request info for this object
-	f->getObjectInfo(object_id);
+	if (avatar_name.empty())
+		// Request info for this object
+		f->getObjectInfo(object_id);
+	else
+		f->setFromAvatar(object_id, avatar_name);
 
 	// Need to deselect on close
 	f->mDeselectOnClose = TRUE;
@@ -479,6 +486,18 @@ void LLFloaterReporter::showFromObject(const LLUUID& object_id)
 }
 
 
+// static
+void LLFloaterReporter::showFromObject(const LLUUID& object_id)
+{
+	show(object_id);
+}
+
+// static
+void LLFloaterReporter::showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name)
+{
+	show(avatar_id, avatar_name);
+}
+
 void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id)
 {
 	childSetText("object_name", object_name);
diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h
index cc2dfb2f9811b0c622e9bbc6490016eb7af2348e..7c6473f975961d1f8a692f5bd46c82ae566766af 100644
--- a/indra/newview/llfloaterreporter.h
+++ b/indra/newview/llfloaterreporter.h
@@ -93,6 +93,7 @@ class LLFloaterReporter
 	static void showFromMenu(EReportType report_type);
 
 	static void showFromObject(const LLUUID& object_id);
+	static void showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name);
 
 	static void onClickSend			(void *userdata);
 	static void onClickCancel		(void *userdata);
@@ -109,6 +110,8 @@ class LLFloaterReporter
 	void setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id);
 
 private:
+	static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null);
+
 	void takeScreenshot();
 	void sendReportViaCaps(std::string url);
 	void uploadImage();
@@ -121,6 +124,7 @@ class LLFloaterReporter
 	void enableControls(BOOL own_avatar);
 	void getObjectInfo(const LLUUID& object_id);
 	void callbackAvatarID(const std::vector<std::string>& names, const std::vector<LLUUID>& ids);
+	void setFromAvatar(const LLUUID& avatar_id, const std::string& avatar_name = LLStringUtil::null);
 
 private:
 	EReportType		mReportType;
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index e75d35bea411f5665b5b98b69436a08cd1c3283c..e01709aa3a0e625561a08bb23d1f29900c9da7e3 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -48,6 +48,7 @@
 #include "lltextutil.h"
 #include "llviewercontrol.h"	// for gSavedSettings
 #include "llviewermenu.h"		// for gMenuHolder
+#include "llvoiceclient.h"
 
 static LLDefaultChildRegistry::Register<LLGroupList> r("group_list");
 S32 LLGroupListItem::sIconWidth = 0;
@@ -271,6 +272,9 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata)
 	if (userdata.asString() == "activate")
 		return gAgent.getGroupID() != selected_group_id;
 
+	if (userdata.asString() == "call")
+		return LLVoiceClient::voiceEnabled()&&gVoiceClient->voiceWorking();
+
 	return real_group_selected;
 }
 
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index ff20a55358c31f067d7d6ce86f1815a21f90fdb2..c2a7969c0d05a880cd36c6b16befbbd5efc3e0bf 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -55,6 +55,7 @@
 #include "llfloaterchatterbox.h"
 #include "llimfloater.h"
 #include "llgroupiconctrl.h"
+#include "llmd5.h"
 #include "llmutelist.h"
 #include "llrecentpeople.h"
 #include "llviewermessage.h"
@@ -215,12 +216,14 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
 		mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID);
 	}
 
+	buildHistoryFileName();
+
 	if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") )
 	{
 		std::list<LLSD> chat_history;
 
 		//involves parsing of a chat history
-		LLLogChat::loadAllHistory(mName, chat_history);
+		LLLogChat::loadAllHistory(mHistoryFileName, chat_history);
 		addMessagesFromHistory(chat_history);
 	}
 }
@@ -467,6 +470,44 @@ bool LLIMModel::LLIMSession::isOtherParticipantAvaline()
 	return !mOtherParticipantIsAvatar;
 }
 
+void LLIMModel::LLIMSession::buildHistoryFileName()
+{
+	mHistoryFileName = mName;
+	
+	//ad-hoc requires sophisticated chat history saving schemes
+	if (isAdHoc())
+	{
+		//in case of outgoing ad-hoc sessions
+		if (mInitialTargetIDs.size())
+		{
+			std::set<LLUUID> sorted_uuids(mInitialTargetIDs.begin(), mInitialTargetIDs.end());
+			mHistoryFileName = mName + " hash" + generateHash(sorted_uuids);
+			return;
+		}
+		
+		//in case of incoming ad-hoc sessions
+		mHistoryFileName = mName + " " + LLLogChat::timestamp(true) + " " + mSessionID.asString().substr(0, 4);
+	}
+}
+
+//static
+std::string LLIMModel::LLIMSession::generateHash(const std::set<LLUUID>& sorted_uuids)
+{
+	LLMD5 md5_uuid;
+	
+	std::set<LLUUID>::const_iterator it = sorted_uuids.begin();
+	while (it != sorted_uuids.end())
+	{
+		md5_uuid.update((unsigned char*)(*it).mData, 16);
+		it++;
+	}
+	md5_uuid.finalize();
+
+	LLUUID participants_md5_hash;
+	md5_uuid.raw_digest((unsigned char*) participants_md5_hash.mData);
+	return participants_md5_hash.asString();
+}
+
 
 void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id)
 {
@@ -614,11 +655,11 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from,
 	return true;
 }
 
-bool LLIMModel::logToFile(const std::string& session_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
+bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
 {
 	if (gSavedPerAccountSettings.getBOOL("LogInstantMessages"))
 	{
-		LLLogChat::saveHistory(session_name, from, from_id, utf8_text);
+		LLLogChat::saveHistory(file_name, from, from_id, utf8_text);
 		return true;
 	}
 	else
@@ -629,15 +670,7 @@ bool LLIMModel::logToFile(const std::string& session_name, const std::string& fr
 
 bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)
 {
-	if (gSavedPerAccountSettings.getBOOL("LogInstantMessages"))
-	{
-		LLLogChat::saveHistory(LLIMModel::getInstance()->getName(session_id), from, from_id, utf8_text);
-		return true;
-	}
-	else
-	{
-		return false;
-	}
+	return logToFile(LLIMModel::getInstance()->getHistoryFileName(session_id), from, from_id, utf8_text);
 }
 
 bool LLIMModel::proccessOnlineOfflineNotification(
@@ -782,6 +815,18 @@ LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const
 	return session->mSpeakers;
 }
 
+const std::string& LLIMModel::getHistoryFileName(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->mHistoryFileName;
+}
+
 
 // TODO get rid of other participant ID
 void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) 
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index a226d66b12ebafab2b2106dccd53449f2a476f02..a3b4f78af0c8b702c79f1bf14ccc9683c9f1ac75 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -69,6 +69,8 @@ class LLIMModel :  public LLSingleton<LLIMModel>
 		void addMessagesFromHistory(const std::list<LLSD>& history);
 		void addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time);
 		void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction);
+		
+		/** @deprecated */
 		static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata);
 
 		bool isAdHoc();
@@ -80,12 +82,20 @@ class LLIMModel :  public LLSingleton<LLIMModel>
 		bool isGroupSessionType() const { return mSessionType == GROUP_SESSION;}
 		bool isAvalineSessionType() const { return mSessionType == AVALINE_SESSION;}
 
+		//*TODO make private
+		/** ad-hoc sessions involve sophisticated chat history file naming schemes */
+		void buildHistoryFileName();
+
+		//*TODO make private
+		static std::string generateHash(const std::set<LLUUID>& sorted_uuids);
+
 		LLUUID mSessionID;
 		std::string mName;
 		EInstantMessage mType;
 		SType mSessionType;
 		LLUUID mOtherParticipantID;
 		std::vector<LLUUID> mInitialTargetIDs;
+		std::string mHistoryFileName;
 
 		// connection to voice channel state change signal
 		boost::signals2::connection mVoiceChannelStateChangeConnection;
@@ -231,6 +241,8 @@ class LLIMModel :  public LLSingleton<LLIMModel>
 	*/
 	LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const;
 
+	const std::string& getHistoryFileName(const LLUUID& session_id) const;
+
 	static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id);
 	static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id,
 						  const std::vector<LLUUID>& ids, EInstantMessage dialog);
@@ -243,7 +255,7 @@ class LLIMModel :  public LLSingleton<LLIMModel>
 	/**
 	 * Saves an IM message into a file
 	 */
-	bool logToFile(const std::string& session_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);
+	bool logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);
 
 private:
 	
diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 0374a1d25b0ad15cf1c389b2d8127c79ab149421..4b0539337ba56114a62ba6655f167632bc7ed105 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -689,7 +689,7 @@ void LLInspectAvatar::onToggleMute()
 
 void LLInspectAvatar::onClickReport()
 {
-	LLFloaterReporter::showFromObject(mAvatarID);
+	LLFloaterReporter::showFromAvatar(mAvatarID, mAvatarName);
 	closeFloater();
 }
 
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index 4e5aaeb66ad4384e64ea57fe48b90c3270b60eeb..dc187bf36ccd563a18cf2478439f70f7a809ab7c 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -237,15 +237,15 @@ void append_to_last_message(std::list<LLSD>& messages, const std::string& line)
 	messages.back()[IM_TEXT] = im_text;
 }
 
-void LLLogChat::loadAllHistory(const std::string& session_name, std::list<LLSD>& messages)
+void LLLogChat::loadAllHistory(const std::string& file_name, std::list<LLSD>& messages)
 {
-	if (session_name.empty())
+	if (file_name.empty())
 	{
 		llwarns << "Session name is Empty!" << llendl;
 		return ;
 	}
 
-	LLFILE* fptr = LLFile::fopen(makeLogFileName(session_name), "r");		/*Flawfinder: ignore*/
+	LLFILE* fptr = LLFile::fopen(makeLogFileName(file_name), "r");		/*Flawfinder: ignore*/
 	if (!fptr) return;	//No previous conversation with this name.
 
 	char buffer[LOG_RECALL_SIZE];		/*Flawfinder: ignore*/
diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h
index 3d3f5c44587d6b2b4b0be7607eb988de01c2a9f2..4290e4bbc08723efb0f38275264884d11075b126 100644
--- a/indra/newview/lllogchat.h
+++ b/indra/newview/lllogchat.h
@@ -56,7 +56,7 @@ class LLLogChat
 		                    void (*callback)(ELogLineType, const LLSD&, void*), 
 							void* userdata);
 
-	static void loadAllHistory(const std::string& session_name, std::list<LLSD>& messages);
+	static void loadAllHistory(const std::string& file_name, std::list<LLSD>& messages);
 private:
 	static std::string cleanFileName(std::string filename);
 };
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 85e95ca1d65bcc502c04795c2e853ba8fb5d9eeb..fe5b20813ac7562c535d996400c553a0036300d7 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -165,6 +165,8 @@ BOOL LLPanelAvatarNotes::postBuild()
 	resetControls();
 	resetData();
 
+	gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this);
+
 	return TRUE;
 }
 
@@ -337,6 +339,8 @@ LLPanelAvatarNotes::~LLPanelAvatarNotes()
 	if(getAvatarId().notNull())
 	{
 		LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
+		if(LLVoiceClient::getInstance())
+			LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
 	}
 }
 
@@ -346,6 +350,17 @@ void LLPanelAvatarNotes::changed(U32 mask)
 	childSetEnabled("teleport", LLAvatarTracker::instance().isBuddyOnline(getAvatarId()));
 }
 
+// virtual
+void LLPanelAvatarNotes::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+
+	childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+}
+
 void LLPanelAvatarNotes::setAvatarId(const LLUUID& id)
 {
 	if(id.notNull())
@@ -437,7 +452,6 @@ void LLPanelProfileTab::updateButtons()
 
 	bool enable_map_btn = is_avatar_online && gAgent.isGodlike() || is_agent_mappable(getAvatarId());
 	childSetEnabled("show_on_map_btn", enable_map_btn);
-	childSetEnabled("call", LLAvatarActions::canCall(getAvatarId()));
 }
 
 //////////////////////////////////////////////////////////////////////////
@@ -485,6 +499,8 @@ BOOL LLPanelAvatarProfile::postBuild()
 	pic = getChild<LLTextureCtrl>("real_world_pic");
 	pic->setFallbackImageName("default_profile_picture.j2c");
 
+	gVoiceClient->addObserver((LLVoiceClientStatusObserver*)this);
+
 	resetControls();
 	resetData();
 
@@ -568,8 +584,6 @@ void LLPanelAvatarProfile::processProfileProperties(const LLAvatarData* avatar_d
 
 	fillPartnerData(avatar_data);
 
-	fillOnlineStatus(avatar_data);
-
 	fillAccountStatus(avatar_data);
 }
 
@@ -637,21 +651,6 @@ void LLPanelAvatarProfile::fillPartnerData(const LLAvatarData* avatar_data)
 	}
 }
 
-void LLPanelAvatarProfile::fillOnlineStatus(const LLAvatarData* avatar_data)
-{
-	bool online = avatar_data->flags & AVATAR_ONLINE;
-	if(LLAvatarActions::isFriend(avatar_data->avatar_id))
-	{
-		// Online status NO could be because they are hidden
-		// If they are a friend, we may know the truth!
-		online = LLAvatarTracker::instance().isBuddyOnline(avatar_data->avatar_id);
-	}
-	childSetValue("online_status", online ?
-		"Online" : "Offline");
-	childSetColor("online_status", online ? 
-		LLColor4::green : LLColor4::red);
-}
-
 void LLPanelAvatarProfile::fillAccountStatus(const LLAvatarData* avatar_data)
 {
 	LLStringUtil::format_map_t args;
@@ -757,6 +756,8 @@ LLPanelAvatarProfile::~LLPanelAvatarProfile()
 	if(getAvatarId().notNull())
 	{
 		LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
+		if(LLVoiceClient::getInstance())
+			LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
 	}
 }
 
@@ -766,6 +767,17 @@ void LLPanelAvatarProfile::changed(U32 mask)
 	childSetEnabled("teleport", LLAvatarTracker::instance().isBuddyOnline(getAvatarId()));
 }
 
+// virtual
+void LLPanelAvatarProfile::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+
+	childSetEnabled("call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+}
+
 void LLPanelAvatarProfile::setAvatarId(const LLUUID& id)
 {
 	if(id.notNull())
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index 22efa5dc351917757c1df2e7991b606cfdb29fa7..ce59f1e93d20b7080345be6062506cb6ff1f8c79 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -36,6 +36,7 @@
 #include "llpanel.h"
 #include "llavatarpropertiesprocessor.h"
 #include "llcallingcard.h"
+#include "llvoiceclient.h"
 
 class LLComboBox;
 class LLLineEditor;
@@ -122,6 +123,7 @@ class LLPanelProfileTab
 class LLPanelAvatarProfile
 	: public LLPanelProfileTab
 	, public LLFriendObserver
+	, public LLVoiceClientStatusObserver
 {
 public:
 	LLPanelAvatarProfile();
@@ -134,6 +136,10 @@ class LLPanelAvatarProfile
 	 */
 	virtual void changed(U32 mask);
 
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
 	/*virtual*/ void setAvatarId(const LLUUID& id);
 
 	/**
@@ -171,11 +177,6 @@ class LLPanelAvatarProfile
 	 */
 	virtual void fillPartnerData(const LLAvatarData* avatar_data);
 
-	/**
-	 * Fills Avatar's online status.
-	 */
-	virtual void fillOnlineStatus(const LLAvatarData* avatar_data);
-
 	/**
 	 * Fills account status.
 	 */
@@ -257,6 +258,7 @@ class LLPanelMyProfile
 class LLPanelAvatarNotes 
 	: public LLPanelProfileTab
 	, public LLFriendObserver
+	, public LLVoiceClientStatusObserver
 {
 public:
 	LLPanelAvatarNotes();
@@ -269,6 +271,10 @@ class LLPanelAvatarNotes
 	 */
 	virtual void changed(U32 mask);
 
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
 	/*virtual*/ void onOpen(const LLSD& key);
 
 	/*virtual*/ BOOL postBuild();
diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp
index c30ef3221d4f43bf47a5ba21a5c434b11fbdce42..1d447a22d73ca102d022ecace49c9b6ebdd2ce28 100644
--- a/indra/newview/llpanelgroup.cpp
+++ b/indra/newview/llpanelgroup.cpp
@@ -101,6 +101,8 @@ LLPanelGroup::LLPanelGroup()
 LLPanelGroup::~LLPanelGroup()
 {
 	LLGroupMgr::getInstance()->removeObserver(this);
+	if(LLVoiceClient::getInstance())
+		LLVoiceClient::getInstance()->removeObserver(this);
 }
 
 void LLPanelGroup::onOpen(const LLSD& key)
@@ -188,6 +190,8 @@ BOOL LLPanelGroup::postBuild()
 
 	if(panel_general)
 		panel_general->setupCtrls(this);
+
+	gVoiceClient->addObserver(this);
 	
 	return TRUE;
 }
@@ -300,6 +304,17 @@ void LLPanelGroup::changed(LLGroupChange gc)
 	update(gc);
 }
 
+// virtual
+void LLPanelGroup::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+
+	childSetEnabled("btn_call", LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking());
+}
+
 void LLPanelGroup::notifyObservers()
 {
 	changed(GC_ALL);
@@ -356,6 +371,13 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
 	for(std::vector<LLPanelGroupTab* >::iterator it = mTabs.begin();it!=mTabs.end();++it)
 		(*it)->setGroupID(group_id);
 
+	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mID);
+	if(gdatap)
+	{
+		childSetValue("group_name", gdatap->mName);
+		childSetToolTip("group_name",gdatap->mName);
+	}
+
 	LLButton* button_apply = findChild<LLButton>("btn_apply");
 	LLButton* button_refresh = findChild<LLButton>("btn_refresh");
 	LLButton* button_create = findChild<LLButton>("btn_create");
@@ -457,17 +479,6 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
 	}
 
 	reposButtons();
-
-	LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mID);
-
-	if(gdatap)
-	{
-		childSetValue("group_name", gdatap->mName);
-		childSetToolTip("group_name",gdatap->mName);
-		
-		//group data is already present, call update manually
-		update(GC_ALL);
-	}
 }
 
 bool LLPanelGroup::apply(LLPanelGroupTab* tab)
diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h
index 7ea5e67b44f30be8911de4ffbb0e1f133076e0d3..8c846956771348b370ce399778ea18cb74774cbf 100644
--- a/indra/newview/llpanelgroup.h
+++ b/indra/newview/llpanelgroup.h
@@ -35,6 +35,7 @@
 #include "llgroupmgr.h"
 #include "llpanel.h"
 #include "lltimer.h"
+#include "llvoiceclient.h"
 
 struct LLOfferInfo;
 
@@ -47,7 +48,8 @@ class LLAgent;
 
 
 class LLPanelGroup : public LLPanel,
-					 public LLGroupMgrObserver 
+					 public LLGroupMgrObserver,
+					 public LLVoiceClientStatusObserver
 {
 public:
 	LLPanelGroup();
@@ -64,6 +66,10 @@ class LLPanelGroup : public LLPanel,
 	// Group manager observer trigger.
 	virtual void changed(LLGroupChange gc);
 
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
 	void showNotice(const std::string& subject,
 					const std::string& message,
 					const bool& has_inventory,
diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp
index 86bdee7c7d58dab77e65819ce66a25336eb1b480..ff1e43b52688dada8ca5522c41993f5d882a96d4 100644
--- a/indra/newview/llpanelimcontrolpanel.cpp
+++ b/indra/newview/llpanelimcontrolpanel.cpp
@@ -64,21 +64,52 @@ void LLPanelChatControlPanel::onOpenVoiceControlsClicked()
 	LLFloaterReg::showInstance("voice_controls");
 }
 
+void LLPanelChatControlPanel::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+
+	updateCallButton();
+}
+
 void LLPanelChatControlPanel::onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state)
 {
 	updateButtons(new_state >= LLVoiceChannel::STATE_CALL_STARTED);
 }
 
+void LLPanelChatControlPanel::updateCallButton()
+{
+	// hide/show call button
+	bool voice_enabled = LLVoiceClient::voiceEnabled() && gVoiceClient->voiceWorking();
+
+	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId);
+	if (!session) return;
+
+	bool session_initialized = session->mSessionInitialized;
+	bool callback_enabled = session->mCallBackEnabled;
+
+	BOOL enable_connect = session_initialized
+		&& voice_enabled
+		&& callback_enabled;
+	childSetEnabled("call_btn", enable_connect);
+}
+
 void LLPanelChatControlPanel::updateButtons(bool is_call_started)
 {
 	childSetVisible("end_call_btn_panel", is_call_started);
 	childSetVisible("voice_ctrls_btn_panel", is_call_started);
 	childSetVisible("call_btn_panel", ! is_call_started);
+	updateCallButton();
+	
 }
 
 LLPanelChatControlPanel::~LLPanelChatControlPanel()
 {
 	mVoiceChannelStateChangeConnection.disconnect();
+	if(LLVoiceClient::getInstance())
+		LLVoiceClient::getInstance()->removeObserver(this);
 }
 
 BOOL LLPanelChatControlPanel::postBuild()
@@ -87,26 +118,9 @@ BOOL LLPanelChatControlPanel::postBuild()
 	childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this));
 	childSetAction("voice_ctrls_btn", boost::bind(&LLPanelChatControlPanel::onOpenVoiceControlsClicked, this));
 
-	return TRUE;
-}
-
-void LLPanelChatControlPanel::draw()
-{
-	// hide/show start call and end call buttons
-	bool voice_enabled = LLVoiceClient::voiceEnabled();
-
-	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId);
-	if (!session) return;
-
-	bool session_initialized = session->mSessionInitialized;
-	bool callback_enabled = session->mCallBackEnabled;
-
-	BOOL enable_connect = session_initialized
-		&& voice_enabled
-		&& callback_enabled;
-	childSetEnabled("call_btn", enable_connect);
+	gVoiceClient->addObserver(this);
 
-	LLPanel::draw();
+	return TRUE;
 }
 
 void LLPanelChatControlPanel::setSessionId(const LLUUID& session_id)
@@ -245,7 +259,6 @@ void LLPanelIMControlPanel::nameUpdatedCallback(const LLUUID& id, const std::str
 LLPanelGroupControlPanel::LLPanelGroupControlPanel(const LLUUID& session_id):
 mParticipantList(NULL)
 {
-	mSpeakerManager = LLIMModel::getInstance()->getSpeakerManager(session_id);
 }
 
 BOOL LLPanelGroupControlPanel::postBuild()
@@ -267,6 +280,8 @@ void LLPanelGroupControlPanel::draw()
 	// Need to resort the participant list if it's in sort by recent speaker order.
 	if (mParticipantList)
 		mParticipantList->updateRecentSpeakersOrder();
+	//* TODO: find better way to properly enable call button for group and remove this call from draw()
+	updateCallButton();
 	LLPanelChatControlPanel::draw();
 }
 
@@ -304,7 +319,10 @@ void LLPanelGroupControlPanel::setSessionId(const LLUUID& session_id)
 
 	// for group and Ad-hoc chat we need to include agent into list 
 	if(!mParticipantList)
-		mParticipantList = new LLParticipantList(mSpeakerManager, getChild<LLAvatarList>("speakers_list"), true,false);
+	{
+		LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(session_id);
+		mParticipantList = new LLParticipantList(speaker_manager, getChild<LLAvatarList>("speakers_list"), true,false);
+	}
 }
 
 
diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h
index c18be5a6df95ab27d6216cdade180400bd07b2f2..3ab505a084d914487437e7ebfd6136222199f4ce 100644
--- a/indra/newview/llpanelimcontrolpanel.h
+++ b/indra/newview/llpanelimcontrolpanel.h
@@ -37,11 +37,11 @@
 #include "llvoicechannel.h"
 #include "llcallingcard.h"
 
-class LLSpeakerMgr;
-class LLAvatarList;
 class LLParticipantList;
 
-class LLPanelChatControlPanel : public LLPanel
+class LLPanelChatControlPanel 
+	: public LLPanel
+	, public LLVoiceClientStatusObserver
 {
 public:
 	LLPanelChatControlPanel() :
@@ -49,15 +49,21 @@ class LLPanelChatControlPanel : public LLPanel
 	~LLPanelChatControlPanel();
 
 	virtual BOOL postBuild();
-	virtual void draw();
 
 	void onCallButtonClicked();
 	void onEndCallButtonClicked();
 	void onOpenVoiceControlsClicked();
 
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
 	virtual void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state);
 
 	void updateButtons(bool is_call_started);
+	
+	// Enables/disables call button depending on voice availability
+	void updateCallButton();
 
 	virtual void setSessionId(const LLUUID& session_id);
 	const LLUUID& getSessionId() { return mSessionId; }
@@ -110,7 +116,6 @@ class LLPanelGroupControlPanel : public LLPanelChatControlPanel
 
 protected:
 	LLUUID mGroupID;
-	LLSpeakerMgr* mSpeakerManager;
 
 	LLParticipantList* mParticipantList;
 
diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp
index ece93125b322bc87e5d2552771a50f8a1b3af848..0f0fb4b94ea34b854318e07b06a11c88a6b84fdb 100644
--- a/indra/newview/llpanelme.cpp
+++ b/indra/newview/llpanelme.cpp
@@ -198,8 +198,6 @@ void LLPanelMyProfileEdit::processProfileProperties(const LLAvatarData* avatar_d
 {
 	fillCommonData(avatar_data);
 
-	fillOnlineStatus(avatar_data);
-
 	fillPartnerData(avatar_data);
 
 	fillAccountStatus(avatar_data);
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index c14b282488c72c479d10df46fb91c315425a24b2..b01cdcc832b25bd4dd4c0ae96cc7626d23be4d14 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -462,6 +462,9 @@ LLPanelPeople::~LLPanelPeople()
 	delete mFriendListUpdater;
 	delete mRecentListUpdater;
 
+	if(LLVoiceClient::getInstance())
+		LLVoiceClient::getInstance()->removeObserver(this);
+
 	LLView::deleteViewByHandle(mGroupPlusMenuHandle);
 	LLView::deleteViewByHandle(mNearbyViewSortMenuHandle);
 	LLView::deleteViewByHandle(mFriendsViewSortMenuHandle);
@@ -612,6 +615,8 @@ BOOL LLPanelPeople::postBuild()
 	if(recent_view_sort)
 		mRecentViewSortMenuHandle  = recent_view_sort->getHandle();
 
+	gVoiceClient->addObserver(this);
+
 	// call this method in case some list is empty and buttons can be in inconsistent state
 	updateButtons();
 
@@ -621,6 +626,17 @@ BOOL LLPanelPeople::postBuild()
 	return TRUE;
 }
 
+// virtual
+void LLPanelPeople::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+	if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL)
+	{
+		return;
+	}
+	
+	updateButtons();
+}
+
 void LLPanelPeople::updateFriendList()
 {
 	if (!mOnlineFriendList || !mAllFriendList)
@@ -775,41 +791,20 @@ void LLPanelPeople::updateButtons()
 		}
 	}
 
+	bool enable_calls = gVoiceClient->voiceWorking() && gVoiceClient->voiceEnabled();
+
 	buttonSetEnabled("teleport_btn",		friends_tab_active && item_selected && isFriendOnline(selected_uuids.front()));
 	buttonSetEnabled("view_profile_btn",	item_selected);
 	buttonSetEnabled("im_btn",				multiple_selected); // allow starting the friends conference for multiple selection
-	buttonSetEnabled("call_btn",			multiple_selected && canCall());
+	buttonSetEnabled("call_btn",			multiple_selected && enable_calls);
 	buttonSetEnabled("share_btn",			item_selected); // not implemented yet
 
 	bool none_group_selected = item_selected && selected_id.isNull();
 	buttonSetEnabled("group_info_btn", !none_group_selected);
-	buttonSetEnabled("group_call_btn", !none_group_selected);
+	buttonSetEnabled("group_call_btn", !none_group_selected && enable_calls);
 	buttonSetEnabled("chat_btn", !none_group_selected);
 }
 
-bool LLPanelPeople::canCall()
-{
-	std::vector<LLUUID> selected_uuids;
-	getCurrentItemIDs(selected_uuids);
-
-	bool result = false;
-
-	std::vector<LLUUID>::const_iterator
-		id = selected_uuids.begin(),
-		uuids_end = selected_uuids.end();
-
-	for (;id != uuids_end; ++id)
-	{
-		if (LLAvatarActions::canCall(*id))
-		{
-			result = true;
-			break;
-		}
-	}
-
-	return result;
-}
-
 std::string LLPanelPeople::getActiveTabName() const
 {
 	return mTabContainer->getCurrentPanel()->getName();
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index 7580fdbeeffb122545070be93f6f26705ade4810..6d3d43615683373faee3b2c1a04b245d441de475 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -36,13 +36,16 @@
 #include <llpanel.h>
 
 #include "llcallingcard.h" // for avatar tracker
+#include "llvoiceclient.h"
 
 class LLFilterEditor;
 class LLTabContainer;
 class LLAvatarList;
 class LLGroupList;
 
-class LLPanelPeople : public LLPanel
+class LLPanelPeople 
+	: public LLPanel
+	, public LLVoiceClientStatusObserver
 {
 	LOG_CLASS(LLPanelPeople);
 public:
@@ -52,6 +55,9 @@ class LLPanelPeople : public LLPanel
 	/*virtual*/ BOOL 	postBuild();
 	/*virtual*/ void	onOpen(const LLSD& key);
 	/*virtual*/ bool	notifyChildren(const LLSD& info);
+	// Implements LLVoiceClientStatusObserver::onChange() to enable call buttons
+	// when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
 
 	// internals
 	class Updater;
@@ -73,7 +79,6 @@ class LLPanelPeople : public LLPanel
 
 	bool					isFriendOnline(const LLUUID& id);
 	bool					isItemsFreeOfFriends(const std::vector<LLUUID>& uuids);
-	bool 					canCall();
 
 	void					updateButtons();
 	std::string				getActiveTabName() const;
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index c1c10e6022091db4786d5b2683ebcdc399b43aa7..d9651a60450abfed328b95dbfc36b91ebfbc4393 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -183,20 +183,7 @@ bool NearbyMenu::enableContextMenuItem(const LLSD& userdata)
 	}
 	else if (item == std::string("can_call"))
 	{
-		bool result = false;
-		std::vector<LLUUID>::const_iterator
-			id = mUUIDs.begin(),
-			uuids_end = mUUIDs.end();
-
-		for (;id != uuids_end; ++id)
-		{
-			if (LLAvatarActions::canCall(*id))
-			{
-				result = true;
-				break;
-			}
-		}
-		return result;
+		return LLAvatarActions::canCall();
 	}
 	return false;
 }
diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp
index b80eb9db381657a05e22ce1bcc5e24fb38daebec..0c10f11bfcbcd54a08eecdc9b44d1094f64d59bc 100644
--- a/indra/newview/llpanelplaceinfo.cpp
+++ b/indra/newview/llpanelplaceinfo.cpp
@@ -34,26 +34,20 @@
 
 #include "llpanelplaceinfo.h"
 
-#include "roles_constants.h"
 #include "llsdutil.h"
-#include "llsecondlifeurls.h"
 
 #include "llsdutil_math.h"
+
 #include "llregionhandle.h"
-#include "message.h"
 
 #include "lliconctrl.h"
 #include "lltextbox.h"
 
 #include "llagent.h"
-#include "llavatarpropertiesprocessor.h"
 #include "llexpandabletextbox.h"
 #include "llpanelpick.h"
 #include "lltexturectrl.h"
-#include "llviewerinventory.h"
-#include "llviewerparcelmgr.h"
 #include "llviewerregion.h"
-#include "llviewertexteditor.h"
 
 LLPanelPlaceInfo::LLPanelPlaceInfo()
 :	LLPanel(),
@@ -265,25 +259,6 @@ void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent)
 	}
 }
 
-// virtual
-void LLPanelPlaceInfo::handleVisibilityChange(BOOL new_visibility)
-{
-	LLPanel::handleVisibilityChange(new_visibility);
-
-	LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance();
-	if (!parcel_mgr)
-		return;
-
-	// Remove land selection when panel hides.
-	if (!new_visibility)
-	{
-		if (!parcel_mgr->selectionEmpty())
-		{
-			parcel_mgr->deselectLand();
-		}
-	}
-}
-
 void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel)
 {
 	std::string region_name = mRegionName->getText();
diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h
index 7dfc7b2444a08af5e0310f0a7208776f62502ffb..3091f7ed24a63abdc7ad7922133c340dc4e9b8d1 100644
--- a/indra/newview/llpanelplaceinfo.h
+++ b/indra/newview/llpanelplaceinfo.h
@@ -94,7 +94,6 @@ class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver
 	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
 
 	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-	/*virtual*/ void handleVisibilityChange (BOOL new_visibility);
 
 	// Create a pick for the location specified
 	// by global_pos.
diff --git a/indra/newview/llpanelplaceprofile.cpp b/indra/newview/llpanelplaceprofile.cpp
index 402d50ba9c30a5fe4ed19dd153e4d6798f2b18fb..d892e2885b4358e2714e6dd0ecab9034ec01f7a5 100644
--- a/indra/newview/llpanelplaceprofile.cpp
+++ b/indra/newview/llpanelplaceprofile.cpp
@@ -257,6 +257,25 @@ void LLPanelPlaceProfile::processParcelInfo(const LLParcelData& parcel_data)
 	}
 }
 
+// virtual
+void LLPanelPlaceProfile::handleVisibilityChange(BOOL new_visibility)
+{
+	LLPanel::handleVisibilityChange(new_visibility);
+
+	LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance();
+	if (!parcel_mgr)
+		return;
+
+	// Remove land selection when panel hides.
+	if (!new_visibility)
+	{
+		if (!parcel_mgr->selectionEmpty())
+		{
+			parcel_mgr->deselectUnused();
+		}
+	}
+}
+
 void LLPanelPlaceProfile::displaySelectedParcelInfo(LLParcel* parcel,
 													LLViewerRegion* region,
 													const LLVector3d& pos_global,
diff --git a/indra/newview/llpanelplaceprofile.h b/indra/newview/llpanelplaceprofile.h
index 8c30ca92fb84ac530271643eb80d872b3be04723..8ca95268750114ff376231823ef654152ea50245 100644
--- a/indra/newview/llpanelplaceprofile.h
+++ b/indra/newview/llpanelplaceprofile.h
@@ -52,6 +52,8 @@ class LLPanelPlaceProfile : public LLPanelPlaceInfo
 
 	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
 
+	/*virtual*/ void handleVisibilityChange(BOOL new_visibility);
+
 	// Displays information about the currently selected parcel
 	// without sending a request to the server.
 	// If is_current_parcel true shows "You Are Here" banner.
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index b037674c3744f4e1ba8271b4b92529c03437ad27..a4f0e55a93258b36d1f0427ed823d844356e27aa 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -289,89 +289,92 @@ BOOL LLPanelPlaces::postBuild()
 
 void LLPanelPlaces::onOpen(const LLSD& key)
 {
-	if(!mPlaceProfile || !mLandmarkInfo || key.size() == 0)
+	if (!mPlaceProfile || !mLandmarkInfo)
 		return;
 
-	mFilterEditor->clear();
-	onFilterEdit("", false);
-
-	mPlaceInfoType = key["type"].asString();
-	mPosGlobal.setZero();
-	mItem = NULL;
-	isLandmarkEditModeOn = false;
-	togglePlaceInfoPanel(TRUE);
-
-	if (mPlaceInfoType == AGENT_INFO_TYPE)
-	{
-		mPlaceProfile->setInfoType(LLPanelPlaceInfo::AGENT);
-	}
-	else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE)
+	if (key.size() != 0)
 	{
-		mLandmarkInfo->setInfoType(LLPanelPlaceInfo::CREATE_LANDMARK);
+		mFilterEditor->clear();
+		onFilterEdit("", false);
 
-		if (key.has("x") && key.has("y") && key.has("z"))
+		mPlaceInfoType = key["type"].asString();
+		mPosGlobal.setZero();
+		mItem = NULL;
+		isLandmarkEditModeOn = false;
+		togglePlaceInfoPanel(TRUE);
+
+		if (mPlaceInfoType == AGENT_INFO_TYPE)
 		{
-			mPosGlobal = LLVector3d(key["x"].asReal(),
-									key["y"].asReal(),
-									key["z"].asReal());
+			mPlaceProfile->setInfoType(LLPanelPlaceInfo::AGENT);
 		}
-		else
+		else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE)
 		{
-			mPosGlobal = gAgent.getPositionGlobal();
-		}
-
-		mLandmarkInfo->displayParcelInfo(LLUUID(), mPosGlobal);
+			mLandmarkInfo->setInfoType(LLPanelPlaceInfo::CREATE_LANDMARK);
 
-		// Disable Save button because there is no item to save yet.
-		// The button will be enabled in onLandmarkLoaded callback.
-		mSaveBtn->setEnabled(FALSE);
-	}
-	else if (mPlaceInfoType == LANDMARK_INFO_TYPE)
-	{
-		mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK);
+			if (key.has("x") && key.has("y") && key.has("z"))
+			{
+				mPosGlobal = LLVector3d(key["x"].asReal(),
+										key["y"].asReal(),
+										key["z"].asReal());
+			}
+			else
+			{
+				mPosGlobal = gAgent.getPositionGlobal();
+			}
 
-		LLInventoryItem* item = gInventory.getItem(key["id"].asUUID());
-		if (!item)
-			return;
+			mLandmarkInfo->displayParcelInfo(LLUUID(), mPosGlobal);
 
-		setItem(item);
-	}
-	else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE)
-	{
-		if (key.has("id"))
+			// Disable Save button because there is no item to save yet.
+			// The button will be enabled in onLandmarkLoaded callback.
+			mSaveBtn->setEnabled(FALSE);
+		}
+		else if (mPlaceInfoType == LANDMARK_INFO_TYPE)
 		{
-			LLUUID parcel_id = key["id"].asUUID();
-			mPlaceProfile->setParcelID(parcel_id);
+			mLandmarkInfo->setInfoType(LLPanelPlaceInfo::LANDMARK);
+
+			LLInventoryItem* item = gInventory.getItem(key["id"].asUUID());
+			if (!item)
+				return;
 
-			// query the server to get the global 3D position of this
-			// parcel - we need this for teleport/mapping functions.
-			mRemoteParcelObserver->setParcelID(parcel_id);
+			setItem(item);
 		}
-		else
+		else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE)
 		{
-			mPosGlobal = LLVector3d(key["x"].asReal(),
-									key["y"].asReal(),
-									key["z"].asReal());
-			mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal);
+			if (key.has("id"))
+			{
+				LLUUID parcel_id = key["id"].asUUID();
+				mPlaceProfile->setParcelID(parcel_id);
+
+				// query the server to get the global 3D position of this
+				// parcel - we need this for teleport/mapping functions.
+				mRemoteParcelObserver->setParcelID(parcel_id);
+			}
+			else
+			{
+				mPosGlobal = LLVector3d(key["x"].asReal(),
+										key["y"].asReal(),
+										key["z"].asReal());
+				mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal);
+			}
+
+			mPlaceProfile->setInfoType(LLPanelPlaceInfo::PLACE);
 		}
+		else if (mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE)
+		{
+			S32 index = key["id"].asInteger();
 
-		mPlaceProfile->setInfoType(LLPanelPlaceInfo::PLACE);
-	}
-	else if (mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE)
-	{
-		S32 index = key["id"].asInteger();
+			const LLTeleportHistoryStorage::slurl_list_t& hist_items =
+						LLTeleportHistoryStorage::getInstance()->getItems();
 
-		const LLTeleportHistoryStorage::slurl_list_t& hist_items =
-					LLTeleportHistoryStorage::getInstance()->getItems();
+			mPosGlobal = hist_items[index].mGlobalPos;
 
-		mPosGlobal = hist_items[index].mGlobalPos;
+			mPlaceProfile->setInfoType(LLPanelPlaceInfo::TELEPORT_HISTORY);
+			mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal);
+		}
 
-		mPlaceProfile->setInfoType(LLPanelPlaceInfo::TELEPORT_HISTORY);
-		mPlaceProfile->displayParcelInfo(LLUUID(), mPosGlobal);
+		updateVerbs();
 	}
 
-	updateVerbs();
-
 	LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance();
 	if (!parcel_mgr)
 		return;
@@ -388,9 +391,12 @@ void LLPanelPlaces::onOpen(const LLSD& key)
 	{
 		parcel_mgr->removeObserver(mParcelObserver);
 
+		// Clear the reference to selection to allow its removal in deselectUnused().
+		mParcel.clear();
+
 		if (!parcel_mgr->selectionEmpty())
 		{
-			parcel_mgr->deselectLand();
+			parcel_mgr->deselectUnused();
 		}
 	}
 }
@@ -765,23 +771,23 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param)
 		mPickPanel->reshape(rect.getWidth(), rect.getHeight());
 		mPickPanel->setRect(rect);
 	}
-    else if (item == "add_to_favbar")
-    {
-        if ( mItem.notNull() ) 
-        {
-            const LLUUID& favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
-            if ( favorites_id.notNull() )
-            {
-                copy_inventory_item(gAgent.getID(),
-                                    mItem->getPermissions().getOwner(),
-                                    mItem->getUUID(),
-                                    favorites_id,
-                                    std::string(),
-                                    LLPointer<LLInventoryCallback>(NULL));
-                llinfos << "Copied inventory item #" << mItem->getUUID() << " to favorites." << llendl;
-            }
-        }
-    }
+	else if (item == "add_to_favbar")
+	{
+		if ( mItem.notNull() )
+		{
+			const LLUUID& favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
+			if ( favorites_id.notNull() )
+			{
+				copy_inventory_item(gAgent.getID(),
+									mItem->getPermissions().getOwner(),
+									mItem->getUUID(),
+									favorites_id,
+									std::string(),
+									LLPointer<LLInventoryCallback>(NULL));
+				llinfos << "Copied inventory item #" << mItem->getUUID() << " to favorites." << llendl;
+			}
+		}
+	}
 }
 
 void LLPanelPlaces::onBackButtonClicked()
@@ -826,6 +832,14 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible)
 
 			mLandmarkInfo->setVisible(FALSE);
 		}
+		else if (mPlaceInfoType == AGENT_INFO_TYPE)
+		{
+			LLViewerParcelMgr::getInstance()->removeObserver(mParcelObserver);
+
+			// Clear reference to parcel selection when closing place profile panel.
+			// LLViewerParcelMgr removes the selection if it has 1 reference to it.
+			mParcel.clear();
+		}
 	}
 	else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE ||
 			 mPlaceInfoType == LANDMARK_INFO_TYPE)
@@ -858,6 +872,20 @@ void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible)
 	}
 }
 
+// virtual
+void LLPanelPlaces::handleVisibilityChange(BOOL new_visibility)
+{
+	LLPanel::handleVisibilityChange(new_visibility);
+
+	if (!new_visibility && mPlaceInfoType == AGENT_INFO_TYPE)
+	{
+		LLViewerParcelMgr::getInstance()->removeObserver(mParcelObserver);
+
+		// Clear reference to parcel selection when closing places panel.
+		mParcel.clear();
+	}
+}
+
 void LLPanelPlaces::changedParcelSelection()
 {
 	if (!mPlaceProfile)
diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h
index 27b5911ebb073b9529014a762102e9a78783f2fd..0eba7f3afc1b8af8e73fcc6cbe480dc44c10652a 100644
--- a/indra/newview/llpanelplaces.h
+++ b/indra/newview/llpanelplaces.h
@@ -97,6 +97,8 @@ class LLPanelPlaces : public LLPanel
 	void togglePickPanel(BOOL visible);
 	void togglePlaceInfoPanel(BOOL visible);
 
+	/*virtual*/ void handleVisibilityChange(BOOL new_visibility);
+
 	void updateVerbs();
 
 	LLPanelPlaceInfo* getCurrentInfoPanel();
diff --git a/indra/newview/llpanelprofileview.cpp b/indra/newview/llpanelprofileview.cpp
index 7832f63e6a698e9f8f302b6e00fde196043c97df..044036ea50e6b46d1d8437af0e2f619c71c998bd 100644
--- a/indra/newview/llpanelprofileview.cpp
+++ b/indra/newview/llpanelprofileview.cpp
@@ -101,8 +101,6 @@ void LLPanelProfileView::onOpen(const LLSD& key)
 		id = key["id"];
 	}
 
-	// subscribe observer to get online status. Request will be sent by LLPanelAvatarProfile itself
-	mAvatarStatusObserver->subscribe();
 	if(id.notNull() && getAvatarId() != id)
 	{
 		setAvatarId(id);
@@ -111,12 +109,9 @@ void LLPanelProfileView::onOpen(const LLSD& key)
 	// Update the avatar name.
 	gCacheName->get(getAvatarId(), FALSE,
 		boost::bind(&LLPanelProfileView::onAvatarNameCached, this, _1, _2, _3, _4));
-/*
-// disable this part of code according to EXT-2022. See processOnlineStatus
-	// status should only show if viewer has permission to view online/offline. EXT-453 
-	mStatusText->setVisible(isGrantedToSeeOnlineStatus());
+
 	updateOnlineStatus();
-*/
+
 
 	LLPanelProfile::onOpen(key);
 }
@@ -164,27 +159,43 @@ bool LLPanelProfileView::isGrantedToSeeOnlineStatus()
 	// *NOTE: GRANT_ONLINE_STATUS is always set to false while changing any other status.
 	// When avatar disallow me to see her online status processOfflineNotification Message is received by the viewer
 	// see comments for ChangeUserRights template message. EXT-453.
-//	return relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS);
-	return true;
+	// If GRANT_ONLINE_STATUS flag is changed it will be applied when viewer restarts. EXT-3880
+	return relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS);
 }
 
+// method was disabled according to EXT-2022. Re-enabled & improved according to EXT-3880
 void LLPanelProfileView::updateOnlineStatus()
 {
+	// set text box visible to show online status for non-friends who has not set in Preferences
+	// "Only Friends & Groups can see when I am online"
+	mStatusText->setVisible(TRUE);
+
 	const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId());
 	if (NULL == relationship)
-		return;
+	{
+		// this is non-friend avatar. Status will be updated from LLAvatarPropertiesProcessor.
+		// in LLPanelProfileView::processOnlineStatus()
 
-	bool online = relationship->isOnline();
+		// subscribe observer to get online status. Request will be sent by LLPanelAvatarProfile itself.
+		// do not subscribe for friend avatar because online status can be wrong overridden
+		// via LLAvatarData::flags if Preferences: "Only Friends & Groups can see when I am online" is set.
+		mAvatarStatusObserver->subscribe();
+		return;
+	}
+	// For friend let check if he allowed me to see his status
 
-	std::string status = getString(online ? "status_online" : "status_offline");
+	// status should only show if viewer has permission to view online/offline. EXT-453, EXT-3880
+	mStatusText->setVisible(isGrantedToSeeOnlineStatus());
 
-	mStatusText->setValue(status);
+	bool online = relationship->isOnline();
+	processOnlineStatus(online);
 }
 
 void LLPanelProfileView::processOnlineStatus(bool online)
 {
-	mAvatarIsOnline = online;
-	mStatusText->setVisible(online);
+	std::string status = getString(online ? "status_online" : "status_offline");
+
+	mStatusText->setValue(status);
 }
 
 void LLPanelProfileView::onAvatarNameCached(const LLUUID& id, const std::string& first_name, const std::string& last_name, BOOL is_group)
@@ -193,17 +204,4 @@ void LLPanelProfileView::onAvatarNameCached(const LLUUID& id, const std::string&
 	getChild<LLUICtrl>("user_name", FALSE)->setValue(first_name + " " + last_name);
 }
 
-void LLPanelProfileView::togglePanel(LLPanel* panel, const LLSD& key)
-{
-	// *TODO: unused method?
-
-	LLPanelProfile::togglePanel(panel);
-	if(FALSE == panel->getVisible())
-	{
-		// LLPanelProfile::togglePanel shows/hides all children,
-		// we don't want to display online status for non friends, so re-hide it here
-		mStatusText->setVisible(mAvatarIsOnline);
-	}
-}
-
 // EOF
diff --git a/indra/newview/llpanelprofileview.h b/indra/newview/llpanelprofileview.h
index 5dc617d4a04e568b04a3f81114f8e4c2c2f59a6a..9b87e146a86a4b10f8c1a2b7d669d19232250f14 100644
--- a/indra/newview/llpanelprofileview.h
+++ b/indra/newview/llpanelprofileview.h
@@ -64,8 +64,6 @@ class LLPanelProfileView : public LLPanelProfile
 	
 	/*virtual*/ BOOL postBuild();
 
-	/*virtual*/ void togglePanel(LLPanel* panel, const LLSD& key = LLSD());
-
 	BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
 						   BOOL drop, EDragAndDropType cargo_type,
 						   void *cargo_data, EAcceptance *accept,
@@ -81,8 +79,21 @@ class LLPanelProfileView : public LLPanelProfile
 protected:
 
 	void onBackBtnClick();
-	bool isGrantedToSeeOnlineStatus(); // deprecated after EXT-2022 is implemented
-	void updateOnlineStatus(); // deprecated after EXT-2022 is implemented
+	bool isGrantedToSeeOnlineStatus();
+
+	/**
+	 * Displays avatar's online status if possible.
+	 *
+	 * Requirements from EXT-3880:
+	 * For friends:
+	 * - Online when online and privacy settings allow to show
+	 * - Offline when offline and privacy settings allow to show
+	 * - Else: nothing
+	 * For other avatars:
+	 *  - Online when online and was not set in Preferences/"Only Friends & Groups can see when I am online"
+	 *  - Else: Offline
+	 */
+	void updateOnlineStatus();
 	void processOnlineStatus(bool online);
 
 private:
@@ -96,7 +107,6 @@ class LLPanelProfileView : public LLPanelProfile
 
 	LLTextBox* mStatusText;
 	AvatarStatusObserver* mAvatarStatusObserver;
-	bool mAvatarIsOnline;
 };
 
 #endif //LL_LLPANELPROFILEVIEW_H
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 88b706fb6bf9aab3c7ab9cb99a214f5dc70cb6d9..c0302eee9e0fce6005bf5a400f7269d881644b06 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -628,7 +628,7 @@ bool LLParticipantList::LLParticipantListMenu::enableContextMenuItem(const LLSD&
 	}
 	else if (item == "can_call")
 	{
-		return LLVoiceClient::voiceEnabled();
+		return LLVoiceClient::voiceEnabled()&&gVoiceClient->voiceWorking();
 	}
 
 	return true;
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 9c4825763bf50ff0e9801e4a8c5038b221acfc50..2b846d33fcdf408b322616c101363246506ab363 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -1103,7 +1103,10 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
 	{
 		if (op == TEXTURE_CANCEL)
 			mViewModel->resetDirty();
-		else
+		// If the "no_commit_on_selection" parameter is set
+		// we get dirty only when user presses OK in the picker
+		// (i.e. op == TEXTURE_SELECT) or texture changes via DnD.
+		else if (mCommitOnSelection || op == TEXTURE_SELECT)
 			mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
 			
 		if( floaterp->isDirty() )
@@ -1125,7 +1128,7 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op)
 			{
 				// If the "no_commit_on_selection" parameter is set
 				// we commit only when user presses OK in the picker
-				// (i.e. op == TEXTURE_SELECT) or changes texture via DnD.
+				// (i.e. op == TEXTURE_SELECT) or texture changes via DnD.
 				if (mCommitOnSelection || op == TEXTURE_SELECT)
 					onCommit();
 			}
@@ -1165,6 +1168,9 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
 		{
 			if(doDrop(item))
 			{
+				if (!mCommitOnSelection)
+					mViewModel->setDirty();
+
 				// This removes the 'Multiple' overlay, since
 				// there is now only one texture selected.
 				setTentative( FALSE ); 
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index 023329a9b2c2b5a5712f53c61799a8561c31ace9..8ca92c3d874f6423cc3f85edead2263092cfbd6a 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -74,7 +74,8 @@ class LLTextureCtrl
 		Optional<std::string>	default_image_name;
 		Optional<bool>			allow_no_texture;
 		Optional<bool>			can_apply_immediately;
-		Optional<bool>			no_commit_on_selection; // don't commit unless it's DnD or OK button press
+		Optional<bool>			no_commit_on_selection; // alternative mode: commit occurs and the widget gets dirty
+														// only on DnD or when OK is pressed in the picker
 		Optional<S32>			label_width;
 		Optional<LLUIColor>		border_color;
 		
diff --git a/indra/newview/lltransientdockablefloater.cpp b/indra/newview/lltransientdockablefloater.cpp
index c9bfe178ce430a3e417e0feaa32541dc3cd05011..9d39aa518241a760acecd38d9f60bb4b60ae5f6a 100644
--- a/indra/newview/lltransientdockablefloater.cpp
+++ b/indra/newview/lltransientdockablefloater.cpp
@@ -48,6 +48,14 @@ LLTransientDockableFloater::LLTransientDockableFloater(LLDockControl* dockContro
 LLTransientDockableFloater::~LLTransientDockableFloater()
 {
 	LLTransientFloaterMgr::getInstance()->unregisterTransientFloater(this);
+	LLView* dock = getDockWidget();
+	LLTransientFloaterMgr::getInstance()->removeControlView(
+			LLTransientFloaterMgr::DOCKED, this);
+	if (dock != NULL)
+	{
+		LLTransientFloaterMgr::getInstance()->removeControlView(
+				LLTransientFloaterMgr::DOCKED, dock);
+	}
 }
 
 void LLTransientDockableFloater::setVisible(BOOL visible)
@@ -55,18 +63,18 @@ void LLTransientDockableFloater::setVisible(BOOL visible)
 	LLView* dock = getDockWidget();
 	if(visible && isDocked())
 	{
-		LLTransientFloaterMgr::getInstance()->addControlView(this);
+		LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::DOCKED, this);
 		if (dock != NULL)
 		{
-			LLTransientFloaterMgr::getInstance()->addControlView(dock);
+			LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::DOCKED, dock);
 		}
 	}
 	else
 	{
-		LLTransientFloaterMgr::getInstance()->removeControlView(this);
+		LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::DOCKED, this);
 		if (dock != NULL)
 		{
-			LLTransientFloaterMgr::getInstance()->removeControlView(dock);
+			LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::DOCKED, dock);
 		}
 	}
 
@@ -78,18 +86,18 @@ void LLTransientDockableFloater::setDocked(bool docked, bool pop_on_undock)
 	LLView* dock = getDockWidget();
 	if(docked)
 	{
-		LLTransientFloaterMgr::getInstance()->addControlView(this);
+		LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::DOCKED, this);
 		if (dock != NULL)
 		{
-			LLTransientFloaterMgr::getInstance()->addControlView(dock);
+			LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::DOCKED, dock);
 		}
 	}
 	else
 	{
-		LLTransientFloaterMgr::getInstance()->removeControlView(this);
+		LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::DOCKED, this);
 		if (dock != NULL)
 		{
-			LLTransientFloaterMgr::getInstance()->removeControlView(dock);
+			LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::DOCKED, dock);
 		}
 	}
 
diff --git a/indra/newview/lltransientfloatermgr.cpp b/indra/newview/lltransientfloatermgr.cpp
index 8f1a738453f996e81bbe71b1a53248ecb4ff1402..d82403070bee8188f068bf2217cb3a19dd6386a8 100644
--- a/indra/newview/lltransientfloatermgr.cpp
+++ b/indra/newview/lltransientfloatermgr.cpp
@@ -46,6 +46,7 @@ LLTransientFloaterMgr::LLTransientFloaterMgr()
 			&LLTransientFloaterMgr::leftMouseClickCallback, this, _1, _2, _3));
 
 	mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(GLOBAL, std::set<LLView*>()));
+	mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(DOCKED, std::set<LLView*>()));
 	mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(IM, std::set<LLView*>()));
 }
 
@@ -132,7 +133,8 @@ void LLTransientFloaterMgr::leftMouseClickCallback(S32 x, S32 y,
 		return;
 	}
 
-	bool hide = isControlClicked(mGroupControls.find(GLOBAL)->second, x, y);
+	bool hide = isControlClicked(mGroupControls.find(DOCKED)->second, x, y)
+			&& isControlClicked(mGroupControls.find(GLOBAL)->second, x, y);
 	if (hide)
 	{
 		hideTransientFloaters(x, y);
diff --git a/indra/newview/lltransientfloatermgr.h b/indra/newview/lltransientfloatermgr.h
index 1f99325a7fb98f4d1fb388d8009b8426ff1f788e..9c5ae295f28f379ad3575a19b11acbfb8d115240 100644
--- a/indra/newview/lltransientfloatermgr.h
+++ b/indra/newview/lltransientfloatermgr.h
@@ -51,7 +51,7 @@ class LLTransientFloaterMgr: public LLSingleton<LLTransientFloaterMgr>
 public:
 	enum ETransientGroup
 	{
-		GLOBAL, IM
+		GLOBAL, DOCKED, IM
 	};
 
 	void registerTransientFloater(LLTransientFloater* floater);
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 7487fa99972184c00367f28cb3bd9c934aab4632..0358efc0afd66f54dd279f3294ed4983f2d124d1 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1472,7 +1472,12 @@ void inventory_offer_handler(LLOfferInfo* info)
 	{
 		LLStringUtil::truncate(msg, indx);
 	}
-	
+
+	if(LLAssetType::AT_LANDMARK == info->mType)
+	{
+		msg = LLViewerInventoryItem::getDisplayName(msg);
+	}
+
 	LLSD args;
 	args["[OBJECTNAME]"] = msg;
 
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index c84afa5af12a2fba3299441e8ca3395a58050ffd..e52d6a089bdbd51b7b7d0a11ecba817ae68b0af5 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -5853,6 +5853,11 @@ bool LLVoiceClient::voiceEnabled()
 	return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice");
 }
 
+bool LLVoiceClient::voiceWorking()
+{
+	return (stateLoggedIn <= mState) && (mState <= stateLeavingSession);
+}
+
 void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
 {
 	mLipSyncEnabled = enabled;
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 6231c6ba29f47b3bb92090a2d93ba986779bd32a..8f668dff196973b6e76d1f671993f90e4a1548ad 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -191,6 +191,8 @@ static	void updatePosition(void);
 		void inputUserControlState(bool down); // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
 		void setVoiceEnabled(bool enabled);
 		static bool voiceEnabled();
+		// Checks is voice working judging from mState
+		bool voiceWorking();
 		void setUsePTT(bool usePTT);
 		void setPTTIsToggle(bool PTTIsToggle);
 		bool getPTTIsToggle();
diff --git a/indra/newview/skins/default/xui/en/favorites_bar_button.xml b/indra/newview/skins/default/xui/en/favorites_bar_button.xml
index 6adf2a595002ae9e360212d9adedc7d516c9d98d..b365040c2028838ef583991af18a8a06d0ddbfcf 100644
--- a/indra/newview/skins/default/xui/en/favorites_bar_button.xml
+++ b/indra/newview/skins/default/xui/en/favorites_bar_button.xml
@@ -10,6 +10,8 @@
  image_selected="transparent.j2c"
  image_unselected="transparent.j2c"
  image_pressed="Favorite_Link_Over"
+ image_hover_selected="Favorite_Link_Over"
+ image_hover_unselected="Favorite_Link_Over"
  hover_glow_amount="0.15"
  label_shadow="false"
  layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index 613530b7aa9bd922303ba88dd83b692cd60ffc1d..d2e54731573870fe48dfb4261048a507f01aadb1 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -11,7 +11,7 @@
  can_dock="false"
  can_minimize="true"
  can_close="true"
- visible="true"
+ visible="false"
  width="360"
  can_resize="true"
  min_width="250"
diff --git a/indra/newview/skins/default/xui/en/floater_voice_controls.xml b/indra/newview/skins/default/xui/en/floater_voice_controls.xml
index f473a51ff6da4ea5b7c202749e7cf153e0243a84..c4411db8c5b6a798ed3514bd81b5a023c64f73ee 100644
--- a/indra/newview/skins/default/xui/en/floater_voice_controls.xml
+++ b/indra/newview/skins/default/xui/en/floater_voice_controls.xml
@@ -56,7 +56,7 @@
              height="18"
              default_icon_name="Generic_Person"
              layout="topleft"
-             left="0"
+             left="5"
              name="user_icon"
              top="0"
              width="18" />
@@ -78,6 +78,7 @@
              follows="top|right"
              height="16"
              layout="topleft"
+             right="-3"
              name="speaking_indicator"
              left_pad="5"
              visible="true"
diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
index 615ade99a2bcbe90456786b8ffb25df48f6f2900..c605975c8e17db5fc7b0540b4953e8b57f7c62b8 100644
--- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
@@ -65,28 +65,18 @@
      height="15"
      layout="topleft"
      left_pad="5"
+     right="-72"
      name="last_interaction"
      text_color="LtGray_50"
      value="0s"
      width="24" />
-    <output_monitor
-     auto_update="true"
-     follows="right"
-     draw_border="false"
-     height="16"
-     layout="topleft"
-     left_pad="5"
-     mouse_opaque="true"
-     name="speaking_indicator"
-     visible="true"
-     width="20" />
     <button
      follows="right"
      height="16"
      image_pressed="Info_Press"
      image_unselected="Info_Over"
      left_pad="3"
-     right="-31"
+     right="-53"
      name="info_btn"
      top_delta="-2"
      width="16" />
@@ -96,9 +86,21 @@
      image_overlay="ForwardArrow_Off"
      layout="topleft"
      left_pad="5"
-     right="-3"
+     right="-28"
      name="profile_btn"
      tool_tip="View profile"
      top_delta="-2"
      width="20" />
+    <output_monitor
+     auto_update="true"
+     follows="right"
+     draw_border="false"
+     height="16"
+     layout="topleft"
+     left_pad="5"
+     right="-3"
+     mouse_opaque="true"
+     name="speaking_indicator"
+     visible="true"
+     width="20" />
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
index de3de45718873d2edeccc035c55156af580b60e8..38e9219b5be8a7f8397a327373101b1707750b60 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
@@ -418,7 +418,6 @@ image_pressed_selected  "Lit" + "Selected" - there are new messages and the Well
                name="Unread"
                image_overlay="Notices_Unread"
                image_overlay_alignment="center"
-               pad_right="15"
                tool_tip="Notifications"
                width="35" >
                   <button.init_callback
diff --git a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
index 673052c3b5d9d043ed04e58bef33efcd702585af..0893c204e76c44a8896eed0ec25bb8015adb679d 100644
--- a/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_info_sidetray.xml
@@ -67,6 +67,7 @@ background_visible="true"
      layout="topleft"
      left="20"
      name="insignia"
+     no_commit_on_selection="true"
      tool_tip="Click to choose a picture"
      top_pad="5"
      width="100" />
diff --git a/indra/newview/skins/default/xui/en/panel_my_profile.xml b/indra/newview/skins/default/xui/en/panel_my_profile.xml
index 34cde61252ce77e2fad1587b6dc45261014205b7..4894ae01da5e2fd0d99c81cd2eaa26450cde67a8 100644
--- a/indra/newview/skins/default/xui/en/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <panel
  follows="all"
- height="535"
+ height="500"
  label="Profile"
  layout="topleft"
  left="0"
@@ -41,7 +41,7 @@
      layout="topleft"
      left="0"
      top="0"
-     height="535"
+     height="480"
      width="313"
      border_size="0">
       <layout_panel
@@ -50,7 +50,7 @@
          layout="topleft"
          top="0"
          left="0"
-         height="505"
+         height="480"
          user_resize="false"
          width="313">
         <scroll_container
@@ -60,7 +60,7 @@
          left="0"
          name="profile_scroll"
          opaque="true"
-         height="505"
+         height="480"
          width="313"
          top="0">
           <panel
@@ -374,8 +374,9 @@
          follows="bottom|right"
          height="23"
          left="20"
-	 top="0"
+	 top="5"
          label="Edit Profile"
+         layout="topleft"
          name="edit_profile_btn"
          tool_tip="Edit your personal information"
          width="130" />
@@ -384,7 +385,9 @@
          height="23"
          label="Edit Appearance"
          left_pad="10"
+         layout="topleft"
          name="edit_appearance_btn"
+         top="5"
          tool_tip="Create/edit your appearance: physical data, clothes and etc."
          width="130" />
  </layout_panel>