diff --git a/.hgtags b/.hgtags
index 3d1be7a97fc2a589de4674ac294b08be155d038c..1f2da5c852023e74e0def89136a872a2cdc5380f 100644
--- a/.hgtags
+++ b/.hgtags
@@ -429,3 +429,4 @@ f6ca5bb75bca975ff0bc77e71e615f6478c4559c 3.5.0-beta3
 53cffdde0b3cc367ba9bb6abd5c83ae14df5e882 3.5.0-beta4
 4d5f6234dc59a0fb6ead5e02c7d343a0610e0488 DRTVWR-304
 dd058a6093c493120d67c8e02c812c0f7b2d3db0 3.5.0-beta5
+fd6b510e83f56830e45670c428653134899d3e25 DRTVWR-305
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 8b9fb47d5ce799a3a6a90f26e5915cd76b22c6fa..7f04c92b27c07ad7da55d8dc2915671d68fefb64 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1801,6 +1801,9 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
 			// (N.B. callbacks don't take const refs as id is local scope)
 			bool is_group = (mContextMenuType == MENU_GROUP);
 			LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+			registrar.add("Url.ShowProfile", boost::bind(&LLScrollListCtrl::showProfile, id, is_group));
+			registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id));
+			registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id));
 			registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group));
 			registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group));
 			registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group));
@@ -1821,11 +1824,33 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
 	return FALSE;
 }
 
-void LLScrollListCtrl::showNameDetails(std::string id, bool is_group)
+void LLScrollListCtrl::showProfile(std::string id, bool is_group)
 {
 	// show the resident's profile or the group profile
 	std::string sltype = is_group ? "group" : "agent";
 	std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about";
+	LLUrlAction::showProfile(slurl);
+}
+
+void LLScrollListCtrl::sendIM(std::string id)
+{
+	// send im to the resident
+	std::string slurl = "secondlife:///app/agent/" + id + "/about";
+	LLUrlAction::sendIM(slurl);
+}
+
+void LLScrollListCtrl::addFriend(std::string id)
+{
+	// add resident to friends list
+	std::string slurl = "secondlife:///app/agent/" + id + "/about";
+	LLUrlAction::addFriend(slurl);
+}
+
+void LLScrollListCtrl::showNameDetails(std::string id, bool is_group)
+{
+	// open the resident's details or the group details
+	std::string sltype = is_group ? "group" : "agent";
+	std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about";
 	LLUrlAction::clickAction(slurl);
 }
 
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index 38450b6313baa4a330e516f1b554e9dc65607ef6..8fa06cc49945016319424c4ddb494fb40a59413f 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -430,6 +430,9 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler,
 	BOOL			setSort(S32 column, BOOL ascending);
 	S32				getLinesPerPage();
 
+	static void		showProfile(std::string id, bool is_group);
+	static void		sendIM(std::string id);
+	static void		addFriend(std::string id);
 	static void		showNameDetails(std::string id, bool is_group);
 	static void		copyNameToClipboard(std::string id, bool is_group);
 	static void		copySLURLToClipboard(std::string id, bool is_group);
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index ebc9ee244e7131733c1e5372629bbfa9f63c97a7..270d5294f9f8076ae25b2c32ed1f918de5f4f09b 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -3201,7 +3201,23 @@ S32	LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
 	LLFontGL::EWordWrapStyle word_wrap_style = (line_offset == 0) 
 		? LLFontGL::WORD_BOUNDARY_IF_POSSIBLE 
 		: LLFontGL::ONLY_WORD_BOUNDARIES;
-	S32 num_chars = mStyle->getFont()->maxDrawableChars(text.c_str() + segment_offset + mStart, 
+	
+	
+	LLWString offsetString(text.c_str() + segment_offset + mStart);
+
+	if(getLength() < segment_offset + mStart)
+	{
+		llerrs << "getLength() < segment_offset + mStart\t getLength()\t" << getLength() << "\tsegment_offset:\t" 
+						<< segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << "\tmax_chars\t" << max_chars << llendl;
+	}
+
+	if(offsetString.length() + 1 < max_chars)
+	{
+		llerrs << "offsetString.length() + 1 < max_chars\t max_chars:\t" << max_chars << "\toffsetString.length():\t" << offsetString.length()
+			<< getLength() << "\tsegment_offset:\t" << segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << llendl;
+	}
+	
+	S32 num_chars = mStyle->getFont()->maxDrawableChars(offsetString.c_str(), 
 												(F32)num_pixels,
 												max_chars, 
 												word_wrap_style);
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index ada374f892d7e500a2c527e4bccf18885f8ab0b4..590f41283b68eb9d94c04af1ae5c00dae70c77a0 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -292,6 +292,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>NearbyChatIsNotCollapsed</key>
+    <map>
+      <key>Comment</key>
+      <string>Saving expanded/collapsed state of the nearby chat between sessions</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>ShowFavoritesOnLogin</key>
         <map>
         <key>Comment</key>
diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp
index b221daf9365283c724366b9551b2b0c5419ff39c..43c6b558bc920e7d6cd7199a7fac6e5eb2fc3881 100644
--- a/indra/newview/llchiclet.cpp
+++ b/indra/newview/llchiclet.cpp
@@ -174,6 +174,7 @@ void LLNotificationChiclet::onMenuItemClicked(const LLSD& user_data)
 	if("close all" == action)
 	{
 		LLNotificationWellWindow::getInstance()->closeAll();
+		LLIMWellWindow::getInstance()->closeAll();
 	}
 }
 
diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp
index be20adeb8a10f647ce7cd675ac584da1e667fbbe..82affcf06885211ab1385ce084de6a73333ebe0e 100644
--- a/indra/newview/lldonotdisturbnotificationstorage.cpp
+++ b/indra/newview/lldonotdisturbnotificationstorage.cpp
@@ -132,6 +132,8 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
 {
 	LLFastTimer _(FTM_LOAD_DND_NOTIFICATIONS);
 	
+	LL_INFOS("LLDoNotDisturbNotificationStorage") << "start loading notifications" << LL_ENDL;
+
 	LLSD input;
 	if (!readNotifications(input) ||input.isUndefined())
 	{
@@ -225,6 +227,8 @@ void LLDoNotDisturbNotificationStorage::loadNotifications()
 
     //writes out empty .xml file (since LLCommunicationChannel::mHistory is empty)
 	saveNotifications();
+
+	LL_INFOS("LLDoNotDisturbNotificationStorage") << "finished loading notifications" << LL_ENDL;
 }
 
 void LLDoNotDisturbNotificationStorage::updateNotifications()
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 5e0cd8ef78ce35989e3519bfdce18077fb067892..7296ec3cedadf17b12a498628b06895c1a7d2e59 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -626,6 +626,12 @@ void LLFloaterIMContainer::setVisible(BOOL visible)
 	LLMultiFloater::setVisible(visible);
 }
 
+void LLFloaterIMContainer::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key)
+{
+	LLMultiFloater::setVisibleAndFrontmost(take_focus, key);
+    selectConversationPair(getSelectedSession(), false, take_focus);
+}
+
 void LLFloaterIMContainer::updateResizeLimits()
 {
 	LLMultiFloater::updateResizeLimits();
@@ -1331,7 +1337,10 @@ void LLFloaterIMContainer::showConversation(const LLUUID& session_id)
     selectConversationPair(session_id, true);
 
     LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::findConversation(session_id);
-    session_floater->restoreFloater();
+    if (session_floater)
+    {
+        session_floater->restoreFloater();
+    }
 }
 
 void LLFloaterIMContainer::clearAllFlashStates()
@@ -1963,10 +1972,13 @@ bool LLFloaterIMContainer::selectNextorPreviousConversation(bool select_next, bo
 
 void LLFloaterIMContainer::expandConversation()
 {
-	LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(get_ptr_in_map(mConversationsWidgets,getSelectedSession()));
-	if (widget)
+	if(!mConversationsPane->isCollapsed())
 	{
-		widget->setOpen(!widget->isOpen());
+		LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(get_ptr_in_map(mConversationsWidgets,getSelectedSession()));
+		if (widget)
+		{
+			widget->setOpen(!widget->isOpen());
+		}
 	}
 }
 
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index 2cbc1e99f9a511217450eee0d8269f36959998c5..52b672241f614b1539de3f56597ef581aea8118e 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -60,6 +60,7 @@ class LLFloaterIMContainer
 	/*virtual*/ void onOpen(const LLSD& key);
 	/*virtual*/ void draw();
 	/*virtual*/ void setVisible(BOOL visible);
+	/*virtual*/ void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
 	/*virtual*/ void updateResizeLimits();
 	void onCloseFloater(LLUUID& id);
 
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index b287950c21979f856b0b14c07d0ae0c39ed03bb8..d86e1b3fd7a52a4bbe913473e2c1be07dc8d01fe 100644
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -283,6 +283,11 @@ void LLFloaterIMNearbyChat::onTearOffClicked()
 void LLFloaterIMNearbyChat::onOpen(const LLSD& key)
 {
 	LLFloaterIMSessionTab::onOpen(key);
+	if(!isMessagePaneExpanded())
+	{
+		restoreFloater();
+		onCollapseToLine(this);
+	}
 	showTranslationCheckbox(LLTranslate::isTranslationConfigured());
 }
 
@@ -322,11 +327,8 @@ void LLFloaterIMNearbyChat::onChatFontChange(LLFontGL* fontp)
 
 void LLFloaterIMNearbyChat::show()
 {
-	if (isChatMultiTab())
-	{
 		openFloater(getKey());
 	}
-}
 
 bool LLFloaterIMNearbyChat::isChatVisible() const
 {
@@ -480,11 +482,14 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke()
 		if (LLGestureMgr::instance().matchPrefix(utf8_trigger, &utf8_out_str))
 		{
 			std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
-			mInputEditor->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part
+			if (!rest_of_match.empty())
+			{
+				mInputEditor->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part
 
-			// Select to end of line, starting from the character
-			// after the last one the user typed.
-			mInputEditor->selectNext(rest_of_match, false);
+				// Select to end of line, starting from the character
+				// after the last one the user typed.
+				mInputEditor->selectNext(rest_of_match, false);
+			}
 		}
 		else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str))
 		{
@@ -741,15 +746,14 @@ void LLFloaterIMNearbyChat::startChat(const char* line)
 	{
 		if(!nearby_chat->isTornOff())
 		{
-			nearby_chat->show();
+			LLFloaterIMContainer::getInstance()->selectConversation(LLUUID(NULL));
 		}
 		if(nearby_chat->isMinimized())
 		{
 			nearby_chat->setMinimized(false);
 		}
-		nearby_chat->setVisible(TRUE);
+		nearby_chat->show();
 		nearby_chat->setFocus(TRUE);
-		nearby_chat->mInputEditor->setFocus(TRUE);
 
 		if (line)
 		{
diff --git a/indra/newview/llfloaterimnearbychathandler.cpp b/indra/newview/llfloaterimnearbychathandler.cpp
index 7afcf288ce55445b75133ff726d63c225e4f3340..0824b2640609b5a0e0037f72c0b51cc24c76b132 100644
--- a/indra/newview/llfloaterimnearbychathandler.cpp
+++ b/indra/newview/llfloaterimnearbychathandler.cpp
@@ -559,9 +559,7 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
 
     LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
 
-	if(( nearby_chat->hasFocus()
-        || im_box->hasFocus()
-		|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
+	if((  ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
 			&& gSavedSettings.getBOOL("UseChatBubbles") )
 		|| mChannel.isDead()
 		|| !mChannel.get()->getShowToasts() )
@@ -606,17 +604,16 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
 			toast_msg = chat_msg.mText;
 		}
 
-		//Don't show nearby toast, if conversation is visible but not focused
-		LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(LLUUID());
-		if (session_floater && session_floater->isMessagePaneExpanded()
-		    && session_floater->isInVisibleChain() && !session_floater->isMinimized()
-		    && !(session_floater->getHost() && session_floater->getHost()->isMinimized()))
+		//Don't show nearby toast, if conversation is visible and selected
+		if (im_box->getSelectedSession().isNull() &&
+				((LLFloater::isVisible(im_box) && !im_box->isMinimized() && im_box->isFrontmost())
+						|| (LLFloater::isVisible(nearby_chat) && !nearby_chat->isMinimized() && nearby_chat->isFrontmost())))
 		{
 			return;
 		}
 
         //Will show toast when chat preference is set        
-        if((gSavedSettings.getString("NotificationNearbyChatOptions") == "toast") || !session_floater->isMessagePaneExpanded())
+        if((gSavedSettings.getString("NotificationNearbyChatOptions") == "toast") || !nearby_chat->isMessagePaneExpanded())
         {
             // Add a nearby chat toast.
             LLUUID id;
diff --git a/indra/newview/llfloaterimsession.cpp b/indra/newview/llfloaterimsession.cpp
index 73adfd0edaf24d125f75037cc1820f2ec6352349..6d5145f205fc754fb43f1a3c35b0dbbaa85c94ea 100644
--- a/indra/newview/llfloaterimsession.cpp
+++ b/indra/newview/llfloaterimsession.cpp
@@ -618,6 +618,8 @@ void LLFloaterIMSession::onClose(bool app_quitting)
 	// Last change:
 	// EXT-3516 X Button should end IM session, _ button should hide
 	gIMMgr->leaveSession(mSessionID);
+    // *TODO: Study why we need to restore the floater before we close it.
+    // Might be because we want to save some state data in some clean open state.
 	LLFloaterIMSessionTab::restoreFloater();
 	// Clean up the conversation *after* the session has been ended
 	LLFloaterIMSessionTab::onClose(app_quitting);
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index eab2ce7798cb11f3628455632b3956518f96b46b..5083331167d7ef17960f090a83929efeae310e81 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -132,6 +132,12 @@ void LLFloaterIMSessionTab::setVisible(BOOL visible)
 			LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container")->setVisible(true);
 		}
 		LLFloaterIMSessionTab::addToHost(mSessionID);
+		LLFloaterIMSessionTab* conversp = LLFloaterIMSessionTab::getConversation(mSessionID);
+
+		if (conversp && conversp->isNearbyChat() && gSavedPerAccountSettings.getBOOL("NearbyChatIsNotCollapsed"))
+		{
+			onCollapseToLine(this);
+		}
 		mInputButtonPanel->setVisible(isTornOff());
 	}
 
@@ -356,7 +362,7 @@ void LLFloaterIMSessionTab::draw()
 		// Restart the refresh timer
 		mRefreshTimer->setTimerExpirySec(REFRESH_INTERVAL);
 	}
-	
+
 	LLTransientDockableFloater::draw();
 }
 
@@ -698,10 +704,12 @@ void LLFloaterIMSessionTab::updateHeaderAndToolbar()
 			&& !mIsP2PChat;
 
 	mParticipantListAndHistoryStack->collapsePanel(mParticipantListPanel, !is_participant_list_visible);
+    mParticipantListPanel->setVisible(is_participant_list_visible);
 
 	// Display collapse image (<<) if the floater is hosted
 	// or if it is torn off but has an open control panel.
 	bool is_expanded = is_not_torn_off || is_participant_list_visible;
+    
 	mExpandCollapseBtn->setImageOverlay(getString(is_expanded ? "collapse_icon" : "expand_icon"));
 	mExpandCollapseBtn->setToolTip(
 			is_not_torn_off?
@@ -818,14 +826,15 @@ void LLFloaterIMSessionTab::onSlide(LLFloaterIMSessionTab* self)
 	{
 		if (!self->mIsP2PChat)
 		{
+            // The state must toggle the collapsed state of the panel
             bool should_be_expanded = self->mParticipantListPanel->isCollapsed();
 
-			// Expand/collapse the participant list panel
-            self->mParticipantListAndHistoryStack->collapsePanel(self->mParticipantListPanel, !should_be_expanded);
-            self->mParticipantListPanel->setVisible(should_be_expanded);
+			// Update the expand/collapse flag of the participant list panel and save it
             gSavedSettings.setBOOL("IMShowControlPanel", should_be_expanded);
             self->mIsParticipantListExpanded = should_be_expanded;
-			self->mExpandCollapseBtn->setImageOverlay(self->getString(should_be_expanded ? "collapse_icon" : "expand_icon"));
+            
+            // Refresh for immediate feedback
+            self->refreshConversation();
 		}
 	}
 
@@ -863,7 +872,7 @@ void LLFloaterIMSessionTab::reshapeFloater(bool collapse)
 		enableResizeCtrls(true, true, true);
 
 	}
-
+	saveCollapsedState();
 	setShape(floater_rect, true);
 	mBodyStack->updateLayout();
 
@@ -885,6 +894,7 @@ void LLFloaterIMSessionTab::restoreFloater()
 		mBodyStack->updateLayout();
 		mExpandCollapseLineBtn->setImageOverlay(getString("expandline_icon"));
 		setMessagePaneExpanded(true);
+		saveCollapsedState();
 		enableResizeCtrls(true, true, true);
 	}
 }
@@ -1060,6 +1070,14 @@ LLConversationItem* LLFloaterIMSessionTab::getCurSelectedViewModelItem()
 	return conversationItem;
 }
 
+void LLFloaterIMSessionTab::saveCollapsedState()
+{
+	LLFloaterIMSessionTab* conversp = LLFloaterIMSessionTab::getConversation(mSessionID);
+	if(conversp->isNearbyChat())
+	{
+		gSavedPerAccountSettings.setBOOL("NearbyChatIsNotCollapsed", isMessagePaneExpanded());
+	}
+}
 BOOL LLFloaterIMSessionTab::handleKeyHere(KEY key, MASK mask )
 {
 	if(mask == MASK_ALT)
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index f0899a3c0934ae0d1fa6ded9c02c18880c69efc4..c7e73bd70d2838c6eb245b15518adc0f6f208606 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -101,6 +101,7 @@ class LLFloaterIMSessionTab
 	bool isMessagePaneExpanded(){return mMessagePaneExpanded;}
 	void setMessagePaneExpanded(bool expanded){mMessagePaneExpanded = expanded;}
 	void restoreFloater();
+	void saveCollapsedState();
 
 protected:
 
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 8c862548bbc5ac2bdb3f986cd2c27200324722b3..76a314f8075e0a2ce7d928d9863a546a6c441173 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -160,163 +160,150 @@ static void on_avatar_name_cache_toast(const LLUUID& agent_id,
 
 void on_new_message(const LLSD& msg)
 {
-    std::string action;
+    std::string user_preferences;
     LLUUID participant_id = msg["from_id"].asUUID();
     LLUUID session_id = msg["session_id"].asUUID();
     LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
 
-    //  determine action for this session
+    // do not show notification which goes from agent
+    if (gAgent.getID() == participant_id)
+    {
+        return;
+    }
+
+    // determine state of conversations floater
+    enum {CLOSED, NOT_ON_TOP, ON_TOP, ON_TOP_AND_ITEM_IS_SELECTED} conversations_floater_status;
+
+    LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
+	LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id);
+
+	if (!LLFloater::isVisible(im_box) || im_box->isMinimized())
+	{
+		conversations_floater_status = CLOSED;
+	}
+	else if ( !im_box->hasFocus() &&
+			(!session_floater || !LLFloater::isVisible(session_floater)
+	            || session_floater->isMinimized() || !session_floater->hasFocus()))
+	{
+		conversations_floater_status = NOT_ON_TOP;
+	}
+	else if (im_box->getSelectedSession() != session_id)
+	{
+		conversations_floater_status = ON_TOP;
+    }
+	else
+	{
+		conversations_floater_status = ON_TOP_AND_ITEM_IS_SELECTED;
+	}
 
+    //  determine user prefs for this session
     if (session_id.isNull())
     {
-        action = gSavedSettings.getString("NotificationNearbyChatOptions");
+    	user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions");
     }
     else if(session->isP2PSessionType())
     {
         if (LLAvatarTracker::instance().isBuddy(participant_id))
         {
-            action = gSavedSettings.getString("NotificationFriendIMOptions");
+        	user_preferences = gSavedSettings.getString("NotificationFriendIMOptions");
         }
         else
         {
-            action = gSavedSettings.getString("NotificationNonFriendIMOptions");
+        	user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions");
         }
     }
     else if(session->isAdHocSessionType())
     {
-        action = gSavedSettings.getString("NotificationConferenceIMOptions");
+    	user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions");
     }
     else if(session->isGroupSessionType())
     {
-        action = gSavedSettings.getString("NotificationGroupChatOptions");
+    	user_preferences = gSavedSettings.getString("NotificationGroupChatOptions");
     }
 
-    // do not show notification which goes from agent
-    if (gAgent.getID() == participant_id)
-    {
-        return;
-    }
-
-    // execution of the action
-
-    LLFloaterIMContainer* im_box = LLFloaterReg::getTypedInstance<LLFloaterIMContainer>("im_container");
-	LLFloaterIMSessionTab* session_floater = LLFloaterIMSessionTab::getConversation(session_id);
-	
-	if (im_box->isFrontmost() && im_box->getSelectedSession() == session_id
-		&& !(session_floater->getHost() ? im_box->isMinimized() : session_floater->isMinimized()))
-	{
-		return;
-	}
-	
-    //session floater not focused (visible or not)
-    bool session_floater_not_focused = session_floater && !session_floater->hasFocus();
-
-    //conv. floater is closed
-    bool conversation_floater_is_closed =
-    		!(  im_box
-    		    && im_box->isInVisibleChain()
-                && !im_box->isMinimized());
-
-    //conversation floater not focused (visible or not)
-    bool conversation_floater_not_focused =
-    		conversation_floater_is_closed || !im_box->hasFocus();
-    // sess. floater is open
-    bool session_floater_is_open =
-            session_floater
-            && session_floater->isInVisibleChain()
-            && !session_floater->isMinimized()
-            && !(session_floater->getHost() && session_floater->getHost()->isMinimized());
-
-    bool conversation_floater_collapsed = !session_floater->isMessagePaneExpanded();
-    if (("toast" == action && !session_floater_is_open) || conversation_floater_collapsed)
-    {
-        //User is not focused on conversation containing the message
-        if(session_floater_not_focused || conversation_floater_collapsed)
-        {
-        	if(!LLMuteList::getInstance()->isMuted(participant_id))
-        	{
-        		im_box->flashConversationItemWidget(session_id, true);
-        	}
-            //The conversation floater isn't focused/open
-            if(conversation_floater_not_focused || conversation_floater_collapsed)
-            {
-            	if(!LLMuteList::getInstance()->isMuted(participant_id) 
-                    && !gAgent.isDoNotDisturb())
-            	{
-            		gToolBarView->flashCommand(LLCommandId("chat"), true);
-            	}
-
-                //Show IM toasts (upper right toasts)
-                // Skip toasting for system messages and for nearby chat
-                if(session_id.notNull() && participant_id.notNull())
-                {
-                    LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
-                }
-            }
-		}
-    }
+    // actions:
 
-    else if ("flash" == action)
+    // 0. nothing - exit
+    if (("none" == user_preferences ||
+    		ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status)
+    	&& session_floater->isMessagePaneExpanded())
     {
-    	if (!gAgent.isDoNotDisturb())
-    	{
-			im_box->flashConversationItemWidget(session_id, true);
-			if(conversation_floater_not_focused)
-			{
-				//User is not focused on conversation containing the message
-				gToolBarView->flashCommand(LLCommandId("chat"), true);
-			}
-		}
-		else if(session_id.notNull() && participant_id.notNull())
-		{
-			//If a DND message, allow notification to be stored so upon DND exit 
-			//useMostItrusiveIMNotification will be called to notify user a message exists
-			LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
-		}
+    	return;
     }
 
-    else if("openconversations" == action)
+    // 1. open floater and [optional] surface it
+    if ("openconversations" == user_preferences &&
+    		(CLOSED == conversations_floater_status
+    				|| NOT_ON_TOP == conversations_floater_status))
     {
-        //User is not focused on conversation containing the message
-        if(session_floater_not_focused)
+    	if(!gAgent.isDoNotDisturb())
         {
-            //Flash line item
-            im_box->flashConversationItemWidget(session_id, true);
-
-            if(!gAgent.isDoNotDisturb())
-            {
-				//Surface conversations floater
-				LLFloaterReg::showInstance("im_container");
-				im_box->collapseMessagesPane(false);
-				if (session_floater)
+			// Open conversations floater
+			LLFloaterReg::showInstance("im_container");
+			im_box->collapseMessagesPane(false);
+			if (session_floater)
+			{
+				if (session_floater->getHost())
 				{
-					if (session_floater->getHost())
+					if (NULL != im_box && im_box->isMinimized())
 					{
-						if (NULL != im_box && im_box->isMinimized())
-						{
-							LLFloater::onClickMinimize(im_box);
-						}
+						LLFloater::onClickMinimize(im_box);
 					}
-					else
+				}
+				else
+				{
+					if (session_floater->isMinimized())
 					{
-						if (session_floater->isMinimized())
-						{
-							LLFloater::onClickMinimize(session_floater);
-						}
+						LLFloater::onClickMinimize(session_floater);
 					}
 				}
 			}
-
-            //If in DND mode, allow notification to be stored so upon DND exit 
+		}
+        else
+        {
+            //If in DND mode, allow notification to be stored so upon DND exit
             //useMostItrusiveIMNotification will be called to notify user a message exists
-            if(session_id.notNull() 
-                && participant_id.notNull()
-                && gAgent.isDoNotDisturb()
-				&& !session_floater_is_open)
+            if(session_id.notNull()
+               && participant_id.notNull()
+		       && !session_floater->isShown())
             {
                 LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
-			}
-		}
+	        }
+        }
+    }
+
+    // 2. Flash line item
+    if ("openconversations" == user_preferences
+    		|| ON_TOP == conversations_floater_status)
+    {
+    	if(!LLMuteList::getInstance()->isMuted(participant_id))
+    	{
+    		im_box->flashConversationItemWidget(session_id, true);
+    	}
+    }
+
+    // 3. Flash FUI button
+    if (("toast" == user_preferences || "flash" == user_preferences) &&
+    		(CLOSED == conversations_floater_status
+    		    || NOT_ON_TOP == conversations_floater_status))
+    {
+    	if(!LLMuteList::getInstance()->isMuted(participant_id)
+            && !gAgent.isDoNotDisturb())
+    	{
+    		gToolBarView->flashCommand(LLCommandId("chat"), true);
+    	}
+    }
+
+    // 4. Toast
+    if ("toast" == user_preferences
+    		    || !session_floater->isMessagePaneExpanded())
+    {
+        //Show IM toasts (upper right toasts)
+        // Skip toasting for system messages and for nearby chat
+        if(session_id.notNull() && participant_id.notNull())
+        {
+            LLAvatarNameCache::get(participant_id, boost::bind(&on_avatar_name_cache_toast, _1, _2, msg));
+        }
     }
 }
 
diff --git a/indra/newview/llnotificationstorage.cpp b/indra/newview/llnotificationstorage.cpp
index b6184f09bfdf6c7f8e38da1290ba5fc42f637e0e..2923221c90787356742b9ad8ee66fa9ef7d86ccd 100644
--- a/indra/newview/llnotificationstorage.cpp
+++ b/indra/newview/llnotificationstorage.cpp
@@ -105,6 +105,8 @@ bool LLNotificationStorage::writeNotifications(const LLSD& pNotificationData) co
 
 bool LLNotificationStorage::readNotifications(LLSD& pNotificationData) const
 {
+	LL_INFOS("LLNotificationStorage") << "starting read '" << mFileName << "'" << LL_ENDL;
+
 	bool didFileRead;
 
 	pNotificationData.clear();
@@ -126,6 +128,8 @@ bool LLNotificationStorage::readNotifications(LLSD& pNotificationData) const
 		}
 	}
 
+	LL_INFOS("LLNotificationStorage") << "ending read '" << mFileName << "'" << LL_ENDL;
+
 	return didFileRead;
 }
 
diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp
index 11c12e6c107c1ae141467e98d922f0422e3fd713..666f10df964ae036a076594ff40117b903704796 100644
--- a/indra/newview/llpersistentnotificationstorage.cpp
+++ b/indra/newview/llpersistentnotificationstorage.cpp
@@ -87,6 +87,8 @@ void LLPersistentNotificationStorage::loadNotifications()
 {
 	LLFastTimer _(FTM_LOAD_NOTIFICATIONS);
 
+	LL_INFOS("LLPersistentNotificationStorage") << "start loading notifications" << LL_ENDL;
+
 	LLNotifications::instance().getChannel("Persistent")->
 		connectChanged(boost::bind(&LLPersistentNotificationStorage::onPersistentChannelChanged, this, _1));
 
@@ -129,6 +131,8 @@ void LLPersistentNotificationStorage::loadNotifications()
 			notification_channel->hideToast(notification->getID());
 		}
 	}
+
+	LL_INFOS("LLPersistentNotificationStorage") << "finished loading notifications" << LL_ENDL;
 }
 
 bool LLPersistentNotificationStorage::onPersistentChannelChanged(const LLSD& payload)
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index d295fc60cd2b8ce5af2ce6c1ee3dca68d9c7f2af..a3093f069dbb92ef4106b35f81b86b2bc1263f34 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -675,7 +675,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mBelowWater(FALSE),
 	mLastAppearanceBlendTime(0.f),
 	mAppearanceAnimating(FALSE),
-	mNameString(),
+    mNameIsSet(false),
 	mTitle(),
 	mNameAway(false),
 	mNameDoNotDisturb(false),
@@ -3096,8 +3096,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name)
 	}
 
 	// Rebuild name tag if state change detected
-	if (mNameString.empty()
-		|| (mNameString.size() == 2 && mNameString[0] == 10 && mNameString[1] == 10) // *TODO : find out why mNameString is sometimes ""
+	if (!mNameIsSet
 		|| new_name
 		|| (!title && !mTitle.empty())
 		|| (title && mTitle != title->getString())
@@ -3292,17 +3291,16 @@ void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color,
 	{
 		mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font);
 	}
-	mNameString += line;
-	mNameString += '\n';
+    mNameIsSet |= !line.empty();
 }
 
 void LLVOAvatar::clearNameTag()
 {
-	mNameString.clear();
+    mNameIsSet = false;
 	if (mNameText)
 	{
 		mNameText->setLabel("");
-		mNameText->setString( "" );
+		mNameText->setString("");
 	}
 	mTimeVisible.reset();
 }
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index c59a3a150c4ba57ba9510e7fceb2822743dfccd2..9f1f209920860b68609715a63fe23eaea514c1f1 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -939,7 +939,7 @@ class LLVOAvatar :
 	static void		getAnimLabels(LLDynamicArray<std::string>* labels);
 	static void		getAnimNames(LLDynamicArray<std::string>* names);	
 private:
-	std::string		mNameString;		// UTF-8 title + name + status
+    bool            mNameIsSet;
 	std::string  	mTitle;
 	bool	  		mNameAway;
 	bool	  		mNameDoNotDisturb;
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index f3342b7ff18bd07150802bef3faec719b828e9d1..c3cc90f040567c7c596c55e7e84825069427e6aa 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -1258,7 +1258,7 @@ void LLVivoxVoiceClient::stateMachine()
 		
 		//MARK: stateCreatingSessionGroup
 		case stateCreatingSessionGroup:
-			if(mSessionTerminateRequested || !mVoiceEnabled && mIsInitialized)
+			if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized))
 			{
 				// *TODO: Question: is this the right way out of this state
 				setState(stateSessionTerminated);
@@ -1274,7 +1274,7 @@ void LLVivoxVoiceClient::stateMachine()
 		//MARK: stateRetrievingParcelVoiceInfo
 		case stateRetrievingParcelVoiceInfo: 
 			// wait until parcel voice info is received.
-			if(mSessionTerminateRequested || !mVoiceEnabled && mIsInitialized)
+			if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized))
 			{
 				// if a terminate request has been received,
 				// bail and go to the stateSessionTerminated
@@ -1294,7 +1294,7 @@ void LLVivoxVoiceClient::stateMachine()
 			// Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync.
 			sendFriendsListUpdates();
 			
-			if(mSessionTerminateRequested || !mVoiceEnabled && mIsInitialized)
+			if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized))
 			{
 				// TODO: Question: Is this the right way out of this state?
 				setState(stateSessionTerminated);
@@ -1442,7 +1442,7 @@ void LLVivoxVoiceClient::stateMachine()
 		//MARK: stateRunning
 		case stateRunning:				// steady state
 			// Disabling voice or disconnect requested.
-			if(!mVoiceEnabled && mIsInitialized || mSessionTerminateRequested)
+			if((!mVoiceEnabled && mIsInitialized) || mSessionTerminateRequested)
 			{
 				leaveAudioSession();
 			}
@@ -2671,33 +2671,19 @@ void LLVivoxVoiceClient::checkFriend(const LLUUID& id)
 {
 	buddyListEntry *buddy = findBuddy(id);
 
-	// Make sure we don't add a name before it's been looked up.
+	// Make sure we don't add a name before it's been looked up in the avatar name cache
 	LLAvatarName av_name;
-	if(LLAvatarNameCache::get(id, &av_name))
+	if (LLAvatarNameCache::get(id, &av_name))
 	{
-		// *NOTE: For now, we feed legacy names to Vivox because I don't know
-		// if their service can support a mix of new and old clients with
-		// different sorts of names.
+		// *NOTE: We feed legacy names to Vivox because we don't know if their service
+		// can support a mix of new and old clients with different sorts of names.
 		std::string name = av_name.getAccountName();
-
-		const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id);
-		bool canSeeMeOnline = false;
-		if(relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS))
-			canSeeMeOnline = true;
-		
-		// When we get here, mNeedsSend is true and mInSLFriends is false.  Change them as necessary.
 		
-		if(buddy)
+		if (buddy)
 		{
-			// This buddy is already in both lists.
-
-			if(name != buddy->mDisplayName)
-			{
-				// The buddy is in the list with the wrong name.  Update it with the correct name.
-				LL_WARNS("Voice") << "Buddy " << id << " has wrong name (\"" << buddy->mDisplayName << "\" should be \"" << name << "\"), updating."<< LL_ENDL;
-				buddy->mDisplayName = name;
-				buddy->mNeedsNameUpdate = true;		// This will cause the buddy to be resent.
-			}
+			// This buddy is already in both lists (vivox buddies and avatar cache).
+            // Trust the avatar cache more for the display name (vivox display name are notoriously wrong)
+            buddy->mDisplayName = name;
 		}
 		else
 		{
@@ -2706,20 +2692,19 @@ void LLVivoxVoiceClient::checkFriend(const LLUUID& id)
 			buddy->mUUID = id;
 		}
 		
-		// In all the above cases, the buddy is in the SL friends list (which is how we got here).
-		buddy->mInSLFriends = true;
-		buddy->mCanSeeMeOnline = canSeeMeOnline;
+		const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id);
+		buddy->mCanSeeMeOnline = (relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS));
+		// In all the above cases, the buddy is in the SL friends list and tha name has been resolved (which is how we got here).
 		buddy->mNameResolved = true;
-		
+		buddy->mInSLFriends = true;
 	}
 	else
 	{
-		// This name hasn't been looked up yet.  Don't do anything with this buddy list entry until it has.
-		if(buddy)
+		// This name hasn't been looked up yet in the avatar cache. Don't do anything with this buddy list entry until it has.
+		if (buddy)
 		{
 			buddy->mNameResolved = false;
 		}
-		
 		// Initiate a lookup.
 		// The "lookup completed" callback will ensure that the friends list is rechecked after it completes.
 		lookupName(id);
@@ -2827,13 +2812,12 @@ void LLVivoxVoiceClient::sendFriendsListUpdates()
 			{
 				std::ostringstream stream;
 
-				if(buddy->mInSLFriends && (!buddy->mInVivoxBuddies || buddy->mNeedsNameUpdate))
+				if(buddy->mInSLFriends && !buddy->mInVivoxBuddies)
 				{					
 					if(mNumberOfAliases > 0)
 					{
 						// Add (or update) this entry in the vivox buddy list
 						buddy->mInVivoxBuddies = true;
-						buddy->mNeedsNameUpdate = false;
 						LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL;
 						stream 
 							<< "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Account.BuddySet.1\">"
@@ -5859,7 +5843,6 @@ LLVivoxVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) :
 	mNameResolved = false;
 	mInVivoxBuddies = false;
 	mInSLFriends = false;
-	mNeedsNameUpdate = false;
 }
 
 void LLVivoxVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName)
@@ -5884,25 +5867,21 @@ LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::stri
 	buddyListEntry *result = NULL;
 	buddyListMap::iterator iter = mBuddyListMap.find(uri);
 	
-	if(iter != mBuddyListMap.end())
+	if (iter != mBuddyListMap.end())
 	{
 		// Found a matching buddy already in the map.
 		LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL;
 		result = iter->second;
 	}
 
-	if(!result)
+	if (!result)
 	{
 		// participant isn't already in one list or the other.
 		LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL;
 		result = new buddyListEntry(uri);
 		result->mDisplayName = displayName;
 
-		if(IDFromName(uri, result->mUUID)) 
-		{
-			// Extracted UUID from name successfully.
-		}
-		else
+		if (!IDFromName(uri, result->mUUID))
 		{
 			LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL;
 		}
@@ -7272,7 +7251,7 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr)
 void LLVivoxProtocolParser::EndTag(const char *tag)
 {
 	const std::string& string = textBuffer;
-	
+
 	responseDepth--;
 	
 	if (ignoringTags)
@@ -7371,6 +7350,8 @@ void LLVivoxProtocolParser::EndTag(const char *tag)
 		}
 		else if (!stricmp("Buddy", tag))
 		{
+            // NOTE : Vivox does *not* give reliable display name for Buddy tags
+            // We don't take those very seriously as a result...
 			LLVivoxVoiceClient::getInstance()->processBuddyListEntry(uriString, displayNameString);
 		}
 		else if (!stricmp("BlockRule", tag))
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 574027de42eba7ed61a990cc93d635a1a80143c6..a6f40eb3e99d8e2adca4c5d08dd147a2a2cb8b4d 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -584,7 +584,6 @@ class LLVivoxVoiceClient :	public LLSingleton<LLVivoxVoiceClient>,
 		bool mNameResolved;
 		bool mInSLFriends;
 		bool mInVivoxBuddies;
-		bool mNeedsNameUpdate;
 	};
 
 	typedef std::map<std::string, buddyListEntry*> buddyListMap;